summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2018-04-24 10:48:39 -0700
committerSean Whitton <spwhitton@spwhitton.name>2018-04-24 10:48:39 -0700
commitde5ee82ed0e287ada3a5b272d8365a04fe8e9f95 (patch)
tree126c941f08f4d1e2775a694d4fd7f7c859b4b81b
parentabcbe3005117f90babc225ce958766845cf59d2b (diff)
parent5e6879dbf98eb5528c7f417b349118aadca40d71 (diff)
New upstream version 2.1.2~dfsg
-rw-r--r--AUTHORS.md197
-rw-r--r--CONTRIBUTING.md125
-rw-r--r--COPYRIGHT105
-rw-r--r--INSTALL.md147
-rw-r--r--MANUAL.txt2024
-rw-r--r--README.md273
-rw-r--r--Setup.hs55
-rw-r--r--benchmark/benchmark-pandoc.hs77
-rw-r--r--benchmark/weigh-pandoc.hs19
-rw-r--r--changelog3340
-rw-r--r--data/abbreviations50
-rw-r--r--data/bash_completion.tpl4
-rw-r--r--data/docx/[Content_Types].xml2
-rw-r--r--data/docx/docProps/core.xml2
-rw-r--r--data/docx/word/_rels/document.xml.rels2
-rw-r--r--data/docx/word/_rels/footnotes.xml.rels2
-rw-r--r--data/docx/word/comments.xml2
-rw-r--r--data/docx/word/document.xml400
-rw-r--r--data/docx/word/footnotes.xml33
-rw-r--r--data/docx/word/numbering.xml2
-rw-r--r--data/docx/word/settings.xml2
-rw-r--r--data/docx/word/styles.xml72
-rw-r--r--data/epub.css2
-rw-r--r--data/init.lua7
-rw-r--r--data/jats.csl205
-rw-r--r--data/pandoc.List.lua120
-rw-r--r--data/pandoc.lua945
-rw-r--r--data/pptx/[Content_Types].xml2
-rw-r--r--data/pptx/_rels/.rels2
-rw-r--r--data/pptx/docProps/app.xml2
-rw-r--r--data/pptx/docProps/core.xml2
-rw-r--r--data/pptx/docProps/thumbnail.jpegbin0 -> 5709 bytes
-rw-r--r--data/pptx/ppt/_rels/presentation.xml.rels2
-rw-r--r--data/pptx/ppt/notesMasters/_rels/notesMaster1.xml.rels2
-rw-r--r--data/pptx/ppt/notesMasters/notesMaster1.xml2
-rw-r--r--data/pptx/ppt/notesSlides/_rels/notesSlide1.xml.rels2
-rw-r--r--data/pptx/ppt/notesSlides/_rels/notesSlide2.xml.rels2
-rw-r--r--data/pptx/ppt/notesSlides/notesSlide1.xml2
-rw-r--r--data/pptx/ppt/notesSlides/notesSlide2.xml2
-rw-r--r--data/pptx/ppt/presProps.xml2
-rw-r--r--data/pptx/ppt/presentation.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout1.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout10.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout11.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout2.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout3.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout4.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout5.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout6.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout7.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout8.xml2
-rw-r--r--data/pptx/ppt/slideLayouts/slideLayout9.xml2
-rw-r--r--data/pptx/ppt/slideMasters/_rels/slideMaster1.xml.rels2
-rw-r--r--data/pptx/ppt/slideMasters/slideMaster1.xml2
-rw-r--r--data/pptx/ppt/slides/_rels/slide1.xml.rels2
-rw-r--r--data/pptx/ppt/slides/_rels/slide2.xml.rels2
-rw-r--r--data/pptx/ppt/slides/slide1.xml2
-rw-r--r--data/pptx/ppt/slides/slide2.xml2
-rw-r--r--data/pptx/ppt/tableStyles.xml2
-rw-r--r--data/pptx/ppt/theme/theme1.xml2
-rw-r--r--data/pptx/ppt/theme/theme2.xml2
-rw-r--r--data/pptx/ppt/viewProps.xml2
-rw-r--r--data/sample.lua10
-rw-r--r--data/templates/default.beamer278
-rw-r--r--data/templates/default.commonmark2
-rw-r--r--data/templates/default.context30
-rw-r--r--data/templates/default.docbook4 (renamed from data/templates/default.docbook)0
-rw-r--r--data/templates/default.docbook56
-rw-r--r--data/templates/default.dzslides13
-rw-r--r--data/templates/default.epub59
-rw-r--r--data/templates/default.epub268
-rw-r--r--data/templates/default.epub310
-rw-r--r--data/templates/default.html64
-rw-r--r--data/templates/default.html469
-rw-r--r--data/templates/default.html525
-rw-r--r--data/templates/default.jats203
-rw-r--r--data/templates/default.latex247
-rw-r--r--data/templates/default.markdown2
-rw-r--r--data/templates/default.ms112
-rw-r--r--data/templates/default.muse44
-rw-r--r--data/templates/default.opendocument129
-rw-r--r--data/templates/default.plain2
-rw-r--r--data/templates/default.revealjs42
-rw-r--r--data/templates/default.rst6
-rw-r--r--data/templates/default.rtf2
-rw-r--r--data/templates/default.s517
-rw-r--r--data/templates/default.slideous11
-rw-r--r--data/templates/default.slidy11
-rw-r--r--data/translations/am.yaml20
-rw-r--r--data/translations/ar.yaml20
-rw-r--r--data/translations/bg.yaml19
-rw-r--r--data/translations/bn.yaml21
-rw-r--r--data/translations/ca.yaml21
-rw-r--r--data/translations/cs.yaml21
-rw-r--r--data/translations/da.yaml21
-rw-r--r--data/translations/de.yaml21
-rw-r--r--data/translations/el.yaml21
-rw-r--r--data/translations/en.yaml22
-rw-r--r--data/translations/eo.yaml20
-rw-r--r--data/translations/es.yaml21
-rw-r--r--data/translations/et.yaml20
-rw-r--r--data/translations/eu.yaml21
-rw-r--r--data/translations/fa.yaml21
-rw-r--r--data/translations/fi.yaml21
-rw-r--r--data/translations/fr.yaml20
-rw-r--r--data/translations/he.yaml22
-rw-r--r--data/translations/hi.yaml20
-rw-r--r--data/translations/hr.yaml21
-rw-r--r--data/translations/hu.yaml21
-rw-r--r--data/translations/is.yaml21
-rw-r--r--data/translations/it.yaml21
-rw-r--r--data/translations/km.yaml21
-rw-r--r--data/translations/ko.yaml17
-rw-r--r--data/translations/lo.yaml21
-rw-r--r--data/translations/lt.yaml21
-rw-r--r--data/translations/lv.yaml20
-rw-r--r--data/translations/nl.yaml21
-rw-r--r--data/translations/no.yaml21
-rw-r--r--data/translations/pl.yaml21
-rw-r--r--data/translations/pt.yaml21
-rw-r--r--data/translations/rm.yaml21
-rw-r--r--data/translations/ro.yaml21
-rw-r--r--data/translations/ru.yaml21
-rw-r--r--data/translations/sk.yaml21
-rw-r--r--data/translations/sl.yaml21
-rw-r--r--data/translations/sq.yaml18
-rw-r--r--data/translations/sr-cyrl.yaml21
-rw-r--r--data/translations/sr.yaml21
-rw-r--r--data/translations/sv.yaml21
-rw-r--r--data/translations/th.yaml20
-rw-r--r--data/translations/tr.yaml22
-rw-r--r--data/translations/uk.yaml22
-rw-r--r--data/translations/ur.yaml22
-rw-r--r--data/translations/vi.yaml21
-rw-r--r--man/capitalizeHeaders.hs20
-rw-r--r--man/manfilter.lua22
-rw-r--r--man/pandoc.12359
-rw-r--r--man/removeLinks.hs9
-rw-r--r--man/removeNotes.hs9
-rw-r--r--pandoc.cabal715
-rw-r--r--pandoc.hs1490
-rw-r--r--prelude/Prelude.hs26
-rw-r--r--src/Text/Pandoc.hs356
-rw-r--r--src/Text/Pandoc/App.hs1636
-rw-r--r--src/Text/Pandoc/Asciify.hs6
-rw-r--r--src/Text/Pandoc/BCP47.hs125
-rw-r--r--src/Text/Pandoc/CSS.hs8
-rw-r--r--src/Text/Pandoc/CSV.hs102
-rw-r--r--src/Text/Pandoc/Class.hs1082
-rw-r--r--src/Text/Pandoc/Data.hs22
-rw-r--r--src/Text/Pandoc/Data.hsb15
-rw-r--r--src/Text/Pandoc/Emoji.hs1
-rw-r--r--src/Text/Pandoc/Error.hs97
-rw-r--r--src/Text/Pandoc/Extensions.hs378
-rw-r--r--src/Text/Pandoc/Filter.hs60
-rw-r--r--src/Text/Pandoc/Filter/JSON.hs97
-rw-r--r--src/Text/Pandoc/Filter/Lua.hs53
-rw-r--r--src/Text/Pandoc/Filter/Path.hs53
-rw-r--r--src/Text/Pandoc/Highlighting.hs63
-rw-r--r--src/Text/Pandoc/ImageSize.hs232
-rw-r--r--src/Text/Pandoc/Logging.hs342
-rw-r--r--src/Text/Pandoc/Lua.hs83
-rw-r--r--src/Text/Pandoc/Lua/Filter.hs170
-rw-r--r--src/Text/Pandoc/Lua/Init.hs117
-rw-r--r--src/Text/Pandoc/Lua/Module/MediaBag.hs108
-rw-r--r--src/Text/Pandoc/Lua/Module/Pandoc.hs134
-rw-r--r--src/Text/Pandoc/Lua/Module/Utils.hs126
-rw-r--r--src/Text/Pandoc/Lua/Packages.hs115
-rw-r--r--src/Text/Pandoc/Lua/StackInstances.hs376
-rw-r--r--src/Text/Pandoc/Lua/Util.hs187
-rw-r--r--src/Text/Pandoc/MIME.hs15
-rw-r--r--src/Text/Pandoc/MediaBag.hs52
-rw-r--r--src/Text/Pandoc/Options.hs389
-rw-r--r--src/Text/Pandoc/PDF.hs351
-rw-r--r--src/Text/Pandoc/Parsing.hs714
-rw-r--r--src/Text/Pandoc/Pretty.hs120
-rw-r--r--src/Text/Pandoc/Process.hs34
-rw-r--r--src/Text/Pandoc/Readers.hs160
-rw-r--r--src/Text/Pandoc/Readers/CommonMark.hs228
-rw-r--r--src/Text/Pandoc/Readers/Creole.hs320
-rw-r--r--src/Text/Pandoc/Readers/DocBook.hs117
-rw-r--r--src/Text/Pandoc/Readers/Docx.hs631
-rw-r--r--src/Text/Pandoc/Readers/Docx/Combine.hs55
-rw-r--r--src/Text/Pandoc/Readers/Docx/Fields.hs89
-rw-r--r--src/Text/Pandoc/Readers/Docx/Lists.hs98
-rw-r--r--src/Text/Pandoc/Readers/Docx/Parse.hs526
-rw-r--r--src/Text/Pandoc/Readers/Docx/StyleMap.hs12
-rw-r--r--src/Text/Pandoc/Readers/Docx/Util.hs27
-rw-r--r--src/Text/Pandoc/Readers/EPUB.hs140
-rw-r--r--src/Text/Pandoc/Readers/HTML.hs944
-rw-r--r--src/Text/Pandoc/Readers/Haddock.hs45
-rw-r--r--src/Text/Pandoc/Readers/JATS.hs496
-rw-r--r--src/Text/Pandoc/Readers/LaTeX.hs3403
-rw-r--r--src/Text/Pandoc/Readers/LaTeX/Types.hs51
-rw-r--r--src/Text/Pandoc/Readers/Markdown.hs1449
-rw-r--r--src/Text/Pandoc/Readers/MediaWiki.hs308
-rw-r--r--src/Text/Pandoc/Readers/Muse.hs924
-rw-r--r--src/Text/Pandoc/Readers/Native.hs36
-rw-r--r--src/Text/Pandoc/Readers/OPML.hs71
-rw-r--r--src/Text/Pandoc/Readers/Odt.hs54
-rw-r--r--src/Text/Pandoc/Readers/Odt/Arrows/State.hs116
-rw-r--r--src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs282
-rw-r--r--src/Text/Pandoc/Readers/Odt/Base.hs7
-rw-r--r--src/Text/Pandoc/Readers/Odt/ContentReader.hs83
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs140
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Utils.hs21
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs323
-rw-r--r--src/Text/Pandoc/Readers/Odt/Namespaces.hs10
-rw-r--r--src/Text/Pandoc/Readers/Odt/StyleReader.hs187
-rw-r--r--src/Text/Pandoc/Readers/Org.hs43
-rw-r--r--src/Text/Pandoc/Readers/Org/BlockStarts.hs84
-rw-r--r--src/Text/Pandoc/Readers/Org/Blocks.hs732
-rw-r--r--src/Text/Pandoc/Readers/Org/DocumentTree.hs304
-rw-r--r--src/Text/Pandoc/Readers/Org/ExportSettings.hs53
-rw-r--r--src/Text/Pandoc/Readers/Org/Inlines.hs443
-rw-r--r--src/Text/Pandoc/Readers/Org/Meta.hs145
-rw-r--r--src/Text/Pandoc/Readers/Org/ParserState.hs156
-rw-r--r--src/Text/Pandoc/Readers/Org/Parsing.hs54
-rw-r--r--src/Text/Pandoc/Readers/Org/Shared.hs38
-rw-r--r--src/Text/Pandoc/Readers/RST.hs1041
-rw-r--r--src/Text/Pandoc/Readers/TWiki.hs215
-rw-r--r--src/Text/Pandoc/Readers/TeXMath.hs48
-rw-r--r--src/Text/Pandoc/Readers/Textile.hs279
-rw-r--r--src/Text/Pandoc/Readers/TikiWiki.hs654
-rw-r--r--src/Text/Pandoc/Readers/Txt2Tags.hs159
-rw-r--r--src/Text/Pandoc/Readers/Vimwiki.hs673
-rw-r--r--src/Text/Pandoc/SelfContained.hs270
-rw-r--r--src/Text/Pandoc/Shared.hs865
-rw-r--r--src/Text/Pandoc/Slides.hs10
-rw-r--r--src/Text/Pandoc/Templates.hs82
-rw-r--r--src/Text/Pandoc/Translations.hs112
-rw-r--r--src/Text/Pandoc/UTF8.hs109
-rw-r--r--src/Text/Pandoc/UUID.hs30
-rw-r--r--src/Text/Pandoc/Writers.hs195
-rw-r--r--src/Text/Pandoc/Writers/AsciiDoc.hs159
-rw-r--r--src/Text/Pandoc/Writers/CommonMark.hs366
-rw-r--r--src/Text/Pandoc/Writers/ConTeXt.hs375
-rw-r--r--src/Text/Pandoc/Writers/Custom.hs384
-rw-r--r--src/Text/Pandoc/Writers/Docbook.hs410
-rw-r--r--src/Text/Pandoc/Writers/Docx.hs923
-rw-r--r--src/Text/Pandoc/Writers/DokuWiki.hs169
-rw-r--r--src/Text/Pandoc/Writers/EPUB.hs683
-rw-r--r--src/Text/Pandoc/Writers/FB2.hs442
-rw-r--r--src/Text/Pandoc/Writers/HTML.hs1134
-rw-r--r--src/Text/Pandoc/Writers/Haddock.hs170
-rw-r--r--src/Text/Pandoc/Writers/ICML.hs189
-rw-r--r--src/Text/Pandoc/Writers/JATS.hs455
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs920
-rw-r--r--src/Text/Pandoc/Writers/Man.hs227
-rw-r--r--src/Text/Pandoc/Writers/Markdown.hs774
-rw-r--r--src/Text/Pandoc/Writers/Math.hs56
-rw-r--r--src/Text/Pandoc/Writers/MediaWiki.hs781
-rw-r--r--src/Text/Pandoc/Writers/Ms.hs639
-rw-r--r--src/Text/Pandoc/Writers/Muse.hs408
-rw-r--r--src/Text/Pandoc/Writers/Native.hs23
-rw-r--r--src/Text/Pandoc/Writers/ODT.hs218
-rw-r--r--src/Text/Pandoc/Writers/OOXML.hs108
-rw-r--r--src/Text/Pandoc/Writers/OPML.hs88
-rw-r--r--src/Text/Pandoc/Writers/OpenDocument.hs313
-rw-r--r--src/Text/Pandoc/Writers/Org.hs242
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint.hs63
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint/Output.hs1834
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint/Presentation.hs987
-rw-r--r--src/Text/Pandoc/Writers/RST.hs330
-rw-r--r--src/Text/Pandoc/Writers/RTF.hs408
-rw-r--r--src/Text/Pandoc/Writers/Shared.hs226
-rw-r--r--src/Text/Pandoc/Writers/TEI.hs330
-rw-r--r--src/Text/Pandoc/Writers/Texinfo.hs191
-rw-r--r--src/Text/Pandoc/Writers/Textile.hs151
-rw-r--r--src/Text/Pandoc/Writers/ZimWiki.hs219
-rw-r--r--src/Text/Pandoc/XML.hs33
-rw-r--r--stack.yaml23
-rw-r--r--test/Tests/Command.hs95
-rw-r--r--test/Tests/Helpers.hs138
-rw-r--r--test/Tests/Lua.hs196
-rw-r--r--test/Tests/Old.hs289
-rw-r--r--test/Tests/Readers/Creole.hs286
-rw-r--r--test/Tests/Readers/Docx.hs401
-rw-r--r--test/Tests/Readers/EPUB.hs40
-rw-r--r--test/Tests/Readers/HTML.hs54
-rw-r--r--test/Tests/Readers/JATS.hs116
-rw-r--r--test/Tests/Readers/LaTeX.hs341
-rw-r--r--test/Tests/Readers/Markdown.hs462
-rw-r--r--test/Tests/Readers/Muse.hs1224
-rw-r--r--test/Tests/Readers/Odt.hs170
-rw-r--r--test/Tests/Readers/Org.hs16
-rw-r--r--test/Tests/Readers/Org/Block.hs192
-rw-r--r--test/Tests/Readers/Org/Block/CodeBlock.hs194
-rw-r--r--test/Tests/Readers/Org/Block/Figure.hs57
-rw-r--r--test/Tests/Readers/Org/Block/Header.hs182
-rw-r--r--test/Tests/Readers/Org/Block/List.hs244
-rw-r--r--test/Tests/Readers/Org/Block/Table.hs150
-rw-r--r--test/Tests/Readers/Org/Directive.hs199
-rw-r--r--test/Tests/Readers/Org/Inline.hs352
-rw-r--r--test/Tests/Readers/Org/Inline/Citation.hs179
-rw-r--r--test/Tests/Readers/Org/Inline/Note.hs86
-rw-r--r--test/Tests/Readers/Org/Inline/Smart.hs46
-rw-r--r--test/Tests/Readers/Org/Meta.hs191
-rw-r--r--test/Tests/Readers/Org/Shared.hs29
-rw-r--r--test/Tests/Readers/RST.hs189
-rw-r--r--test/Tests/Readers/Txt2Tags.hs437
-rw-r--r--test/Tests/Shared.hs39
-rw-r--r--test/Tests/Writers/AsciiDoc.hs56
-rw-r--r--test/Tests/Writers/ConTeXt.hs149
-rw-r--r--test/Tests/Writers/Docbook.hs303
-rw-r--r--test/Tests/Writers/Docx.hs157
-rw-r--r--test/Tests/Writers/FB2.hs34
-rw-r--r--test/Tests/Writers/HTML.hs44
-rw-r--r--test/Tests/Writers/JATS.hs122
-rw-r--r--test/Tests/Writers/LaTeX.hs176
-rw-r--r--test/Tests/Writers/Markdown.hs267
-rw-r--r--test/Tests/Writers/Muse.hs385
-rw-r--r--test/Tests/Writers/Native.hs22
-rw-r--r--test/Tests/Writers/OOXML.hs184
-rw-r--r--test/Tests/Writers/Org.hs25
-rw-r--r--test/Tests/Writers/Plain.hs21
-rw-r--r--test/Tests/Writers/Powerpoint.hs93
-rw-r--r--test/Tests/Writers/RST.hs117
-rw-r--r--test/Tests/Writers/TEI.hs43
-rw-r--r--test/bodybg.gif (renamed from tests/bodybg.gif)bin10119 -> 10119 bytes
-rw-r--r--test/command/1166.md48
-rw-r--r--test/command/1279.md19
-rw-r--r--test/command/1390.md20
-rw-r--r--test/command/1592.md49
-rw-r--r--test/command/1629.md10
-rw-r--r--test/command/168.md43
-rw-r--r--test/command/1710.md89
-rw-r--r--test/command/1718.md11
-rw-r--r--test/command/1745.md13
-rw-r--r--test/command/1773.md6
-rw-r--r--test/command/1841.md42
-rw-r--r--test/command/1881.md55
-rw-r--r--test/command/1905.md30
-rw-r--r--test/command/2118.md11
-rw-r--r--test/command/2228.md6
-rw-r--r--test/command/2378.md27
-rw-r--r--test/command/2397.md9
-rw-r--r--test/command/2434.md59
-rw-r--r--test/command/2549.md38
-rw-r--r--test/command/2552.md14
-rw-r--r--test/command/256.md12
-rw-r--r--test/command/2602.md18
-rw-r--r--test/command/2606.md58
-rw-r--r--test/command/262.md26
-rw-r--r--test/command/2649.md106
-rw-r--r--test/command/2662.md11
-rw-r--r--test/command/2834.md29
-rw-r--r--test/command/2874.md14
-rw-r--r--test/command/2994.md10
-rw-r--r--test/command/3113.md13
-rw-r--r--test/command/3236.md9
-rw-r--r--test/command/3257.md13
-rw-r--r--test/command/3309.md52
-rw-r--r--test/command/3314.md34
-rw-r--r--test/command/3337.md13
-rw-r--r--test/command/3348.md17
-rw-r--r--test/command/3401.md19
-rw-r--r--test/command/3407.md13
-rw-r--r--test/command/3422.md9
-rw-r--r--test/command/3432.md289
-rw-r--r--test/command/3432a.md19
-rw-r--r--test/command/3450.md12
-rw-r--r--test/command/3475.md45
-rw-r--r--test/command/3487.md11
-rw-r--r--test/command/3494.md40
-rw-r--r--test/command/3497.md51
-rw-r--r--test/command/3499.md18
-rw-r--r--test/command/3510-export.latex1
-rw-r--r--test/command/3510-src.hs1
-rw-r--r--test/command/3510-subdoc.org5
-rw-r--r--test/command/3510.md20
-rw-r--r--test/command/3511.md46
-rw-r--r--test/command/3512.md13
-rw-r--r--test/command/3516.md51
-rw-r--r--test/command/3518.md6
-rw-r--r--test/command/3526.md14
-rw-r--r--test/command/3529.md15
-rw-r--r--test/command/3530.md22
-rw-r--r--test/command/3531.md21
-rw-r--r--test/command/3533-rst-csv-tables.csv4
-rw-r--r--test/command/3533-rst-csv-tables.md56
-rw-r--r--test/command/3534.md23
-rw-r--r--test/command/3537.md28
-rw-r--r--test/command/3539.md45
-rw-r--r--test/command/3558.md12
-rw-r--r--test/command/3568.md15
-rw-r--r--test/command/3570.md6
-rw-r--r--test/command/3577.md37
-rw-r--r--test/command/3585.md16
-rw-r--r--test/command/3587.md21
-rw-r--r--test/command/3596.md59
-rw-r--r--test/command/3615.md18
-rw-r--r--test/command/3619.md28
-rw-r--r--test/command/3630.md8
-rw-r--r--test/command/3667.md13
-rw-r--r--test/command/3674.md39
-rw-r--r--test/command/3675.md15
-rw-r--r--test/command/3681.md27
-rw-r--r--test/command/3690.md8
-rw-r--r--test/command/3701.md60
-rw-r--r--test/command/3706.md44
-rw-r--r--test/command/3708.md15
-rw-r--r--test/command/3715.md15
-rw-r--r--test/command/3716.md6
-rw-r--r--test/command/3730.md21
-rw-r--r--test/command/3733.md13
-rw-r--r--test/command/3734.md50
-rw-r--r--test/command/3736.md25
-rw-r--r--test/command/3755.md23
-rw-r--r--test/command/3771.md14
-rw-r--r--test/command/3773.md14
-rw-r--r--test/command/3779.md28
-rw-r--r--test/command/3792.md13
-rw-r--r--test/command/3794.md7
-rw-r--r--test/command/3803.md10
-rw-r--r--test/command/3804.md6
-rw-r--r--test/command/3816.md32
-rw-r--r--test/command/3824.md14
-rw-r--r--test/command/3840.md15
-rw-r--r--test/command/3853.md26
-rw-r--r--test/command/3880.md6
-rw-r--r--test/command/3880.txt1
-rw-r--r--test/command/3916.md11
-rw-r--r--test/command/3937.md13
-rw-r--r--test/command/3947.md11
-rw-r--r--test/command/3958.md20
-rw-r--r--test/command/3968.md10
-rw-r--r--test/command/3971.md9
-rw-r--r--test/command/3971b.tex2
-rw-r--r--test/command/3974.md6
-rw-r--r--test/command/3978.md6
-rw-r--r--test/command/3983.md29
-rw-r--r--test/command/3989.md7
-rw-r--r--test/command/4007.md23
-rw-r--r--test/command/4012.md8
-rw-r--r--test/command/4016.md47
-rw-r--r--test/command/4019.md8
-rw-r--r--test/command/4038.md6
-rw-r--r--test/command/4054.md14
-rw-r--r--test/command/4056.md24
-rw-r--r--test/command/4061.md14
-rw-r--r--test/command/4062.md6
-rw-r--r--test/command/4068.md9
-rw-r--r--test/command/4091.md6
-rw-r--r--test/command/4113.md12
-rw-r--r--test/command/4119.md18
-rw-r--r--test/command/4125.md6
-rw-r--r--test/command/4134.md25
-rw-r--r--test/command/4156.md10
-rw-r--r--test/command/4159.md8
-rw-r--r--test/command/4162.md10
-rw-r--r--test/command/4164.md35
-rw-r--r--test/command/4171.md34
-rw-r--r--test/command/4172.md29
-rw-r--r--test/command/4183.md32
-rw-r--r--test/command/4193.md10
-rw-r--r--test/command/4199.md6
-rw-r--r--test/command/4208.md18
-rw-r--r--test/command/4235.md12
-rw-r--r--test/command/4240.md33
-rw-r--r--test/command/4253.md8
-rw-r--r--test/command/4254.md12
-rw-r--r--test/command/4280.md7
-rw-r--r--test/command/4281.md18
-rw-r--r--test/command/4374.md7
-rw-r--r--test/command/4424.md10
-rw-r--r--test/command/512.md42
-rw-r--r--test/command/645.md12
-rw-r--r--test/command/853.md18
-rw-r--r--test/command/934.md12
-rw-r--r--test/command/982.md11
-rw-r--r--test/command/987.md12
-rw-r--r--test/command/SVG_logo-without-xml-declaration.svg32
-rw-r--r--test/command/SVG_logo.svg33
-rw-r--r--test/command/abbrevs2
-rw-r--r--test/command/adjacent_latex_blocks.md9
-rw-r--r--test/command/cite-in-inline-note.md6
-rw-r--r--test/command/corrupt.svg5
-rw-r--r--test/command/dots.md12
-rw-r--r--test/command/empty_paragraphs.md95
-rw-r--r--test/command/gfm.md103
-rw-r--r--test/command/hspace.md56
-rw-r--r--test/command/html-read-figure.md45
-rw-r--r--test/command/hyphenat.md49
-rw-r--r--test/command/ifstrequal.md10
-rw-r--r--test/command/indented-fences.md20
-rw-r--r--test/command/inkscape-cube.svg119
-rw-r--r--test/command/latex-color.md127
-rw-r--r--test/command/latex-command-comment.md7
-rw-r--r--test/command/latex-fontawesome.md13
-rw-r--r--test/command/latex-tabular-column-specs.md24
-rw-r--r--test/command/lettrine.md9
-rw-r--r--test/command/lstlisting.md25
-rw-r--r--test/command/macros.md103
-rw-r--r--test/command/md-abbrevs.md31
-rw-r--r--test/command/multiple-metadata-blocks.md15
-rw-r--r--test/command/parse-raw.md27
-rw-r--r--test/command/refs.md54
-rw-r--r--test/command/rst-links.md18
-rw-r--r--test/command/smart.md45
-rw-r--r--test/command/sub-file-chapter-1.tex8
-rw-r--r--test/command/sub-file-chapter-2.tex8
-rw-r--r--test/command/svg.md132
-rw-r--r--test/command/tabularx.md110
-rw-r--r--test/command/translations.md29
-rw-r--r--test/command/vars-and-metadata.md15
-rw-r--r--test/command/write18.md14
-rw-r--r--test/command/yaml-with-chomp.md12
-rw-r--r--test/creole-reader.native95
-rw-r--r--test/creole-reader.txt137
-rw-r--r--test/docbook-reader.docbook (renamed from tests/docbook-reader.docbook)0
-rw-r--r--test/docbook-reader.native (renamed from tests/docbook-reader.native)0
-rw-r--r--test/docbook-xref.docbook (renamed from tests/docbook-xref.docbook)0
-rw-r--r--test/docbook-xref.native (renamed from tests/docbook-xref.native)0
-rw-r--r--test/docx/0_level_headers.docxbin0 -> 35146 bytes
-rw-r--r--test/docx/0_level_headers.native25
-rw-r--r--test/docx/already_auto_ident.docx (renamed from tests/docx/already_auto_ident.docx)bin8463 -> 8463 bytes
-rw-r--r--test/docx/already_auto_ident.native (renamed from tests/docx/already_auto_ident.native)0
-rw-r--r--test/docx/block_quotes.docxbin0 -> 41855 bytes
-rw-r--r--test/docx/block_quotes_parse_indent.native (renamed from tests/docx/block_quotes_parse_indent.native)0
-rw-r--r--test/docx/char_styles.docxbin0 -> 30134 bytes
-rw-r--r--test/docx/char_styles.native (renamed from tests/docx/char_styles.native)0
-rw-r--r--test/docx/codeblock.docx (renamed from tests/docx/codeblock.docx)bin8465 -> 8465 bytes
-rw-r--r--test/docx/codeblock.native (renamed from tests/docx/codeblock.native)0
-rw-r--r--test/docx/comments.docx (renamed from tests/docx/comments.docx)bin17109 -> 17109 bytes
-rw-r--r--test/docx/comments.native (renamed from tests/docx/comments.native)0
-rw-r--r--test/docx/comments_no_comments.native (renamed from tests/docx/comments_no_comments.native)0
-rw-r--r--test/docx/comments_warning.docx (renamed from tests/docx/comments_warning.docx)bin17078 -> 17078 bytes
-rw-r--r--test/docx/custom-style-no-styles.native4
-rw-r--r--test/docx/custom-style-reference.docx (renamed from tests/docx/custom-style-reference.docx)bin14846 -> 14846 bytes
-rw-r--r--test/docx/custom-style-roundtrip-end.native (renamed from tests/docx/custom-style-roundtrip-end.native)0
-rw-r--r--test/docx/custom-style-with-styles.native7
-rw-r--r--test/docx/custom_style.native (renamed from tests/docx/custom-style-roundtrip-start.native)0
-rw-r--r--test/docx/deep_normalize.docxbin0 -> 29246 bytes
-rw-r--r--test/docx/deep_normalize.native (renamed from tests/docx/deep_normalize.native)0
-rw-r--r--test/docx/definition_list.docx (renamed from tests/docx/definition_list.docx)bin8455 -> 8455 bytes
-rw-r--r--test/docx/definition_list.native (renamed from tests/docx/definition_list.native)0
-rw-r--r--test/docx/drop_cap.docxbin0 -> 26931 bytes
-rw-r--r--test/docx/drop_cap.native (renamed from tests/docx/drop_cap.native)0
-rw-r--r--test/docx/dummy_item_after_list_item.docx (renamed from tests/docx/dummy_item_after_list_item.docx)bin70197 -> 70197 bytes
-rw-r--r--test/docx/dummy_item_after_list_item.native (renamed from tests/docx/dummy_item_after_list_item.native)0
-rw-r--r--test/docx/dummy_item_after_paragraph.docx (renamed from tests/docx/dummy_item_after_paragraph.docx)bin70234 -> 70234 bytes
-rw-r--r--test/docx/dummy_item_after_paragraph.native (renamed from tests/docx/dummy_item_after_paragraph.native)0
-rw-r--r--test/docx/enumerated_headings.docx (renamed from tests/docx/enumerated_headings.docx)bin12539 -> 12539 bytes
-rw-r--r--test/docx/enumerated_headings.native (renamed from tests/docx/enumerated_headings.native)0
-rw-r--r--test/docx/german_styled_lists.docx (renamed from tests/docx/german_styled_lists.docx)bin43957 -> 43957 bytes
-rw-r--r--test/docx/german_styled_lists.native (renamed from tests/docx/german_styled_lists.native)0
-rw-r--r--test/docx/golden/block_quotes.docxbin0 -> 9778 bytes
-rw-r--r--test/docx/golden/codeblock.docxbin0 -> 9638 bytes
-rw-r--r--test/docx/golden/comments.docxbin0 -> 9960 bytes
-rw-r--r--test/docx/golden/custom_style_no_reference.docxbin0 -> 9724 bytes
-rw-r--r--test/docx/golden/custom_style_reference.docxbin0 -> 12118 bytes
-rw-r--r--test/docx/golden/definition_list.docxbin0 -> 9617 bytes
-rw-r--r--test/docx/golden/headers.docxbin0 -> 9765 bytes
-rw-r--r--test/docx/golden/image.docxbin0 -> 26452 bytes
-rw-r--r--test/docx/golden/inline_code.docxbin0 -> 9560 bytes
-rw-r--r--test/docx/golden/inline_formatting.docxbin0 -> 9737 bytes
-rw-r--r--test/docx/golden/inline_images.docxbin0 -> 26506 bytes
-rw-r--r--test/docx/golden/link_in_notes.docxbin0 -> 9781 bytes
-rw-r--r--test/docx/golden/links.docxbin0 -> 9960 bytes
-rw-r--r--test/docx/golden/lists.docxbin0 -> 10031 bytes
-rw-r--r--test/docx/golden/lists_continuing.docxbin0 -> 9830 bytes
-rw-r--r--test/docx/golden/lists_restarting.docxbin0 -> 9830 bytes
-rw-r--r--test/docx/golden/nested_anchors_in_header.docxbin0 -> 9882 bytes
-rw-r--r--test/docx/golden/notes.docxbin0 -> 9731 bytes
-rw-r--r--test/docx/golden/table_one_row.docxbin0 -> 9581 bytes
-rw-r--r--test/docx/golden/table_with_list_cell.docxbin0 -> 9948 bytes
-rw-r--r--test/docx/golden/tables.docxbin0 -> 9963 bytes
-rw-r--r--test/docx/golden/track_changes_deletion.docxbin0 -> 9604 bytes
-rw-r--r--test/docx/golden/track_changes_insertion.docxbin0 -> 9587 bytes
-rw-r--r--test/docx/golden/track_changes_move.docxbin0 -> 9621 bytes
-rw-r--r--test/docx/golden/unicode.docxbin0 -> 9545 bytes
-rw-r--r--test/docx/golden/verbatim_subsuper.docxbin0 -> 9593 bytes
-rw-r--r--test/docx/hanging_indent.docxbin0 -> 29924 bytes
-rw-r--r--test/docx/hanging_indent.native (renamed from tests/docx/hanging_indent.native)0
-rw-r--r--test/docx/headers.docxbin0 -> 29659 bytes
-rw-r--r--test/docx/headers.native (renamed from tests/docx/headers.native)0
-rw-r--r--test/docx/i18n_blocks.docx (renamed from tests/docx/i18n_blocks.docx)bin13680 -> 13680 bytes
-rw-r--r--test/docx/i18n_blocks.native (renamed from tests/docx/i18n_blocks.native)0
-rw-r--r--test/docx/image.docx (renamed from tests/docx/image.docx)bin35407 -> 35407 bytes
-rw-r--r--test/docx/image_no_embed.native (renamed from tests/docx/image_no_embed.native)0
-rw-r--r--test/docx/image_no_embed_writer.native (renamed from tests/docx/image_no_embed_writer.native)0
-rw-r--r--test/docx/image_vml.docx (renamed from tests/docx/image_vml.docx)bin23559 -> 23559 bytes
-rw-r--r--test/docx/image_vml.native (renamed from tests/docx/image_vml.native)0
-rw-r--r--test/docx/image_writer_test.native8
-rw-r--r--test/docx/inline_code.docx (renamed from tests/docx/inline_code.docx)bin8379 -> 8379 bytes
-rw-r--r--test/docx/inline_code.native (renamed from tests/docx/inline_code.native)0
-rw-r--r--test/docx/inline_formatting.docxbin0 -> 32322 bytes
-rw-r--r--test/docx/inline_formatting.native5
-rw-r--r--test/docx/inline_formatting_writer.native (renamed from tests/docx/inline_formatting_writer.native)0
-rw-r--r--test/docx/inline_images.docxbin0 -> 15875 bytes
-rw-r--r--test/docx/inline_images.native (renamed from tests/docx/inline_images.native)0
-rw-r--r--test/docx/inline_images_writer.native (renamed from tests/docx/inline_images_writer.native)0
-rw-r--r--test/docx/inline_images_writer_test.native2
-rw-r--r--test/docx/instrText_hyperlink.docxbin0 -> 13628 bytes
-rw-r--r--test/docx/instrText_hyperlink.native1
-rw-r--r--test/docx/link_in_notes.docxbin0 -> 27357 bytes
-rw-r--r--test/docx/link_in_notes.native (renamed from tests/docx/link_in_notes.native)0
-rw-r--r--test/docx/links.docxbin0 -> 45115 bytes
-rw-r--r--test/docx/links.native (renamed from tests/docx/links.native)0
-rw-r--r--test/docx/links_writer.native (renamed from tests/docx/links_writer.native)0
-rw-r--r--test/docx/lists.docxbin0 -> 31775 bytes
-rw-r--r--test/docx/lists.native (renamed from tests/docx/lists.native)0
-rw-r--r--test/docx/lists_continuing.docxbin0 -> 17717 bytes
-rw-r--r--test/docx/lists_continuing.native7
-rw-r--r--test/docx/lists_restarting.docxbin0 -> 18189 bytes
-rw-r--r--test/docx/lists_restarting.native8
-rw-r--r--test/docx/lists_writer.native (renamed from tests/docx/lists_writer.native)0
-rw-r--r--test/docx/metadata.docxbin0 -> 39538 bytes
-rw-r--r--test/docx/metadata.native (renamed from tests/docx/metadata.native)0
-rw-r--r--test/docx/metadata_after_normal.docxbin0 -> 56276 bytes
-rw-r--r--test/docx/metadata_after_normal.native (renamed from tests/docx/metadata_after_normal.native)0
-rw-r--r--test/docx/nested_anchors_in_header.docx (renamed from tests/docx/nested_anchors_in_header.docx)bin17535 -> 17535 bytes
-rw-r--r--test/docx/nested_anchors_in_header.native15
-rw-r--r--test/docx/nested_sdt.docxbin0 -> 11694 bytes
-rw-r--r--test/docx/nested_sdt.native3
-rw-r--r--test/docx/normalize.docxbin0 -> 25791 bytes
-rw-r--r--test/docx/normalize.native (renamed from tests/docx/normalize.native)0
-rw-r--r--test/docx/notes.docxbin0 -> 30734 bytes
-rw-r--r--test/docx/notes.native (renamed from tests/docx/notes.native)0
-rw-r--r--test/docx/numbered_header.docxbin0 -> 26129 bytes
-rw-r--r--test/docx/numbered_header.native (renamed from tests/docx/numbered_header.native)0
-rw-r--r--test/docx/overlapping_targets.docxbin0 -> 13747 bytes
-rw-r--r--test/docx/overlapping_targets.native3
-rw-r--r--test/docx/paragraph_insertion_deletion.docxbin0 -> 12066 bytes
-rw-r--r--test/docx/paragraph_insertion_deletion_accept.native2
-rw-r--r--test/docx/paragraph_insertion_deletion_all.native3
-rw-r--r--test/docx/paragraph_insertion_deletion_reject.native2
-rw-r--r--test/docx/sdt_elements.docxbin0 -> 29409 bytes
-rw-r--r--test/docx/sdt_elements.native10
-rw-r--r--test/docx/special_punctuation.docx (renamed from tests/docx/special_punctuation.docx)bin8408 -> 8408 bytes
-rw-r--r--test/docx/special_punctuation.native (renamed from tests/docx/special_punctuation.native)0
-rw-r--r--test/docx/table_one_row.docx (renamed from tests/docx/table_one_row.docx)bin25251 -> 25251 bytes
-rw-r--r--test/docx/table_one_row.native (renamed from tests/docx/table_one_row.native)0
-rw-r--r--test/docx/table_variable_width.docxbin0 -> 10006 bytes
-rw-r--r--test/docx/table_variable_width.native13
-rw-r--r--test/docx/table_with_list_cell.docxbin0 -> 32615 bytes
-rw-r--r--test/docx/table_with_list_cell.native (renamed from tests/docx/table_with_list_cell.native)0
-rw-r--r--test/docx/tables.docxbin0 -> 49780 bytes
-rw-r--r--test/docx/tables.native (renamed from tests/docx/tables.native)0
-rw-r--r--test/docx/tabs.docx (renamed from tests/docx/tabs.docx)bin12919 -> 12919 bytes
-rw-r--r--test/docx/tabs.native (renamed from tests/docx/tabs.native)0
-rw-r--r--test/docx/track_changes_deletion.docx (renamed from tests/docx/track_changes_deletion.docx)bin13350 -> 13350 bytes
-rw-r--r--test/docx/track_changes_deletion_accept.native (renamed from tests/docx/track_changes_deletion_accept.native)0
-rw-r--r--test/docx/track_changes_deletion_all.native (renamed from tests/docx/track_changes_deletion_all.native)0
-rw-r--r--test/docx/track_changes_deletion_reject.native (renamed from tests/docx/track_changes_deletion_reject.native)0
-rw-r--r--test/docx/track_changes_insertion.docx (renamed from tests/docx/track_changes_insertion.docx)bin12956 -> 12956 bytes
-rw-r--r--test/docx/track_changes_insertion_accept.native (renamed from tests/docx/track_changes_insertion_accept.native)0
-rw-r--r--test/docx/track_changes_insertion_all.native (renamed from tests/docx/track_changes_insertion_all.native)0
-rw-r--r--test/docx/track_changes_insertion_reject.native (renamed from tests/docx/track_changes_insertion_reject.native)0
-rw-r--r--test/docx/track_changes_move.docx (renamed from tests/docx/track_changes_move.docx)bin26151 -> 26151 bytes
-rw-r--r--test/docx/track_changes_move_accept.native (renamed from tests/docx/track_changes_move_accept.native)0
-rw-r--r--test/docx/track_changes_move_all.native (renamed from tests/docx/track_changes_move_all.native)0
-rw-r--r--test/docx/track_changes_move_reject.native (renamed from tests/docx/track_changes_move_reject.native)0
-rw-r--r--test/docx/trailing_spaces_in_formatting.docx (renamed from tests/docx/trailing_spaces_in_formatting.docx)bin12916 -> 12916 bytes
-rw-r--r--test/docx/trailing_spaces_in_formatting.native (renamed from tests/docx/trailing_spaces_in_formatting.native)0
-rw-r--r--test/docx/unicode.docx (renamed from tests/docx/unicode.docx)bin11506 -> 11506 bytes
-rw-r--r--test/docx/unicode.native (renamed from tests/docx/unicode.native)0
-rw-r--r--test/docx/unused_anchors.docxbin0 -> 13276 bytes
-rw-r--r--test/docx/unused_anchors.native3
-rw-r--r--test/docx/verbatim_subsuper.docx (renamed from tests/docx/verbatim_subsuper.docx)bin10353 -> 10353 bytes
-rw-r--r--test/docx/verbatim_subsuper.native (renamed from tests/docx/verbatim_subsuper.native)0
-rw-r--r--test/dokuwiki_external_images.dokuwiki (renamed from tests/dokuwiki_external_images.dokuwiki)0
-rw-r--r--test/dokuwiki_external_images.native (renamed from tests/dokuwiki_external_images.native)0
-rw-r--r--test/dokuwiki_inline_formatting.dokuwiki (renamed from tests/dokuwiki_inline_formatting.dokuwiki)0
-rw-r--r--test/dokuwiki_inline_formatting.native (renamed from tests/dokuwiki_inline_formatting.native)0
-rw-r--r--test/dokuwiki_multiblock_table.dokuwiki (renamed from tests/dokuwiki_multiblock_table.dokuwiki)0
-rw-r--r--test/dokuwiki_multiblock_table.native (renamed from tests/dokuwiki_multiblock_table.native)0
-rw-r--r--test/epub/features.epub (renamed from tests/epub/features.epub)bin66370 -> 66370 bytes
-rw-r--r--test/epub/features.native93
-rw-r--r--test/epub/formatting.epub (renamed from tests/epub/formatting.epub)bin13460 -> 13460 bytes
-rw-r--r--test/epub/formatting.native (renamed from tests/epub/formatting.native)0
-rw-r--r--test/epub/img.epub (renamed from tests/epub/img.epub)bin61768 -> 61768 bytes
-rw-r--r--test/epub/wasteland.epub (renamed from tests/epub/wasteland.epub)bin101870 -> 101870 bytes
-rw-r--r--test/epub/wasteland.native (renamed from tests/epub/wasteland.native)0
-rw-r--r--test/fb2/basic.fb23
-rw-r--r--test/fb2/basic.markdown (renamed from tests/fb2/basic.markdown)0
-rw-r--r--test/fb2/images-embedded.fb22
-rw-r--r--test/fb2/images-embedded.html (renamed from tests/fb2/images-embedded.html)0
-rw-r--r--test/fb2/images.fb22
-rw-r--r--test/fb2/images.markdown (renamed from tests/fb2/images.markdown)0
-rw-r--r--test/fb2/math.fb22
-rw-r--r--test/fb2/math.markdown (renamed from tests/fb2/math.markdown)0
-rw-r--r--test/fb2/test-small.png (renamed from tests/fb2/test-small.png)bin4090 -> 4090 bytes
-rw-r--r--test/fb2/test.jpg (renamed from tests/fb2/test.jpg)bin153610 -> 153610 bytes
-rw-r--r--test/fb2/titles.fb23
-rw-r--r--test/fb2/titles.markdown6
-rw-r--r--test/haddock-reader.haddock (renamed from tests/haddock-reader.haddock)0
-rw-r--r--test/haddock-reader.native (renamed from tests/haddock-reader.native)0
-rw-r--r--test/html-reader.html710
-rw-r--r--test/html-reader.native473
-rw-r--r--test/insert (renamed from tests/insert)0
-rw-r--r--test/jats-reader.native422
-rw-r--r--test/jats-reader.xml1785
-rw-r--r--test/lalune.jpg (renamed from tests/lalune.jpg)bin16270 -> 16270 bytes
-rw-r--r--test/latex-reader.latex847
-rw-r--r--test/latex-reader.native375
-rw-r--r--test/lhs-test-markdown.native (renamed from tests/lhs-test-markdown.native)0
-rw-r--r--test/lhs-test.fragment.html+lhs (renamed from tests/lhs-test.fragment.html+lhs)0
-rw-r--r--test/lhs-test.html99
-rw-r--r--test/lhs-test.html+lhs99
-rw-r--r--test/lhs-test.latex125
-rw-r--r--test/lhs-test.latex+lhs88
-rw-r--r--test/lhs-test.markdown (renamed from tests/lhs-test.markdown)0
-rw-r--r--test/lhs-test.markdown+lhs (renamed from tests/lhs-test.markdown+lhs)0
-rw-r--r--test/lhs-test.native (renamed from tests/lhs-test.native)0
-rw-r--r--test/lhs-test.rst (renamed from tests/lhs-test.rst)0
-rw-r--r--test/lhs-test.rst+lhs (renamed from tests/lhs-test.rst+lhs)0
-rw-r--r--test/lua/attr-test.lua6
-rw-r--r--test/lua/block-count.lua11
-rw-r--r--test/lua/hello-world-doc.lua10
-rw-r--r--test/lua/implicit-doc-filter.lua6
-rw-r--r--test/lua/markdown-reader.lua12
-rw-r--r--test/lua/metatable-catch-all.lua20
-rw-r--r--test/lua/plain-to-para.lua6
-rw-r--r--test/lua/script-name.lua3
-rw-r--r--test/lua/single-to-double-quoted.lua10
-rw-r--r--test/lua/smallcaps-title.lua12
-rw-r--r--test/lua/strmacro.lua11
-rw-r--r--test/lua/test-pandoc-utils.lua115
-rw-r--r--test/lua/undiv.lua3
-rw-r--r--test/lua/uppercase-header.lua9
-rw-r--r--test/markdown-citations.native17
-rw-r--r--test/markdown-citations.txt (renamed from tests/markdown-citations.txt)0
-rw-r--r--test/markdown-reader-more.native198
-rw-r--r--test/markdown-reader-more.txt320
-rw-r--r--test/media/rId25.jpg (renamed from tests/media/rId25.jpg)bin1332 -> 1332 bytes
-rw-r--r--test/media/rId26.jpg (renamed from tests/media/rId26.jpg)bin1332 -> 1332 bytes
-rw-r--r--test/media/rId27.jpg (renamed from tests/media/rId27.jpg)bin1332 -> 1332 bytes
-rw-r--r--test/mediawiki-reader.native (renamed from tests/mediawiki-reader.native)0
-rw-r--r--test/mediawiki-reader.wiki (renamed from tests/mediawiki-reader.wiki)0
-rw-r--r--test/movie.jpg (renamed from tests/movie.jpg)bin1046 -> 1046 bytes
-rw-r--r--test/odt/markdown/bold.md (renamed from tests/odt/markdown/bold.md)0
-rw-r--r--test/odt/markdown/citation.md (renamed from tests/odt/markdown/citation.md)0
-rw-r--r--test/odt/markdown/endnote.md (renamed from tests/odt/markdown/endnote.md)0
-rw-r--r--test/odt/markdown/externalLink.md (renamed from tests/odt/markdown/externalLink.md)0
-rw-r--r--test/odt/markdown/footnote.md (renamed from tests/odt/markdown/footnote.md)0
-rw-r--r--test/odt/markdown/headers.md (renamed from tests/odt/markdown/headers.md)0
-rw-r--r--test/odt/markdown/horizontalRule.md (renamed from tests/odt/markdown/horizontalRule.md)0
-rw-r--r--test/odt/markdown/image.md (renamed from tests/odt/markdown/image.md)0
-rw-r--r--test/odt/markdown/imageIndex.md (renamed from tests/odt/markdown/imageIndex.md)0
-rw-r--r--test/odt/markdown/imageWithCaption.md (renamed from tests/odt/markdown/imageWithCaption.md)0
-rw-r--r--test/odt/markdown/italic.md (renamed from tests/odt/markdown/italic.md)0
-rw-r--r--test/odt/markdown/listBlocks.md (renamed from tests/odt/markdown/listBlocks.md)0
-rw-r--r--test/odt/markdown/paragraph.md (renamed from tests/odt/markdown/paragraph.md)0
-rw-r--r--test/odt/markdown/strikeout.md (renamed from tests/odt/markdown/strikeout.md)0
-rw-r--r--test/odt/markdown/trackedChanges.md (renamed from tests/odt/markdown/trackedChanges.md)0
-rw-r--r--test/odt/markdown/underlined.md (renamed from tests/odt/markdown/underlined.md)0
-rw-r--r--test/odt/native/blockquote.native (renamed from tests/odt/native/blockquote.native)0
-rw-r--r--test/odt/native/image.native (renamed from tests/odt/native/image.native)0
-rw-r--r--test/odt/native/imageIndex.native (renamed from tests/odt/native/imageIndex.native)0
-rw-r--r--test/odt/native/imageWithCaption.native (renamed from tests/odt/native/imageWithCaption.native)0
-rw-r--r--test/odt/native/inlinedCode.native (renamed from tests/odt/native/inlinedCode.native)0
-rw-r--r--test/odt/native/orderedListMixed.native (renamed from tests/odt/native/orderedListMixed.native)0
-rw-r--r--test/odt/native/orderedListRoman.native (renamed from tests/odt/native/orderedListRoman.native)0
-rw-r--r--test/odt/native/orderedListSimple.native (renamed from tests/odt/native/orderedListSimple.native)0
-rw-r--r--test/odt/native/referenceToChapter.native (renamed from tests/odt/native/referenceToChapter.native)0
-rw-r--r--test/odt/native/referenceToListItem.native (renamed from tests/odt/native/referenceToListItem.native)0
-rw-r--r--test/odt/native/referenceToText.native (renamed from tests/odt/native/referenceToText.native)0
-rw-r--r--test/odt/native/simpleTable.native (renamed from tests/odt/native/simpleTable.native)0
-rw-r--r--test/odt/native/simpleTableWithCaption.native (renamed from tests/odt/native/simpleTableWithCaption.native)0
-rw-r--r--test/odt/native/tableWithContents.native (renamed from tests/odt/native/tableWithContents.native)0
-rw-r--r--test/odt/native/textMixedStyles.native (renamed from tests/odt/native/textMixedStyles.native)0
-rw-r--r--test/odt/native/unicode.native (renamed from tests/odt/native/unicode.native)0
-rw-r--r--test/odt/native/unorderedList.native (renamed from tests/odt/native/unorderedList.native)0
-rw-r--r--test/odt/odt/blockquote.odt (renamed from tests/odt/odt/blockquote.odt)bin8594 -> 8594 bytes
-rw-r--r--test/odt/odt/bold.odt (renamed from tests/odt/odt/bold.odt)bin10377 -> 10377 bytes
-rw-r--r--test/odt/odt/citation.odt (renamed from tests/odt/odt/citation.odt)bin10842 -> 10842 bytes
-rw-r--r--test/odt/odt/endnote.odt (renamed from tests/odt/odt/endnote.odt)bin10950 -> 10950 bytes
-rw-r--r--test/odt/odt/expression.odt (renamed from tests/odt/odt/expression.odt)bin10916 -> 10916 bytes
-rw-r--r--test/odt/odt/expressionUnevaluated.odt (renamed from tests/odt/odt/expressionUnevaluated.odt)bin10829 -> 10829 bytes
-rw-r--r--test/odt/odt/externalLink.odt (renamed from tests/odt/odt/externalLink.odt)bin10735 -> 10735 bytes
-rw-r--r--test/odt/odt/footnote.odt (renamed from tests/odt/odt/footnote.odt)bin10843 -> 10843 bytes
-rw-r--r--test/odt/odt/formula.odt (renamed from tests/odt/odt/formula.odt)bin14252 -> 14252 bytes
-rw-r--r--test/odt/odt/headers.odt (renamed from tests/odt/odt/headers.odt)bin10515 -> 10515 bytes
-rw-r--r--test/odt/odt/hiddenTextByStyle.odt (renamed from tests/odt/odt/hiddenTextByStyle.odt)bin10798 -> 10798 bytes
-rw-r--r--test/odt/odt/hiddenTextByVariable.odt (renamed from tests/odt/odt/hiddenTextByVariable.odt)bin10788 -> 10788 bytes
-rw-r--r--test/odt/odt/horizontalRule.odt (renamed from tests/odt/odt/horizontalRule.odt)bin10130 -> 10130 bytes
-rw-r--r--test/odt/odt/image.odt (renamed from tests/odt/odt/image.odt)bin33360 -> 33360 bytes
-rw-r--r--test/odt/odt/imageIndex.odt (renamed from tests/odt/odt/imageIndex.odt)bin34417 -> 34417 bytes
-rw-r--r--test/odt/odt/imageWithCaption.odt (renamed from tests/odt/odt/imageWithCaption.odt)bin33811 -> 33811 bytes
-rw-r--r--test/odt/odt/inlinedCode.odt (renamed from tests/odt/odt/inlinedCode.odt)bin10141 -> 10141 bytes
-rw-r--r--test/odt/odt/italic.odt (renamed from tests/odt/odt/italic.odt)bin10426 -> 10426 bytes
-rw-r--r--test/odt/odt/listBlocks.odt (renamed from tests/odt/odt/listBlocks.odt)bin10565 -> 10565 bytes
-rw-r--r--test/odt/odt/orderedListMixed.odt (renamed from tests/odt/odt/orderedListMixed.odt)bin11970 -> 11970 bytes
-rw-r--r--test/odt/odt/orderedListRoman.odt (renamed from tests/odt/odt/orderedListRoman.odt)bin11730 -> 11730 bytes
-rw-r--r--test/odt/odt/orderedListSimple.odt (renamed from tests/odt/odt/orderedListSimple.odt)bin11817 -> 11817 bytes
-rw-r--r--test/odt/odt/paragraph.odt (renamed from tests/odt/odt/paragraph.odt)bin8538 -> 8538 bytes
-rw-r--r--test/odt/odt/referenceAllInOne.odt (renamed from tests/odt/odt/referenceAllInOne.odt)bin10878 -> 10878 bytes
-rw-r--r--test/odt/odt/referenceToChapter.odt (renamed from tests/odt/odt/referenceToChapter.odt)bin10487 -> 10487 bytes
-rw-r--r--test/odt/odt/referenceToListItem.odt (renamed from tests/odt/odt/referenceToListItem.odt)bin10855 -> 10855 bytes
-rw-r--r--test/odt/odt/referenceToText.odt (renamed from tests/odt/odt/referenceToText.odt)bin10208 -> 10208 bytes
-rw-r--r--test/odt/odt/simpleTable.odt (renamed from tests/odt/odt/simpleTable.odt)bin10705 -> 10705 bytes
-rw-r--r--test/odt/odt/simpleTableWithCaption.odt (renamed from tests/odt/odt/simpleTableWithCaption.odt)bin10396 -> 10396 bytes
-rw-r--r--test/odt/odt/strikeout.odt (renamed from tests/odt/odt/strikeout.odt)bin10582 -> 10582 bytes
-rw-r--r--test/odt/odt/table.odt (renamed from tests/odt/odt/table.odt)bin10763 -> 10763 bytes
-rw-r--r--test/odt/odt/tableWithCaption.odt (renamed from tests/odt/odt/tableWithCaption.odt)bin10623 -> 10623 bytes
-rw-r--r--test/odt/odt/tableWithContents.odt (renamed from tests/odt/odt/tableWithContents.odt)bin8817 -> 8817 bytes
-rw-r--r--test/odt/odt/textMixedStyles.odt (renamed from tests/odt/odt/textMixedStyles.odt)bin10571 -> 10571 bytes
-rw-r--r--test/odt/odt/trackedChanges.odt (renamed from tests/odt/odt/trackedChanges.odt)bin11135 -> 11135 bytes
-rw-r--r--test/odt/odt/underlined.odt (renamed from tests/odt/odt/underlined.odt)bin10513 -> 10513 bytes
-rw-r--r--test/odt/odt/unicode.odt (renamed from tests/odt/odt/unicode.odt)bin11787 -> 11787 bytes
-rw-r--r--test/odt/odt/unorderedList.odt (renamed from tests/odt/odt/unorderedList.odt)bin9505 -> 9505 bytes
-rw-r--r--test/odt/odt/variable.odt (renamed from tests/odt/odt/variable.odt)bin10851 -> 10851 bytes
-rw-r--r--test/opml-reader.native (renamed from tests/opml-reader.native)0
-rw-r--r--test/opml-reader.opml (renamed from tests/opml-reader.opml)0
-rw-r--r--test/pipe-tables.native115
-rw-r--r--test/pipe-tables.txt (renamed from tests/pipe-tables.txt)0
-rw-r--r--test/pptx/endnotes.native2
-rw-r--r--test/pptx/endnotes.pptxbin0 -> 26678 bytes
-rw-r--r--test/pptx/endnotes_templated.pptxbin0 -> 394003 bytes
-rw-r--r--test/pptx/endnotes_toc.pptxbin0 -> 27602 bytes
-rw-r--r--test/pptx/endnotes_toc_templated.pptxbin0 -> 394926 bytes
-rw-r--r--test/pptx/images.native5
-rw-r--r--test/pptx/images.pptxbin0 -> 44338 bytes
-rw-r--r--test/pptx/images_templated.pptxbin0 -> 411657 bytes
-rw-r--r--test/pptx/inline_formatting.native5
-rw-r--r--test/pptx/inline_formatting.pptxbin0 -> 25842 bytes
-rw-r--r--test/pptx/inline_formatting_templated.pptxbin0 -> 393163 bytes
-rw-r--r--test/pptx/lists.native18
-rw-r--r--test/pptx/lists.pptxbin0 -> 26765 bytes
-rw-r--r--test/pptx/lists_templated.pptxbin0 -> 394091 bytes
-rw-r--r--test/pptx/reference_depth.pptxbin0 -> 397502 bytes
-rw-r--r--test/pptx/remove_empty_slides.native5
-rw-r--r--test/pptx/remove_empty_slides.pptxbin0 -> 43784 bytes
-rw-r--r--test/pptx/remove_empty_slides_templated.pptxbin0 -> 411101 bytes
-rw-r--r--test/pptx/slide_breaks.native7
-rw-r--r--test/pptx/slide_breaks.pptxbin0 -> 28290 bytes
-rw-r--r--test/pptx/slide_breaks_slide_level_1.pptxbin0 -> 27461 bytes
-rw-r--r--test/pptx/slide_breaks_slide_level_1_templated.pptxbin0 -> 394785 bytes
-rw-r--r--test/pptx/slide_breaks_templated.pptxbin0 -> 395614 bytes
-rw-r--r--test/pptx/slide_breaks_toc.pptxbin0 -> 29248 bytes
-rw-r--r--test/pptx/slide_breaks_toc_templated.pptxbin0 -> 396572 bytes
-rw-r--r--test/pptx/speaker_notes.native17
-rw-r--r--test/pptx/speaker_notes.pptxbin0 -> 35156 bytes
-rw-r--r--test/pptx/speaker_notes_templated.pptxbin0 -> 402475 bytes
-rw-r--r--test/pptx/tables.native35
-rw-r--r--test/pptx/tables.pptxbin0 -> 27282 bytes
-rw-r--r--test/pptx/tables_templated.pptxbin0 -> 394610 bytes
-rw-r--r--test/pptx/two_column.native9
-rw-r--r--test/pptx/two_column.pptxbin0 -> 25785 bytes
-rw-r--r--test/pptx/two_column_templated.pptxbin0 -> 393106 bytes
-rw-r--r--test/rst-reader.native335
-rw-r--r--test/rst-reader.rst (renamed from tests/rst-reader.rst)0
-rw-r--r--test/s5-basic.html61
-rw-r--r--test/s5-fancy.html262
-rw-r--r--test/s5-fragment.html (renamed from tests/s5-fragment.html)0
-rw-r--r--test/s5-inserts.html39
-rw-r--r--test/s5.native (renamed from tests/s5.native)0
-rw-r--r--test/tables-rstsubset.native114
-rw-r--r--test/tables.asciidoc67
-rw-r--r--test/tables.context230
-rw-r--r--test/tables.custom201
-rw-r--r--test/tables.docbook4432
-rw-r--r--test/tables.docbook5432
-rw-r--r--test/tables.dokuwiki47
-rw-r--r--test/tables.fb23
-rw-r--r--test/tables.haddock76
-rw-r--r--test/tables.html4204
-rw-r--r--test/tables.html5204
-rw-r--r--test/tables.icml757
-rw-r--r--test/tables.jats430
-rw-r--r--test/tables.latex170
-rw-r--r--test/tables.man267
-rw-r--r--test/tables.markdown76
-rw-r--r--test/tables.mediawiki146
-rw-r--r--test/tables.ms267
-rw-r--r--test/tables.muse46
-rw-r--r--test/tables.native114
-rw-r--r--test/tables.opendocument397
-rw-r--r--test/tables.org (renamed from tests/tables.org)0
-rw-r--r--test/tables.plain76
-rw-r--r--test/tables.rst90
-rw-r--r--test/tables.rtf360
-rw-r--r--test/tables.tei171
-rw-r--r--test/tables.texinfo (renamed from tests/tables.texinfo)0
-rw-r--r--test/tables.textile (renamed from tests/tables.textile)0
-rw-r--r--test/tables.txt (renamed from tests/tables.txt)0
-rw-r--r--test/tables.zimwiki56
-rw-r--r--test/test-pandoc.hs83
-rw-r--r--test/testsuite.native409
-rw-r--r--test/testsuite.txt725
-rw-r--r--test/textile-reader.native180
-rw-r--r--test/textile-reader.textile279
-rw-r--r--test/tikiwiki-reader.native130
-rw-r--r--test/tikiwiki-reader.tikiwiki148
-rw-r--r--test/twiki-reader.native (renamed from tests/twiki-reader.native)0
-rw-r--r--test/twiki-reader.twiki (renamed from tests/twiki-reader.twiki)0
-rw-r--r--test/txt2tags.native611
-rw-r--r--test/txt2tags.t2t (renamed from tests/txt2tags.t2t)0
-rw-r--r--test/vimwiki-reader.native309
-rw-r--r--test/vimwiki-reader.wiki424
-rw-r--r--test/writer.asciidoc658
-rw-r--r--test/writer.context901
-rw-r--r--test/writer.custom783
-rw-r--r--test/writer.docbook41416
-rw-r--r--test/writer.docbook51391
-rw-r--r--test/writer.dokuwiki638
-rw-r--r--test/writer.fb21015
-rw-r--r--test/writer.haddock656
-rw-r--r--test/writer.html4549
-rw-r--r--test/writer.html5551
-rw-r--r--test/writer.icml3275
-rw-r--r--test/writer.jats1448
-rw-r--r--test/writer.latex997
-rw-r--r--test/writer.man791
-rw-r--r--test/writer.markdown742
-rw-r--r--test/writer.mediawiki645
-rw-r--r--test/writer.ms1005
-rw-r--r--test/writer.muse725
-rw-r--r--test/writer.native409
-rw-r--r--test/writer.opendocument1537
-rw-r--r--test/writer.opml72
-rw-r--r--test/writer.org851
-rw-r--r--test/writer.plain691
-rw-r--r--test/writer.rst890
-rw-r--r--test/writer.rtf443
-rw-r--r--test/writer.tei859
-rw-r--r--test/writer.texinfo1057
-rw-r--r--test/writer.textile719
-rw-r--r--test/writer.zimwiki619
-rw-r--r--test/writers-lang-and-dir.context123
-rw-r--r--test/writers-lang-and-dir.latex157
-rw-r--r--test/writers-lang-and-dir.native (renamed from tests/writers-lang-and-dir.native)0
-rw-r--r--tests/Tests/Helpers.hs85
-rw-r--r--tests/Tests/Old.hs290
-rw-r--r--tests/Tests/Readers/Docx.hs343
-rw-r--r--tests/Tests/Readers/EPUB.hs37
-rw-r--r--tests/Tests/Readers/HTML.hs33
-rw-r--r--tests/Tests/Readers/LaTeX.hs225
-rw-r--r--tests/Tests/Readers/Markdown.hs459
-rw-r--r--tests/Tests/Readers/Odt.hs166
-rw-r--r--tests/Tests/Readers/Org.hs1723
-rw-r--r--tests/Tests/Readers/RST.hs174
-rw-r--r--tests/Tests/Readers/Txt2Tags.hs429
-rw-r--r--tests/Tests/Shared.hs60
-rw-r--r--tests/Tests/Walk.hs46
-rw-r--r--tests/Tests/Writers/AsciiDoc.hs55
-rw-r--r--tests/Tests/Writers/ConTeXt.hs70
-rw-r--r--tests/Tests/Writers/Docbook.hs302
-rw-r--r--tests/Tests/Writers/Docx.hs149
-rw-r--r--tests/Tests/Writers/HTML.hs43
-rw-r--r--tests/Tests/Writers/LaTeX.hs173
-rw-r--r--tests/Tests/Writers/Markdown.hs263
-rw-r--r--tests/Tests/Writers/Native.hs21
-rw-r--r--tests/Tests/Writers/Plain.hs21
-rw-r--r--tests/Tests/Writers/RST.hs107
-rw-r--r--tests/Tests/Writers/TEI.hs43
-rw-r--r--tests/docx/adjacent_links.docxbin8538 -> 0 bytes
-rw-r--r--tests/docx/adjacent_links.native1
-rw-r--r--tests/docx/inline_formatting.native5
-rw-r--r--tests/docx/nested_anchors_in_header.native10
-rw-r--r--tests/epub/features.native93
-rw-r--r--tests/fb2/basic.fb22
-rw-r--r--tests/fb2/images-embedded.fb22
-rw-r--r--tests/fb2/images.fb22
-rw-r--r--tests/fb2/math.fb22
-rw-r--r--tests/fb2/titles.fb22
-rw-r--r--tests/fb2/titles.markdown10
-rw-r--r--tests/html-reader.html708
-rw-r--r--tests/html-reader.native463
-rw-r--r--tests/latex-reader.latex848
-rw-r--r--tests/latex-reader.native375
-rw-r--r--tests/lhs-test.html63
-rw-r--r--tests/lhs-test.html+lhs63
-rw-r--r--tests/lhs-test.latex125
-rw-r--r--tests/lhs-test.latex+lhs87
-rw-r--r--tests/markdown-citations.native17
-rw-r--r--tests/markdown-reader-more.native198
-rw-r--r--tests/markdown-reader-more.txt320
-rw-r--r--tests/pipe-tables.native115
-rw-r--r--tests/rst-reader.native341
-rw-r--r--tests/s5-basic.html56
-rw-r--r--tests/s5-inserts.html34
-rw-r--r--tests/tables-rstsubset.native117
-rw-r--r--tests/tables.asciidoc67
-rw-r--r--tests/tables.context175
-rw-r--r--tests/tables.docbook432
-rw-r--r--tests/tables.docbook5432
-rw-r--r--tests/tables.dokuwiki47
-rw-r--r--tests/tables.fb22
-rw-r--r--tests/tables.haddock76
-rw-r--r--tests/tables.html204
-rw-r--r--tests/tables.icml757
-rw-r--r--tests/tables.latex168
-rw-r--r--tests/tables.man267
-rw-r--r--tests/tables.markdown78
-rw-r--r--tests/tables.mediawiki146
-rw-r--r--tests/tables.native114
-rw-r--r--tests/tables.opendocument397
-rw-r--r--tests/tables.plain78
-rw-r--r--tests/tables.rst90
-rw-r--r--tests/tables.rtf359
-rw-r--r--tests/tables.tei171
-rw-r--r--tests/tables.zimwiki56
-rw-r--r--tests/test-pandoc.hs67
-rw-r--r--tests/testsuite.native411
-rw-r--r--tests/testsuite.txt730
-rw-r--r--tests/textile-reader.native176
-rw-r--r--tests/textile-reader.textile278
-rw-r--r--tests/txt2tags.native552
-rw-r--r--tests/writer.asciidoc693
-rw-r--r--tests/writer.context888
-rw-r--r--tests/writer.docbook1422
-rw-r--r--tests/writer.docbook51397
-rw-r--r--tests/writer.dokuwiki642
-rw-r--r--tests/writer.fb22
-rw-r--r--tests/writer.haddock660
-rw-r--r--tests/writer.html546
-rw-r--r--tests/writer.icml3317
-rw-r--r--tests/writer.latex971
-rw-r--r--tests/writer.man795
-rw-r--r--tests/writer.markdown746
-rw-r--r--tests/writer.mediawiki653
-rw-r--r--tests/writer.native411
-rw-r--r--tests/writer.opendocument1539
-rw-r--r--tests/writer.opml72
-rw-r--r--tests/writer.org855
-rw-r--r--tests/writer.plain695
-rw-r--r--tests/writer.rst892
-rw-r--r--tests/writer.rtf451
-rw-r--r--tests/writer.tei861
-rw-r--r--tests/writer.texinfo1061
-rw-r--r--tests/writer.textile723
-rw-r--r--tests/writer.zimwiki627
-rw-r--r--tests/writers-lang-and-dir.context109
-rw-r--r--tests/writers-lang-and-dir.latex153
-rw-r--r--trypandoc/Makefile4
-rw-r--r--trypandoc/index.html48
-rw-r--r--trypandoc/trypandoc.hs77
1041 files changed, 96611 insertions, 53388 deletions
diff --git a/AUTHORS.md b/AUTHORS.md
new file mode 100644
index 000000000..a2c66d1e9
--- /dev/null
+++ b/AUTHORS.md
@@ -0,0 +1,197 @@
+# Contributors
+
+- Arata Mizuki
+- Aaron Wolen
+- Albert Krewinkel
+- Alex Ivkin
+- Alex Vong
+- Alexander Kondratskiy
+- Alexander Krotov
+- Alexander Sulfrian
+- Alexander V Vershilov
+- Alfred Wechselberger
+- Andreas Lööw
+- Andrew Dunning
+- Antoine Latter
+- Arata Mizuki
+- Arlo O'Keeffe
+- Artyom Kazak
+- Agustín Martín Barbero
+- B. Scott Michel
+- Ben Firshman
+- Ben Gamari
+- Beni Cherniavsky-Paskin
+- Benoit Schweblin
+- Bjorn Buckwalter
+- Bradley Kuhn
+- Brent Yorgey
+- Bryan O'Sullivan
+- Caleb McDaniel
+- Calvin Beck
+- Carlos Sosa
+- Chris Black
+- Christian Conkle
+- Christoffer Ackelman
+- Christoffer Sawicki
+- Clare Macrae
+- Clint Adams
+- Conal Elliott
+- Craig S. Bosma
+- Daniel Bergey
+- Daniel T. Staal
+- Daniele D'Orazio
+- David A Roberts
+- David Lazar
+- David Röthlisberger
+- Denis Laxalde
+- Douglas Calvert
+- Emanuel Evans
+- Emily Eisenberg
+- Eric Kow
+- Eric Seidel
+- Felix Yan
+- Florian Eitel
+- François Gannaz
+- Freiric Barral
+- Freirich Raabe
+- Frerich Raabe
+- Fyodor Sheremetyev
+- Gabor Pali
+- Gavin Beatty
+- Gottfried Haider
+- Greg Maslov
+- Greg Rundlett
+- Grégory Bataille
+- Gwern Branwen
+- Hamish Mackenzie
+- Hans-Peter Deifel
+- Henrik Tramberend
+- Henry de Valence
+- Hubert Plociniczak
+- Ilya V. Portnov
+- Ivo Clarysse
+- J. Lewis Muir
+- Jaime Marquínez Ferrándiz
+- Jakob Voß
+- James Aspnes
+- Jamie F. Olson
+- Jan Larres
+- Jan Schulz
+- Jason Ronallo
+- Jeff Arnold
+- Jeff Runningen
+- Jens Getreu
+- Jens Petersen
+- Jesse Rosenthal
+- Joe Hillenbrand
+- John MacFarlane
+- John Muccigrosso
+- John Luke Bentley
+- Jonas Smedegaard
+- Jonathan Daugherty
+- Jose Luis Duran
+- Josef Svenningsson
+- Julien Cretel
+- Juliusz Gonera
+- Justin Bogner
+- Jérémy Bobbio
+- Keiichiro Shikano
+- Kelsey Hightower
+- Kolen Cheung
+- Konstantin Zudov
+- Kristof Bastiaensen
+- Herwig Stuetz
+- Lars-Dominik Braun
+- Luke Plant
+- Marc Schreiber
+- Mark Szepieniec
+- Mark Wright
+- Martin Linn
+- Masayoshi Takahashi
+- Matej Kollar
+- Mathias Schenner
+- Mathieu Duponchelle
+- Matthew Eddey
+- Matthew Pickering
+- Matthias C. M. Troffaes
+- Mauro Bieg
+- Max Bolingbroke
+- Max Rydahl Andersen
+- Merijn Verstraaten
+- Michael Beaumont
+- Michael Chladek
+- Michael Snoyman
+- Michael Thompson
+- MinRK
+- Morton Fox
+- Nathan Gass
+- Neil Mayhew
+- Nick Bart
+- Nicolas Kaiser
+- Nikolay Yakimov
+- Oliver Matthews
+- Ophir Lifshitz
+- Or Neeman
+- Pablo Rodríguez
+- Paul Rivier
+- Paulo Tanimoto
+- Peter Wang
+- Philippe Ombredanne
+- Phillip Alday
+- Prayag Verma
+- Puneeth Chaganti
+- Ralf Stephan
+- Raniere Silva
+- Recai Oktaş
+- Roland Hieber
+- RyanGlScott
+- Sascha Wilde
+- Scott Morrison
+- Sebastian Talmon
+- Sergei Trofimovich
+- Sergey Astanin
+- Shahbaz Youssefi
+- Shaun Attfield
+- Sidarth Kapur
+- Sidharth Kapur
+- Simon Hengel
+- Stefan Dresselhaus
+- Sumit Sahrawat
+- Thenaesh Elango
+- Thomas Hodgson
+- Thomas Weißschuh
+- Tim Lin
+- Timm Albers
+- Timothy Humphries
+- Tiziano Müller
+- Todd Sifleet
+- Tom Leese
+- Uli Köhler
+- Václav Zeman
+- Viktor Kronvall
+- Vincent
+- Václav Haisman
+- Václav Zeman
+- Wandmalfarbe
+- Waldir Pimenta
+- Wikiwide
+- Xavier Olive
+- Yuchen Pei
+- bucklereed
+- bumper314
+- csforste
+- d-dorazio
+- iandol
+- infinity0x
+- lwolfsonkin
+- nkalvi
+- oltolm
+- qerub
+- robabla
+- roblabla
+- rodja.trappe
+- rski
+- shreevatsa.public
+- takahashim
+- tgkokk
+- thsutton
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d9c95702e..1145dd835 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,18 +1,24 @@
Contributing to pandoc
======================
+Have a question?
+----------------
+
+Ask on [pandoc-discuss].
+
+
Found a bug?
------------
Bug reports are welcome! Please report all bugs on pandoc's github
[issue tracker].
-Before you submit a bug report, search the (open *and* closed) issues to make
-sure the issue hasn't come up before. Also, check the [User's Guide] and [FAQs]
-for anything relevant.
+Before you submit a bug report, search the [open issues] *and* [closed issues]
+to make sure the issue hasn't come up before. Also, check the [User's Guide] and
+[FAQs] for anything relevant.
-Make sure you can reproduce the bug with the latest released version of pandoc
-(or, even better, the development version).
+Make sure you can reproduce the bug with the [latest released version] of pandoc
+(or, even better, the [development version]).
Your report should give detailed, *reproducible* instructions, including
@@ -31,25 +37,25 @@ Out of scope?
A less than perfect conversion does not necessarily mean there's
a bug in pandoc. Quoting from the MANUAL:
-> Because Pandoc's intermediate representation of a document is less
+> Because pandoc's intermediate representation of a document is less
> expressive than many of the formats it converts between, one should
> not expect perfect conversions between every format and every other.
> Pandoc attempts to preserve the structural elements of a document, but
> not formatting details such as margin size. And some document elements,
-> such as complex tables, may not fit into Pandoc's simple document
-> model. While conversions from Pandoc's Markdown to all formats aspire
-> to be perfect, conversions from formats more expressive than Pandoc's
+> such as complex tables, may not fit into pandoc's simple document
+> model. While conversions from pandoc's Markdown to all formats aspire
+> to be perfect, conversions from formats more expressive than pandoc's
> Markdown can be expected to be lossy.
-For example, both docx and odt can represent margin size, but because
-pandoc's internal document model does not contain a representation of
+For example, both `docx` and `odt` formats can represent margin size, but
+because pandoc's internal document model does not contain a representation of
margin size, this information will be lost on converting from docx
-to odt. (You can, however, customize margin size using `--reference-odt`.)
+to `odt`. (You can, however, customize margin size using `--reference-doc`.)
So before submitting a bug report, consider whether it might be
-"out of scope." If it concerns a feature of documents that isn't
+"out of scope." If it concerns a feature of documents that isn't
representable in pandoc's Markdown, then it very likely is.
-(If in doubt, you can always ask on pandoc-discuss.)
+(If in doubt, you can always ask on [pandoc-discuss].)
Fixing bugs from the issue tracker
----------------------------------
@@ -57,9 +63,9 @@ Fixing bugs from the issue tracker
Almost all the bugs on the issue tracker have one or more associated
tags. These are used to indicate the *complexity* and *nature* of a
bug. There is not yet a way to indicate priority. An up to date
-summary of issues can be found [here](https://github.com/jgm/pandoc/labels).
+summary of issues can be found on [GitHub labels].
-* [beginner-friendly] — The perfect starting point for new contributors. The
+* [good first issue] — The perfect starting point for new contributors. The
issue is generic and can be resolved without deep knowledge of the code
base.
* [enhancement] — A feature which would be desirable. We recommend
@@ -71,7 +77,7 @@ summary of issues can be found [here](https://github.com/jgm/pandoc/labels).
knowledge of the code base.
* [new:reader] — A request to add a new input format.
* [new:writer] — A request to add a new output format.
-* [docs] — A discrepency, or ambiguity in the documentation.
+* [docs] — A discrepancy, or ambiguity in the documentation.
* [status:in-progress] — Someone is actively working on or planning to work on the
ticket.
* [status:more-discussion-needed] — It is unclear what the correct approach
@@ -86,8 +92,8 @@ or bug reports related to Markdown are labelled with [format:markdown].
Have an idea for a new feature?
-------------------------------
-First, search [pandoc-discuss] and the issue tracker (both open and closed
-issues) to make sure that the idea has not been discussed before.
+First, search [pandoc-discuss] and the issue tracker (both [open issues] *and*
+[closed issues]) to make sure that the idea has not been discussed before.
Explain the rationale for the feature you're requesting. Why would this
feature be useful? Consider also any possible drawbacks, including backwards
@@ -130,7 +136,7 @@ Please follow these guidelines:
below under [Tests](#tests).) If you are adding a new writer or reader,
you must include tests.
-7. If you are adding a new feature, include updates to MANUAL.txt.
+7. If you are adding a new feature, include updates to `MANUAL.txt`.
8. All code must be released under the general license governing pandoc
(GPL v2).
@@ -140,7 +146,7 @@ Please follow these guidelines:
10. We aim for compatibility with ghc versions from 7.8.3 to the
latest release. All pull requests and commits are tested
- automatically on travis-ci.org, using GHC versions in the
+ automatically on <travis-ci.org>, using GHC versions in the
`Tested-With` stanza of `pandoc.cabal`. We currently relax
the "`-Wall` clean" requirement for GHC 7.10.x, because
there are so many warnings relating to the addition of type
@@ -161,7 +167,7 @@ or, if you're using [stack],
stack setup
stack test
-The test program is `tests/test-pandoc.hs`.
+The test program is `test/test-pandoc.hs`.
Benchmarks
----------
@@ -176,6 +182,11 @@ With stack:
stack bench
+You can also build pandoc with the `weigh-pandoc` flag and
+run `weigh-pandoc` to get some statistics on memory usage.
+(Eventually this should be incorporated into the benchmark
+suite.)
+
Using the REPL
--------------
@@ -186,43 +197,60 @@ a ghci REPL for working with pandoc. With [stack], use
We recommend using the following `.ghci` file (which can be
placed in the source directory):
-```
-:set -fobject-code
-:set -XTypeSynonymInstances
-:set -XScopedTypeVariables
-:set -XOverloadedStrings
-```
+ :set -fobject-code
+ :set -XTypeSynonymInstances
+ :set -XScopedTypeVariables
+ :set -XOverloadedStrings
-The code
---------
+Profiling
+---------
-Pandoc has a publicly accessible git repository on
-github: <http://github.com/jgm/pandoc>. To get a local copy of the source:
+To use the GHC profiler with cabal:
- git clone git://github.com/jgm/pandoc.git
+ cabal clean
+ cabal install --enable-library-profiling --enable-executable-profiling
+ pandoc +RTS -p -RTS [file]...
+ less pandoc.prof
-Note: after cloning the repository (and in the future after pulling from it),
-you should do
+With stack:
- git submodule update --init
+ stack clean
+ stack install --profile
+ pandoc +RTS -p -RTS [file]...
+ less pandoc.prof
-to pull in changes to the templates (`data/templates/`). You can automate this
-by creating a file `.git/hooks/post-merge` with the contents:
+Templates
+---------
- #!/bin/sh
- git submodule update --init
+The default templates live in `data/templates`, which is a git
+subtree linked to <https://github.com/jgm/pandoc-templates.git>.
+The purpose of maintaining a separate repository is to allow
+people to maintain variant templates as a fork.
-and making it executable:
+You can modify the templates and submit patches without worrying
+much about this: when these patches are merged, we will
+push them to the main templates repository by doing
+
+ git subtree push --prefix=data/templates templates master
+
+where `templates` is a remote pointing to the templates
+repository.
+
+The code
+--------
+
+Pandoc has a publicly accessible git repository on
+github: <http://github.com/jgm/pandoc>. To get a local copy of the source:
- chmod +x .git/hooks/post-merge
+ git clone https://github.com/jgm/pandoc.git
The source for the main pandoc program is `pandoc.hs`. The source for
the pandoc library is in `src/`, the source for the tests is in
-`tests/`, and the source for the benchmarks is in `benchmark/`.
+`test/`, and the source for the benchmarks is in `benchmark/`.
The modules `Text.Pandoc.Definition`, `Text.Pandoc.Builder`, and
`Text.Pandoc.Generic` are in a separate library `pandoc-types`. The code can
-be found in a <http://github.com/jgm/pandoc-types>.
+be found in <http://github.com/jgm/pandoc-types>.
To build pandoc, you will need a working installation of the
[Haskell platform].
@@ -261,7 +289,7 @@ The library is structured as follows:
the needs of pandoc.
- `Text.Pandoc.SelfContained` contains functions for making an HTML
file "self-contained," by importing remotely linked images, CSS,
- and javascript and turning them into `data:` URLs.
+ and JavaScript and turning them into `data:` URLs.
- `Text.Pandoc.Shared` is a grab-bag of shared utility functions.
- `Text.Pandoc.Writers.Shared` contains utilities used in writers only.
- `Text.Pandoc.Slides` contains functions for splitting a markdown document
@@ -274,6 +302,10 @@ The library is structured as follows:
- `Text.Pandoc.UUID` contains functions for generating UUIDs.
- `Text.Pandoc.XML` contains functions for formatting XML.
+[open issues]: https://github.com/jgm/pandoc/issues
+[closed issues]: https://github.com/jgm/pandoc/issues?q=is%3Aissue+is%3Aclosed
+[latest released version]: https://github.com/jgm/pandoc/releases/latest
+[development version]: https://github.com/pandoc-extras/pandoc-nightly/releases/latest
[pandoc-discuss]: http://groups.google.com/group/pandoc-discuss
[issue tracker]: https://github.com/jgm/pandoc/issues
[User's Guide]: http://pandoc.org/MANUAL.html
@@ -281,7 +313,8 @@ The library is structured as follows:
[EditorConfig]: http://editorconfig.org/
[Haskell platform]: http://www.haskell.org/platform/
[hsb2hs]: http://hackage.haskell.org/package/hsb2hs
-[beginner-friendly]: https://github.com/jgm/pandoc/labels/beginner-friendly
+[GitHub labels]: https://github.com/jgm/pandoc/labels
+[good first issue]:https://github.com/jgm/pandoc/labels/good%20first%20issue
[enhancement]: https://github.com/jgm/pandoc/labels/enhancement
[bug]: https://github.com/jgm/pandoc/labels/bug
[complexity:low]: https://github.com/jgm/pandoc/labels/complexity:low
diff --git a/COPYRIGHT b/COPYRIGHT
index 70781a2de..711b8f299 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,7 +1,8 @@
Pandoc
-Copyright (C) 2006-2017 John MacFarlane <jgm at berkeley dot edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm at berkeley dot edu>
-This code is released under the [GPL], version 2 or later:
+With the exceptions noted below, this code is released under the [GPL],
+version 2 or later:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,38 +28,101 @@ Pandoc's complete source code is available from the [Pandoc home page].
[Pandoc home page]: http://pandoc.org
-Pandoc includes some code from other authors. The copyright and license
-statements for these sources are included below. All are GPL-compatible
-licenses.
+Pandoc includes some code with different copyrights, or subject to different
+licenses. The copyright and license statements for these sources are included
+below. All are GPL-compatible licenses.
+
+----------------------------------------------------------------------
+The modules in the `pandoc-types` repository (Text.Pandoc.Definition,
+Text.Pandoc.Builder, Text.Pandoc.Generics, Text.Pandoc.JSON,
+Text.Pandoc.Walk) are licensed under the BSD 3-clause license:
+
+Copyright (c) 2006-2018, John MacFarlane
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of John MacFarlane nor the names of other
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+Pandoc's templates (in `data/templates`) are dual-licensed GPL (v2 or
+higher, same as pandoc) and the BSD 3-clause license.
+
+Copyright (c) 2014--2018, John MacFarlane
+
+----------------------------------------------------------------------
+src/Text/Pandoc/Writers/Muse.hs
+Copyright (C) 2017-2018 Alexander Krotov
+
+Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Writers/Texinfo.hs
-Copyright (C) 2008-2015 John MacFarlane and Peter Wang
+Copyright (C) 2008-2018 John MacFarlane and Peter Wang
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Writers/OpenDocument.hs
-Copyright (C) 2008-2015 Andrea Rossato and John MacFarlane
+Copyright (C) 2008-2018 Andrea Rossato and John MacFarlane
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Writers/Org.hs
-Copyright (C) 2010-2015 Puneeth Chaganti and John MacFarlane
+Copyright (C) 2010-2018 Puneeth Chaganti, John MacFarlane, and
+ Albert Krewinkel
+
+Released under the GNU General Public License version 2 or later.
+
+----------------------------------------------------------------------
+src/Text/Pandoc/Writers/ZimWiki.hs
+Copyright (C) 2017 Alex Ivkin
+
+Released under the GNU General Public License version 2 or later.
+
+----------------------------------------------------------------------
+src/Text/Pandoc/Readers/Docx.hs
+src/Text/Pandoc/Readers/Docx/*
+Copyright (C) 2014-2018 Jesse Rosenthal
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Readers/Textile.hs
-Copyright (C) 2010-2015 Paul Rivier and John MacFarlane
+Copyright (C) 2010-2018 Paul Rivier and John MacFarlane
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Readers/Org.hs
-tests/Tests/Readers/Org.hs
-Copyright (C) 2014-2015 Albert Krewinkel
+src/Text/Pandoc/Readers/Org/*
+test/Tests/Readers/Org/*
+Copyright (C) 2014-2018 Albert Krewinkel
Released under the GNU General Public License version 2 or later.
@@ -77,7 +141,13 @@ Copyright (C) 2004 Peter Jipsen http://www.chapman.edu/~jipsen
Released under the GNU General Public License version 2 or later.
------------------------------------------------------------------------
-The dzslides template contains javascript and CSS from Paul Rouget's
+data/pandoc.lua
+Copyright (C) 2017-2018 Albert Krewinkel
+
+Released under the GNU General Public License version 2 or later.
+
+----------------------------------------------------------------------
+The dzslides template contains JavaScript and CSS from Paul Rouget's
dzslides template.
http://github.com/paulrouget/dzslides
@@ -86,7 +156,7 @@ Released under the Do What the Fuck You Want To Public License.
------------------------------------------------------------------------
Pandoc embeds a lua interpreter (via hslua).
-Copyright © 1994–2015 Lua.org, PUC-Rio.
+Copyright © 1994–2017 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -106,3 +176,12 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+------------------------------------------------------------------------
+The template pandoc.jats is Copyright 2013--15 Martin Fenner,
+released under GPL version 2 or later.
+
+The file data/jats.csl is derived from a csl file by Martin Fenner,
+revised by Martin Paul Eve and then John MacFarlane.
+"This work is licensed under a Creative Commons Attribution-ShareAlike 3.0
+License. Originally by Martin Fenner."
diff --git a/INSTALL.md b/INSTALL.md
index 631641307..7e983d1c0 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -3,41 +3,32 @@
## Windows
- There is a package installer at pandoc's [download page].
+ This will install pandoc, replacing older versions, and
+ update your path to include the directory where pandoc's
+ binaries are installed.
+
+ - If you prefer not to use the msi installer, we also provide
+ a zip file that contains pandoc's binaries and
+ documentation. Simply unzip this file and move the binaries
+ to a directory of your choice.
- For PDF output, you'll also need to install LaTeX.
We recommend [MiKTeX](http://miktex.org/).
- - If you'd prefer, you can extract the pandoc and pandoc-citeproc
- executables from the MSI and copy them directly to any directory,
- without running the installer. Here is an example showing how to
- extract the executables from the pandoc-1.19.1 installer and copy
- them to `C:\Utils\Console\`:
-
- mkdir "%TEMP%\pandoc\"
- start /wait msiexec.exe /a pandoc-1.19.1-windows.msi /qn targetdir="%TEMP%\pandoc\"
- copy /y "%TEMP%\pandoc\pandoc.exe" C:\Utils\Console\
- copy /y "%TEMP%\pandoc\pandoc-citeproc.exe" C:\Utils\Console\
- rmdir /s /q "%TEMP%\pandoc\"
+## macOS
-## Mac OS X
+ - You can install pandoc using
+ [homebrew](http://brew.sh): `brew install pandoc`.
- There is a package installer at pandoc's [download page].
If you later want to uninstall the package, you can do so
by downloading [this script][uninstaller]
and running it with `perl uninstall-pandoc.pl`.
- - It is possible to extract the pandoc and pandoc-citeproc
- executables from the osx pkg file, if you'd rather not run
- the installer. To do this (for the version 1.19.1 package):
-
- mkdir pandoc-extract
- cd pandoc-extract
- xar -x ../pandoc-1.19.1-osx.pkg
- cat pandoc.pkg/Payload | gunzip -dc | cpio -i
- # executables are now in ./usr/bin/, man pages in ./usr/share/man
-
- - You can also install pandoc using
- [homebrew](http://brew.sh): `brew install pandoc`.
+ - We also provide a zip file containing the binaries and man
+ pages, for those who prefer not to use the installer. Simply
+ unzip the file and move the binaries and man pages to
+ whatever directory you like.
- For PDF output, you'll also need LaTeX. Because a full [MacTeX]
installation takes more than a gigabyte of disk space, we recommend
@@ -55,28 +46,37 @@
Note, however, that versions in the repositories are often
old.
- - For 64-bit [Debian] and [Ubuntu], we provide a debian package
- on the [download page].
+ - We provide a binary package for amd64 architecture on
+ the [download page]. This provides both `pandoc` and
+ `pandoc-citeproc`. The executables are statically linked and
+ have no dynamic dependencies or dependencies on external
+ data files. Note: because of the static
+ linking, the pandoc binary from this package cannot use lua
+ filters that require external lua modules written in C.
+
+ Both a tarball and a deb installer are provided. To install the deb:
sudo dpkg -i $DEB
- where `$DEB` is the path to the downloaded deb, will
- install the `pandoc` and `pandoc-citeproc` executables
- and man pages. If you use an RPM-based distro, you may be
- able to install this deb using `alien`, or try
+ where `$DEB` is the path to the downloaded deb. This will
+ install the `pandoc` and `pandoc-citeproc` executables and
+ man pages.
+
+ If you use an RPM-based distro, you may be able to install
+ the deb from our download page using `alien`.
- ar p $DEB data.tar.gz | sudo tar xvz --strip-components 2 -C /usr/local
+ On any distro, you may install from the tarball into `$DEST`
+ (say, `/usr/local/` or `$HOME/.local`) by doing
- - If you'd rather install pandoc in your home directory, say
- in `$HOME/.local`, then you can extract the files manually
- from the deb:
+ tar xvzf $TGZ --strip-components 1 -C $DEST
- ar p $DEB data.tar.gz | tar xvz --strip-components 2 -C $HOME/.local/
+ where `$TGZ` is the path to the downloaded zipped tarball.
+ For Pandoc versions before 2.0, which don't provide
+ a tarball, try instead
- where, again, `$DEB` is the path to the downloaded deb.
+ ar p $DEB data.tar.gz | tar xvz --strip-components 2 -C $DEST
- - If the version in your repository is too old and you cannot
- use the deb we provide, you can install from source, using the
+ - You can also install from source, using the
instructions below under [Compiling from source].
Note that most distros have the Haskell platform in their
package repositories. For example, on Debian/Ubuntu,
@@ -110,7 +110,6 @@ Or you can fetch the development code by cloning the repository:
git clone https://github.com/jgm/pandoc
cd pandoc
- git submodule update --init # to fetch the templates
Note: there may be times when the development code is broken
or depends on other libraries which must be installed
@@ -121,7 +120,7 @@ the last released version.
The easiest way to build pandoc from source is to use [stack]:
-1. Install [stack].
+1. Install [stack]. Note that Pandoc requires stack >= 1.6.0.
2. Change to the pandoc source directory and issue the following commands:
@@ -138,7 +137,7 @@ The easiest way to build pandoc from source is to use [stack]:
1. Install the [Haskell platform]. This will give you [GHC] and
the [cabal-install] build tool. Note that pandoc requires
- GHC >= 7.8.
+ GHC >= 7.10.
2. Update your package database:
@@ -157,13 +156,6 @@ The easiest way to build pandoc from source is to use [stack]:
cabal install
- Note: If you obtained the source from the git repository (rather
- than a release tarball), you'll need to do
-
- git submodule update --init
-
- to fetch the contents of `data/templates` before `cabal install`.
-
4. Make sure the `$CABALDIR/bin` directory is in your path. You should
now be able to run `pandoc`:
@@ -186,7 +178,7 @@ The easiest way to build pandoc from source is to use [stack]:
Note that this requires the `text-icu` library, which in turn
depends on the C library `icu4c`. Installation directions
- vary by platform. Here is how it might work on OSX with homebrew:
+ vary by platform. Here is how it might work on macOS with homebrew:
brew install icu4c
cabal install --extra-lib-dirs=/usr/local/Cellar/icu4c/51.1/lib \
@@ -232,9 +224,6 @@ assume that the pandoc source directory is your working directory.
- `embed_data_files`: embed all data files into the binary (default no).
This is helpful if you want to create a relocatable binary.
- Note: if this option is selected, you need to install the
- `hsb2hs` preprocessor: `cabal install hsb2hs` (version 0.3.1 or
- higher is required).
- `https`: enable support for downloading resources over https
(using the `http-client` and `http-client-tls` libraries).
@@ -281,16 +270,24 @@ To run with cabal, `cabal test`; to run with stack, `stack
test`.
To run particular tests (pattern-matching on their names), use
-the `-t` option:
+the `-p` option:
+
+ cabal test --test-options='-p markdown'
+
+Or with stack:
- cabal test --test-options='-t markdown'
+ stack test --test-arguments='-p markdown'
+
+It is often helpful to add `-j4` (run tests in parallel)
+and `--hide-successes` (don't clutter output with successes)
+to the test arguments as well.
If you add a new feature to pandoc, please add tests as well, following
the pattern of the existing tests. The test suite code is in
-`tests/test-pandoc.hs`. If you are adding a new reader or writer, it is
-probably easiest to add some data files to the `tests` directory, and
-modify `tests/Tests/Old.hs`. Otherwise, it is better to modify the module
-under the `tests/Tests` hierarchy corresponding to the pandoc module you
+`test/test-pandoc.hs`. If you are adding a new reader or writer, it is
+probably easiest to add some data files to the `test` directory, and
+modify `test/Tests/Old.hs`. Otherwise, it is better to modify the module
+under the `test/Tests` hierarchy corresponding to the pandoc module you
are changing.
### Running benchmarks
@@ -312,34 +309,10 @@ To run just the markdown benchmarks:
cabal bench --benchmark-options='markdown'
-### Building the whole pandoc ecosystem
-
-Sometimes pandoc's development code depends on unreleased versions
-of dependent libraries. You'll need to build these as well. A
-maximal build method would be
-
- mkdir pandoc-build
- cd pandoc-build
- git clone https://github.com/jgm/pandoc-types
- git clone https://github.com/jgm/texmath
- git clone https://github.com/jgm/pandoc-citeproc
- git clone https://github.com/jgm/pandoc
- git clone https://github.com/jgm/cmark-hs
- git clone https://github.com/jgm/zip-archive
- cd pandoc
- git submodule update --init
- stack install --test --install-ghc --stack-yaml stack.full.yaml
-
-To pull in the latest changes, after you've done this and there have been
-changes in the repositories: Visit each repository in pandoc-build
-(pandoc-types, texmath, pandoc-citeproc, pandoc, zip-archive, cmark-hs) and do
-`git pull`. In the pandoc repo, also do `git submodule update` and `stack
-install --test --stack-yaml stack.full.yaml`.
-
[Arch]: https://www.archlinux.org/packages/community/x86_64/pandoc/
[Cabal User's Guide]: http://www.haskell.org/cabal/release/latest/doc/users-guide/builders.html#setup-configure-paths
-[Debian]: http://packages.debian.org/lenny/pandoc
+[Debian]: https://packages.debian.org/pandoc
[Fedora]: https://apps.fedoraproject.org/packages/pandoc
[FreeBSD ports]: http://www.freshports.org/textproc/pandoc/
[GHC]: http://www.haskell.org/ghc/
@@ -348,9 +321,9 @@ install --test --stack-yaml stack.full.yaml`.
[MacPorts]: http://trac.macports.org/browser/trunk/dports/textproc/pandoc/Portfile
[MacTeX]: https://tug.org/mactex/
[NetBSD]: http://pkgsrc.se/wip/pandoc
-[NixOS]: http://nixos.org/nixos/
-[Slackware]: http://www.linuxpackages.net/search_view.php?by=name&name=pandoc&ver=
-[Ubuntu]: http://www.ubuntu.com
+[NixOS]: https://nixos.org/nixos/packages.html
+[Slackware]: https://www.slackbuilds.org/result/?search=pandoc&sv=
+[Ubuntu]: https://packages.ubuntu.com/pandoc
[download page]: https://github.com/jgm/pandoc/releases/latest
[gentoo]: http://packages.gentoo.org/package/app-text/pandoc
[haskell repository]: https://wiki.archlinux.org/index.php/Haskell_Package_Guidelines#.5Bhaskell.5D
@@ -358,4 +331,4 @@ install --test --stack-yaml stack.full.yaml`.
[source tarball]: http://hackage.haskell.org/package/pandoc
[stack]: http://docs.haskellstack.org/en/stable/install_and_upgrade.html
[cabal-install]: http://hackage.haskell.org/trac/hackage/wiki/CabalInstall
-[uninstaller]: https://raw.githubusercontent.com/jgm/pandoc/master/osx/uninstall-pandoc.pl
+[uninstaller]: https://raw.githubusercontent.com/jgm/pandoc/master/macos/uninstall-pandoc.pl
diff --git a/MANUAL.txt b/MANUAL.txt
index ba6f25a3e..168f1784e 100644
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -1,6 +1,6 @@
% Pandoc User's Guide
% John MacFarlane
-% January 29, 2017
+% March 2, 2018
Synopsis
========
@@ -11,36 +11,42 @@ Description
===========
Pandoc is a [Haskell] library for converting from one markup format to
-another, and a command-line tool that uses this library. It can read
-[Markdown], [CommonMark], [PHP Markdown Extra], [GitHub-Flavored Markdown],
-[MultiMarkdown], and (subsets of) [Textile], [reStructuredText], [HTML],
-[LaTeX], [MediaWiki markup], [TWiki markup], [Haddock markup], [OPML], [Emacs
-Org mode], [DocBook], [txt2tags], [EPUB], [ODT] and [Word docx]; and it can
-write plain text, [Markdown], [CommonMark], [PHP Markdown Extra],
-[GitHub-Flavored Markdown], [MultiMarkdown], [reStructuredText], [XHTML],
-[HTML5], [LaTeX] \(including [`beamer`] slide shows\), [ConTeXt], [RTF], [OPML],
-[DocBook], [OpenDocument], [ODT], [Word docx], [GNU Texinfo], [MediaWiki
-markup], [DokuWiki markup], [ZimWiki markup], [Haddock markup],
-[EPUB] \(v2 or v3\), [FictionBook2], [Textile], [groff man] pages,
-[Emacs Org mode], [AsciiDoc], [InDesign ICML], [TEI Simple], and [Slidy],
-[Slideous], [DZSlides], [reveal.js] or [S5] HTML slide shows. It can also
-produce [PDF] output on systems where LaTeX, ConTeXt, or `wkhtmltopdf` is
-installed.
-
-Pandoc's enhanced version of Markdown includes syntax for [footnotes],
-[tables], flexible [ordered lists], [definition lists], [fenced code blocks],
-[superscripts and subscripts], [strikeout], [metadata blocks], automatic tables of
-contents, embedded LaTeX [math], [citations], and [Markdown inside HTML block
-elements][Extension: `markdown_in_html_blocks`]. (These enhancements, described
-further under [Pandoc's Markdown], can be disabled using the
-`markdown_strict` input or output format.)
-
-In contrast to most existing tools for converting Markdown to HTML, which
-use regex substitutions, pandoc has a modular design: it consists of a
-set of readers, which parse text in a given format and produce a native
-representation of the document, and a set of writers, which convert
+another, and a command-line tool that uses this library.
+
+Pandoc can read [Markdown], [CommonMark], [PHP Markdown Extra],
+[GitHub-Flavored Markdown], [MultiMarkdown], and (subsets of) [Textile],
+[reStructuredText], [HTML], [LaTeX], [MediaWiki markup], [TWiki
+markup], [TikiWiki markup], [Creole 1.0], [Haddock markup], [OPML],
+[Emacs Org mode], [DocBook], [JATS], [Muse], [txt2tags], [Vimwiki],
+[EPUB], [ODT], and [Word docx].
+
+Pandoc can write plain text, [Markdown],
+[CommonMark], [PHP Markdown Extra], [GitHub-Flavored Markdown],
+[MultiMarkdown], [reStructuredText], [XHTML], [HTML5], [LaTeX]
+\(including [`beamer`] slide shows\), [ConTeXt], [RTF], [OPML],
+[DocBook], [JATS], [OpenDocument], [ODT], [Word docx], [GNU Texinfo],
+[MediaWiki markup], [DokuWiki markup], [ZimWiki markup], [Haddock
+markup], [EPUB] \(v2 or v3\), [FictionBook2], [Textile], [groff man],
+[groff ms], [Emacs Org mode], [AsciiDoc], [InDesign ICML], [TEI
+Simple], [Muse], [PowerPoint] slide shows and [Slidy], [Slideous],
+[DZSlides], [reveal.js] or [S5] HTML slide shows. It can also produce
+[PDF] output on systems where LaTeX, ConTeXt, `pdfroff`,
+`wkhtmltopdf`, `prince`, or `weasyprint` is installed.
+
+Pandoc's enhanced version of Markdown includes syntax for [tables],
+[definition lists], [metadata blocks], [`Div` blocks][Extension:
+`fenced_divs`], [footnotes] and [citations], embedded
+[LaTeX][Extension: `raw_tex`] (including [math]), [Markdown inside HTML
+block elements][Extension: `markdown_in_html_blocks`], and much more.
+These enhancements, described further under [Pandoc's Markdown],
+can be disabled using the `markdown_strict` format.
+
+Pandoc has a modular design: it consists of a set of readers, which parse
+text in a given format and produce a native representation of the document
+(like an _abstract syntax tree_ or AST), and a set of writers, which convert
this native representation into a target format. Thus, adding an input
-or output format requires only adding a reader or writer.
+or output format requires only adding a reader or writer. Users can also
+run custom [pandoc filters] to modify the intermediate AST.
Because pandoc's intermediate representation of a document is less
expressive than many of the formats it converts between, one should
@@ -63,6 +69,7 @@ Markdown can be expected to be lossy.
[Slideous]: http://goessner.net/articles/slideous/
[HTML]: http://www.w3.org/html/
[HTML5]: http://www.w3.org/TR/html5/
+[polyglot markup]: https://www.w3.org/TR/html-polyglot/
[XHTML]: http://www.w3.org/TR/xhtml1/
[LaTeX]: http://latex-project.org
[`beamer`]: https://ctan.org/pkg/beamer
@@ -70,6 +77,7 @@ Markdown can be expected to be lossy.
[ConTeXt]: http://www.contextgarden.net/
[RTF]: http://en.wikipedia.org/wiki/Rich_Text_Format
[DocBook]: http://docbook.org
+[JATS]: https://jats.nlm.nih.gov
[txt2tags]: http://txt2tags.org
[EPUB]: http://idpf.org/epub
[OPML]: http://dev.opml.org/spec2.html
@@ -80,8 +88,11 @@ Markdown can be expected to be lossy.
[DokuWiki markup]: https://www.dokuwiki.org/dokuwiki
[ZimWiki markup]: http://zim-wiki.org/manual/Help/Wiki_Syntax.html
[TWiki markup]: http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules
+[TikiWiki markup]: https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax
[Haddock markup]: https://www.haskell.org/haddock/doc/html/ch03s08.html
+[Creole 1.0]: http://www.wikicreole.org/wiki/Creole1.0
[groff man]: http://man7.org/linux/man-pages/man7/groff_man.7.html
+[groff ms]: http://man7.org/linux/man-pages/man7/groff_ms.7.html
[Haskell]: https://www.haskell.org
[GNU Texinfo]: http://www.gnu.org/software/texinfo/
[Emacs Org mode]: http://orgmode.org
@@ -91,44 +102,41 @@ Markdown can be expected to be lossy.
[PDF]: https://www.adobe.com/pdf/
[reveal.js]: http://lab.hakim.se/reveal-js/
[FictionBook2]: http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1
-[InDesign ICML]: https://www.adobe.com/content/dam/Adobe/en/devnet/indesign/cs55-docs/IDML/idml-specification.pdf
+[InDesign ICML]: http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf
[TEI Simple]: https://github.com/TEIC/TEI-Simple
+[Muse]: https://amusewiki.org/library/manual
+[PowerPoint]: https://en.wikipedia.org/wiki/Microsoft_PowerPoint
+[Vimwiki]: https://vimwiki.github.io
Using `pandoc`
--------------
-If no *input-file* is specified, input is read from *stdin*.
-Otherwise, the *input-files* are concatenated (with a blank
-line between each) and used as input. Output goes to *stdout* by
-default (though output to *stdout* is disabled for the `odt`, `docx`,
-`epub`, and `epub3` output formats). For output to a file, use the
-`-o` option:
+If no *input-files* are specified, input is read from *stdin*.
+Output goes to *stdout* by default. For output to a file,
+use the `-o` option:
pandoc -o output.html input.txt
-By default, pandoc produces a document fragment, not a standalone
-document with a proper header and footer. To produce a standalone
-document, use the `-s` or `--standalone` flag:
+By default, pandoc produces a document fragment. To produce a standalone
+document (e.g. a valid HTML file including `<head>` and `<body>`),
+use the `-s` or `--standalone` flag:
pandoc -s -o output.html input.txt
For more information on how standalone documents are produced, see
-[Templates], below.
-
-Instead of a file, an absolute URI may be given. In this case
-pandoc will fetch the content using HTTP:
-
- pandoc -f html -t markdown http://www.fsf.org
+[Templates] below.
If multiple input files are given, `pandoc` will concatenate them all (with
-blank lines between them) before parsing. This feature is disabled for
- binary input formats such as `EPUB`, `odt`, and `docx`.
+blank lines between them) before parsing. (Use `--file-scope` to parse files
+individually.)
+
+Specifying formats
+------------------
The format of the input and output can be specified explicitly using
command-line options. The input format can be specified using the
-`-r/--read` or `-f/--from` options, the output format using the
-`-w/--write` or `-t/--to` options. Thus, to convert `hello.txt` from
-Markdown to LaTeX, you could type:
+`-f/--from` option, the output format using the `-t/--to` option.
+Thus, to convert `hello.txt` from Markdown to LaTeX, you could type:
pandoc -f markdown -t latex hello.txt
@@ -136,14 +144,15 @@ To convert `hello.html` from HTML to Markdown:
pandoc -f html -t markdown hello.html
-Supported output formats are listed below under the `-t/--to` option.
-Supported input formats are listed below under the `-f/--from` option. Note
-that the `rst`, `textile`, `latex`, and `html` readers are not complete;
-there are some constructs that they do not parse.
+Supported input and output formats are listed below under [Options]
+(see `-f` for input formats and `-t` for output formats). You
+can also use `pandoc --list-input-formats` and
+`pandoc --list-output-formats` to print lists of supported
+formats.
If the input or output format is not specified explicitly, `pandoc`
-will attempt to guess it from the extensions of
-the input and output filenames. Thus, for example,
+will attempt to guess it from the extensions of the filenames.
+Thus, for example,
pandoc -o hello.tex hello.txt
@@ -152,7 +161,10 @@ is specified (so that output goes to *stdout*), or if the output file's
extension is unknown, the output format will default to HTML.
If no input file is specified (so that input comes from *stdin*), or
if the input files' extensions are unknown, the input format will
-be assumed to be Markdown unless explicitly specified.
+be assumed to be Markdown.
+
+Character encoding
+------------------
Pandoc uses the UTF-8 character encoding for both input and output.
If your local character encoding is not UTF-8, you
@@ -170,45 +182,56 @@ will only be included if you use the `-s/--standalone` option.
Creating a PDF
--------------
-To produce a PDF, specify an output file with a `.pdf` extension.
-By default, pandoc will use LaTeX to convert it to PDF:
+To produce a PDF, specify an output file with a `.pdf` extension:
pandoc test.txt -o test.pdf
-Production of a PDF requires that a LaTeX engine be installed (see
-`--latex-engine`, below), and assumes that the following LaTeX packages
-are available: [`amsfonts`], [`amsmath`], [`lm`],
-[`ifxetex`], [`ifluatex`], [`eurosym`], [`listings`] (if the
-`--listings` option is used), [`fancyvrb`], [`longtable`],
-[`booktabs`], [`graphicx`] and [`grffile`] (if the
-document contains images), [`hyperref`], [`ulem`],
-[`geometry`] (with the `geometry` variable set), [`setspace`] (with
-`linestretch`), and [`babel`] (with `lang`). The use of `xelatex` or
-`lualatex` as the LaTeX engine requires [`fontspec`]; `xelatex` uses
-[`mathspec`], [`polyglossia`] (with `lang`), [`xecjk`], and
-[`bidi`] (with the `dir` variable set). The [`upquote`] and
-[`microtype`] packages are used if available, and [`csquotes`] will
-be used for [smart punctuation] if added to the template or included in
-any header file. The [`natbib`], [`biblatex`], [`bibtex`], and [`biber`]
-packages can optionally be used for [citation rendering]. These are
-included with all recent versions of [TeX Live].
-
-Alternatively, pandoc can use ConTeXt or `wkhtmltopdf` to create a PDF.
-To do this, specify an output file with a `.pdf` extension,
-as before, but add `-t context` or `-t html5` to the command line.
+By default, pandoc will use LaTeX to create the PDF, which requires
+that a LaTeX engine be installed (see `--pdf-engine` below).
+
+Alternatively, pandoc can use [ConTeXt], `pdfroff`, or any of the
+following HTML/CSS-to-PDF-engines, to create a PDF: [`wkhtmltopdf`],
+[`weasyprint`] or [`prince`].
+To do this, specify an output file with a `.pdf` extension, as before,
+but add the `--pdf-engine` option or `-t context`, `-t html`, or `-t ms`
+to the command line (`-t html` defaults to `--pdf-engine=wkhtmltopdf`).
PDF output can be controlled using [variables for LaTeX] (if
LaTeX is used) and [variables for ConTeXt] (if ConTeXt is used).
+When using an HTML/CSS-to-PDF-engine, `--css` affects the output.
If `wkhtmltopdf` is used, then the variables `margin-left`,
-`margin-right`, `margin-top`, `margin-bottom`, and `papersize`
-will affect the output, as will `--css`.
+`margin-right`, `margin-top`, `margin-bottom`, `footer-html`,
+`header-html` and `papersize` will affect the output.
+
+To debug the PDF creation, it can be useful to look at the intermediate
+representation: instead of `-o test.pdf`, use for example `-s -o test.tex`
+to output the generated LaTeX. You can then test it with `pdflatex test.tex`.
+
+When using LaTeX, the following packages need to be available
+(they are included with all recent versions of [TeX Live]):
+[`amsfonts`], [`amsmath`], [`lm`], [`unicode-math`],
+[`ifxetex`], [`ifluatex`], [`listings`] (if the
+`--listings` option is used), [`fancyvrb`], [`longtable`],
+[`booktabs`], [`graphicx`] and [`grffile`] (if the document
+contains images), [`hyperref`], [`xcolor`] (with `colorlinks`),
+[`ulem`], [`geometry`] (with the `geometry` variable set),
+[`setspace`] (with `linestretch`), and
+[`babel`] (with `lang`). The use of `xelatex` or `lualatex` as
+the LaTeX engine requires [`fontspec`]. `xelatex` uses
+[`polyglossia`] (with `lang`), [`xecjk`], and [`bidi`] (with the
+`dir` variable set). If the `mathspec` variable is set,
+`xelatex` will use [`mathspec`] instead of [`unicode-math`].
+The [`upquote`] and [`microtype`] packages are used if
+available, and [`csquotes`] will be used for [typography]
+if added to the template or included in any header file. The
+[`natbib`], [`biblatex`], [`bibtex`], and [`biber`] packages can
+optionally be used for [citation rendering].
[`amsfonts`]: https://ctan.org/pkg/amsfonts
[`amsmath`]: https://ctan.org/pkg/amsmath
[`lm`]: https://ctan.org/pkg/lm
[`ifxetex`]: https://ctan.org/pkg/ifxetex
[`ifluatex`]: https://ctan.org/pkg/ifluatex
-[`eurosym`]: https://ctan.org/pkg/eurosym
[`listings`]: https://ctan.org/pkg/listings
[`fancyvrb`]: https://ctan.org/pkg/fancyvrb
[`longtable`]: https://ctan.org/pkg/longtable
@@ -223,6 +246,7 @@ will affect the output, as will `--css`.
[`babel`]: https://ctan.org/pkg/babel
[`bidi`]: https://ctan.org/pkg/bidi
[`mathspec`]: https://ctan.org/pkg/mathspec
+[`unicode-math`]: https://ctan.org/pkg/unicode-math
[`polyglossia`]: https://ctan.org/pkg/polyglossia
[`fontspec`]: https://ctan.org/pkg/fontspec
[`upquote`]: https://ctan.org/pkg/upquote
@@ -233,6 +257,23 @@ will affect the output, as will `--css`.
[`bibtex`]: https://ctan.org/pkg/bibtex
[`biber`]: https://ctan.org/pkg/biber
[TeX Live]: http://www.tug.org/texlive/
+[`wkhtmltopdf`]: https://wkhtmltopdf.org
+[`weasyprint`]: http://weasyprint.org
+[`prince`]: https://www.princexml.com/
+
+Reading from the Web
+--------------------
+
+Instead of an input file, an absolute URI may be given. In this case
+pandoc will fetch the content using HTTP:
+
+ pandoc -f html -t markdown http://www.fsf.org
+
+It is possible to supply a custom User-Agent string or other
+header when requesting a document from a URL:
+
+ pandoc -f html -t markdown --request-header User-Agent:"Mozilla/5.0" \
+ http://www.fsf.org
Options
=======
@@ -245,23 +286,20 @@ General options
: Specify input format. *FORMAT* can be `native` (native Haskell),
`json` (JSON version of native AST), `markdown` (pandoc's
extended Markdown), `markdown_strict` (original unextended
- Markdown), `markdown_phpextra` (PHP Markdown Extra), `markdown_github`
- (GitHub-Flavored Markdown), `markdown_mmd` (MultiMarkdown),
+ Markdown), `markdown_phpextra` (PHP Markdown Extra),
+ `markdown_mmd` (MultiMarkdown), `gfm` (GitHub-Flavored Markdown),
`commonmark` (CommonMark Markdown), `textile` (Textile), `rst`
(reStructuredText), `html` (HTML), `docbook` (DocBook), `t2t`
(txt2tags), `docx` (docx), `odt` (ODT), `epub` (EPUB), `opml` (OPML),
`org` (Emacs Org mode), `mediawiki` (MediaWiki markup), `twiki` (TWiki
- markup), `haddock` (Haddock markup), or `latex` (LaTeX). If
- `+lhs` is appended to `markdown`, `rst`, `latex`, or `html`, the
- input will be treated as literate Haskell source: see [Literate
- Haskell support], below. Markdown
- syntax extensions can be individually enabled or disabled by
- appending `+EXTENSION` or `-EXTENSION` to the format name. So, for
- example, `markdown_strict+footnotes+definition_lists` is strict
- Markdown with footnotes and definition lists enabled, and
- `markdown-pipe_tables+hard_line_breaks` is pandoc's Markdown
- without pipe tables and with hard line breaks. See [Pandoc's
- Markdown], below, for a list of extensions and
+ markup), `tikiwiki` (TikiWiki markup), `creole` (Creole 1.0),
+ `haddock` (Haddock markup), or `latex` (LaTeX).
+ (`markdown_github` provides deprecated and less accurate support
+ for Github-Flavored Markdown; please use `gfm` instead, unless you
+ need to use extensions other than `smart`.)
+ Extensions can be individually enabled or disabled by
+ appending `+EXTENSION` or `-EXTENSION` to the format name.
+ See [Extensions] below, for a list of extensions and
their names. See `--list-input-formats` and `--list-extensions`,
below.
@@ -271,46 +309,45 @@ General options
`json` (JSON version of native AST), `plain` (plain text),
`markdown` (pandoc's extended Markdown), `markdown_strict`
(original unextended Markdown), `markdown_phpextra` (PHP Markdown
- Extra), `markdown_github` (GitHub-Flavored Markdown), `markdown_mmd`
- (MultiMarkdown), `commonmark` (CommonMark Markdown), `rst`
- (reStructuredText), `html` (XHTML), `html5` (HTML5), `latex`
- (LaTeX), `beamer` (LaTeX beamer slide show), `context` (ConTeXt),
- `man` (groff man), `mediawiki` (MediaWiki markup),
- `dokuwiki` (DokuWiki markup), `zimwiki` (ZimWiki markup),
- `textile` (Textile), `org` (Emacs Org mode),
- `texinfo` (GNU Texinfo), `opml` (OPML), `docbook` (DocBook 4),
- `docbook5` (DocBook 5), `opendocument` (OpenDocument), `odt`
- (OpenOffice text document), `docx` (Word docx), `haddock`
- (Haddock markup), `rtf` (rich text format), `epub` (EPUB v2
- book), `epub3` (EPUB v3), `fb2` (FictionBook2 e-book),
- `asciidoc` (AsciiDoc), `icml` (InDesign ICML), `tei` (TEI
- Simple), `slidy` (Slidy HTML and JavaScript slide show),
- `slideous` (Slideous HTML and JavaScript slide show),
- `dzslides` (DZSlides HTML5 + JavaScript slide show),
- `revealjs` (reveal.js HTML5 + JavaScript slide show), `s5`
- (S5 HTML and JavaScript slide show), or the path of a custom
- lua writer (see [Custom writers], below). Note that `odt`,
- `epub`, and `epub3` output will not be directed to *stdout*;
- an output filename must be specified using the `-o/--output`
- option. If `+lhs` is appended to `markdown`, `rst`, `latex`,
- `beamer`, `html`, or `html5`, the output will be rendered as
- literate Haskell source: see [Literate Haskell support],
- below. Markdown syntax extensions can be individually
- enabled or disabled by appending `+EXTENSION` or
- `-EXTENSION` to the format name, as described above under `-f`.
- See `--list-output-formats` and `--list-extensions`, below.
+ Extra), `markdown_mmd` (MultiMarkdown), `gfm` (GitHub-Flavored
+ Markdown), `commonmark` (CommonMark Markdown), `rst`
+ (reStructuredText), `html4` (XHTML 1.0 Transitional), `html` or
+ `html5` (HTML5/XHTML [polyglot markup]), `latex` (LaTeX), `beamer`
+ (LaTeX beamer slide show), `context` (ConTeXt), `man` (groff man),
+ `mediawiki` (MediaWiki markup), `dokuwiki` (DokuWiki markup),
+ `zimwiki` (ZimWiki markup), `textile` (Textile), `org` (Emacs Org
+ mode), `texinfo` (GNU Texinfo), `opml` (OPML), `docbook` or
+ `docbook4` (DocBook 4), `docbook5` (DocBook 5), `jats` (JATS XML),
+ `opendocument` (OpenDocument), `odt` (OpenOffice text document),
+ `docx` (Word docx), `haddock` (Haddock markup), `rtf` (rich text
+ format), `epub2` (EPUB v2 book), `epub` or `epub3` (EPUB v3),
+ `fb2` (FictionBook2 e-book), `asciidoc` (AsciiDoc), `icml`
+ (InDesign ICML), `tei` (TEI Simple), `slidy` (Slidy HTML and
+ JavaScript slide show), `slideous` (Slideous HTML and JavaScript
+ slide show), `dzslides` (DZSlides HTML5 + JavaScript slide show),
+ `revealjs` (reveal.js HTML5 + JavaScript slide show), `s5` (S5
+ HTML and JavaScript slide show), `pptx` (PowerPoint slide show) or
+ the path of a custom lua writer (see [Custom writers],
+ below). (`markdown_github` provides deprecated and less accurate
+ support for Github-Flavored Markdown; please use `gfm` instead,
+ unless you use extensions that do not work with `gfm`.) Note that
+ `odt`, `docx`, and `epub` output will not be directed to *stdout*
+ unless forced with `-o -`. Extensions can be individually enabled or
+ disabled by appending `+EXTENSION` or `-EXTENSION` to the format
+ name. See [Extensions] below, for a list of extensions and their
+ names. See `--list-output-formats` and `--list-extensions`, below.
`-o` *FILE*, `--output=`*FILE*
: Write output to *FILE* instead of *stdout*. If *FILE* is
- `-`, output will go to *stdout*. (Exception: if the output
- format is `odt`, `docx`, `epub`, or `epub3`, output to stdout is disabled.)
+ `-`, output will go to *stdout*, even if a non-textual format
+ (`docx`, `odt`, `epub2`, `epub3`) is specified.
`--data-dir=`*DIRECTORY*
: Specify the user data directory to search for pandoc data files.
If this option is not specified, the default user data directory
- will be used. This is, in Unix:
+ will be used. This is, in UNIX:
$HOME/.pandoc
@@ -333,13 +370,27 @@ General options
: Generate a bash completion script. To enable bash completion
with pandoc, add this to your `.bashrc`:
- eval "$(pandoc --bash-completion)"
+ eval "$(pandoc --bash-completion)"
`--verbose`
: Give verbose debugging output. Currently this only has an effect
with PDF output.
+`--quiet`
+
+: Suppress warning messages.
+
+`--fail-if-warnings`
+
+: Exit with error status if there are any warnings.
+
+`--log=`*FILE*
+
+: Write log messages in machine-readable JSON format to
+ *FILE*. All messages above DEBUG level will be written,
+ regardless of verbosity settings (`--verbose`, `--quiet`).
+
`--list-input-formats`
: List supported input formats, one per line.
@@ -348,11 +399,12 @@ General options
: List supported output formats, one per line.
-`--list-extensions`
+`--list-extensions`[`=`*FORMAT*]
-: List supported Markdown extensions, one per line, followed
+: List supported extensions, one per line, preceded
by a `+` or `-` indicating whether it is enabled by default
- in pandoc's Markdown.
+ in *FORMAT*. If *FORMAT* is not specified, defaults for
+ pandoc's Markdown are given.
`--list-highlight-languages`
@@ -375,36 +427,17 @@ General options
Reader options
--------------
-`-R`, `--parse-raw`
-
-: Parse untranslatable HTML codes and LaTeX environments as raw HTML
- or LaTeX, instead of ignoring them. Affects only HTML and LaTeX
- input. Raw HTML can be printed in Markdown, reStructuredText, Emacs Org
- mode, HTML, Slidy, Slideous, DZSlides, reveal.js, and S5 output; raw LaTeX
- can be printed in Markdown, reStructuredText, Emacs Org mode, LaTeX, and
- ConTeXt output. The default is for the readers to omit untranslatable
- HTML codes and LaTeX environments. (The LaTeX reader does pass through
- untranslatable LaTeX *commands*, even if `-R` is not specified.)
-
-`-S`, `--smart`
-
-: Produce typographically correct output, converting straight quotes
- to curly quotes, `---` to em-dashes, `--` to en-dashes, and
- `...` to ellipses. Nonbreaking spaces are inserted after certain
- abbreviations, such as "Mr." (Note: This option is selected automatically
- when the output format is `latex` or `context`, unless `--no-tex-ligatures`
- is used. It has no effect for `latex` input.)
-
-`--old-dashes`
-
-: Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes: `-` before
- a numeral is an en-dash, and `--` is an em-dash. This option is selected
- automatically for `textile` input.
-
`--base-header-level=`*NUMBER*
: Specify the base level for headers (defaults to 1).
+`--strip-empty-paragraphs`
+
+: *Deprecated. Use the `+empty_paragraphs` extension instead.*
+ Ignore paragraphs with no content. This option is useful
+ for converting word processing documents where users have
+ used empty paragraphs to create inter-paragraph space.
+
`--indented-code-classes=`*CLASSES*
: Specify classes to use for indented code blocks--for example,
@@ -448,7 +481,7 @@ Reader options
Those who would prefer to write filters in python can use the
module [`pandocfilters`], installable from PyPI. There are also
pandoc filter libraries in [PHP], [perl], and
- [javascript/node.js].
+ [JavaScript/node.js].
In order of preference, pandoc will look for filters in
@@ -456,9 +489,39 @@ Reader options
non-executable)
2. `$DATADIR/filters` (executable or non-executable)
+ where `$DATADIR` is the user data directory (see
+ `--data-dir`, above).
3. `$PATH` (executable only)
+ Filters and lua-filters are applied in the order specified
+ on the command line.
+
+`--lua-filter=`*SCRIPT*
+
+: Transform the document in a similar fashion as JSON filters (see
+ `--filter`), but use pandoc's build-in lua filtering system. The given
+ lua script is expected to return a list of lua filters which will be
+ applied in order. Each lua filter must contain element-transforming
+ functions indexed by the name of the AST element on which the filter
+ function should be applied.
+
+ The `pandoc` lua module provides helper functions for element
+ creation. It is always loaded into the script's lua environment.
+
+ The following is an example lua script for macro-expansion:
+
+ function expand_hello_world(inline)
+ if inline.c == '{{helloworld}}' then
+ return pandoc.Emph{ pandoc.Str "Hello, World" }
+ else
+ return inline
+ end
+ end
+
+ return {{Str = expand_hello_world}}
+
+
`-M` *KEY*[`=`*VAL*], `--metadata=`*KEY*[`:`*VAL*]
: Set the metadata field *KEY* to the value *VAL*. A value specified
@@ -470,11 +533,6 @@ Reader options
underlying document (which is accessible from filters and may be
printed in some output formats).
-`--normalize`
-
-: Normalize the document after reading: merge adjacent
- `Str` or `Emph` elements, for example, and remove repeated `Space`s.
-
`-p`, `--preserve-tabs`
: Preserve tabs instead of converting them to spaces (the default).
@@ -496,20 +554,41 @@ Reader options
`insertion`, `deletion`, `comment-start`, and `comment-end`
classes, respectively. The author and time of change is
included. `all` is useful for scripting: only accepting changes
- from a certain reviewer, say, or before a certain date. This
- option only affects the docx reader.
+ from a certain reviewer, say, or before a certain date. If a
+ paragraph is inserted or deleted, `track-changes=all` produces a
+ span with the class `paragraph-insertion`/`paragraph-deletion`
+ before the affected paragraph break. This option only affects the
+ docx reader.
`--extract-media=`*DIR*
-: Extract images and other media contained in a docx or epub container
- to the path *DIR*, creating it if necessary, and adjust the images
- references in the document so they point to the extracted files.
- This option only affects the docx and epub readers.
+: Extract images and other media contained in or linked from
+ the source document to the path *DIR*, creating it if
+ necessary, and adjust the images references in the document
+ so they point to the extracted files. If the source format is
+ a binary container (docx, epub, or odt), the media is
+ extracted from the container and the original
+ filenames are used. Otherwise the media is read from the
+ file system or downloaded, and new filenames are constructed
+ based on SHA1 hashes of the contents.
+
+`--abbreviations=`*FILE*
+
+: Specifies a custom abbreviations file, with abbreviations
+ one to a line. If this option is not specified, pandoc will
+ read the data file `abbreviations` from the user data
+ directory or fall back on a system default. To see the
+ system default, use
+ `pandoc --print-default-data-file=abbreviations`. The only
+ use pandoc makes of this list is in the Markdown reader.
+ Strings ending in a period that are found in this list will
+ be followed by a nonbreaking space, so that the period will
+ not produce sentence-ending space in formats like LaTeX.
[`pandocfilters`]: https://github.com/jgm/pandocfilters
[PHP]: https://github.com/vinai/pandocfilters-php
[perl]: https://metacpan.org/pod/Pandoc::Filter
-[javascript/node.js]: https://github.com/mvhenderson/pandoc-filter-node
+[JavaScript/node.js]: https://github.com/mvhenderson/pandoc-filter-node
General writer options
----------------------
@@ -553,7 +632,15 @@ General writer options
: Print a system default data file. Files in the user data directory
are ignored.
+`--eol=crlf`|`lf`|`native`
+
+: Manually specify line endings: `crlf` (Windows), `lf`
+ (macOS/Linux/UNIX), or `native` (line endings appropriate
+ to the OS on which pandoc is being run). The default is
+ `native`.
+
`--dpi`=*NUMBER*
+
: Specify the dpi (dots per inch) value for conversion from pixels
to inch/centimeters and vice versa. The default is 96dpi.
Technically, the correct term would be ppi (pixels per inch).
@@ -570,10 +657,6 @@ General writer options
will be nonsemantic newlines in the output as well).
Automatic wrapping does not currently work in HTML output.
-`--no-wrap`
-
-: Deprecated synonym for `--wrap=none`.
-
`--columns=`*NUMBER*
: Specify length of lines in characters. This affects text wrapping
@@ -583,9 +666,10 @@ General writer options
`--toc`, `--table-of-contents`
: Include an automatically generated table of contents (or, in
- the case of `latex`, `context`, `docx`, and `rst`, an instruction to create
- one) in the output document. This option has no effect on `man`,
- `docbook`, `docbook5`, `slidy`, `slideous`, `s5`, or `odt` output.
+ the case of `latex`, `context`, `docx`, `odt`,
+ `opendocument`, `rst`, or `ms`, an instruction to create
+ one) in the output document. This option has no effect on
+ `man`, `docbook4`, `docbook5`, or `jats` output.
`--toc-depth=`*NUMBER*
@@ -593,12 +677,20 @@ General writer options
of contents. The default is 3 (which means that level 1, 2, and 3
headers will be listed in the contents).
+`--strip-comments`
+
+: Strip out HTML comments in the Markdown or Textile source,
+ rather than passing them on to Markdown, Textile or HTML
+ output as raw HTML. This does not apply to HTML comments
+ inside raw HTML blocks when the `markdown_in_html_blocks`
+ extension is not set.
+
`--no-highlight`
: Disables syntax highlighting for code blocks and inlines, even when
a language attribute is given.
-`--highlight-style=`*STYLE*
+`--highlight-style=`*STYLE*|*FILE*
: Specifies the coloring style to be used in highlighted source code.
Options are `pygments` (the default), `kate`, `monochrome`,
@@ -607,6 +699,28 @@ General writer options
[Syntax highlighting], below. See also
`--list-highlight-styles`.
+ Instead of a *STYLE* name, a JSON file with extension
+ `.theme` may be supplied. This will be parsed as a KDE
+ syntax highlighting theme and (if valid) used as the
+ highlighting style.
+
+ To generate the JSON version of an existing style,
+ use `--print-highlight-style`.
+
+`--print-highlight-style=`*STYLE*|*FILE*
+
+: Prints a JSON version of a highlighting style, which can
+ be modified, saved with a `.theme` extension, and used
+ with `--highlight-style`.
+
+`--syntax-definition=`*FILE*
+
+: Instructs pandoc to load a KDE XML syntax definition file,
+ which will be used for syntax highlighting of appropriately
+ marked code blocks. This can be used to add support for
+ new languages or to use altered syntax definitions for
+ existing languages.
+
`-H` *FILE*, `--include-in-header=`*FILE*
: Include contents of *FILE*, verbatim, at the end of the header.
@@ -632,6 +746,25 @@ General writer options
repeatedly to include multiple files. They will be included in the
order specified. Implies `--standalone`.
+`--resource-path=`*SEARCHPATH*
+
+: List of paths to search for images and other resources.
+ The paths should be separated by `:` on Linux, UNIX, and
+ macOS systems, and by `;` on Windows. If `--resource-path`
+ is not specified, the default resource path is the working
+ directory. Note that, if `--resource-path` is specified,
+ the working directory must be explicitly listed or it
+ will not be searched. For example:
+ `--resource-path=.:test` will search the working directory
+ and the `test` subdirectory, in that order.
+
+`--request-header=`*NAME*`:`*VAL*
+
+: Set the request header *NAME* to the value *VAL* when making
+ HTTP requests (for example, when a URL is given on the
+ command line, or when resources used in a document must be
+ downloaded).
+
Options affecting specific writers
----------------------------------
@@ -639,19 +772,22 @@ Options affecting specific writers
: Produce a standalone HTML file with no external dependencies, using
`data:` URIs to incorporate the contents of linked scripts, stylesheets,
- images, and videos. The resulting file should be "self-contained,"
- in the sense that it needs no external files and no net access to be
- displayed properly by a browser. This option works only with HTML output
- formats, including `html`, `html5`, `html+lhs`, `html5+lhs`, `s5`,
- `slidy`, `slideous`, `dzslides`, and `revealjs`. Scripts, images, and
- stylesheets at absolute URLs will be downloaded; those at relative URLs
- will be sought relative to the working directory (if the first source
+ images, and videos. Implies `--standalone`. The resulting file should be
+ "self-contained," in the sense that it needs no external files and no net
+ access to be displayed properly by a browser. This option works only with
+ HTML output formats, including `html4`, `html5`, `html+lhs`, `html5+lhs`,
+ `s5`, `slidy`, `slideous`, `dzslides`, and `revealjs`. Scripts, images,
+ and stylesheets at absolute URLs will be downloaded; those at relative
+ URLs will be sought relative to the working directory (if the first source
file is local) or relative to the base URL (if the first source
- file is remote). Limitation: resources that are loaded dynamically
- through JavaScript cannot be incorporated; as a result, `--self-contained`
- does not work with `--mathjax`, and some advanced features (e.g.
- zoom or speaker notes) may not work in an offline "self-contained"
- `reveal.js` slide show.
+ file is remote). Elements with the attribute
+ `data-external="1"` will be left alone; the documents they
+ link to will not be incorporated in the document.
+ Limitation: resources that are loaded dynamically through
+ JavaScript cannot be incorporated; as a result,
+ `--self-contained` does not work with `--mathjax`, and some
+ advanced features (e.g. zoom or speaker notes) may not work
+ in an offline "self-contained" `reveal.js` slide show.
`--html-q-tags`
@@ -659,8 +795,8 @@ Options affecting specific writers
`--ascii`
-: Use only ASCII characters in output. Currently supported only
- for HTML output (which uses numerical entities instead of
+: Use only ASCII characters in output. Currently supported only for
+ HTML and DocBook output (which uses numerical entities instead of
UTF-8 when this option is selected).
`--reference-links`
@@ -681,10 +817,7 @@ Options affecting specific writers
: Use ATX-style headers in Markdown and AsciiDoc output. The default is
to use setext-style headers for levels 1-2, and then ATX headers.
-
-`--chapters`
-
-: Deprecated synonym for `--top-level-division=chapter`.
+ (Note: for `gfm` output, ATX headers are always used.)
`--top-level-division=[default|section|chapter|part]`
@@ -717,22 +850,6 @@ Options affecting specific writers
be numbered "1.5", specify `--number-offset=1,4`.
Offsets are 0 by default. Implies `--number-sections`.
-`--no-tex-ligatures`
-
-: Do not use the TeX ligatures for quotation marks, apostrophes,
- and dashes (`` `...' ``, ` ``..'' `, `--`, `---`) when
- writing or reading LaTeX or ConTeXt. In reading LaTeX,
- parse the characters `` ` ``, `'`, and `-` literally, rather
- than parsing ligatures for quotation marks and dashes. In
- writing LaTeX or ConTeXt, print unicode quotation mark and
- dash characters literally, rather than converting them to
- the standard ASCII TeX ligatures. Note: normally `--smart`
- is selected automatically for LaTeX and ConTeXt output, but
- it must be specified explicitly if `--no-tex-ligatures` is
- selected. If you use literal curly quotes, dashes, and
- ellipses in your source, then you may want to use
- `--no-tex-ligatures` without `--smart`.
-
`--listings`
: Use the [`listings`] package for LaTeX code blocks
@@ -748,14 +865,16 @@ Options affecting specific writers
slides (for `beamer`, `s5`, `slidy`, `slideous`, `dzslides`). Headers
above this level in the hierarchy are used to divide the
slide show into sections; headers below this level create
- subheads within a slide. The default is to set the slide level
- based on the contents of the document; see
- [Structuring the slide show].
+ subheads within a slide. Note that content that is
+ not contained under slide-level headers will not appear in
+ the slide show. The default is to set the slide level based
+ on the contents of the document; see [Structuring the slide
+ show].
`--section-divs`
-: Wrap sections in `<div>` tags (or `<section>` tags in HTML5),
- and attach identifiers to the enclosing `<div>` (or `<section>`)
+: Wrap sections in `<section>` tags (or `<div>` tags for `html4`),
+ and attach identifiers to the enclosing `<section>` (or `<div>`)
rather than the header itself. See
[Header identifiers], below.
@@ -769,10 +888,10 @@ Options affecting specific writers
`--id-prefix=`*STRING*
-: Specify a prefix to be added to all automatically generated identifiers
- in HTML and DocBook output, and to footnote numbers in Markdown output.
- This is useful for preventing duplicate identifiers when generating
- fragments to be included in other pages.
+: Specify a prefix to be added to all identifiers and internal links
+ in HTML and DocBook output, and to footnote numbers in Markdown
+ and Haddock output. This is useful for preventing duplicate
+ identifiers when generating fragments to be included in other pages.
`-T` *STRING*, `--title-prefix=`*STRING*
@@ -786,59 +905,87 @@ Options affecting specific writers
: Link to a CSS style sheet. This option can be used repeatedly to
include multiple files. They will be included in the order specified.
-`--reference-odt=`*FILE*
-
-: Use the specified file as a style reference in producing an ODT.
- For best results, the reference ODT should be a modified version
- of an ODT produced using pandoc. The contents of the reference ODT
- are ignored, but its stylesheets are used in the new ODT. If no
- reference ODT is specified on the command line, pandoc will look
- for a file `reference.odt` in the user data directory (see
- `--data-dir`). If this is not found either, sensible defaults will be
- used.
-
- To produce a custom `reference.odt`, first get a copy of
- the default `reference.odt`: `pandoc
- --print-default-data-file reference.odt >
- custom-reference.odt`. Then open `custom-reference.docx` in
- LibreOffice, modify the styles as you wish, and save the
- file.
-
-`--reference-docx=`*FILE*
-
-: Use the specified file as a style reference in producing a docx file.
- For best results, the reference docx should be a modified version
- of a docx file produced using pandoc. The contents of the reference docx
- are ignored, but its stylesheets and document properties (including
- margins, page size, header, and footer) are used in the new docx. If no
- reference docx is specified on the command line, pandoc will look
- for a file `reference.docx` in the user data directory (see
- `--data-dir`). If this is not found either, sensible defaults will be
- used.
-
- To produce a custom `reference.docx`, first get a copy of
- the default `reference.docx`: `pandoc
- --print-default-data-file reference.docx >
- custom-reference.docx`. Then open `custom-reference.docx`
- in Word, modify the styles as you wish, and save the file.
- For best results, do not make changes to this file other
- than modifying the styles used by pandoc: [paragraph] Normal,
- Body Text, First Paragraph, Compact, Title, Subtitle,
- Author, Date, Abstract, Bibliography, Heading 1, Heading 2,
- Heading 3, Heading 4, Heading 5, Heading 6, Block Text,
- Footnote Text, Definition Term, Definition, Caption, Table
- Caption, Image Caption, Figure, Figure With Caption, TOC
- Heading; [character] Default Paragraph Font, Body Text Char,
- Verbatim Char, Footnote Reference, Hyperlink; [table] Normal
- Table.
-
-`--epub-stylesheet=`*FILE*
-
-: Use the specified CSS file to style the EPUB. If no stylesheet
- is specified, pandoc will look for a file `epub.css` in the
+ A stylesheet is required for generating EPUB. If none is
+ provided using this option (or the `stylesheet` metadata
+ field), pandoc will look for a file `epub.css` in the
user data directory (see `--data-dir`). If it is not
found there, sensible defaults will be used.
+`--reference-doc=`*FILE*
+
+: Use the specified file as a style reference in producing a
+ docx or ODT file.
+
+ Docx
+
+ : For best results, the reference docx should be a modified
+ version of a docx file produced using pandoc. The contents
+ of the reference docx are ignored, but its stylesheets and
+ document properties (including margins, page size, header,
+ and footer) are used in the new docx. If no reference docx
+ is specified on the command line, pandoc will look for a
+ file `reference.docx` in the user data directory (see
+ `--data-dir`). If this is not found either, sensible
+ defaults will be used.
+
+ To produce a custom `reference.docx`, first get a copy of
+ the default `reference.docx`: `pandoc
+ --print-default-data-file reference.docx >
+ custom-reference.docx`. Then open `custom-reference.docx`
+ in Word, modify the styles as you wish, and save the file.
+ For best results, do not make changes to this file other
+ than modifying the styles used by pandoc: [paragraph]
+ Normal, Body Text, First Paragraph, Compact, Title,
+ Subtitle, Author, Date, Abstract, Bibliography, Heading 1,
+ Heading 2, Heading 3, Heading 4, Heading 5, Heading 6,
+ Heading 7, Heading 8, Heading 9, Block Text, Footnote Text,
+ Definition Term, Definition, Caption, Table Caption,
+ Image Caption, Figure, Captioned Figure, TOC Heading;
+ [character] Default Paragraph Font, Body Text Char,
+ Verbatim Char, Footnote Reference, Hyperlink; [table]
+ Table.
+
+ ODT
+
+ : For best results, the reference ODT should be a modified
+ version of an ODT produced using pandoc. The contents of
+ the reference ODT are ignored, but its stylesheets are used
+ in the new ODT. If no reference ODT is specified on the
+ command line, pandoc will look for a file `reference.odt` in
+ the user data directory (see `--data-dir`). If this is not
+ found either, sensible defaults will be used.
+
+ To produce a custom `reference.odt`, first get a copy of
+ the default `reference.odt`: `pandoc
+ --print-default-data-file reference.odt >
+ custom-reference.odt`. Then open `custom-reference.odt` in
+ LibreOffice, modify the styles as you wish, and save the
+ file.
+
+ PowerPoint
+
+ : Any template included with a recent install of Microsoft
+ PowerPoint (either with `.pptx` or `.potx` extension) should
+ work, as will most templates derived from these.
+
+ The specific requirement is that the template should contain
+ the following four layouts as its first four layouts:
+
+ 1. Title Slide
+ 2. Title and Content
+ 3. Section Header
+ 4. Two Content
+
+ All templates included with a recent version of MS PowerPoint
+ will fit these criteria. (You can click on `Layout` under the
+ `Home` menu to check.)
+
+ You can also modify the default `reference.pptx`: first run
+ `pandoc --print-default-data-file reference.pptx >
+ custom-reference.pptx`, and then modify
+ `custom-reference.pptx` in MS PowerPoint (pandoc will use the
+ first four layout slides, as mentioned above).
+
`--epub-cover-image=`*FILE*
: Use the specified image as the EPUB cover. It is recommended
@@ -875,7 +1022,7 @@ Options affecting specific writers
line, be sure to escape them or put the whole filename in single quotes,
to prevent them from being interpreted by the shell. To use the
embedded fonts, you will need to add declarations like the following
- to your CSS (see `--epub-stylesheet`):
+ to your CSS (see `--css`):
@font-face {
font-family: DejaVuSans;
@@ -913,15 +1060,21 @@ Options affecting specific writers
documents with few level 1 headers, one might want to use a chapter
level of 2 or 3.
-`--latex-engine=pdflatex`|`lualatex`|`xelatex`
+`--epub-subdirectory=`*DIRNAME*
+
+: Specify the subdirectory in the OCF container that is to hold
+ the EPUB-specific contents. The default is `EPUB`. To put
+ the EPUB contents in the top level, use an empty string.
-: Use the specified LaTeX engine when producing PDF output.
+`--pdf-engine=pdflatex`|`lualatex`|`xelatex`|`wkhtmltopdf`|`weasyprint`|`prince`|`context`|`pdfroff`
+
+: Use the specified engine when producing PDF output.
The default is `pdflatex`. If the engine is not in your PATH,
the full path of the engine may be specified here.
-`--latex-engine-opt=`*STRING*
+`--pdf-engine-opt=`*STRING*
-: Use the given string as a command-line argument to the `latex-engine`.
+: Use the given string as a command-line argument to the `pdf-engine`.
If used multiple times, the arguments are provided with spaces between
them. Note that no check for duplicate options is done.
@@ -971,55 +1124,37 @@ Citation rendering
Math rendering in HTML
----------------------
-`-m` [*URL*], `--latexmathml`[`=`*URL*]
-
-: Use the [LaTeXMathML] script to display embedded TeX math in HTML output.
- To insert a link to a local copy of the `LaTeXMathML.js` script,
- provide a *URL*. If no *URL* is provided, the contents of the
- script will be inserted directly into the HTML header, preserving
- portability at the price of efficiency. If you plan to use math on
- several pages, it is much better to link to a copy of the script,
- so it can be cached.
-
-`--mathml`[`=`*URL*]
-
-: Convert TeX math to [MathML] (in `docbook`, `docbook5`, `html` and `html5`).
- In standalone `html` output, a small JavaScript (or a link to such a
- script if a *URL* is supplied) will be inserted that allows the MathML to
- be viewed on some browsers.
-
-`--jsmath`[`=`*URL*]
-
-: Use [jsMath] to display embedded TeX math in HTML output.
- The *URL* should point to the jsMath load script (e.g.
- `jsMath/easy/load.js`); if provided, it will be linked to in
- the header of standalone HTML documents. If a *URL* is not provided,
- no link to the jsMath load script will be inserted; it is then
- up to the author to provide such a link in the HTML template.
+The default is to render TeX math as far as possible using Unicode characters.
+Formulas are put inside a `span` with `class="math"`, so that they may be styled
+differently from the surrounding text if needed. However, this gives acceptable
+results only for basic math, usually you will want to use `--mathjax` or another
+of the following options.
`--mathjax`[`=`*URL*]
: Use [MathJax] to display embedded TeX math in HTML output.
+ TeX math will be put between `\(...\)` (for inline math)
+ or `\[...\]` (for display math) and wrapped in `<span>` tags
+ with class `math`. Then the MathJax JavaScript will render it.
The *URL* should point to the `MathJax.js` load script.
- If a *URL* is not provided, a link to the MathJax CDN will
+ If a *URL* is not provided, a link to the Cloudflare CDN will
be inserted.
-`--gladtex`
-
-: Enclose TeX math in `<eq>` tags in HTML output. These can then
- be processed by [gladTeX] to produce links to images of the typeset
- formulas.
-
-`--mimetex`[`=`*URL*]
+`--mathml`
-: Render TeX math using the [mimeTeX] CGI script. If *URL* is not
- specified, it is assumed that the script is at `/cgi-bin/mimetex.cgi`.
+: Convert TeX math to [MathML] (in `epub3`, `docbook4`, `docbook5`, `jats`,
+ `html4` and `html5`). This is the default in `odt` output. Note that
+ currently only Firefox and Safari (and select e-book readers) natively
+ support MathML.
`--webtex`[`=`*URL*]
-: Render TeX formulas using an external script that converts TeX
- formulas to images. The formula will be concatenated with the URL
- provided. If *URL* is not specified, the CodeCogs will be used.
+: Convert TeX formulas to `<img>` tags that link to an external script
+ that converts formulas to images. The formula will be URL-encoded
+ and concatenated with the URL provided. For SVG images you can for
+ example use `--webtex https://latex.codecogs.com/svg.latex?`.
+ If no URL is specified, the CodeCogs URL generating PNGs
+ will be used (`https://latex.codecogs.com/png.latex?`).
Note: the `--webtex` option will affect Markdown output
as well as HTML, which is useful if you're targeting a
version of Markdown without native math support.
@@ -1027,9 +1162,8 @@ Math rendering in HTML
`--katex`[`=`*URL*]
: Use [KaTeX] to display embedded TeX math in HTML output.
- The *URL* should point to the `katex.js` load script. If a *URL* is
+ The *URL* is the base URL for the KaTeX library. If a *URL* is
not provided, a link to the KaTeX CDN will be inserted.
- Note: [KaTeX] seems to work best with `html5` output.
`--katex-stylesheet=`*URL*
@@ -1037,6 +1171,48 @@ Math rendering in HTML
not specified, a link to the KaTeX CDN will be inserted. Note that this
option does not imply `--katex`.
+`-m` [*URL*], `--latexmathml`[`=`*URL*]
+
+: *Deprecated.*
+ Use the [LaTeXMathML] script to display embedded TeX math in HTML output.
+ TeX math will be displayed between `$` or `$$` characters and put in
+ `<span>` tags with class `LaTeX`. The LaTeXMathML JavaScript will then
+ change it to MathML. Note that currently only Firefox and Safari
+ (and select e-book readers) natively support MathML.
+ To insert a link the `LaTeXMathML.js` script, provide a *URL*.
+
+`--jsmath`[`=`*URL*]
+
+: *Deprecated.*
+ Use [jsMath] (the predecessor of MathJax) to display embedded TeX
+ math in HTML output. TeX math will be put inside `<span>` tags
+ (for inline math) or `<div>` tags (for display math) with class
+ `math` and rendered by the jsMath script. The *URL* should point to
+ the script (e.g. `jsMath/easy/load.js`); if provided, it will be linked
+ to in the header of standalone HTML documents. If a *URL* is not provided,
+ no link to the jsMath load script will be inserted; it is then
+ up to the author to provide such a link in the HTML template.
+
+`--gladtex`
+
+: *Deprecated.*
+ Enclose TeX math in `<eq>` tags in HTML output. The resulting HTML
+ can then be processed by [gladTeX] to produce images of the typeset
+ formulas and an HTML file with links to these images.
+ So, the procedure is:
+
+ pandoc -s --gladtex input.md -o myfile.htex
+ gladtex -d myfile-images myfile.htex
+ # produces myfile.html and images in myfile-images
+
+`--mimetex`[`=`*URL*]
+
+: *Deprecated.*
+ Render TeX math using the [mimeTeX] CGI script, which generates an
+ image for each TeX formula. This should work in all browsers. If
+ *URL* is not specified, it is assumed that the script is at
+ `/cgi-bin/mimetex.cgi`.
+
[MathML]: http://www.w3.org/Math/
[LaTeXMathML]: http://math.etsu.edu/LaTeXMathML/
[jsMath]: http://www.math.union.edu/~dpvc/jsmath/
@@ -1088,10 +1264,11 @@ directory (see `--data-dir`, above). *Exceptions:*
- For `odt` output, customize the `default.opendocument`
template.
- For `pdf` output, customize the `default.latex` template
- (or the `default.beamer` template, if you use `-t beamer`,
- or the `default.context` template, if you use `-t context`).
+ (or the `default.context` template, if you use `-t context`,
+ or the `default.ms` template, if you use `-t ms`, or the
+ `default.html5` template, if you use `-t html5`).
- `docx` has no template (however, you can use
- `--reference-docx` to customize the output).
+ `--reference-doc` to customize the output).
Templates contain *variables*, which allow for the inclusion of
arbitrary information at any point in the file. Variables may be set
@@ -1107,6 +1284,22 @@ Some variables are set automatically by pandoc. These vary somewhat
depending on the output format, but include metadata fields as well
as the following:
+`sourcefile`, `outputfile`
+: source and destination filenames, as given on the command line.
+ `sourcefile` can also be a list if input comes from multiple files, or empty
+ if input is from stdin. You can use the following snippet in your template
+ to distinguish them:
+
+ $if(sourcefile)$
+ $for(sourcefile)$
+ $sourcefile$
+ $endfor$
+ $else$
+ (stdin)
+ $endif$
+
+ Similarly, `outputfile` can be `-` if output goes to the terminal.
+
`title`, `author`, `date`
: allow identification of basic aspects of the document. Included
in PDF metadata through LaTeX and ConTeXt. These can be set
@@ -1144,7 +1337,8 @@ as the following:
: non-null value if `--toc/--table-of-contents` was specified
`toc-title`
-: title of table of contents (works only with EPUB and docx)
+: title of table of contents (works only with EPUB,
+ opendocument, odt, docx, pptx)
`include-before`
: contents specified by `-B/--include-before-body` (may have
@@ -1158,7 +1352,8 @@ as the following:
: body of document
`meta-json`
-: JSON representation of all of the document's metadata
+: JSON representation of all of the document's metadata. Field
+ values are transformed to the selected output format.
[^subtitle]: To make `subtitle` work with other LaTeX
document classes, you can add the following to `header-includes`:
@@ -1179,21 +1374,12 @@ Language variables
format stored in the additional variables `babel-lang`,
`polyglossia-lang` (LaTeX) and `context-lang` (ConTeXt).
- Native pandoc `span`s and `div`s with the lang attribute
+ Native pandoc Spans and Divs with the lang attribute
(value in BCP 47) can be used to switch the language in
- that range.
-
-`otherlangs`
-: a list of other languages used in the document
- in the YAML metadata, according to [BCP 47]. For example:
- `otherlangs: [en-GB, fr]`.
- This is automatically generated from the `lang` attributes
- in all `span`s and `div`s but can be overridden.
- Currently only used by LaTeX through the generated
- `babel-otherlangs` and `polyglossia-otherlangs` variables.
- The LaTeX writer outputs polyglossia commands in the text but
- the `babel-newcommands` variable contains mappings for them
- to the corresponding babel.
+ that range. In LaTeX output, `babel-otherlangs` and
+ `polyglossia-otherlangs` variables will be generated
+ automatically based on the `lang` attributes of Spans
+ and Divs in the document.
`dir`
: the base direction of the document, either `rtl` (right-to-left)
@@ -1207,7 +1393,7 @@ Language variables
[Unicode Bidirectional Algorithm].
When using LaTeX for bidirectional documents, only the `xelatex` engine
- is fully supported (use `--latex-engine=xelatex`).
+ is fully supported (use `--pdf-engine=xelatex`).
[BCP 47]: https://tools.ietf.org/html/bcp47
[Unicode Bidirectional Algorithm]: http://www.w3.org/International/articles/inline-bidi-markup/uba-basics
@@ -1218,9 +1404,15 @@ Variables for slides
Variables are available for [producing slide shows with pandoc],
including all [reveal.js configuration options].
+`titlegraphic`
+: title graphic for Beamer documents
+
+`logo`
+: logo for Beamer documents
+
`slidy-url`
: base URL for Slidy documents (defaults to
- `http://www.w3.org/Talks/Tools/Slidy2`)
+ `https://www.w3.org/Talks/Tools/Slidy2`)
`slideous-url`
: base URL for Slideous documents (defaults to `slideous`)
@@ -1250,13 +1442,10 @@ including all [reveal.js configuration options].
: when true, the `beamerarticle` package is loaded (for
producing an article from beamer slides).
-`colorlinks`
-: add color to link text; automatically enabled if any of `linkcolor`, `citecolor`,
- `urlcolor`, or `toccolor` are set (for beamer only).
-
-`linkcolor`, `citecolor`, `urlcolor`, `toccolor`
-: color for internal links, citation links, external links, and links in table
- of contents: uses any of the [predefined LaTeX colors] (for beamer only).
+`aspectratio`
+: aspect ratio of slides (for beamer only, `1610` for 16:10, `169` for 16:9,
+ `149` for 14:9, `141` for 1.41:1, `54` for 5:4, `43` for 4:3 which is the
+ default, and `32` for 3:2).
[reveal.js configuration options]: https://github.com/hakimel/reveal.js#configuration
@@ -1266,7 +1455,7 @@ Variables for LaTeX
LaTeX variables are used when [creating a PDF].
`papersize`
-: paper size, e.g. `letter`, `A4`
+: paper size, e.g. `letter`, `a4`
`fontsize`
: font size for body text (e.g. `10pt`, `12pt`)
@@ -1325,7 +1514,7 @@ LaTeX variables are used when [creating a PDF].
`linkcolor`, `citecolor`, `urlcolor`, `toccolor`
: color for internal links, citation links, external links, and links in table of contents:
- uses any of the [predefined LaTeX colors]
+ uses options allowed by [`xcolor`], including the `dvipsnames`, `svgnames`, and `x11names` lists
`links-as-notes`
: causes links to be printed as footnotes
@@ -1365,12 +1554,20 @@ LaTeX variables are used when [creating a PDF].
`biblatexoptions`
: list of options for biblatex.
+`natbiboptions`
+: list of options for natbib.
+
+`pagestyle`
+: An option for LaTeX's `\pagestyle{}`. The default article class
+ supports 'plain' (default), 'empty', and 'headings'; headings puts
+ section titles in the header.
+
[`article`]: https://ctan.org/pkg/article
[`report`]: https://ctan.org/pkg/report
[`book`]: https://ctan.org/pkg/book
[KOMA-Script]: https://ctan.org/pkg/koma-script
[`memoir`]: https://ctan.org/pkg/memoir
-[predefined LaTeX colors]: https://en.wikibooks.org/wiki/LaTeX/Colors#Predefined_colors
+[`xcolor`]: https://ctan.org/pkg/xcolor
[LaTeX Font Catalogue]: http://www.tug.dk/FontCatalogue/
[`mathpazo`]: https://ctan.org/pkg/mathpazo
[LaTeX font encodings]: https://ctan.org/pkg/encguide
@@ -1456,6 +1653,21 @@ Variables for man pages
`hyphenate`
: if `true` (the default), hyphenation will be used
+Variables for ms
+----------------
+
+`pointsize`
+: point size (e.g. `10p`)
+
+`lineheight`
+: line height (e.g. `12p`)
+
+`fontfamily`
+: font family (e.g. `T` or `P`)
+
+`indent`
+: paragraph indent (e.g. `2m`)
+
Using variables in templates
----------------------------
@@ -1505,8 +1717,292 @@ and modifying your custom templates accordingly. An easy way to do this
is to fork the [pandoc-templates] repository and merge in changes after each
pandoc release.
+Templates may contain comments: anything on a line after `$--`
+will be treated as a comment and ignored.
+
[pandoc-templates]: https://github.com/jgm/pandoc-templates
+Extensions
+==========
+
+The behavior of some of the readers and writers can be adjusted by
+enabling or disabling various extensions.
+
+An extension can be enabled by adding `+EXTENSION`
+to the format name and disabled by adding `-EXTENSION`. For example,
+`--from markdown_strict+footnotes` is strict Markdown with footnotes
+enabled, while `--from markdown-footnotes-pipe_tables` is pandoc's
+Markdown without footnotes or pipe tables.
+
+The markdown reader and writer make by far the most use of extensions.
+Extensions only used by them are therefore covered in the
+section [Pandoc's Markdown] below (See [Markdown variants] for
+`commonmark` and `gfm`.) In the following, extensions that also work
+for other formats are covered.
+
+Typography
+----------
+
+#### Extension: `smart` ####
+
+Interpret straight quotes as curly quotes, `---` as em-dashes,
+`--` as en-dashes, and `...` as ellipses. Nonbreaking spaces are
+inserted after certain abbreviations, such as "Mr."
+
+This extension can be enabled/disabled for the following formats:
+
+input formats
+: `markdown`, `commonmark`, `latex`, `mediawiki`, `org`, `rst`, `twiki`
+
+output formats
+: `markdown`, `latex`, `context`, `rst`
+
+enabled by default in
+: `markdown`, `latex`, `context` (both input and output)
+
+Note: If you are *writing* Markdown, then the `smart` extension
+has the reverse effect: what would have been curly quotes comes
+out straight.
+
+In LaTeX, `smart` means to use the standard TeX ligatures
+for quotation marks (` `` ` and ` '' ` for double quotes,
+`` ` `` and `` ' `` for single quotes) and dashes (`--` for
+en-dash and `---` for em-dash). If `smart` is disabled,
+then in reading LaTeX pandoc will parse these characters
+literally. In writing LaTeX, enabling `smart` tells pandoc
+to use the ligatures when possible; if `smart` is disabled
+pandoc will use unicode quotation mark and dash characters.
+
+Headers and sections
+--------------------
+
+#### Extension: `auto_identifiers` ####
+
+A header without an explicitly specified identifier will be
+automatically assigned a unique identifier based on the header text.
+
+This extension can be enabled/disabled for the following formats:
+
+input formats
+: `markdown`, `latex`, `rst`, `mediawiki`, `textile`
+
+output formats
+: `markdown`, `muse`
+
+enabled by default in
+: `markdown`, `muse`
+
+The algorithm used to derive the identifier from the header text is:
+
+ - Remove all formatting, links, etc.
+ - Remove all footnotes.
+ - Remove all punctuation, except underscores, hyphens, and periods.
+ - Replace all spaces and newlines with hyphens.
+ - Convert all alphabetic characters to lowercase.
+ - Remove everything up to the first letter (identifiers may
+ not begin with a number or punctuation mark).
+ - If nothing is left after this, use the identifier `section`.
+
+Thus, for example,
+
+ Header Identifier
+ ------------------------------- ----------------------------
+ `Header identifiers in HTML` `header-identifiers-in-html`
+ `*Dogs*?--in *my* house?` `dogs--in-my-house`
+ `[HTML], [S5], or [RTF]?` `html-s5-or-rtf`
+ `3. Applications` `applications`
+ `33` `section`
+
+These rules should, in most cases, allow one to determine the identifier
+from the header text. The exception is when several headers have the
+same text; in this case, the first will get an identifier as described
+above; the second will get the same identifier with `-1` appended; the
+third with `-2`; and so on.
+
+These identifiers are used to provide link targets in the table of
+contents generated by the `--toc|--table-of-contents` option. They
+also make it easy to provide links from one section of a document to
+another. A link to this section, for example, might look like this:
+
+ See the section on
+ [header identifiers](#header-identifiers-in-html-latex-and-context).
+
+Note, however, that this method of providing links to sections works
+only in HTML, LaTeX, and ConTeXt formats.
+
+If the `--section-divs` option is specified, then each section will
+be wrapped in a `section` (or a `div`, if `html4` was specified),
+and the identifier will be attached to the enclosing `<section>`
+(or `<div>`) tag rather than the header itself. This allows entire
+sections to be manipulated using JavaScript or treated differently in
+CSS.
+
+#### Extension: `ascii_identifiers` ####
+
+Causes the identifiers produced by `auto_identifiers` to be pure ASCII.
+Accents are stripped off of accented Latin letters, and non-Latin
+letters are omitted.
+
+Math Input
+----------
+
+The extensions [`tex_math_dollars`](#extension-tex_math_dollars),
+[`tex_math_single_backslash`](#extension-tex_math_single_backslash), and
+[`tex_math_double_backslash`](#extension-tex_math_double_backslash)
+are described in the section about Pandoc's Markdown.
+
+However, they can also be used with HTML input. This is handy for
+reading web pages formatted using MathJax, for example.
+
+Raw HTML/TeX
+------------
+
+The following extensions (especially how they affect Markdown
+input/output) are also described in more detail in their respective
+sections of [Pandoc's Markdown].
+
+#### [Extension: `raw_html`] {#raw_html}
+
+When converting from HTML, parse elements to raw HTML which are not
+representable in pandoc's AST.
+By default, this is disabled for HTML input.
+
+#### [Extension: `raw_tex`] {#raw_tex}
+
+Allows raw LaTeX, TeX, and ConTeXt to be included in a document.
+
+This extension can be enabled/disabled for the following formats
+(in addition to `markdown`):
+
+input formats
+: `latex`, `org`, `textile`
+
+output formats
+: `textile`
+
+#### [Extension: `native_divs`] {#native_divs}
+
+This extension is enabled by default for HTML input. This means that
+`div`s are parsed to pandoc native elements. (Alternatively, you
+can parse them to raw HTML using `-f html-native_divs+raw_html`.)
+
+When converting HTML to Markdown, for example, you may want to drop all
+`div`s and `span`s:
+
+ pandoc -f html-native_divs-native_spans -t markdown
+
+#### [Extension: `native_spans`] {#native_spans}
+
+Analogous to `native_divs` above.
+
+
+Literate Haskell support
+------------------------
+
+#### Extension: `literate_haskell` ####
+
+Treat the document as literate Haskell source.
+
+This extension can be enabled/disabled for the following formats:
+
+input formats
+: `markdown`, `rst`, `latex`
+
+output formats
+: `markdown`, `rst`, `latex`, `html`
+
+If you append `+lhs` (or `+literate_haskell`) to one of the formats
+above, pandoc will treat the document as literate Haskell source.
+This means that
+
+ - In Markdown input, "bird track" sections will be parsed as Haskell
+ code rather than block quotations. Text between `\begin{code}`
+ and `\end{code}` will also be treated as Haskell code. For
+ ATX-style headers the character '=' will be used instead of '#'.
+
+ - In Markdown output, code blocks with classes `haskell` and `literate`
+ will be rendered using bird tracks, and block quotations will be
+ indented one space, so they will not be treated as Haskell code.
+ In addition, headers will be rendered setext-style (with underlines)
+ rather than ATX-style (with '#' characters). (This is because ghc
+ treats '#' characters in column 1 as introducing line numbers.)
+
+ - In restructured text input, "bird track" sections will be parsed
+ as Haskell code.
+
+ - In restructured text output, code blocks with class `haskell` will
+ be rendered using bird tracks.
+
+ - In LaTeX input, text in `code` environments will be parsed as
+ Haskell code.
+
+ - In LaTeX output, code blocks with class `haskell` will be rendered
+ inside `code` environments.
+
+ - In HTML output, code blocks with class `haskell` will be rendered
+ with class `literatehaskell` and bird tracks.
+
+Examples:
+
+ pandoc -f markdown+lhs -t html
+
+reads literate Haskell source formatted with Markdown conventions and writes
+ordinary HTML (without bird tracks).
+
+ pandoc -f markdown+lhs -t html+lhs
+
+writes HTML with the Haskell code in bird tracks, so it can be copied
+and pasted as literate Haskell source.
+
+Note that GHC expects the bird tracks in the first column, so indentend literate
+code blocks (e.g. inside an itemized environment) will not be picked up by the
+Haskell compiler.
+
+Other extensions
+----------------
+
+#### Extension: `empty_paragraphs` ####
+
+Allows empty paragraphs. By default empty paragraphs are
+omitted.
+
+This extension can be enabled/disabled for the following formats:
+
+input formats
+: `docx`, `html`
+
+output formats
+: `markdown`, `docx`, `odt`, `opendocument`, `html`
+
+#### Extension: `styles` #### {#ext-styles}
+
+Read all docx styles as divs (for paragraph styles) and spans (for
+character styles) regardless of whether pandoc understands the meaning
+of these styles. This can be used with [docx custom
+styles](#custom-styles-in-docx). Disabled by default.
+
+input formats
+: `docx`
+
+#### Extension: `amuse` ####
+
+In the `muse` input format, this enables Text::Amuse
+extensions to Emacs Muse markup.
+
+#### Extension: `citations` {#org-citations}
+
+Some aspects of [Pandoc's Markdown citation syntax](#citations) are also accepted
+in `org` input.
+
+#### Extension: `ntb` ####
+
+In the `context` output format this enables the use of [Natural Tables
+(TABLE)](http://wiki.contextgarden.net/TABLE) instead of the default
+[Extreme Tables (xtables)](http://wiki.contextgarden.net/xtables).
+Natural tables allow more fine-grained global customization but come
+at a performance penalty compared to extreme tables.
+
+
Pandoc's Markdown
=================
@@ -1514,11 +2010,9 @@ Pandoc understands an extended and slightly revised version of
John Gruber's [Markdown] syntax. This document explains the syntax,
noting differences from standard Markdown. Except where noted, these
differences can be suppressed by using the `markdown_strict` format instead
-of `markdown`. An extensions can be enabled by adding `+EXTENSION`
-to the format name and disabled by adding `-EXTENSION`. For example,
-`markdown_strict+footnotes` is strict Markdown with footnotes
-enabled, while `markdown-footnotes-pipe_tables` is pandoc's
-Markdown without footnotes or pipe tables.
+of `markdown`. Extensions can be enabled or disabled to specify the
+behavior more granularly. They are described in the following. See also
+[Extensions] above, for extensions that work also on other formats.
Philosophy
----------
@@ -1601,9 +2095,17 @@ wrapping). Consider, for example:
I like several of their flavors of ice cream:
#22, for example, and #5.
+#### Extension: `space_in_atx_header` ####
+
+Many Markdown implementations do not require a space between the
+opening `#`s of an ATX header and the header text, so that
+`#5 bolt` and `#hashtag` count as headers. With this extension,
+pandoc does require the space.
### Header identifiers ###
+See also the [`auto_identifiers` extension](#extension-auto_identifiers) above.
+
#### Extension: `header_attributes` ####
Headers can be assigned attributes using this syntax at the end
@@ -1640,55 +2142,6 @@ is just the same as
# My header {.unnumbered}
-#### Extension: `auto_identifiers` ####
-
-A header without an explicitly specified identifier will be
-automatically assigned a unique identifier based on the header text.
-To derive the identifier from the header text,
-
- - Remove all formatting, links, etc.
- - Remove all footnotes.
- - Remove all punctuation, except underscores, hyphens, and periods.
- - Replace all spaces and newlines with hyphens.
- - Convert all alphabetic characters to lowercase.
- - Remove everything up to the first letter (identifiers may
- not begin with a number or punctuation mark).
- - If nothing is left after this, use the identifier `section`.
-
-Thus, for example,
-
- Header Identifier
- ------------------------------- ----------------------------
- `Header identifiers in HTML` `header-identifiers-in-html`
- `*Dogs*?--in *my* house?` `dogs--in-my-house`
- `[HTML], [S5], or [RTF]?` `html-s5-or-rtf`
- `3. Applications` `applications`
- `33` `section`
-
-These rules should, in most cases, allow one to determine the identifier
-from the header text. The exception is when several headers have the
-same text; in this case, the first will get an identifier as described
-above; the second will get the same identifier with `-1` appended; the
-third with `-2`; and so on.
-
-These identifiers are used to provide link targets in the table of
-contents generated by the `--toc|--table-of-contents` option. They
-also make it easy to provide links from one section of a document to
-another. A link to this section, for example, might look like this:
-
- See the section on
- [header identifiers](#header-identifiers-in-html-latex-and-context).
-
-Note, however, that this method of providing links to sections works
-only in HTML, LaTeX, and ConTeXt formats.
-
-If the `--section-divs` option is specified, then each section will
-be wrapped in a `div` (or a `section`, if `--html5` was specified),
-and the identifier will be attached to the enclosing `<div>`
-(or `<section>`) tag rather than the header itself. This allows entire
-sections to be manipulated using JavaScript or treated differently in
-CSS.
-
#### Extension: `implicit_header_references` ####
Pandoc behaves as if reference links have been defined for each header.
@@ -1846,11 +2299,11 @@ this syntax:
Here `mycode` is an identifier, `haskell` and `numberLines` are classes, and
`startFrom` is an attribute with value `100`. Some output formats can use this
information to do syntax highlighting. Currently, the only output formats
-that uses this information are HTML and LaTeX. If highlighting is supported
-for your output format and language, then the code block above will appear
-highlighted, with numbered lines. (To see which languages are supported, type
-`pandoc --list-highlight-languages`.) Otherwise, the code block above will
-appear as follows:
+that uses this information are HTML, LaTeX, Docx, Ms, and PowerPoint. If
+highlighting is supported for your output format and language, then the code
+block above will appear highlighted, with numbered lines. (To see which
+languages are supported, type `pandoc --list-highlight-languages`.) Otherwise,
+the code block above will appear as follows:
<pre id="mycode" class="haskell numberLines" startFrom="100">
<code>
@@ -1858,6 +2311,12 @@ appear as follows:
</code>
</pre>
+The `numberLines` (or `number-lines`) class will cause the lines
+of the code block to be numbered, starting with `1` or the value
+of the `startFrom` attribute. The `lineAnchors` (or
+`line-anchors`) class will cause the lines to be clickable
+anchors in HTML output.
+
A shortcut form can also be used for specifying the language of
the code block:
@@ -1949,12 +2408,12 @@ But Markdown also allows a "lazy" format:
list item.
* and my second.
-### The four-space rule ###
+### Block content in list items ###
A list item may contain multiple paragraphs and other block-level
content. However, subsequent paragraphs must be preceded by a blank line
-and indented four spaces or a tab. The list will look better if the first
-paragraph is aligned with the rest:
+and indented to line up with the first non-space content after
+the list marker.
* First paragraph.
@@ -1965,19 +2424,29 @@ paragraph is aligned with the rest:
{ code }
+Exception: if the list marker is followed by an indented code
+block, which must begin 5 spaces after the list marker, then
+subsequent paragraphs must begin two columns after the last
+character of the list marker:
+
+ * code
+
+ continuation paragraph
+
List items may include other lists. In this case the preceding blank
-line is optional. The nested list must be indented four spaces or
-one tab:
+line is optional. The nested list must be indented to line up with
+the first non-space character after the list marker of the
+containing list item.
* fruits
- + apples
- - macintosh
- - red delicious
- + pears
- + peaches
+ + apples
+ - macintosh
+ - red delicious
+ + pears
+ + peaches
* vegetables
- + broccoli
- + chard
+ + broccoli
+ + chard
As noted above, Markdown allows you to write list items "lazily," instead of
indenting continuation lines. However, if there are multiple paragraphs or
@@ -1992,21 +2461,6 @@ other blocks in a list item, the first line of each must be indented.
Second paragraph of second
list item.
-**Note:** Although the four-space rule for continuation paragraphs
-comes from the official [Markdown syntax guide], the reference implementation,
-`Markdown.pl`, does not follow it. So pandoc will give different results than
-`Markdown.pl` when authors have indented continuation paragraphs fewer than
-four spaces.
-
-The [Markdown syntax guide] is not explicit whether the four-space
-rule applies to *all* block-level content in a list item; it only
-mentions paragraphs and code blocks. But it implies that the rule
-applies to all block-level content (including nested lists), and
-pandoc interprets it that way.
-
- [Markdown syntax guide]:
- http://daringfireball.net/projects/markdown/syntax#list
-
### Ordered lists ###
Ordered lists work just like bulleted lists, except that the items
@@ -2172,6 +2626,12 @@ document:
The label can be any string of alphanumeric characters, underscores,
or hyphens.
+Note: continuation paragraphs in example lists must always
+be indented four spaces, regardless of the length of the
+list marker. That is, example lists always behave as if the
+`four_space_rule` extension is set. This is because example
+labels tend to be long, and indenting content to the
+first non-space character after the label would be awkward.
### Compact and loose lists ###
@@ -2180,9 +2640,9 @@ cases" involving lists. Consider this source:
+ First
+ Second:
- - Fee
- - Fie
- - Foe
+ - Fee
+ - Fie
+ - Foe
+ Third
@@ -2394,6 +2854,18 @@ For headerless tables, the colons go on the top line instead:
| Right | Left | Centered |
+---------------+---------------+--------------------+
+##### Grid Table Limitations #####
+
+Pandoc does not support grid tables with row spans or column spans.
+This means that neither variable numbers of columns across rows nor
+variable numbers of rows across columns are supported by Pandoc.
+All grid tables must have the same number of columns in each row,
+and the same number of rows in each column. For example, the
+Docutils [sample grid tables] will not render as expected with
+Pandoc.
+
+[sample grid tables]: http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#grid-tables
+
#### Extension: `pipe_tables` ####
@@ -2428,7 +2900,10 @@ and lists, and cannot span multiple lines. If a pipe table contains a
row whose printable content is wider than the column width (see
`--columns`), then the cell contents will wrap, with the
relative cell widths determined by the widths of the separator
-lines.
+lines. (In this case, the table will take up the full text
+width.) If no lines are wider than column width, then
+cell contents will not be wrapped, and the cells will be sized
+to their contents.
Note: pandoc also recognizes pipe tables of the following
form, as can be produced by Emacs' orgtbl-mode:
@@ -2557,7 +3032,7 @@ Note that YAML escaping rules must be followed. Thus, for example,
if a title contains a colon, it must be quoted. The pipe character
(`|`) can be used to begin an indented block that will be interpreted
literally, without need for escaping. This form is necessary
-when the field contains blank lines:
+when the field contains blank lines or block-level formatting:
---
title: 'This is the title: it contains a colon'
@@ -2604,6 +3079,17 @@ template:
$endif$
$endfor$
+Raw content to include in the document's header may be specified
+using `header-includes`; however, it is important to mark up
+this content as raw code for a particular output format, using
+the [`raw_attribute` extension](#extension-raw_attribute)), or it
+will be interpreted as markdown. For example:
+
+ header-includes:
+ - ```{=latex}
+ \let\oldsection\section
+ \renewcommand{\section}[1]{\clearpage\oldsection{#1}}
+ ```
Backslash escapes
-----------------
@@ -2644,20 +3130,6 @@ two trailing spaces on a line.
Backslash escapes do not work in verbatim contexts.
-Smart punctuation
------------------
-
-#### Extension ####
-
-If the `--smart` option is specified, pandoc will produce typographically
-correct output, converting straight quotes to curly quotes, `---` to
-em-dashes, `--` to en-dashes, and `...` to ellipses. Nonbreaking spaces
-are inserted after certain abbreviations, such as "Mr."
-
-Note: if your LaTeX template or any included header file call for the
-[`csquotes`] package, pandoc will detect this automatically and use
-`\enquote{...}` for quoted text.
-
Inline formatting
-----------------
@@ -2746,16 +3218,20 @@ Attributes can be attached to verbatim text, just as with
### Small caps ###
-To write small caps, you can use an HTML span tag:
+To write small caps, use the `smallcaps` class:
- <span style="font-variant:small-caps;">Small caps</span>
+ [Small caps]{.smallcaps}
-(The semicolon is optional and there may be space after the
-colon.) This will work in all output formats that support small caps.
+Or, without the `bracketed_spans` extension:
-Alternatively, you can also use the new `bracketed_spans` syntax:
+ <span class="smallcaps">Small caps</span>
+
+For compatibility with other Markdown flavors, CSS is also supported:
+
+ <span style="font-variant:small-caps;">Small caps</span>
+
+This will work in all output formats that support small caps.
- [Small caps]{style="font-variant:small-caps;"}
Math
----
@@ -2794,10 +3270,13 @@ MediaWiki, DokuWiki
Textile
~ It will be rendered inside `<span class="math">` tags.
-RTF, OpenDocument, ODT
+RTF, OpenDocument
~ It will be rendered, if possible, using Unicode characters,
and will otherwise appear verbatim.
+ODT
+ ~ It will be rendered, if possible, using MathML.
+
DocBook
~ If the `--mathml` flag is used, it will be rendered using MathML
in an `inlineequation` or `informalequation` tag. Otherwise it
@@ -2813,51 +3292,8 @@ FictionBook2
HTML, Slidy, DZSlides, S5, EPUB
~ The way math is rendered in HTML will depend on the
- command-line options selected:
-
- 1. The default is to render TeX math as far as possible using Unicode
- characters, as with RTF, DocBook, and OpenDocument output. Formulas
- are put inside a `span` with `class="math"`, so that they may be
- styled differently from the surrounding text if needed.
-
- 2. If the `--latexmathml` option is used, TeX math will be displayed
- between `$` or `$$` characters and put in `<span>` tags with class `LaTeX`.
- The [LaTeXMathML] script will be used to render it as formulas.
- (This trick does not work in all browsers, but it works in Firefox.
- In browsers that do not support LaTeXMathML, TeX math will appear
- verbatim between `$` characters.)
-
- 3. If the `--jsmath` option is used, TeX math will be put inside
- `<span>` tags (for inline math) or `<div>` tags (for display math)
- with class `math`. The [jsMath] script will be used to render
- it.
-
- 4. If the `--mimetex` option is used, the [mimeTeX] CGI script will
- be called to generate images for each TeX formula. This should
- work in all browsers. The `--mimetex` option takes an optional URL
- as argument. If no URL is specified, it will be assumed that the
- mimeTeX CGI script is at `/cgi-bin/mimetex.cgi`.
-
- 5. If the `--gladtex` option is used, TeX formulas will be enclosed
- in `<eq>` tags in the HTML output. The resulting `htex` file may then
- be processed by [gladTeX], which will produce image files for each
- formula and an HTML file with links to these images. So, the
- procedure is:
-
- pandoc -s --gladtex myfile.txt -o myfile.htex
- gladtex -d myfile-images myfile.htex
- # produces myfile.html and images in myfile-images
-
- 6. If the `--webtex` option is used, TeX formulas will be converted
- to `<img>` tags that link to an external script that converts
- formulas to images. The formula will be URL-encoded and concatenated
- with the URL provided. If no URL is specified, the CodeCogs
- will be used (`https://latex.codecogs.com/png.latex?`).
-
- 7. If the `--mathjax` option is used, TeX math will be displayed
- between `\(...\)` (for inline math) or `\[...\]` (for display
- math) and put in `<span>` tags with class `math`.
- The [MathJax] script will be used to render it as formulas.
+ command-line options selected. Therefore see [Math rendering in HTML]
+ above.
[interpreted text role `:math:`]: http://docutils.sourceforge.net/docs/ref/rst/roles.html#math
@@ -2928,9 +3364,6 @@ For the most part this should give the same output as `raw_html`,
but it makes it easier to write pandoc filters to manipulate groups
of inlines.
-Raw TeX
--------
-
#### Extension: `raw_tex` ####
In addition to raw HTML, pandoc allows raw LaTeX, TeX, and ConTeXt to be
@@ -2955,23 +3388,58 @@ LaTeX, not as Markdown.
Inline LaTeX is ignored in output formats other than Markdown, LaTeX,
Emacs Org mode, and ConTeXt.
+### Generic raw attribute ###
+
+#### Extension: `raw_attribute` ####
+
+Inline spans and fenced code blocks with a special
+kind of attribute will be parsed as raw content with the
+designated format. For example, the following produces a raw
+groff `ms` block:
+
+ ```{=ms}
+ .MYMACRO
+ blah blah
+ ```
+And the following produces a raw `html` inline element:
+
+ This is `<a>html</a>`{=html}
+
+The format name should match the target format name (see
+`-t/--to`, above, for a list, or use `pandoc
+--list-output-formats`).
+
+This extension presupposes that the relevant kind of
+inline code or fenced code block is enabled. Thus, for
+example, to use a raw attribute with a backtick code block,
+`backtick_code_blocks` must be enabled.
+
+The raw attribute cannot be combined with regular attributes.
+
LaTeX macros
------------
#### Extension: `latex_macros` ####
-For output formats other than LaTeX, pandoc will parse LaTeX `\newcommand` and
-`\renewcommand` definitions and apply the resulting macros to all LaTeX
-math. So, for example, the following will work in all output formats,
-not just LaTeX:
+For output formats other than LaTeX, pandoc will parse LaTeX
+macro definitions and apply the resulting macros to all LaTeX
+math and raw LaTeX. So, for example, the following will work in
+all output formats, not just LaTeX:
\newcommand{\tuple}[1]{\langle #1 \rangle}
$\tuple{a, b, c}$
-In LaTeX output, the `\newcommand` definition will simply be passed
-unchanged to the output.
+Note that LaTeX macros will not be applied if they occur
+inside inside a raw span or block marked with the
+[`raw_attribute` extension](#extension-raw_attribute).
+When `latex_macros` is disabled, the raw LaTeX and math will
+not have macros applied. This is usually a better approach when
+you are targeting LaTeX or PDF.
+
+Whether or not `latex_macros` is enabled, the macro definitions
+will still be passed through as raw LaTeX.
Links
-----
@@ -3010,7 +3478,8 @@ definition, which may occur elsewhere in the document (either
before or after the link).
The link consists of link text in square brackets, followed by a label in
-square brackets. (There can be space between the two.) The link definition
+square brackets. (There cannot be space between the two unless the
+`spaced_reference_links` extension is enabled.) The link definition
consists of the bracketed label, followed by a colon and a space, followed by
the URL, and optionally (after a space) a link title either in quotes or in
parentheses. The label must not be parseable as a citation (assuming
@@ -3095,23 +3564,26 @@ The link text will be used as the image's alt text:
#### Extension: `implicit_figures` ####
-An image occurring by itself in a paragraph will be rendered as
-a figure with a caption.[^5] (In LaTeX, a figure environment will be
-used; in HTML, the image will be placed in a `div` with class
-`figure`, together with a caption in a `p` with class `caption`.)
-The image's alt text will be used as the caption.
+An image with nonempty alt text, occurring by itself in a
+paragraph, will be rendered as a figure with a caption. The
+image's alt text will be used as the caption.
![This is the caption](/url/of/image.png)
-[^5]: This feature is not yet implemented for RTF, OpenDocument, or
- ODT. In those formats, you'll just get an image in a paragraph by
- itself, with no caption.
+How this is rendered depends on the output format. Some output
+formats (e.g. RTF) do not yet support figures. In those
+formats, you'll just get an image in a paragraph by itself, with
+no caption.
If you just want a regular inline image, just make sure it is not
the only thing in the paragraph. One way to do this is to insert a
nonbreaking space after the image:
- ![This image won't be a figure](/url/of/image.png)\
+ ![This image won't be a figure](/url/of/image.png)\
+
+Note that in reveal.js slide shows, an image in a paragraph
+by itself that has the `stretch` class will fill the screen,
+and the caption and figure tags will be omitted.
#### Extension: `link_attributes` ####
@@ -3156,13 +3628,59 @@ For example:
is to look at the image resolution and the dpi metadata embedded in
the image file.
-Spans
------
+Divs and Spans
+--------------
+
+Using the `native_divs` and `native_spans` extensions
+(see [above][Extension: `native_divs`]), HTML syntax can
+be used as part of markdown to create native `Div` and `Span`
+elements in the pandoc AST (as opposed to raw HTML).
+However, there is also nicer syntax available:
+
+#### Extension: `fenced_divs` ####
+
+Allow special fenced syntax for native `Div` blocks. A Div
+starts with a fence containing at least three consecutive
+colons plus some attributes. The attributes may optionally
+be followed by another string of consecutive colons.
+The attribute syntax is exactly as in fenced code blocks (see
+[Extension: `fenced_code_attributes`]). As with fenced
+code blocks, one can use either attributes in curly braces
+or a single unbraced word, which will be treated as a class
+name. The Div ends with another line containing a string of at
+least three consecutive colons. The fenced Div should be
+separated by blank lines from preceding and following blocks.
+
+Example:
+
+ ::::: {#special .sidebar}
+ Here is a paragraph.
+
+ And another.
+ :::::
+
+Fenced divs can be nested. Opening fences are distinguished
+because they *must* have attributes:
+
+ ::: Warning ::::::
+ This is a warning.
+
+ ::: Danger
+ This is a warning within a warning.
+ :::
+ ::::::::::::::::::
+
+Fences without attributes are always closing fences. Unlike
+with fenced code blocks, the number of colons in the closing
+fence need not match the number in the opening fence. However,
+it can be helpful for visual clarity to use fences of different
+lengths to distinguish nested divs from their parents.
+
#### Extension: `bracketed_spans` ####
A bracketed sequence of inlines, as one would use to begin
-a link, will be treated as a span with attributes if it is
+a link, will be treated as a `Span` with attributes if it is
followed immediately by attributes:
[This is *some text*]{.class key="val"}
@@ -3214,7 +3732,6 @@ they cannot contain multiple paragraphs). The syntax is as follows:
Inline and regular footnotes may be mixed freely.
-
Citations
---------
@@ -3415,6 +3932,13 @@ in pandoc, but may be enabled by adding `+EXTENSION` to the format
name, where `EXTENSION` is the name of the extension. Thus, for
example, `markdown+hard_line_breaks` is Markdown with hard line breaks.
+#### Extension: `old_dashes` ####
+
+Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes:
+`-` before a numeral is an en-dash, and `--` is an em-dash.
+This option only has an effect if `smart` is enabled. It is
+selected automatically for `textile` input.
+
#### Extension: `angle_brackets_escapable` ####
Allow `<` and `>` to be backslash-escaped, as they can be in
@@ -3426,6 +3950,19 @@ implied by pandoc's default `all_symbols_escapable`.
Allow a list to occur right after a paragraph, with no intervening
blank space.
+#### Extension: `four_space_rule` ####
+
+Selects the pandoc <= 2.0 behavior for parsing lists, so that
+four spaces indent are needed for list item continuation
+paragraphs.
+
+#### Extension: `spaced_reference_links` ####
+
+Allow whitespace between the two components of a reference link,
+for example,
+
+ [foo] [bar].
+
#### Extension: `hard_line_breaks` ####
Causes all newlines within a paragraph to be interpreted as hard line
@@ -3446,7 +3983,7 @@ between two East Asian wide characters. This is a better choice
than `ignore_line_breaks` for texts that include a mix of East
Asian wide characters and other characters.
-##### Extension: `emoji` ####
+#### Extension: `emoji` ####
Parses textual emojis like `:smile:` as Unicode emoticons.
@@ -3499,12 +4036,6 @@ simply skipped (as opposed to being parsed as paragraphs).
Makes all absolute URIs into links, even when not surrounded by
pointy braces `<...>`.
-#### Extension: `ascii_identifiers` ####
-
-Causes the identifiers produced by `auto_identifiers` to be pure ASCII.
-Accents are stripped off of accented Latin letters, and non-Latin
-letters are omitted.
-
#### Extension: `mmd_link_attributes` ####
Parses multimarkdown style key-value attributes on link
@@ -3558,13 +4089,14 @@ variants are supported:
: `footnotes`, `pipe_tables`, `raw_html`, `markdown_attribute`,
`fenced_code_blocks`, `definition_lists`, `intraword_underscores`,
`header_attributes`, `link_attributes`, `abbreviations`,
- `shortcut_reference_links`.
+ `shortcut_reference_links`, `spaced_reference_links`.
-`markdown_github` (GitHub-Flavored Markdown)
-: `pipe_tables`, `raw_html`, `fenced_code_blocks`, `auto_identifiers`,
+`markdown_github` (deprecated GitHub-Flavored Markdown)
+: `pipe_tables`, `raw_html`, `fenced_code_blocks`, `gfm_auto_identifiers`,
`ascii_identifiers`, `backtick_code_blocks`, `autolink_bare_uris`,
- `intraword_underscores`, `strikeout`, `hard_line_breaks`, `emoji`,
- `shortcut_reference_links`, `angle_brackets_escapable`.
+ `space_in_atx_header`, `intraword_underscores`, `strikeout`,
+ `emoji`, `shortcut_reference_links`, `angle_brackets_escapable`,
+ `lists_without_preceding_blankline`.
`markdown_mmd` (MultiMarkdown)
: `pipe_tables`, `raw_html`, `markdown_attribute`, `mmd_link_attributes`,
@@ -3572,24 +4104,28 @@ variants are supported:
`mmd_title_block`, `footnotes`, `definition_lists`,
`all_symbols_escapable`, `implicit_header_references`,
`auto_identifiers`, `mmd_header_identifiers`,
- `shortcut_reference_links`.
+ `shortcut_reference_links`, `implicit_figures`,
+ `superscript`, `subscript`, `backtick_code_blocks`,
+ `spaced_reference_links`, `raw_attribute`.
`markdown_strict` (Markdown.pl)
-: `raw_html`
-
-Extensions with formats other than Markdown
--------------------------------------------
+: `raw_html`, `shortcut_reference_links`,
+ `spaced_reference_links`.
-Some of the extensions discussed above can be used with formats
-other than Markdown:
+We also support `commonmark` and `gfm` (GitHub-Flavored Markdown,
+which is implemented as a set of extensions on `commonmark`).
-* `auto_identifiers` can be used with `latex`, `rst`, `mediawiki`,
- and `textile` input (and is used by default).
+Note, however, that `commonmark` and `gfm` have limited support
+for extensions. Only those listed below (and `smart` and
+`raw_tex`) will work. The extensions can, however, all be
+individually disabled.
+Also, `raw_tex` only affects `gfm` output, not input.
-* `tex_math_dollars`, `tex_math_single_backslash`, and
- `tex_math_double_backslash` can be used with `html` input.
- (This is handy for reading web pages formatted using MathJax,
- for example.)
+`gfm` (GitHub-Flavored Markdown)
+: `pipe_tables`, `raw_html`, `fenced_code_blocks`, `auto_identifiers`,
+ `ascii_identifiers`, `backtick_code_blocks`, `autolink_bare_uris`,
+ `intraword_underscores`, `strikeout`, `hard_line_breaks`, `emoji`,
+ `shortcut_reference_links`, `angle_brackets_escapable`.
Producing slide shows with pandoc
=================================
@@ -3597,7 +4133,8 @@ Producing slide shows with pandoc
You can use pandoc to produce an HTML + JavaScript slide presentation
that can be viewed via a web browser. There are five ways to do this,
using [S5], [DZSlides], [Slidy], [Slideous], or [reveal.js].
-You can also produce a PDF slide show using LaTeX [`beamer`].
+You can also produce a PDF slide show using LaTeX [`beamer`], or
+slides shows in Microsoft [PowerPoint] format.
Here's the Markdown source for a simple slide show, `habits.txt`:
@@ -3659,6 +4196,10 @@ To produce a PDF slide show using beamer, type
Note that a reveal.js slide show can also be converted to a PDF
by printing it to a file from the browser.
+To produce a Powerpoint slide show, type
+
+ pandoc habits.txt -o habits.pptx
+
Structuring the slide show
--------------------------
@@ -3683,6 +4224,9 @@ rules:
"title slides," which just contain the section title
and help to break the slide show into sections.
+ * Content *above* the slide level will not appear in the slide
+ show.
+
* A title page is constructed automatically from the document's title
block, if present. (In the case of beamer, this can be disabled
by commenting out some lines in the default template.)
@@ -3704,14 +4248,38 @@ Incremental lists
By default, these writers produce lists that display "all at once."
If you want your lists to display incrementally (one item at a time),
use the `-i` option. If you want a particular list to depart from the
-default (that is, to display incrementally without the `-i` option and
-all at once with the `-i` option), put it in a block quote:
+default, put it in a `div` block with class `incremental` or
+`nonincremental`. So, for example, using the `fenced div` syntax, the
+following would be incremental regardless of the document default:
+
+ ::: incremental
+
+ - Eat spaghetti
+ - Drink wine
+
+ :::
+
+or
+
+ ::: nonincremental
+
+ - Eat spaghetti
+ - Drink wine
+
+ :::
+
+While using `incremental` and `nonincremental` divs are the
+recommended method of setting incremental lists on a per-case basis,
+an older method is also supported: putting lists inside a blockquote
+will depart from the document default (that is, it will display
+incrementally without the `-i` option and all at once with the `-i`
+option):
> - Eat spaghetti
> - Drink wine
-In this way incremental and nonincremental lists can be mixed in
-a single document.
+Both methods allow incremental and nonincremental lists to be mixed
+in a single document.
Inserting pauses
----------------
@@ -3766,21 +4334,41 @@ bibliographies:
Speaker notes
-------------
-reveal.js has good support for speaker notes. You can add notes to your
-Markdown document thus:
+Speaker notes are supported in reveal.js and PowerPoint (pptx)
+output. You can add notes to your Markdown document thus:
+
+ ::: notes
- <div class="notes">
This is my note.
- It can contain Markdown
- like this list
- </div>
+ :::
+
+To show the notes window in reveal.js, press `s` while viewing the
+presentation. Speaker notes in PowerPoint will be available, as usual,
+in handouts and presenter view.
-To show the notes window, press `s` while viewing the presentation.
Notes are not yet supported for other slide formats, but the notes
will not appear on the slides themselves.
+Columns
+-------
+
+To put material in side by side columns, you can use a native
+div container with class `columns`, containing two or more div
+containers with class `column` and a `width` attribute:
+
+ :::::::::::::: {.columns}
+ ::: {.column width="40%"}
+ contents...
+ :::
+ ::: {.column width="60%"}
+ contents...
+ :::
+ ::::::::::::::
+
Frame attributes in beamer
--------------------------
@@ -3822,6 +4410,8 @@ block][Extension: `yaml_metadata_block`]. Here is an example:
text: doi:10.234234.234/33
publisher: My Press
rights: © 2007 John Smith, CC BY-NC
+ ibooks:
+ version: 1.3.4
...
The following fields are recognized:
@@ -3887,6 +4477,16 @@ The following fields are recognized:
~ Either `ltr` or `rtl`. Specifies the `page-progression-direction`
attribute for the [`spine` element].
+`ibooks`
+ ~ iBooks-specific metadata, with the following fields:
+
+ - `version`: (string)
+ - `specified-fonts`: `true`|`false` (default `false`)
+ - `ipad-orientation-lock`: `portrait-only`|`landscape-only`
+ - `iphone-orientation-lock`: `portrait-only`|`landscape-only`
+ - `binding`: `true`|`false` (default `true`)
+ - `scroll-axis`: `vertical`|`horizontal`|`default`
+
[MARC relators]: http://loc.gov/marc/relators/relaterm.html
[`spine` element]: http://idpf.org/epub/301/spec/epub-publications.html#sec-spine-elem
@@ -3905,74 +4505,78 @@ with the `src` attribute. For example:
</source>
</audio>
-Literate Haskell support
-========================
+Syntax highlighting
+===================
-If you append `+lhs` (or `+literate_haskell`) to an appropriate input or output
-format (`markdown`, `markdown_strict`, `rst`, or `latex` for input or output;
-`beamer`, `html` or `html5` for output only), pandoc will treat the document as
-literate Haskell source. This means that
+Pandoc will automatically highlight syntax in [fenced code blocks] that
+are marked with a language name. The Haskell library [skylighting] is
+used for highlighting, which works in HTML, Docx, Ms, and LaTeX/PDF output.
+To see a list of language names that pandoc will recognize, type
+`pandoc --list-highlight-languages`.
- - In Markdown input, "bird track" sections will be parsed as Haskell
- code rather than block quotations. Text between `\begin{code}`
- and `\end{code}` will also be treated as Haskell code. For
- ATX-style headers the character '=' will be used instead of '#'.
+The color scheme can be selected using the `--highlight-style` option.
+The default color scheme is `pygments`, which imitates the default color
+scheme used by the Python library pygments (though pygments is not actually
+used to do the highlighting). To see a list of highlight styles,
+type `pandoc --list-highlight-styles`.
- - In Markdown output, code blocks with classes `haskell` and `literate`
- will be rendered using bird tracks, and block quotations will be
- indented one space, so they will not be treated as Haskell code.
- In addition, headers will be rendered setext-style (with underlines)
- rather than ATX-style (with '#' characters). (This is because ghc
- treats '#' characters in column 1 as introducing line numbers.)
+To disable highlighting, use the `--no-highlight` option.
- - In restructured text input, "bird track" sections will be parsed
- as Haskell code.
+[skylighting]: https://github.com/jgm/skylighting
- - In restructured text output, code blocks with class `haskell` will
- be rendered using bird tracks.
+Custom Styles in Docx
+=====================
- - In LaTeX input, text in `code` environments will be parsed as
- Haskell code.
+Input
+-----
- - In LaTeX output, code blocks with class `haskell` will be rendered
- inside `code` environments.
+The docx reader, by default, only reads those styles that it can
+convert into pandoc elements, either by direct conversion or
+interpreting the derivation of the input document's styles.
- - In HTML output, code blocks with class `haskell` will be rendered
- with class `literatehaskell` and bird tracks.
+By enabling the [`styles` extension](#ext-styles) in the docx reader
+(`-f docx+styles`), you can produce output that maintains the styles
+of the input document, using the `custom-style` class. Paragraph
+styles are interpreted as divs, while character styles are interpreted
+as spans.
-Examples:
+For example, using the `custom-style-reference.docx` file in the test
+directory, we have the following different outputs:
- pandoc -f markdown+lhs -t html
+Without the `+styles` extension:
-reads literate Haskell source formatted with Markdown conventions and writes
-ordinary HTML (without bird tracks).
+ $ pandoc test/docx/custom-style-reference.docx -f docx -t markdown
+ This is some text.
- pandoc -f markdown+lhs -t html+lhs
+ This is text with an *emphasized* text style. And this is text with a
+ **strengthened** text style.
-writes HTML with the Haskell code in bird tracks, so it can be copied
-and pasted as literate Haskell source.
+ > Here is a styled paragraph that inherits from Block Text.
-Syntax highlighting
-===================
+And with the extension:
-Pandoc will automatically highlight syntax in [fenced code blocks] that
-are marked with a language name. The Haskell library [highlighting-kate] is
-used for highlighting, which works in HTML, Docx, and LaTeX/PDF output.
-To see a list of language names that pandoc will recognize, type
-`pandoc --list-highlight-languages`.
+ $ pandoc test/docx/custom-style-reference.docx -f docx+styles -t markdown
-The color scheme can be selected using the `--highlight-style` option.
-The default color scheme is `pygments`, which imitates the default color
-scheme used by the Python library pygments (though pygments is not actually
-used to do the highlighting). To see a list of highlight styles,
-type `pandoc --list-highlight-styles`.
+ ::: {custom-style="FirstParagraph"}
+ This is some text.
+ :::
-To disable highlighting, use the `--no-highlight` option.
+ ::: {custom-style="BodyText"}
+ This is text with an [emphasized]{custom-style="Emphatic"} text style.
+ And this is text with a [strengthened]{custom-style="Strengthened"}
+ text style.
+ :::
-[highlighting-kate]: https://github.com/jgm/highlighting-kate
+ ::: {custom-style="MyBlockStyle"}
+ > Here is a styled paragraph that inherits from Block Text.
+ :::
-Custom Styles in Docx Output
-============================
+With these custom styles, you can use your input document as a
+reference-doc while creating docx output (see below), and maintain the
+same styles in your input and output files.
+
+Output
+------
By default, pandoc's docx output applies a predefined set of styles for
blocks such as paragraphs and block quotes, and uses largely default
@@ -3984,19 +4588,19 @@ using `div`s and `span`s, respectively.
If you define a `div` or `span` with the attribute `custom-style`,
pandoc will apply your specified style to the contained elements. So,
-for example,
+for example using the `bracketed_spans` syntax,
- <span custom-style="Emphatically">Get out,</span> he said.
+ [Get out]{custom-style="Emphatically"}, he said.
-would produce a docx file with "Get out," styled with character
-style `Emphatically`. Similarly,
+would produce a docx file with "Get out" styled with character
+style `Emphatically`. Similarly, using the `fenced_divs` syntax,
Dickinson starts the poem simply:
- <div custom-style="Poetry">
+ ::: {custom-style="Poetry"}
| A Bird came down the Walk---
| He did not know I saw---
- </div>
+ :::
would style the two contained lines with the `Poetry` paragraph style.
@@ -4012,7 +4616,7 @@ want all italics to be transformed to the `Emphasis` character style
transform all italicized inlines to inlines within an `Emphasis`
custom-style `span`.
-[pandoc filters]: http://pandoc.org/scripting.html
+[pandoc filters]: http://pandoc.org/filters.html
Custom writers
==============
@@ -4036,182 +4640,10 @@ which you can modify according to your needs, do
Authors
=======
-© 2006-2016 John MacFarlane (jgm@berkeley.edu). Released under the
-[GPL], version 2 or greater. This software carries no warranty of
-any kind. (See COPYRIGHT for full copyright and warranty notices.)
-
-Contributors include
-Arata Mizuki,
-Aaron Wolen,
-Albert Krewinkel,
-Alex Ivkin,
-Alex Vong,
-Alexander Kondratskiy,
-Alexander Sulfrian,
-Alexander V Vershilov,
-Alfred Wechselberger,
-Andreas Lööw,
-Andrew Dunning,
-Antoine Latter,
-Arata Mizuki,
-Arlo O'Keeffe,
-Artyom Kazak,
-B. Scott Michel,
-Ben Gamari,
-Beni Cherniavsky-Paskin,
-Benoit Schweblin,
-Bjorn Buckwalter,
-Bradley Kuhn,
-Brent Yorgey,
-Bryan O'Sullivan,
-Caleb McDaniel,
-Calvin Beck,
-Carlos Sosa,
-Chris Black,
-Christian Conkle,
-Christoffer Ackelman,
-Christoffer Sawicki,
-Clare Macrae,
-Clint Adams,
-Conal Elliott,
-Craig S. Bosma,
-Daniel Bergey,
-Daniel T. Staal,
-Daniele D'Orazio,
-David Lazar,
-David Röthlisberger,
-Denis Laxalde,
-Douglas Calvert,
-Emanuel Evans,
-Emily Eisenberg,
-Eric Kow,
-Eric Seidel,
-Felix Yan,
-Florian Eitel,
-François Gannaz,
-Freiric Barral,
-Freirich Raabe,
-Frerich Raabe,
-Fyodor Sheremetyev,
-Gabor Pali,
-Gavin Beatty,
-Gottfried Haider,
-Greg Maslov,
-Greg Rundlett,
-Grégory Bataille,
-Gwern Branwen,
-Hans-Peter Deifel,
-Henrik Tramberend,
-Henry de Valence,
-Hubert Plociniczak,
-Ilya V. Portnov,
-Ivo Clarysse,
-J. Lewis Muir,
-Jaime Marquínez Ferrándiz,
-Jakob Voß,
-James Aspnes,
-Jamie F. Olson,
-Jan Larres,
-Jan Schulz,
-Jason Ronallo,
-Jeff Arnold,
-Jeff Runningen,
-Jens Petersen,
-Jesse Rosenthal,
-Joe Hillenbrand,
-John MacFarlane,
-John Muccigrosso,
-Jonas Smedegaard,
-Jonathan Daugherty,
-Jose Luis Duran,
-Josef Svenningsson,
-Julien Cretel,
-Juliusz Gonera,
-Justin Bogner,
-Jérémy Bobbio,
-Kelsey Hightower,
-Kolen Cheung,
-Konstantin Zudov,
-Kristof Bastiaensen,
-Lars-Dominik Braun,
-Luke Plant,
-Mark Szepieniec,
-Mark Wright,
-Martin Linn,
-Masayoshi Takahashi,
-Matej Kollar,
-Mathias Schenner,
-Mathieu Duponchelle,
-Matthew Eddey,
-Matthew Pickering,
-Matthias C. M. Troffaes,
-Mauro Bieg,
-Max Bolingbroke,
-Max Rydahl Andersen,
-Merijn Verstraaten,
-Michael Beaumont,
-Michael Chladek,
-Michael Snoyman,
-Michael Thompson,
-MinRK,
-Morton Fox,
-Nathan Gass,
-Neil Mayhew,
-Nick Bart,
-Nicolas Kaiser,
-Nikolay Yakimov,
-Oliver Matthews,
-Ophir Lifshitz,
-Pablo Rodríguez,
-Paul Rivier,
-Paulo Tanimoto,
-Peter Wang,
-Philippe Ombredanne,
-Phillip Alday,
-Prayag Verma,
-Puneeth Chaganti,
-Ralf Stephan,
-Raniere Silva,
-Recai Oktaş,
-RyanGlScott,
-Scott Morrison,
-Sergei Trofimovich,
-Sergey Astanin,
-Shahbaz Youssefi,
-Shaun Attfield,
-Sidarth Kapur,
-Sidharth Kapur,
-Simon Hengel,
-Sumit Sahrawat,
-Thomas Hodgson,
-Thomas Weißschuh,
-Tim Lin,
-Timothy Humphries,
-Tiziano Müller,
-Todd Sifleet,
-Tom Leese,
-Uli Köhler,
-Václav Zeman,
-Viktor Kronvall,
-Vincent,
-Václav Haisman,
-Václav Zeman,
-Wandmalfarbe,
-Waldir Pimenta,
-Wikiwide,
-Xavier Olive,
-bumper314,
-csforste,
-infinity0x,
-nkalvi,
-qerub,
-robabla,
-roblabla,
-rodja.trappe,
-rski,
-shreevatsa.public,
-takahashim,
-tgkokk,
-thsutton.
+Copyright 2006-2017 John MacFarlane (jgm@berkeley.edu). Released
+under the [GPL], version 2 or greater. This software carries no
+warranty of any kind. (See COPYRIGHT for full copyright and
+warranty notices.) For a full list of contributors, see the file
+AUTHORS.md in the pandoc source code.
[GPL]: http://www.gnu.org/copyleft/gpl.html "GNU General Public License"
diff --git a/README.md b/README.md
index 4388d4d07..3f57b05aa 100644
--- a/README.md
+++ b/README.md
@@ -1,146 +1,149 @@
-Pandoc
-======
+<!-- Do not edit this file. It is generated automatically from
+README.template and MANUAL.txt via the command:
+pandoc --lua-filter tools/update-readme.lua README.template -o README.md
+-->
-[![github release](https://img.shields.io/github/release/jgm/pandoc.svg?label=current+release)](https://github.com/jgm/pandoc/releases)
-[![hackage release](https://img.shields.io/hackage/v/pandoc.svg?label=hackage)](http://hackage.haskell.org/package/pandoc)
+# Pandoc
+
+[![github
+release](https://img.shields.io/github/release/jgm/pandoc.svg?label=current+release)](https://github.com/jgm/pandoc/releases)
+[![hackage
+release](https://img.shields.io/hackage/v/pandoc.svg?label=hackage)](http://hackage.haskell.org/package/pandoc)
[![homebrew](https://img.shields.io/homebrew/v/pandoc.svg)](http://brewformulas.org/Pandoc)
-[![stackage LTS package](http://stackage.org/package/pandoc/badge/lts)](http://stackage.org/lts/package/pandoc)
-[![travis build status](https://img.shields.io/travis/jgm/pandoc/master.svg?label=travis+build)](https://travis-ci.org/jgm/pandoc)
-[![appveyor build status](https://ci.appveyor.com/api/projects/status/nvqs4ct090igjiqc?svg=true)](https://ci.appveyor.com/project/jgm/pandoc)
+[![stackage LTS
+package](http://stackage.org/package/pandoc/badge/lts)](http://stackage.org/lts/package/pandoc)
+[![travis build
+status](https://img.shields.io/travis/jgm/pandoc/master.svg?label=travis+build)](https://travis-ci.org/jgm/pandoc)
+[![appveyor build
+status](https://ci.appveyor.com/api/projects/status/nvqs4ct090igjiqc?svg=true)](https://ci.appveyor.com/project/jgm/pandoc)
[![license](https://img.shields.io/badge/license-GPLv2+-lightgray.svg)](https://www.gnu.org/licenses/gpl.html)
-[![pandoc-discuss on google groups](https://img.shields.io/badge/pandoc-discuss-red.svg?style=social)](https://groups.google.com/forum/#!forum/pandoc-discuss)
-
-
-The universal markup converter
-------------------------------
-
-Pandoc is a [Haskell] library for converting from one markup format to
-another, and a command-line tool that uses this library. It can read
-[Markdown], [CommonMark], [PHP Markdown Extra], [GitHub-Flavored Markdown],
-[MultiMarkdown], and (subsets of) [Textile], [reStructuredText], [HTML],
-[LaTeX], [MediaWiki markup], [TWiki markup], [Haddock markup], [OPML], [Emacs
-Org mode], [DocBook], [txt2tags], [EPUB], [ODT] and [Word docx]; and it can
-write plain text, [Markdown], [CommonMark], [PHP Markdown Extra],
-[GitHub-Flavored Markdown], [MultiMarkdown], [reStructuredText], [XHTML],
-[HTML5], [LaTeX] \(including [`beamer`] slide shows\), [ConTeXt], [RTF], [OPML],
-[DocBook], [OpenDocument], [ODT], [Word docx], [GNU Texinfo], [MediaWiki
-markup], [DokuWiki markup], [ZimWiki markup], [Haddock markup],
-[EPUB] \(v2 or v3\), [FictionBook2], [Textile], [groff man] pages,
-[Emacs Org mode], [AsciiDoc], [InDesign ICML], [TEI Simple], and [Slidy],
-[Slideous], [DZSlides], [reveal.js] or [S5] HTML slide shows. It can also
-produce [PDF] output on systems where LaTeX, ConTeXt, or `wkhtmltopdf` is
+[![pandoc-discuss on google
+groups](https://img.shields.io/badge/pandoc-discuss-red.svg?style=social)](https://groups.google.com/forum/#!forum/pandoc-discuss)
+
+## The universal markup converter
+
+<div id="description">
+
+Pandoc is a [Haskell](https://www.haskell.org) library for converting
+from one markup format to another, and a command-line tool that uses
+this library.
+
+Pandoc can read
+[Markdown](http://daringfireball.net/projects/markdown/),
+[CommonMark](http://commonmark.org), [PHP Markdown
+Extra](https://michelf.ca/projects/php-markdown/extra/),
+[GitHub-Flavored
+Markdown](https://help.github.com/articles/github-flavored-markdown/),
+[MultiMarkdown](http://fletcherpenney.net/multimarkdown/), and (subsets
+of) [Textile](http://redcloth.org/textile),
+[reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html),
+[HTML](http://www.w3.org/html/), [LaTeX](http://latex-project.org),
+[MediaWiki markup](https://www.mediawiki.org/wiki/Help:Formatting),
+[TWiki markup](http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules),
+[TikiWiki
+markup](https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax),
+[Creole 1.0](http://www.wikicreole.org/wiki/Creole1.0), [Haddock
+markup](https://www.haskell.org/haddock/doc/html/ch03s08.html),
+[OPML](http://dev.opml.org/spec2.html), [Emacs Org
+mode](http://orgmode.org), [DocBook](http://docbook.org),
+[JATS](https://jats.nlm.nih.gov),
+[Muse](https://amusewiki.org/library/manual),
+[txt2tags](http://txt2tags.org), [Vimwiki](https://vimwiki.github.io),
+[EPUB](http://idpf.org/epub),
+[ODT](http://en.wikipedia.org/wiki/OpenDocument), and [Word
+docx](https://en.wikipedia.org/wiki/Office_Open_XML).
+
+Pandoc can write plain text,
+[Markdown](http://daringfireball.net/projects/markdown/),
+[CommonMark](http://commonmark.org), [PHP Markdown
+Extra](https://michelf.ca/projects/php-markdown/extra/),
+[GitHub-Flavored
+Markdown](https://help.github.com/articles/github-flavored-markdown/),
+[MultiMarkdown](http://fletcherpenney.net/multimarkdown/),
+[reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html),
+[XHTML](http://www.w3.org/TR/xhtml1/),
+[HTML5](http://www.w3.org/TR/html5/), [LaTeX](http://latex-project.org)
+(including [`beamer`](https://ctan.org/pkg/beamer) slide shows),
+[ConTeXt](http://www.contextgarden.net/),
+[RTF](http://en.wikipedia.org/wiki/Rich_Text_Format),
+[OPML](http://dev.opml.org/spec2.html), [DocBook](http://docbook.org),
+[JATS](https://jats.nlm.nih.gov),
+[OpenDocument](http://opendocument.xml.org),
+[ODT](http://en.wikipedia.org/wiki/OpenDocument), [Word
+docx](https://en.wikipedia.org/wiki/Office_Open_XML), [GNU
+Texinfo](http://www.gnu.org/software/texinfo/), [MediaWiki
+markup](https://www.mediawiki.org/wiki/Help:Formatting), [DokuWiki
+markup](https://www.dokuwiki.org/dokuwiki), [ZimWiki
+markup](http://zim-wiki.org/manual/Help/Wiki_Syntax.html), [Haddock
+markup](https://www.haskell.org/haddock/doc/html/ch03s08.html),
+[EPUB](http://idpf.org/epub) (v2 or v3),
+[FictionBook2](http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1),
+[Textile](http://redcloth.org/textile), [groff
+man](http://man7.org/linux/man-pages/man7/groff_man.7.html), [groff
+ms](http://man7.org/linux/man-pages/man7/groff_ms.7.html), [Emacs Org
+mode](http://orgmode.org),
+[AsciiDoc](http://www.methods.co.nz/asciidoc/), [InDesign
+ICML](http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf),
+[TEI Simple](https://github.com/TEIC/TEI-Simple),
+[Muse](https://amusewiki.org/library/manual),
+[PowerPoint](https://en.wikipedia.org/wiki/Microsoft_PowerPoint) slide
+shows and [Slidy](http://www.w3.org/Talks/Tools/Slidy/),
+[Slideous](http://goessner.net/articles/slideous/),
+[DZSlides](http://paulrouget.com/dzslides/),
+[reveal.js](http://lab.hakim.se/reveal-js/) or
+[S5](http://meyerweb.com/eric/tools/s5/) HTML slide shows. It can also
+produce [PDF](https://www.adobe.com/pdf/) output on systems where LaTeX,
+ConTeXt, `pdfroff`, `wkhtmltopdf`, `prince`, or `weasyprint` is
installed.
-Pandoc's enhanced version of Markdown includes syntax for [footnotes],
-[tables], flexible [ordered lists], [definition lists], [fenced code blocks],
-[superscripts and subscripts], [strikeout], [metadata blocks], automatic tables of
-contents, embedded LaTeX [math], [citations], and [Markdown inside HTML block
-elements]. (These enhancements, described
-further under [Pandoc's Markdown], can be disabled using the
-`markdown_strict` input or output format.)
-
-In contrast to most existing tools for converting Markdown to HTML, which
-use regex substitutions, pandoc has a modular design: it consists of a
-set of readers, which parse text in a given format and produce a native
-representation of the document, and a set of writers, which convert
-this native representation into a target format. Thus, adding an input
-or output format requires only adding a reader or writer.
-
-Because pandoc's intermediate representation of a document is less
-expressive than many of the formats it converts between, one should
-not expect perfect conversions between every format and every other.
-Pandoc attempts to preserve the structural elements of a document, but
-not formatting details such as margin size. And some document elements,
-such as complex tables, may not fit into pandoc's simple document
-model. While conversions from pandoc's Markdown to all formats aspire
-to be perfect, conversions from formats more expressive than pandoc's
-Markdown can be expected to be lossy.
-
-[Markdown]: http://daringfireball.net/projects/markdown/
-[CommonMark]: http://commonmark.org
-[PHP Markdown Extra]: https://michelf.ca/projects/php-markdown/extra/
-[GitHub-Flavored Markdown]: https://help.github.com/articles/github-flavored-markdown/
-[MultiMarkdown]: http://fletcherpenney.net/multimarkdown/
-[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
-[S5]: http://meyerweb.com/eric/tools/s5/
-[Slidy]: http://www.w3.org/Talks/Tools/Slidy/
-[Slideous]: http://goessner.net/articles/slideous/
-[HTML]: http://www.w3.org/html/
-[HTML5]: http://www.w3.org/TR/html5/
-[XHTML]: http://www.w3.org/TR/xhtml1/
-[LaTeX]: http://latex-project.org
-[`beamer`]: https://ctan.org/pkg/beamer
-[Beamer User's Guide]: http://ctan.math.utah.edu/ctan/tex-archive/macros/latex/contrib/beamer/doc/beameruserguide.pdf
-[ConTeXt]: http://www.contextgarden.net/
-[RTF]: http://en.wikipedia.org/wiki/Rich_Text_Format
-[DocBook]: http://docbook.org
-[txt2tags]: http://txt2tags.org
-[EPUB]: http://idpf.org/epub
-[OPML]: http://dev.opml.org/spec2.html
-[OpenDocument]: http://opendocument.xml.org
-[ODT]: http://en.wikipedia.org/wiki/OpenDocument
-[Textile]: http://redcloth.org/textile
-[MediaWiki markup]: https://www.mediawiki.org/wiki/Help:Formatting
-[DokuWiki markup]: https://www.dokuwiki.org/dokuwiki
-[ZimWiki markup]: http://zim-wiki.org/manual/Help/Wiki_Syntax.html
-[TWiki markup]: http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules
-[Haddock markup]: https://www.haskell.org/haddock/doc/html/ch03s08.html
-[groff man]: http://man7.org/linux/man-pages/man7/groff_man.7.html
-[Haskell]: https://www.haskell.org
-[GNU Texinfo]: http://www.gnu.org/software/texinfo/
-[Emacs Org mode]: http://orgmode.org
-[AsciiDoc]: http://www.methods.co.nz/asciidoc/
-[DZSlides]: http://paulrouget.com/dzslides/
-[Word docx]: https://en.wikipedia.org/wiki/Office_Open_XML
-[PDF]: https://www.adobe.com/pdf/
-[reveal.js]: http://lab.hakim.se/reveal-js/
-[FictionBook2]: http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1
-[InDesign ICML]: https://www.adobe.com/content/dam/Adobe/en/devnet/indesign/cs55-docs/IDML/idml-specification.pdf
-[TEI Simple]: https://github.com/TEIC/TEI-Simple
-
-
-
-
-[footnotes]: http://pandoc.org/MANUAL.html#footnotes
-[tables]: http://pandoc.org/MANUAL.html#tables
-[ordered lists]: http://pandoc.org/MANUAL.html#ordered-lists
-[definition lists]: http://pandoc.org/MANUAL.html#definition-lists
-[fenced code blocks]: http://pandoc.org/MANUAL.html#fenced-code-blocks
-[superscripts and subscripts]: http://pandoc.org/MANUAL.html#superscripts-and-subscripts
-[strikeout]: http://pandoc.org/MANUAL.html#strikeout
-[metadata blocks]: http://pandoc.org/MANUAL.html#metadata-blocks
-[math]: http://pandoc.org/MANUAL.html#math
-[citations]: http://pandoc.org/MANUAL.html#citations
-[Markdown inside HTML block elements]: http://pandoc.org/MANUAL.html#extension-markdown_in_html_blocks
-[Pandoc's Markdown]: http://pandoc.org/MANUAL.html#pandocs-markdown
-
-Installing
-----------
-
-Here's [how to install pandoc](INSTALL.md).
-
-Documentation
--------------
-
-Pandoc's website contains a full [User's Guide](https://pandoc.org/MANUAL.html).
-It is also available [here](MANUAL.txt) as pandoc-flavored Markdown.
-The website also contains some [examples of the use of
+Pandoc’s enhanced version of Markdown includes syntax for tables,
+definition lists, metadata blocks, `Div` blocks, footnotes and
+citations, embedded LaTeX (including math), Markdown inside HTML block
+elements, and much more. These enhancements, described further under
+Pandoc’s Markdown, can be disabled using the `markdown_strict` format.
+
+Pandoc has a modular design: it consists of a set of readers, which
+parse text in a given format and produce a native representation of the
+document (like an *abstract syntax tree* or AST), and a set of writers,
+which convert this native representation into a target format. Thus,
+adding an input or output format requires only adding a reader or
+writer. Users can also run custom [pandoc
+filters](http://pandoc.org/filters.html) to modify the intermediate AST.
+
+Because pandoc’s intermediate representation of a document is less
+expressive than many of the formats it converts between, one should not
+expect perfect conversions between every format and every other. Pandoc
+attempts to preserve the structural elements of a document, but not
+formatting details such as margin size. And some document elements, such
+as complex tables, may not fit into pandoc’s simple document model.
+While conversions from pandoc’s Markdown to all formats aspire to be
+perfect, conversions from formats more expressive than pandoc’s Markdown
+can be expected to be lossy.
+
+</div>
+
+## Installing
+
+Here’s [how to install pandoc](INSTALL.md).
+
+## Documentation
+
+Pandoc’s website contains a full [User’s
+Guide](https://pandoc.org/MANUAL.html). It is also available
+[here](MANUAL.txt) as pandoc-flavored Markdown. The website also
+contains some [examples of the use of
pandoc](https://pandoc.org/demos.html) and a limited [online
demo](https://pandoc.org/try).
-Contributing
-------------
-
-Pull requests, bug reports, and feature requests are welcome. Please make
-sure to read [the contributor guidelines](CONTRIBUTING.md) before opening a
-new issue.
-
+## Contributing
-License
--------
+Pull requests, bug reports, and feature requests are welcome. Please
+make sure to read [the contributor guidelines](CONTRIBUTING.md) before
+opening a new issue.
-© 2006-2016 John MacFarlane (jgm@berkeley.edu). Released under the
-[GPL], version 2 or greater. This software carries no warranty of
-any kind. (See COPYRIGHT for full copyright and warranty notices.)
+## License
-[GPL]: http://www.gnu.org/copyleft/gpl.html "GNU General Public License"
+© 2006-2018 John MacFarlane (jgm@berkeley.edu). Released under the
+[GPL](http://www.gnu.org/copyleft/gpl.html "GNU General Public License"),
+version 2 or greater. This software carries no warranty of any kind.
+(See COPYRIGHT for full copyright and warranty notices.)
diff --git a/Setup.hs b/Setup.hs
index af5731b71..889004bc0 100644
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,10 +1,5 @@
-{-# LANGUAGE CPP #-}
-#if !defined(MIN_VERSION_Cabal)
-# define MIN_VERSION_Cabal(a,b,c) 0
-#endif
-
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,58 +17,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
import Distribution.Simple
-import Distribution.Simple.PreProcess
-import Distribution.Simple.Setup (ConfigFlags(..), CopyFlags(..), fromFlag)
+import Distribution.Simple.Setup (CopyFlags(..), fromFlag)
import Distribution.PackageDescription (PackageDescription(..))
-import Distribution.Simple.Utils ( rawSystemExitCode, findProgramVersion )
-import System.Exit
-import Distribution.Simple.Utils (info, notice, installOrdinaryFiles)
-import Distribution.Simple.Program (simpleProgram, Program(..))
+import Distribution.Simple.Utils (notice, installOrdinaryFiles)
import Distribution.Simple.LocalBuildInfo
-import Control.Monad (when)
-
-#if MIN_VERSION_Cabal(2,0,0)
-import Distribution.PackageDescription (mkFlagName)
-#else
-import Distribution.PackageDescription (FlagName(..))
-#endif
main :: IO ()
main = defaultMainWithHooks $ simpleUserHooks {
- -- enable hsb2hs preprocessor for .hsb files
- hookedPreProcessors = [ppBlobSuffixHandler]
- , hookedPrograms = [(simpleProgram "hsb2hs"){
- programFindVersion = \verbosity fp ->
- findProgramVersion "--version" id verbosity fp }]
- , postCopy = installManPage
+ postCopy = installManPage
}
-ppBlobSuffixHandler :: PPSuffixHandler
-#if MIN_VERSION_Cabal(2,0,0)
-ppBlobSuffixHandler = ("hsb", \_ lbi _ ->
-#else
-ppBlobSuffixHandler = ("hsb", \_ lbi ->
-#endif
- PreProcessor {
- platformIndependent = True,
- runPreProcessor = mkSimplePreProcessor $ \infile outfile verbosity ->
-#if MIN_VERSION_Cabal(2,0,0)
- do let embedData = case lookup (mkFlagName "embed_data_files")
-#else
- do let embedData = case lookup (FlagName "embed_data_files")
-#endif
- (configConfigurationsFlags (configFlags lbi)) of
- Just True -> True
- _ -> False
- when embedData $
- do info verbosity $ "Preprocessing " ++ infile ++ " to " ++ outfile
- ec <- rawSystemExitCode verbosity "hsb2hs"
- [infile, infile, outfile]
- case ec of
- ExitSuccess -> return ()
- ExitFailure _ -> error "hsb2hs is needed to build this program"
- })
-
installManPage :: Args -> CopyFlags
-> PackageDescription -> LocalBuildInfo -> IO ()
installManPage _ flags pkg lbi = do
diff --git a/benchmark/benchmark-pandoc.hs b/benchmark/benchmark-pandoc.hs
index e2707de20..489d5c39b 100644
--- a/benchmark/benchmark-pandoc.hs
+++ b/benchmark/benchmark-pandoc.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE TupleSections #-}
{-
-Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,38 +17,70 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
import Text.Pandoc
+import qualified Text.Pandoc.UTF8 as UTF8
+import qualified Data.ByteString as B
import Criterion.Main
import Criterion.Types (Config(..))
+import Data.List (intersect)
import Data.Maybe (mapMaybe)
-import Debug.Trace (trace)
+import System.Environment (getArgs)
readerBench :: Pandoc
- -> (String, ReaderOptions -> String -> IO (Either PandocError Pandoc))
+ -> String
-> Maybe Benchmark
-readerBench doc (name, reader) =
- case lookup name writers of
- Just (PureStringWriter writer) ->
- let inp = writer def{ writerWrapText = WrapAuto} doc
- in return $ bench (name ++ " reader") $ nfIO $
- (fmap handleError <$> reader def{ readerSmart = True }) inp
- _ -> trace ("\nCould not find writer for " ++ name ++ "\n") Nothing
+readerBench doc name =
+ case res of
+ Right (readerFun, inp) ->
+ Just $ bench (name ++ " reader")
+ $ nf (\i -> either (error . show) id $ runPure (readerFun i))
+ inp
+ Left _ -> Nothing
+ where res = runPure $ do
+ (TextReader r, rexts)
+ <- either (fail . show) return $ getReader name
+ (TextWriter w, wexts)
+ <- either (fail . show) return $ getWriter name
+ inp <- w def{ writerWrapText = WrapAuto, writerExtensions = wexts }
+ doc
+ return (r def{ readerExtensions = rexts }, inp)
writerBench :: Pandoc
- -> (String, WriterOptions -> Pandoc -> String)
- -> Benchmark
-writerBench doc (name, writer) = bench (name ++ " writer") $ nf
- (writer def{ writerWrapText = WrapAuto }) doc
+ -> String
+ -> Maybe Benchmark
+writerBench doc name =
+ case res of
+ Right writerFun ->
+ Just $ bench (name ++ " writer")
+ $ nf (\d -> either (error . show) id $
+ runPure (writerFun d)) doc
+ _ -> Nothing
+ where res = runPure $ do
+ (TextWriter w, wexts)
+ <- either (fail . show) return $ getWriter name
+ return $ w def{ writerExtensions = wexts }
main :: IO ()
main = do
- inp <- readFile "tests/testsuite.txt"
- let opts = def{ readerSmart = True }
- let doc = handleError $ readMarkdown opts inp
- let readers' = [(n,r) | (n, StringReader r) <- readers]
+ args <- filter (\x -> take 1 x /= "-") <$> getArgs
+ print args
+ let matchReader (n, TextReader _) =
+ null args || ("reader" `elem` args && n `elem` args)
+ matchReader _ = False
+ let matchWriter (n, TextWriter _) =
+ null args || ("writer" `elem` args && n `elem` args)
+ matchWriter _ = False
+ let matchedReaders = map fst $ (filter matchReader readers
+ :: [(String, Reader PandocPure)])
+ let matchedWriters = map fst $ (filter matchWriter writers
+ :: [(String, Writer PandocPure)])
+ inp <- UTF8.toText <$> B.readFile "test/testsuite.txt"
+ let opts = def
+ let doc = either (error . show) id $ runPure $ readMarkdown opts inp
let readerBs = mapMaybe (readerBench doc)
- $ filter (\(n,_) -> n /="haddock") readers'
- let writers' = [(n,w) | (n, PureStringWriter w) <- writers]
- let writerBs = map (writerBench doc)
- $ writers'
+ $ filter (/="haddock")
+ (matchedReaders `intersect` matchedWriters)
+ -- we need the corresponding writer to generate
+ -- input for the reader
+ let writerBs = mapMaybe (writerBench doc) matchedWriters
defaultMainWith defaultConfig{ timeLimit = 6.0 }
(writerBs ++ readerBs)
diff --git a/benchmark/weigh-pandoc.hs b/benchmark/weigh-pandoc.hs
index 198d09b46..d3cada8c0 100644
--- a/benchmark/weigh-pandoc.hs
+++ b/benchmark/weigh-pandoc.hs
@@ -1,13 +1,14 @@
import Weigh
import Text.Pandoc
+import Data.Text (Text)
main :: IO ()
main = do
- doc <- read <$> readFile "tests/testsuite.native"
+ doc <- read <$> readFile "test/testsuite.native"
mainWith $ do
func "Pandoc document" id doc
mapM_
- (\(n,r) -> weighReader doc n (handleError . r def{ readerSmart = True }))
+ (\(n,r) -> weighReader doc n (either (error . show) id . runPure . r def{readerExtensions = pandocExtensions}))
[("markdown", readMarkdown)
,("html", readHtml)
,("docbook", readDocBook)
@@ -15,22 +16,22 @@ main = do
,("commonmark", readCommonMark)
]
mapM_
- (\(n,w) -> weighWriter doc n (w def))
+ (\(n,w) -> weighWriter doc n (either (error . show) id . runPure . w def))
[("markdown", writeMarkdown)
- ,("html", writeHtmlString)
- ,("docbook", writeDocbook)
+ ,("html", writeHtml5String)
+ ,("docbook", writeDocbook5)
,("latex", writeLaTeX)
,("commonmark", writeCommonMark)
]
-weighWriter :: Pandoc -> String -> (Pandoc -> String) -> Weigh ()
+weighWriter :: Pandoc -> String -> (Pandoc -> Text) -> Weigh ()
weighWriter doc name writer = func (name ++ " writer") writer doc
-weighReader :: Pandoc -> String -> (String -> Pandoc) -> Weigh ()
+weighReader :: Pandoc -> String -> (Text -> Pandoc) -> Weigh ()
weighReader doc name reader = do
case lookup name writers of
- Just (PureStringWriter writer) ->
- let inp = writer def{ writerWrapText = WrapAuto} doc
+ Just (TextWriter writer) ->
+ let inp = either (error . show) id $ runPure $ writer def{ writerWrapText = WrapAuto} doc
in func (name ++ " reader") reader inp
_ -> return () -- no writer for reader
diff --git a/changelog b/changelog
index c5f3739fd..7c8516e2d 100644
--- a/changelog
+++ b/changelog
@@ -1,26 +1,3252 @@
-pandoc (1.19.2.4)
+pandoc (2.1.2)
- * Add dependencies on texmath and skylighting to the executable.
- This is needed for dependency version numbers to be available,
- with Cabal > 2.
+ * Markdown reader:
+
+ + Fix parsing bug with nested fenced divs (#4281). Previously we allowed
+ "nonindent spaces" before the opening and closing `:::`, but this
+ interfered with list parsing, so now we require the fences to be flush with
+ the margin of the containing block.
+
+ * Commonmark reader:
+
+ + `raw_html` is now on by default. It can be disabled explicitly
+ using `-f commonmark-raw_html`.
+
+ * Org reader (Albert Krewinkel):
+
+ + Move citation tests to separate module.
+ + Allow changing emphasis syntax (#4378). The characters allowed before
+ and after emphasis can be configured via `#+pandoc-emphasis-pre` and
+ `#+pandoc-emphasis-post`, respectively. This allows to change which
+ strings are recognized as emphasized text on a per-document or even
+ per-paragraph basis. Example:
+
+ #+pandoc-emphasis-pre: "-\t ('\"{"
+ #+pandoc-emphasis-post: "-\t\n .,:!?;'\")}["
+
+ * LaTeX reader:
+
+ + Fixed comments inside citations (#4374).
+ + Fix regression in package options including underscore (#4424).
+ + Make `--trace` work.
+ + Fixed parsing of `tabular*` environment (#4279).
+
+ * RST reader:
+
+ + Fix regression in parsing of headers with trailing space (#4280).
+
+ * Muse reader (Alexander Krotov):
+
+ + Enable `<literal>` tags even if amuse extension is enabled.
+ Amusewiki disables <literal> tags for security reasons.
+ If user wants similar behavior in pandoc, RawBlocks and RawInlines
+ can be removed or replaced with filters.
+ + Remove space prefix from `<literal>` tag contents.
+ + Do not consume whitespace while looking for closing end tag.
+ + Convert alphabetical list markers to decimal in round-trip test.
+ Alphabetical lists are an addition of Text::Amuse.
+ They are not present in Emacs Muse and can be ambiguous
+ when list starts with "i.", "c." etc.
+ + Allow `<quote>` and other tags to be indented.
+ + Allow single colon in definition list term.
+ + Fix parsing of verse in lists.
+ + Improved parsing efficiency. Avoid `parseFromString`.
+ Lists are parsed in linear instead of exponential time now.
+ + Replace ParserState with MuseState.
+ + Prioritize lists with roman numerals over alphabetical lists.
+ This is to make sure "i." starts a roman numbered list,
+ instead of a list with letter "i" (followed by "j", "k", ...").
+ + Fix directive parsing.
+ + Parse definition lists with multiple descriptions.
+ + Parse next list item before parsing more item contents.
+ + Fixed a bug: headers did not terminate lists.
+ + Move indentation parsing from `definitionListItem` to `definitionList`.
+ + Paragraph indentation does not indicate nested quote.
+ Muse allows indentation to indicate quotation or alignment,
+ but only on the top level, not within a <quote> or list.
+ + Require that block tags are on separate lines.
+ Text::Amuse already explicitly requires it anyway.
+ + Fix matching of closing inline tags.
+ + Various internal changes.
+ + Fix parsing of nested definition lists.
+ + Require only one space for nested definition list indentation.
+ + Do not remove trailing whitespace from `<code>`.
+ + Fix parsing of trailing whitespace. Newline after whitespace now
+ results in softbreak instead of space.
+
+ * Docx reader (Jesse Rosenthal, except where noted):
+
+ + Handle nested sdt tags (#4415).
+ + Don't look up dependant run styles if `+styles` is enabled.
+ + Move pandoc inline styling inside custom-style span.
+ + Read custom styles (#1843). This will read all paragraph and
+ character classes as divs and spans, respectively. Dependent styles
+ will still be resolved, but will be wrapped with appropriate style
+ tags. It is controlled by the `+styles` extension (`-f docx+styles`).
+ This can be used in conjunction with the `custom-style` feature in the
+ docx writer for a pandoc-docx editing workflow. Users can convert from
+ an input docx, reading the custom-styles, and then use that same input
+ docx file as a reference-doc for producing an output docx file. Styles
+ will be maintained across the conversion, even if pandoc doesn't
+ understand them.
+ + Small change to Fields hyperlink parser. Previously, unquoted string
+ required a space at the end of the line (and consumed it). Now we
+ either take a space (and don't consume it), or end of input.
+ + Pick table width from the longest row or header (Francesco Occhipinti,
+ #4360).
+
+ * Muse writer (Alexander Krotov):
+
+ + Change verse markup: `> ` instead of `<verse>` tag.
+ + Remove empty strings during inline normalization.
+ + Don't indent nested definition lists.
+ + Use unicode quotes for quoted text.
+ + Write image width specified in percent in Text::Amuse mode.
+ + Don't wrap displayMath into `<verse>`.
+ + Escape nonbreaking space (`~~`).
+ + Join code with different attributes during normalization.
+ + Indent lists inside Div.
+ + Support definitions with multiple descriptions.
+
+ * Powerpoint writer (Jesse Rosenthal):
+
+ + Use table styles This will use the default table style in the
+ reference-doc file. As a result they will be easier when using
+ in a template, and match the color scheme.
+ + Remove empty slides. Because of the way that slides were split, these
+ could be accidentally produced by comments after images. When animations
+ are added, there will be a way to add an empty slide with either
+ incremental lists or pauses.
+ + Implement syntax highlighting. Note that background colors can't
+ be implemented in PowerPoint, so highlighting styles that require
+ these will be incomplete.
+ + New test framework for pptx. We now compare the output of the
+ Powerpoint writer with files that we know to (a) not be corrupt,
+ and (b) to show the desired output behavior (details below).
+ + Add `notesMaster` to `presentation.xml` if necessary.
+ + Ignore links and (end)notes in speaker notes.
+ + Output speaker notes.
+ + Read speaker note templates conditionally. If there are speaker
+ notes in the presentation, we read in the notesMasters templates
+ from the reference pptx file.
+ + Fix deletion track changes (#4303, Jesse Rosenthal).
+
+ * Markdown writer: properly escape @ to avoid capture as citation
+ (#4366).
+
+ * LaTeX writer:
+
+ + Put hypertarget inside figure environment (#4388).
+ This works around a problem with the endfloat package and
+ makes pandoc's output compatible with it.
+ + Fix image height with percentage (#4389). This previously caused
+ the image to be resized to a percentage of textwidth, rather than
+ textheight.
+
+ * ConTeXt writer (Henri Menke):
+
+ + New section syntax and support `--section-divs` (#2609).
+ `\section[my-header]{My Header}` ->
+ `\section[title={My Header},reference={my-header}]`.
+ The ConTeXt writer now supports the `--section-divs` option to
+ write sections in the fenced style, with `\startsection` and
+ `\stopsection`.
+ + xtables: correct wrong usage of caption (Henri Menke).
+
+ * Docx writer:
+
+ + Fix image resizing with multiple images (#3930, Andrew Pritchard).
+ + Use new golden framework (Jesse Rosenthal).
+ + Make more deterministic to facilitate testing (Jesse Rosenthal).
+ - `getUniqueId` now calls to the state to get an incremented digit,
+ instead of calling to P.uniqueHash.
+ - we always start the PRNG in mkNumbering/mkAbstractNum with the same
+ seed (1848), so our randoms should be the same each time.
+ + Fix ids in comment writing (Jesse Rosenthal). Comments from
+ `--track-changes=all` were producing corrupt docx, because the
+ writer was trying to get id from the `(ID,_,_)` field of
+ the attributes, and ignoring the "id" entry in the key-value pairs. We
+ now check both.
+
+ * Ms writer: Added papersize variable.
+
+ * TEI writer:
+
+ + Use `height` instead of `depth` for images (#4331).
+ + Ensure that id prefix is always used.
+ + Don't emit `role` attribute; that was a leftover from the
+ Docbook writer.
+ + Use 'xml:id', not 'id' attribute (#4371).
+
+ * AsciiDoc writer:
+
+ + Do not output implicit heading IDs (#4363, Alexander
+ Krotov). Convert to `asciidoc-auto_identifiers` for old behaviour.
+
+ * RST writer:
+
+ + Remove `blockToRST'` moving its logic into `fixBlocks`
+ (Francesco Occhipinti).
+ + Insert comment between lists and quotes (#4248, Francesco Occchipinti).
+
+ * RST template: remove definition of 'math' role as raw.
+ This used to be needed prior to v 0.8 of docutils, but
+ now math support is built-in.
+
+ * Slides: Use divs to set incremental/non-incremental (#4381,
+ Jesse Rosenthal). The old method (list inside blockquote) still
+ works, but we are encouraging the use of divs with class
+ `incremental` or `nonincremental`.
+
+ * Text.Pandoc.ImageSize:
+
+ + Make image size detection for PDFs more robust (#4322).
+ + Determine image size for PDFs (#4322).
+ + EMF Image size support (#4375, Andrew Pritchard).
+
+ * Text.Pandoc.Extensions:
+
+ + Add `Ext_styles` (Jesse Rosenthal, API change). This will be used in
+ the docx reader (defaulting to off) to read pargraph and character
+ styles not understood by pandoc (as divs and spans, respectively).
+ + Made `Ext_raw_html` default for `commonmark` format.
+
+ * Text.Pandoc.Parsing:
+
+ + Export `manyUntil` (Alexander Krotov, API change).
+ + Export improved `sepBy1` (Alexander Krotov).
+ + Export list marker parsers: `upperRoman`, `lowerRoman`,
+ `decimal`, `lowerAlpha`, `upperAlpha` (Alexander Krotov, API change).
+
+ * Tests/Lua: fix tests on windows (Albert Krewinkel).
-pandoc (1.19.2.3)
+ * Lua: register script name in global variable (#4393). The name of the Lua
+ script which is executed is made available in the global Lua variable
+ `PANDOC_SCRIPT_FILE`, both for Lua filters and custom writers.
+
+ * Tests: Abstract powerpoint tests out to OOXML tests (Jesse Rosenthal).
+ There is very little pptx-specific in these tests, so we abstract out
+ the basic testing function so it can be used for docx as well. This
+ should allow us to catch some errors in the docx writer that slipped
+ by the roundtrip testing.
+
+ * Lua filters: store constructors in registry (Albert Krewinkel). Lua
+ functions used to construct AST element values are stored in the Lua
+ registry for quicker access. Getting a value from the registry is much
+ faster than getting a global value (partly to idiosyncrasies of hslua);
+ this change results in a considerable performance boost.
+
+ * Documentation:
+
+ + `doc/org.md` Add draft of Org-mode documentation (Albert Krewinkel).
+ + `doc/lua-filters.md`: document global vars set for filters
+ (Albert Krewinkel).
+ + INSTALL.md: mention Stack version. (#4343, Adam Brandizzi).
+ + MANUAL: add documentation on custom styles (Jesse Rosenthal).
+ + MANUAL.txt: Document incremental and nonincremental divs (Jesse
+ Rosenthal). Blockquoted lists are still described, but fenced divs are
+ presented in preference.
+ + MANUAL.txt: document header and footer variables (newmana).
+ + MANUAL.txt: self-contained implies standalone (#4304, Daniel Lublin).
+ + CONTRIBUTING.md: label was renamed. (#4310, Alexander Brandizzi).
+
+ * Require tagsoup 0.14.3 (#4282), fixing HTML tokenization bug.
+
+ * Use latest texmath.
+
+ * Use latest pandoc-citeproc.
+
+ * Allow exceptions 0.9.
+
+ * Require aeson-pretty 0.8.5 (#4394).
+
+ * Bump blaze-markup, blaze-html lower bounds to 0.8, 0.9 (#4334).
+
+ * Update tagsoup to 0.14.6 (Alexander Krotov, #4282).
+
+ * Removed ghc-prof-options. As of cabal 1.24, sensible defaults are used.
+
+ * Update default.nix to current nixpkgs-unstable for hslua-0.9.5 (#4348,
+ jarlg).
+
+
+pandoc (2.1.1)
+
+ * Markdown reader:
+
+ + Don't coalesce adjacent raw LaTeX blocks if they are separated by a
+ blank line. See lierdakil/pandoc-crossref#160.
+ + Improved `inlinesInBalancedBrackets` (#4272, jgm/pandoc-citeproc#315).
+ The change both improves performance and fixes a regression whereby
+ normal citations inside inline notes and figure captions were not
+ parsed correctly.
+
+ * RST reader:
+
+ + Better handling for headers with an anchor (#4240). Instead of creating a
+ Div containing the header, we put the id directly on the header.
+ This way header promotion will work properly.
+ + Add aligned environment when needed in math (#4254). `rst2latex.py`
+ uses an `align*` environment for math in `.. math::` blocks, so this
+ math may contain line breaks. If it does, we put the math in an
+ `aligned` environment to simulate `rst2latex.py`'s behavior.
+
+ * HTML reader:
+
+ + Fix col width parsing for percentages < 10% (#4262, n3fariox).
+
+ * LaTeX reader:
+
+ + Advance source position at end of stream.
+ + Pass through macro defs in `rawLaTeXBlock` even if the `latex_macros`
+ extension is set (#4246). This reverts to earlier behavior and is
+ probably safer on the whole, since some macros only modify things in
+ included packages, which pandoc's macro expansion can't modify.
+ + Fixed pos calculation in tokenizing escaped space.
+ + Allow macro definitions inside macros (#4253). Previously we went into
+ an infinite loop with
+ ```
+ \newcommand{\noop}[1]{#1}
+ \noop{\newcommand{\foo}[1]{#1}}
+ \foo{hi}
+ ```
+ + Fix inconsistent column widths (#4238). This fixes a bug whereby column
+ widths for the body were different from widths for the header in some
+ tables.
+
+ * Docx reader (Jesse Rosenthal):
+
+ + Parse hyperlinks in `instrText` tags (#3389, #4266). This was a form of
+ hyperlink found in older versions of word. The changes introduced for
+ this, though, create a framework for parsing further fields in MS Word
+ (see the spec, ECMA-376-1:2016, §17.16.5, for more on these fields).
+ We introduce a new module, `Text.Pandoc.Readers.Docx.Fields` which
+ contains a simple parsec parser. At the moment, only simple hyperlink
+ fields are accepted, but that can be extended in the future.
+
+ * Muse reader (Alexander Krotov):
+
+ + Parse `~~` as non-breaking space in Text::Amuse mode.
+ + Refactor list parsing.
+
+ * Powerpoint writer (Jesse Rosenthal):
+
+ + Change reference to `notesSlide` to `endNotesSlide`.
+ + Move image sizing into `picProps`.
+ + Improve table placement.
+ + Make our own `_rels/.rels` file.
+ + Import reference-doc images properly.
+ + Move `Presentation.hs` out of `PandocMonad`.
+ + Refactor into separate modules. T.P.W.Powerpoint.Presentation
+ defines the Presentation datatype and goes Pandoc->Presentation;
+ T.P.W.Pandoc.Output goes Presentation->Archive.
+ Text.Pandoc.Writers.Powerpoint a thin wrapper around the two modules.
+ + Avoid overlapping blocks in column output.
+ + Position images correctly in two-column layout.
+ + Make content shape retrieval environment-aware.
+ + Improve image handling. We now determine image and caption placement
+ by getting the dimensions of the content box in a given layout.
+ This allows for images to be correctly sized and positioned in a
+ different template. Note that images without captions and headers are
+ no longer full-screened. We can't do this dependably in different
+ layouts, because we don't know where the header is (it could be to
+ the side of the content, for example).
+ + Read presentation size from reference file. Our presentation size is
+ now dependent on the reference/template file we use.
+ + Handle (sub)headers above slidelevel correctly. Above the slidelevel,
+ subheaders will be printed in bold and given a bit of extra space
+ before them. Note that at the moment, no distinction is made between
+ levels of headers above the slide header, though that can be changed.
+ + Check for required files. Since we now import from reference/dist
+ file by glob, we need to make sure that we're getting the files we
+ need to make a non-corrupt Powerpoint. This performs that check.
+ + Improve templating using `--reference-doc`. Templating should work
+ much more reliably now.
+ + Include Notes slide in TOC.
+ + Set notes slide header to slide-level.
+ + Add table of contents. This is triggered by the `--toc` flag. Note
+ that in a long slide deck this risks overrunning the text box. The user
+ can address this by setting `--toc-depth=1`.
+ + Set notes slide number correctly.
+ + Clean up adding metadata slide. We want to count the slide numbers
+ correctly if it's in there.
+ + Add anchor links. For anchor-type links (`[foo](#bar)`) we produce
+ an anchor link. In powerpoint these are links to slides, so we keep
+ track of a map relating anchors to the slides they occur on.
+ + Make the slide number available to the blocks. For anchors,
+ block-processing functions need to know what slide number
+ they're in. We make the `envCurSlideId` available to blocks.
+ + Move `curSlideId` to environment.
+ + Allow setting `toc-title` in metadata.
+ + Link notes to endnotes slide.
+
+ * Markdown writer:
+
+ + Fix cell width calculation (#4265). Previously we could get
+ ever-lengthening cell widths when a table was run repeatedly through
+ `pandoc -f markdown -t markdown`.
+
+ * LaTeX writer:
- * Add CPP to Setup.hs so it works with Cabal >= 2 and < 2.
+ + Escape `&` in lstinline (Robert Schütz).
+
+ * ConTeXt writer:
+
+ + Use xtables instead of Tables (#4223, Henri Menke).
+ Default to xtables for context output. Natural Tables are used
+ if the new `ntb` extension is set.
+
+ * HTML writer:
+
+ + Fixed footnote backlinks with `--id-prefix` (#4235).
+
+ * `Text.Pandoc.Extensions`: Added `Ext_ntb` constructor (API change,
+ Henri Menke).
+
+ * `Text.Pandoc.ImageSize`: add derived `Eq` instance to `Dimension`
+ (Jesse Rosenthal, API change).
+
+ * Lua filters (Albert Krewinkel):
+
+ + Make `PANDOC_READER_OPTIONS` available.
+ The options which were used to read the document are made available to
+ Lua filters via the `PANDOC_READER_OPTIONS` global.
+ + Add lua module `pandoc.utils.run_json_filter`, which runs a JSON filter
+ on a Pandoc document.
+ + Refactor filter-handling code into `Text.Pandoc.Filter.JSON`,
+ `Text.Pandoc.Filter.Lua`, and `Text.Pandoc.Filter.Path`.
+ + Improve error messages. Provide more context about the task
+ which caused an error.
+
+ * data/pandoc.lua (Albert Krewinkel):
+
+ + Accept singleton inline as a list. Every constructor which accepts a
+ list of inlines now also accepts a single inline element for
+ convenience.
+ + Accept single block as singleton list. Every constructor which accepts
+ a list of blocks now also accepts a single block element for
+ convenience. Furthermore, strings are accepted as shorthand for
+ `{pandoc.Str "text"}` in constructors.
+ + Add attr, listAttributes accessors. Elements with
+ attributes got an additional `attr` accessor. Attributes were
+ accessible only via the `identifier`, `classes`, and `attributes`,
+ which was in conflict with the documentation, which indirectly states
+ that such elements have the an `attr` property.
+ + Drop `_VERSION`. Having a `_VERSION` became superfluous, as this
+ module is closely tied to the pandoc version, which is available via
+ `PANDOC_VERSION`.
+ + Fix access to Attr components. Accessing an Attr value (e.g.,
+ ` Attr().classes`) was broken; the more common case of accessing it via
+ an Inline or Block element was unaffected by this.
+
+ * Move `metaValueToInlines` to from Docx writer to
+ `Text.Pandoc.Writers.Shared`, so it can be used by other writers
+ (Jesse Rosenthal).
+
+ * MANUAL.txt:
+
+ + Clarify otherlangs in LaTeX (#4072).
+ + Clarify `latex_macros` extension.
+ + Recommend use of `raw_attribute` extension in header includes (#4253).
+
+ * Allow latest QuickCheck, tasty, criterion.
+
+ * Remove custom prelude and ghc 7.8 support.
+
+ * Reduce compiler noise (exact paths for compiled modules).
+
+pandoc (2.1)
+
+ * Allow filters and lua filters to be interspersed (#4196). Previously
+ we ran all lua filters before JSON filters. Now we run filters in
+ the order they are presented on the command line, whether lua or JSON.
+ There are two incompatible API changes: The type of `applyFilters`
+ has changed, and `applyLuaFilters` has been removed. `Filter` is
+ also now exported.
+
+ * Use latest skylighting and omit the `missingIncludes` check, fixing
+ a major performance regression in earlier releases of the 2.x series
+ (#4226). Behavior change: If you use a custom syntax definition that
+ refers to a syntax you haven't loaded, pandoc will now complain when
+ it is highlighting the text, rather than doing a check at the start.
+ This change dramatically speeds up invocations of pandoc on short
+ inputs.
+
+ * Text.Pandoc.Class: make `FileTree` opaque (don't export
+ `FileTree` constructor). This forces users to interact with it using
+ `insertInFileTree` and `getFileInfo`, which normalize file names.
+
+ * Markdown reader:
+
+ + Rewrite `inlinesInBalancedBrackets`. The rewrite is much more
+ direct, avoiding `parseFromString`. And it performs significantly
+ better; unfortunately, parsing time still increases exponentially
+ (see #1735).
+ + Avoid parsing raw tex unless `\` + letter seen. This seems to
+ help with the performance problem, #4216.
+
+ * LaTeX reader: Simplified a check for raw tex command.
+
+ * Muse reader (Alexander Krotov):
+
+ + Enable round trip test (#4107).
+ + Automatically translate `#cover` into `#cover-image`.
+ Amusewiki uses #cover directive to specify cover image.
+
+ * Docx reader (Jesse Rosenthal):
+
+ + Allow for insertion/deletion of paragraphs (#3927).
+ If the paragraph has a deleted or inserted paragraph break (depending
+ on the track-changes setting) we hold onto it until the next
+ paragraph. This takes care of accept and reject. For this we introduce
+ a new state which holds the ils from the previous para if necessary.
+ For `--track-changes=all`, we add an empty span with class
+ `paragraph-insertion`/`paragraph-deletion` at the end of the paragraph
+ prior to the break to be inserted or deleted.
+ + Remove unused anchors (#3679). Docx produces a lot of anchors with
+ nothing pointing to them---we now remove these to produce cleaner
+ output. Note that this has to occur at the end of the process
+ because it has to follow link/anchor rewriting.
+ + Read multiple children of `w:sdtContents`.
+ + Combine adjacent anchors. There isn't any reason to have numerous
+ anchors in the same place, since we can't maintain docx's
+ non-nesting overlapping. So we reduce to a single anchor.
+ + Improved tests.
+
+ * Muse writer (Alexander Krotov): don't escape URIs from AST
+
+ * Docx writer:
+
+ + Removed redundant subtitle in title (Sebastian Talmon).
+ + `firstRow` table definition compatibility for Word 2016 (Sebastian
+ Talmon). Word 2016 seems to use a default value of "1" for table
+ headers, if there is no firstRow definition (although a default
+ value of 0 is documented), so all tables get the first Row formatted
+ as header. Setting the parameter to 0 if the table has no header
+ row fixes this for Word 2016
+ + Fix custom styles with spaces in the name (#3290).
+
+ * Powerpoint writer (Jesse Rosenthal):
+
+ + Ignore Notes div for parity with other slide outputs.
+ + Set default slidelevel correctly. We had previously defaulted to
+ slideLevel 2. Now we use the correct behavior of defaulting to the
+ highest level header followed by content. We change an expected test
+ result to match this behavior.
+ + Split blocks correctly for linked images.
+ + Combine adjacent runs.
+ + Make inline code inherit code size. Previously (a) the code size
+ wasn't set when we force size, and (b) the properties was set from
+ the default, instead of inheriting.
+ + Simplify `replaceNamedChildren` function.
+ + Allow linked images. The following markdown:
+ `[![Image Title](image.jpg)](http://www.example.com)`
+ will now produce a linked image in the resulting PowerPoint file.
+ + Fix error with empty table cell. We require an empty `<a:p>` tag,
+ even if the cell contains no paragraphs---otherwise PowerPoint
+ complains of corruption.
+ + Implement two-column slides. This uses the columns/column div
+ format described in the pandoc manual. At the moment, only two
+ columns (half the screen each) are allowed. Custom widths are not
+ supported.
+ + Added more tests.
+
+ * OpenDocument/ODT writers: improved rendering of formulas (#4170, oltolm).
+
+ * Lua filters (Albert Krewinkel):
+
+ + `data/pandoc.lua`: drop 'pandoc-api-version' from Pandoc objects
+ + The current pandoc-types version is made available to Lua programs in
+ the global `PANDOC_API_VERSION`. It contains the version as a list of
+ numbers.
+ + The pandoc version available as a global `PANDOC_VERSION` (a list
+ of numbers).
+ + `data/pandoc.lua`: make `Attr` an `AstElement`.
+ + `data/pandoc.lua`: make all types subtypes of `AstElement`.
+ `Pandoc`, `Meta`, and `Citation` were just plain functions and did
+ not set a metatable on the returned value, which made it difficult
+ to amend objects of these types with new behavior. They are now
+ subtypes of AstElement, meaning that all their objects can gain
+ new features when a method is added to the behavior object
+ (e.g., `pandoc.Pandoc.behavior`).
+ + `data/pandoc.lua`: split type and behavior tables. Clearly distinguish
+ between a type and the behavioral properties of an instance of that
+ type. The behavior of a type (and all its subtypes) can now be
+ amended by adding methods to that types `behavior` object, without
+ exposing the type objects internals. E.g.:
+ ```lua
+ pandoc.Inline.behavior.frob = function () print'42' end
+ local str = pandoc.Str'hello'
+ str.frob() -- outputs '42'
+ ```
+ + `data/pandoc.lua`: fix Element inheritance. Extending all elements
+ of a given type (e.g., all inline elements) was difficult, as the
+ table used to lookup unknown methods would be reset every time a
+ new element of that type was created, preventing recursive property
+ lookup. This is was changed in that all methods and attributes of
+ supertypes are now available to their subtypes.
+ + `data/pandoc.lua`: fix attribute names of Citation (#4222). The
+ fields were named like the Haskell fields, not like the documented,
+ shorter version. The names are changed to match the documentation
+ and Citations are given a shared metatable to enable simple
+ extensibility.
+ + `data/pandoc.lua`: drop function `pandoc.global_filter`.
+ + Bump `hslua` version to 0.9.5. This version fixes a bug that made it
+ difficult to handle failures while getting lists or a Map from Lua.
+ A bug in pandoc, which made it necessary to always pass a tag when
+ using MetaList or MetaBlock, is fixed as a result. Using the pandoc
+ module's constructor functions for these values is now optional
+ (if still recommended).
+ + Stop exporting `pushPandocModule` (API change). The introduction
+ of `runPandocLua` renders direct use of this function obsolete.
+ + Update generation of module docs for lua filters.
+ + `Lua.Module.Utils`: make stringify work on `MetaValues` (John
+ MacFarlane). I'm sure this was intended in the first place,
+ but currently only `Meta` is supported.
+
+ * Improve benchmarks.
+
+ + Set the default extensions properly.
+ + Improve benchmark argument parsing. You can now say
+ `make bench BENCHARGS="markdown latex reader"` and both the
+ markdown and latex readers will be benchmarked.
+
+ * MANUAL.txt simplify and add more structure (Mauro Bieg).
+
+ * Generate README.md from template and MANUAL.txt.
+ `make README.md` will generate the README.md after changes
+ to MANUAL.txt have been made.
+
+ * Update copyright notices to include 2018 (Albert Krewinkel).
+
+pandoc (2.0.6)
+
+ * Added `jats` as an input format.
+
+ + Add Text.Pandoc.Readers.JATS, exporting `readJATS` (API
+ change) (Hamish Mackenzie).
+ + Improved citation handling in JATS reader. JATS citations
+ are now converted to pandoc citations, and JATS ref-lists
+ are converted into a `references` field in metadata, suitable
+ for use with pandoc-citeproc. Thus a JATS article with embedded
+ bibliographic information can be processed with pandoc and
+ pandoc-citeproc to produce a formatted bibliography.
+
+ * Allow `--list-extensions` to take an optional FORMAT argument.
+ This lists the extensions set by default for the selected FORMAT.
+ The extensions are now alphabetized, and the `+` or `-`
+ indicating the default setting comes before, rather than after,
+ the extension.
+
+ * Markdown reader:
+
+ + Preserve original whitespace between blocks.
+ + Recognize `\placeformula` as context.
+ + Be pickier about table captions. A caption starts with a `:` which
+ can't be followed by punctuation. Otherwise we can falsely interpret
+ the start of a fenced div, or even a table header line like
+ `:--:|:--:`, as a caption.
+ + Always use four space rule for example lists. It would be awkward
+ to indent example list contents to the first non-space character after
+ the label, since example list labels are often long. Thanks to
+ Bernhard Fisseni for the suggestion.
+ + Improve raw tex parsing. Note that the Markdown reader is also
+ affected by the `latex_macros` extension changes described below
+ under the LaTeX reader.
+
+ * LaTeX reader:
+
+ + `latex_macros` extension changes (#4179). Don't pass through macro
+ definitions themselves when `latex_macros` is set. The macros
+ have already been applied. If `latex_macros` is enabled, then
+ `rawLaTeXBlock` in Text.Pandoc.Readers.LaTeX will succeed in parsing
+ a macro definition, and will update pandoc's internal macro map
+ accordingly, but the empty string will be returned.
+ + Export `tokenize`, `untokenize` (API change).
+ + Use `applyMacros` in `rawLaTeXBlock`, `rawLaTeXInline`.
+ + Refactored `inlineCommand`.
+ + Fix bug in tokenizer. Material following `^^` was
+ dropped if it wasn't a character escape. This only affected
+ invalid LaTeX, so we didn't see it in the wild, but it appeared
+ in a QuickCheck test failure.
+ + Fix regression in LateX tokenization (#4159). This mainly affects the
+ Markdown reader when parsing raw LaTeX with escaped spaces.
+ + Add tests of LaTeX tokenizer.
+ + Support `\foreignlanguage` from babel.
+ + Be more tolerant of `&` character (#4208). This allows us to parse
+ unknown tabular environments as raw LaTeX.
+
+ * Muse reader (Alexander Krotov):
+
+ + Parse anchors immediately after headings as IDs.
+ + Require that note references does not start with 0.
+ + Parse empty comments correctly.
+
+ * Org reader (Albert Krewinkel):
+
+ + Fix asterisks-related parsing error (#4180).
+ + Support minlevel option for includes (#4154). The level of headers
+ in included files can be shifted to a higher level by specifying a
+ minimum header level via the `:minlevel` parameter. E.g.
+ `#+include: "tour.org" :minlevel 1` will shift the headers in
+ tour.org such that the topmost headers become level 1 headers.
+ + Break-up org reader test file into multiple modules.
+
+ * OPML reader:
+
+ + Enable raw HTML and other extensions by default for notes
+ (#4164). This fixes a regression in 2.0. Note that extensions can
+ now be individually disabled, e.g. `-f opml-smart-raw_html`.
+
+ * RST reader:
+
+ + Allow empty list items (#4193).
+ + More accurate parsing of references (#4156). Previously we erroneously
+ included the enclosing backticks in a reference ID (#4156). This
+ change also disables interpretation of syntax inside references, as
+ in docutils. So, there is no emphasis in `` `my *link*`_ ``.
+
+ * Docx reader:
+
+ + Continue lists after interruption (#4025, Jesse Rosenthal).
+ Docx expects that lists will continue where they left off after an
+ interruption and introduces a new id if a list is starting again. So
+ we keep track of the state of lists and use them to define a "start"
+ attribute, if necessary.
+ + Add tests for structured document tags unwrapping (Jesse Rosenthal).
+ + Preprocess Document body to unwrap `w:sdt` elements (Jesse Rosenthal,
+ #4190).
+
+ * Plain writer:
+
+ + Don't linkify table of contents.
+
+ * RST writer:
+
+ + Fix anchors for headers (#4188). We were missing an `_`.
+
+ * PowerPoint writer (Jesse Rosenthal):
+
+ + Treat lists inside BlockQuotes as lists. We don't yet produce
+ incremental lists in PowerPoint, but we should at least treat lists
+ inside BlockQuotes as lists, for compatibility with other slide formats.
+ + Add ability to force size. This replaces the more specific
+ `blockQuote runProp`, which only affected the size of blockquotes. We
+ can use this for notes, etc.
+ + Implement notes. This currently prints all notes on a final slide.
+ Note that at the moment, there is a danger of text overflowing the
+ note slide, since there is no logic for adding further slides.
+ + Implement basic definition list functionality to PowerPoint writer.
+ + Don't look for default template file for Powerpoint (#4181).
+ + Add pptx to isTextFormat list. This is used to check standalone
+ and not writing to the terminal.
+ + Obey slide level option (Jesse Rosenthal).
+ + Introduce tests.
+
+ * Docx writer:
+
+ + Ensure that `distArchive` is the one that comes with pandoc
+ (#4182). Previously a `reference.docx` in `~/.pandoc` (or the user data
+ dir) would be used instead, and this could cause problems because a
+ user-modified docx sometimes lacks vital sections that we count
+ on the `distArchive` to supply.
+
+ * Org writer:
+
+ + Do not wrap "-" to avoid accidental bullet lists (Alexander Krotov).
+ + Don't allow fn refs to wrap to beginning of line (#4171, with help from
+ Alexander Krotov). Otherwise they can be interpreted as footnote
+ definitions.
+
+ * Muse writer (Alexander Krotov):
+
+ + Don't wrap note references to the next line (#4172).
+
+ * HTML writer:
+
+ + Use br elements in line blocks instead of relying on CSS
+ (#4162). HTML-based templates have had the custom CSS for
+ `div.line-block` removed. Those maintaining custom templates will want
+ to remove this too. We still enclose line blocks in a div with class
+ `line-block`.
+
+ * LaTeX writer:
+
+ + Use `\renewcommand` for `\textlatin` with babel (#4161).
+ This avoids a clash with a deprecated `\textlatin` command defined
+ in Babel.
+ + Allow fragile=singleslide attribute in beamer slides (#4169).
+ + Use `\endhead` after `\toprule` in headerless tables (#4207).
+
+ * FB2 writer:
+
+ + Add cover image specified by `cover-image` meta (Alexander Krotov,
+ #4195).
+
+ * JATS writer (Hamish Mackenzie):
+
+ + Support writing `<fig>` and `<table-wrap>` elements
+ with `<title>` and `<caption>` inside them by using Divs with class set
+ to one of `fig`, `table-wrap` or `caption` (Hamish Mackenzie). The
+ title is included as a Heading so the constraint on where Heading can
+ occur is also relaxed.
+ + Leave out empty alt attributes on links.
+ + Deduplicate image mime type code.
+ + Make `<p>` optional in `<td>` and `<th>` (#4178).
+ + Self closing tags for empty xref (#4187).
+ + Improve support for code language.
+
+ * Custom writer:
+
+ + Use init file to setup Lua interpreter (Albert Krewinkel).
+ The same init file (`data/init`) that is used to setup the Lua
+ interpreter for Lua filters is also used to setup the interpreter of
+ custom writers.lua.
+ + Define instances for newtype wrapper (Albert Krewinkel). The custom
+ writer used its own `ToLuaStack` instance definitions, which made
+ it difficult to share code with Lua filters, as this could result
+ in conflicting instances. A `Stringify` wrapper is introduced to
+ avoid this problem.
+ + Added tests for custom writer.
+ + Fixed definition lists and tables in `data/sample.lua`.
+
+ * Fixed regression: when target is PDF, writer extensions were being
+ ignored. So, for example, `pandoc -t latex-smart -o file.pdf`
+ did not work properly.
+
+ * Lua modules (Albert Krewinkel):
+
+ + Add `pandoc.utils` module, to hold utility functions.
+ + Create a Haskell module Text.Pandoc.Lua.Module.Pandoc to
+ define the `pandoc` lua module.
+ + Make a Haskell module for each Lua module. Move definitions for the
+ `pandoc.mediabag` modules to a separate Haskell module.
+ + Move `sha1` from the main `pandoc` module to `pandoc.utils`.
+ + Add function `pandoc.utils.hierarchicalize` (convert list of
+ Pandoc blocks into (hierarchical) list of Elements).
+ + Add function `pandoc.utils.normalize_date` (parses a date and
+ converts it (if possible) to "YYYY-MM-DD" format).
+ + Add function `pandoc.utils.to_roman_numeral` (allows conversion
+ of numbers below 4000 into roman numerals).
+ + Add function `pandoc.utils.stringify` (converts any AST element
+ to a string with formatting removed).
+ + `data/init.lua`: load `pandoc.utils` by default
+ + Turn pipe, read into full Haskell functions. The `pipe` and `read`
+ utility functions are converted from hybrid lua/haskell functions
+ into full Haskell functions. This avoids the need for intermediate
+ `_pipe`/`_read` helper functions, which have dropped.
+ + pandoc.lua: re-add missing MetaMap function. This was a bug
+ introduced in version 2.0.4.
+
+ * Text.Pandoc.Class: Add `insertInFileTree` [API change]. This gives
+ a pure way to insert an ersatz file into a `FileTree`. In addition, we
+ normalize paths both on insertion and on lookup.
+
+ * Text.Pandoc.Shared: export `blocksToInlines'` (API change, Maura Bieg).
+
+ * Text.Pandoc.MIME: Add opus to MIME type table as audio/ogg (#4198).
+
+ * Text.Pandoc.Extensions: Alphabetical order constructors for
+ `Extension`. This makes them appear in order in `--list-extensions`.
+
+ * Allow lenient decoding of latex error logs, which are not always
+ properly UTF8-encoded (#4200).
+
+ * Update latex template to work with recent versions of beamer.
+ The old template produced numbered sections with some recent
+ versions of beamer. Thanks to Thomas Hodgson.
+
+ * Updated reference.docx (#4175). Instead of just "Hello, world", the
+ document now contains exemplars of most of the styles that have an
+ effect on pandoc documents. This makes it easier to see the effect
+ of style changes.
+
+ * Removed `default.theme` data file (#4096). It is no longer needed now
+ that we have `--print-highlight-style`.
+
+ * Added `stack.lts9.yaml` for building with lts 9 and ghc 8.0.2.
+ We still need this for the alpine static linux build, since
+ we don't have ghc 8.2.2 for that yet.
+
+ * Removed `stack.pkg.yaml`. We only really need `stack.yaml`; we
+ can put flag settings for pandoc-citeproc there.
+
+ * Makefile: Add 'trypandoc' and 'pandoc-templates' targets to
+ make releases easier.
+
+ * MANUAL.txt:
+
+ + Add note on what formats have `+smart` by default.
+ + Use native syntax for custom-style (#4174, Mauro Bieg).
+ + Introduce dedicated Extensions section, since some extensions
+ affect formats other than markdown (Mauro Bieg, #4204).
+ + Clarify default html output for `--section-divs` (Richard Edwards).
+
+ * filters.md: say that Text.Pandoc.JSON comes form pandoc-types.
+ Closes jgm/pandoc-website#16.
+
+ * epub.md: Delete removed `-S` option from command (#4151, Georger Araújo).
+
+pandoc (2.0.5)
+
+ * Fix a bug in 2.0.4, whereby pandoc could not read the theme files
+ generated with `--print-highlight-style` (#4133). Improve JSON
+ serialization of styles.
+
+ * Fix CSS issues involving line numbers (#4128).
+ Highlighted code blocks are now enclosed in a div with class `sourceCode`.
+ Highlighting CSS no longer sets a generic color for pre and code; we only
+ set these for class `sourceCode`.
+
+ * `--pdf-engine-opt`: fix bug where option order was reversed (#4137).
+
+ * Add PowerPoint (pptx) writer (Jesse Rosenthal).
+ It works following the standard Pandoc conventions for making other
+ sorts of slides. Caveats:
+
+ + Syntax highlighting is not yet implemented. (This is difficult
+ because there are no character classes in Powerpoint.)
+ + Footnotes and Definition lists are not yet implemented. (Notes will
+ usually take the form of a final slide.
+ + Image placement and auto-resizing has a few glitches.
+ + Reference powerpoint files don't work dependably from the command
+ line. This will be implemented, but at the moment users are advised
+ to change themes from within Powerpoint.
+
+ * Create shared Text.Pandoc.Writers.OOXML module (Jesse Rosenthal).
+ This is for functions used by both Powerpoint and Docx writers.
+
+ * Add default pptx data for Powerpoint writer (Jesse Rosenthal).
+
+ * Add `empty_paragraphs` extension.
+
+ + Deprecate `--strip-empty-paragraphs` option. Instead we now
+ use an `empty_paragraphs` extension that can be enabled on
+ the reader or writer. By default, disabled.
+ + Add `Ext_empty_paragraphs` constructor to `Extension`.
+ + Revert "Docx reader: don't strip out empty paragraphs."
+ This reverts commit d6c58eb836f033a48955796de4d9ffb3b30e297b.
+ + Implement `empty_paragraphs` extension in docx reader and writer,
+ opendocument writer, HTML reader and writer.
+ + Add tests for `empty_paragraphs` extension.
+
+ * Markdown reader:
+
+ + Don't parse native div as table caption (#4119).
+ + Improved computation of column widths in pipe tables.
+ Pipe tables with lines longer than the text width (as set
+ by `--columns`) are now scaled to text width, with the relative
+ widths of columns determined by the ratios between the
+ header lines. Previously we computed column widths using
+ the ratio of header line lengths to column width, so that
+ tables with narrow header lines were extremely thin, which
+ was very rarely the desired result.
+
+ * LaTeX reader: fix `\` before newline (#4134). This should be a space,
+ as long as it's not followed by a blank line. This has been fixed at the
+ tokenizer level.
+
+ * Muse reader (Alexander Krotov):
+
+ + Add test for `#disable-tables` directive in Emacs mode.
+ + Don't allow emphasis to be preceded by letter.
+ + Add underline support in Emacs Muse mode..
+ + Support multiline directives in Amusewiki mode
+
+ * Man writer: omit internal links (#4136). That is, just print the link
+ text without the URL.
+
+ * Markdown reader: accept processing instructions as raw HTML (#4125).
+
+ * Lua filters (Albert Krewinkel):
+
+ + Use script to initialize the interpreter. The file `init.lua` is
+ used to initialize the Lua interpreter which is used in Lua filters.
+ This gives users the option to require libraries which they want to
+ use in all of their filters, and to extend default modules.
+ + Fix package loading for Lua 5.1. The list of package searchers is
+ named `package.loaders` in Lua 5.1 and LuaJIT, and `package.searchers`
+ in Lua 5.2 and later.
+ + Refactor lua module handling. The integration with Lua's package/module
+ system is improved: A pandoc-specific package searcher is prepended to
+ the searchers in `package.searchers`. The modules `pandoc` and
+ `pandoc.mediabag` can now be loaded via `require`.
+ + Bump lower bound of hslua. The release hslua 0.9.3 contains a new
+ function which makes using Haskell functions as package loaders much
+ easier.
+
+ * reveal.js template: add title-slide identifier to title slide (#4120).
+ This allows it to be styled more easily.
+
+ * LaTeX template: Added support for `pagestyle` variable (#4135,
+ Thomas Hodgson)
+
+ * Add `-threaded` to ghc-options for executable (#4130, fixes a build
+ error on linux).
+
+
+pandoc (2.0.4)
+
+ * Add `--print-highlight-style` option. This generates a JSON version
+ of a highlighting style, which can be saved as a `.theme` file, modified,
+ and used with `--highlight-style` (#4106, #4096).
+
+ * Add `--strip-empty-paragraphs` option. This works for any input format.
+ It is primarily intended for use with docx and odt documents where
+ empty paragraphs have been used for inter-paragraph spaces.
+
+ * Support `--webtex` for `gfm` output.
+
+ * Recognize `.muse` file extension.
+
+ * Support beamer `\alert` in LaTeX reader. Closes #4091.
+
+ * Docx reader: don't strip out empty paragraphs (#2252).
+ Users who have a conversion pipeline from docx may want to consider adding
+ `--strip-empty-paragraphs` to the command line.
+
+ * Org reader (Albert Krewinkel): Allow empty list items (#4090).
+
+ * Muse reader (Alexander Krotov):
+
+ + Parse markup in definition list terms.
+ + Allow definition to end with EOF.
+ + Make code blocks round trip.
+ + Drop common space prefix from list items.
+ + Add partial round trip test.
+ + Don't interpret XML entities.
+ + Remove `nested`.
+ + Parse `~~` as non-breaking space in Emacs mode.
+ + Correctly remove indentation from notes. Exactly one space is
+ required and considered to be part of the marker.
+ + Allow list items to be empty.
+ + Add ordered list test.
+ + Add more multiline definition tests.
+ + Don't allow blockquotes within lists.
+ + Fix reading of multiline definitions.
+ + Add inline `<literal>` support.
+ + Concatenate inlines of the same type
+
+ * Docx writer: allow empty paragraphs (#2252).
+
+ * CommonMark/gfm writer:
+
+ + Use raw html for native divs/spans (#4113). This allows a pandoc
+ markdown native div or span to be rendered in gfm using raw html tags.
+ + Implement `raw_html` and `raw_tex` extensions. Note that `raw_html`
+ is enabled by default for `gfm`, while `raw_tex` is disabled by default.
+
+ * Muse writer (Alexander Krotov):
+
+ + Test that inline math conversion result is normalized.
+ Without normalization this test produced
+ `<em>a</em><em>b</em><em>c</em>`.
+ + Improve inline list normalization and move to writer.
+ + Escape hash symbol.
+ + Escape `----` to avoid accidental horizontal rules.
+ + Escape only `</code>` inside code tag.
+ + Additional `<verbatim>` is not needed as `<code>` is verbatim already.
+
+ * LaTeX writer:
+
+ + Allow specifying just width or height for image size.
+ Previously both needed to be specified (unless the image was
+ being resized to be smaller than its original size).
+ If height but not width is specified, we now set width to
+ textwidth. If width but not height is specified, we now set
+ height to textheight. Since we have `keepaspectratio`, this
+ yields the desired result.
+ + Escape `~` and `_` in code with `--listings` (#4111).
+
+ * HTML writer: export `tagWithAttributes`. This is a helper allowing
+ other writers to create single HTML tags.
+
+ * Let papersizes `a0`, `a1`, `a2`, ... be case-insensitive by
+ converting the case as needed in LaTeX and ConTeXt writers.
+
+ * Change `fixDisplayMath` from `Text.Pandoc.Writers.Shared`
+ so that it no longer produces empty `Para`'s as an artifact.
+
+ * `Text.Pandoc.Shared.blocksToInlines`: rewrote using builder.
+ This gives us automatic normalization, so we don't get
+ for example two consecutive Spaces.
+
+ * Include default CSS for 'underline' class in HTML-based templates.
+
+ * revealjs template: add `tex2jax` configuration for the
+ math plugin. With the next release of reveal.js, this will
+ fix the problem of `$`s outside of math contexts being
+ interpreted as math delimiters (#4027).
+
+ * `pandoc.lua` module for use in lua filters (Albert Krewinkel):
+
+ + Add basic lua List module (#4099, #4081). The List module is
+ automatically loaded, but not assigned to a global variable. It can be
+ included in filters by calling `List = require 'List'`. Lists of blocks,
+ lists of inlines, and lists of classes are now given `List` as a metatable,
+ making working with them more convenient. E.g., it is now possible to
+ concatenate lists of inlines using Lua's concatenation operator `..`
+ (requires at least one of the operants to have `List` as a metatable):
+
+ function Emph (emph)
+ local s = {pandoc.Space(), pandoc.Str 'emphasized'}
+ return pandoc.Span(emph.content .. s)
+ end
+
+ The `List` metatable is assigned to the tables which get passed to
+ the constructors `MetaBlocks`, `MetaInline`, and `MetaList`. This
+ enables the use of the resulting objects as lists.
+ + `Lua/StackInstances`: push Pandoc and Meta via constructor.
+ Pandoc and Meta elements are now pushed by calling the respective
+ constructor functions of the pandoc Lua module. This makes serialization
+ consistent with the way blocks and inlines are pushed to lua and allows
+ to use List methods with the `blocks` value.
+ + Add documentation for pandoc.List in `lua-filters.md`.
+
+ * Use latest tagsoup. This fixes a bug in parsing HTML tags with
+ `&` (but not a valid entity) following them (#4094, #4088).
+
+ * Use skylighting 0.4.4.1, fixing the color of unmarked code text
+ when `numberLines` is used (#4103).
+
+ * Make `normalizeDate` more forgiving (Mauro Bieg, #4101), not
+ requiring a leading 0 on single-digit days.
+
+ * Fix `--help` output for `--highlight-style` to include `FILE` (Mauro
+ Bieg, #4095).
+
+ * Clearer deprecation warning for `--latexmathml, --asciimathml, -m`.
+ Previously we only mentioned `--latexmathml`, even if `-m` was
+ used.
+
+ * Changelog: fix description of lua filters in 2.0 release
+ (Albert Krewinkel). Lua filters were initially run *after* conventional
+ (JSON) filters. However, this was changed later to make it easier to deal
+ with files in the mediabag. The changelog is updated to describe that
+ feature of the 2.0 release correctly.
+
+ * Change Generic JSON instances to TemplateHaskell (Jasper Van der Jeugt,
+ #4085). This reduces compile time and memory usage significantly.
+
+ * `lua-filters.md`: Added tikz filter example.
+
+ * Create alternative zip file for macOS binaries.
+
+ * Create alternative zip file for Windows binaries.
+
+ * Update INSTALL.md since we now provide zips for binaries.
+
+ * Relax `http-types` dependency (Justus Sagemüller, #4084).
+
+ * Add `epub.md`, `getting-started.md` to docs. These used to live in
+ the website repo.
+
+ * Add `packages` target to Makefile.
+
+ * Bump bounds for binary, http-types, tasty-hunit
+
+pandoc (2.0.3)
+
+ * Lua filters: preload text module (Albert Krewinkel, #4077).
+ The `text` module is preloaded in lua. The module contains some UTF-8
+ aware string functions, implemented in Haskell. The module is loaded on
+ request only, e.g.:
+
+ text = require 'text'
+ function Str (s)
+ s.text = text.upper(s.text)
+ return s
+ end
+
+ * Allow table-like access to attributes in lua filters (Albert Krewinkel,
+ #4071). Attribute lists are represented as associative lists in Lua. Pure
+ associative lists are awkward to work with. A metatable is attached to
+ attribute lists, allowing to access and use the associative list as if
+ the attributes were stored in as normal key-value pair in table.
+ Note that this changes the way `pairs` works on attribute lists. Instead
+ of producing integer keys and two-element tables, the resulting iterator
+ function now returns the key and value of those pairs. Use `ipairs` to
+ get the old behavior. Warning: the new iteration mechanism only works if
+ pandoc has been compiled with Lua 5.2 or later (current default: 5.3).
+
+ * Text.Pandoc.Parsing.uri: allow `&` and `=` as word characters (#4068).
+ This fixes a bug where pandoc would stop parsing a URI with an
+ empty attribute: for example, `&a=&b=` wolud stop at `a`.
+ (The uri parser tries to guess which punctuation characters
+ are part of the URI and which might be punctuation after it.)
+
+ * Introduce `HasSyntaxExtensions` typeclass (Alexander Krotov, #4074).
+
+ + Added new `HasSyntaxExtensions` typeclass for `ReaderOptions` and
+ `WriterOptions`.
+ + Reimplemented `isEnabled` function from `Options.hs` to accept both
+ `ReaderOptions` and `WriterOptions`.
+ + Replaced `enabled` from `CommonMark.hs` with new `isEnabled`.
+
+ * Add `amuse` extension (Alexander Krotov) to enable Amuse wiki
+ behavior for `muse`. New `Ext_amuse` constructor for
+ `Extension`. Note: this is switched on by default; for
+ Emacs behavior, use `muse-amuse`.
+
+ * Muse reader (Alexander Krotov):
+
+ + Count only one space as part of list item marker.
+ + Produce SoftBreaks on newlines. Now wrapping can be preserved
+ with `--wrap=preserve`.
+ + Add Text::Amuse footnote extensions. Footnote end is indicated by
+ indentation, so footnotes can be placed anywhere in the text,
+ not just at the end of it.
+ + Accept Emacs Muse definition lists when `-amuse`.
+ Emacs Muse does not require indentation.
+
+ * HTML reader:
+
+ + Ensure we don't produce level 0 headers (#4076), even for chapter
+ sections in epubs. This causes problems because writers aren't set
+ up to expect these.
+ + Allow spaces after `\(` and before `\)` with `tex_math_single_backslash`.
+ Previously `\( \frac{1}{a} < \frac{1}{b} \)` was not parsed as math in
+ `markdown` or `html` `+tex_math_single_backslash`.
+ + Parse div with class `line-block` as LineBlock.
+ + Don't fail with block-level content in figcaption (Mauro Bieg, #4183).
+
+ * MANUAL: clarify that math extensions work with HTML.
+ Clarify that `tex_math_dollars` and `tex_math_single_backslash`
+ will work with HTML as well as Markdown.
+
+ * Creole reader: Fix performance issue for longer lists (Sascha Wilde,
+ #4067).
+
+ * RST reader: better support for 'container' directive (#4066).
+ Create a div, incorporate name attribute and classes.
+
+ * LaTeX reader:
+
+ + Support column specs like `*{2}{r}` (#4056). This is equivalent to
+ `rr`. We now expand it like a macro.
+ + Allow optional args for parbox (#4056).
+ + Allow optional arguments on `\footnote` (#4062).
+
+ * EPUB writer: Fixed path for cover image (#4069). It was previously
+ `media/media/imagename`, and should have been `media/imagename`.
+
+ * Markdown writer: fix bug with doubled footnotes in grid tables
+ (#4061).
+
+ * LaTeX template: include natbib/biblatex after polyglossia (#4073).
+ Otherwise we seem to get an error; biblatex wants polyglossia
+ language to be defined.
+
+ * Added examples to lua filters documentation.
+
+
+pandoc (2.0.2)
+
+ * Deprecated ancient HTML math methods: `--latexmathml`, `--gladtex`,
+ `--mimetex`, `--jsmath`.
+
+ * Fixed URIs in `data/jats.csl`. They were being rendered twice,
+ leading to invalid XML in default JATS output with pandoc-citeproc.
+
+ * `lua-filters.md`: use real-world man page filter as example.
+
+ * Add lua filter functions `walk_inline` and `walk_block`
+ in the pandoc module, to apply filters inside particular
+ inline and block elements.
+
+ * Refactored some code from `Text.Pandoc.Lua.PandocModule`
+ into new internal module `Text.Pandoc.Lua.Filter`.
+
+ * Markdown reader:
+
+ + Allow fenced code blocks to be indented 1-3 spaces (#4011).
+ This brings our handling of them into alignment with CommonMark's.
+ + Fix YAML metadata with "chomp" (`|-`). Previously if a
+ YAML block under `|-` contained a blank line, pandoc would
+ not parse it as metadata.
+
+ * Removed `etc.` from abbreviations file. Often `etc.` ends a
+ sentence, and we want the period to be treated as a
+ sentence-ending period.
+
+ * Fix regression with `--metadata` (#4054). Values specified with
+ `--metadata` should replace a metadata value set in the document
+ itself, rather than creating a list including a new value.
+
+ * EPUB writer:
+
+ + Fix EPUB OCF structure. #3720 had been improperly implemented.
+ + Fix modified paths for raw HTML tags (src, poster, etc.)
+ (#4050, #4055). This had not been updated for the new EPUB
+ container layout, with a separate text/ subdirectory.
+ + Fix image paths with empty `--epub-subdirectory`.
+
+ * Miscellaneous code cleanup (Alexander Krotov).
+
+ * Use pandoc-types 1.17.3, which adds `Walkable` instances
+ for `[Block] Block` and `[Inline] Inline`.
+
+ * Remove obsolete `stack.full.yaml` (#4052).
+
+ * Change to using pandoc-citeproc 0.12.1 in binary packages.
+
+ * Consolidate math output method documentation (#4049, Mauro Bieg).
+
+ * `MANUAL.txt`: fix header level of "Extension: emoji" (Albert Krewinkel).
+
+ * Use lua filter to generate man page from `MANUAL.txt`, replacing old
+ Haskell filters. This is easier and faster.
+
+ * Improved `INSTALL.md`.
+
+ * Update commands to extract deb archive on Linux (#4043, Salim B).
+
+
+pandoc (2.0.1.1)
+
+ * Improved fix to #3989 (parsing of HTML tags containing
+ `>` in an attribute or comment). The previous fix (in 2.0.1) only
+ worked in certain cases.
+
+ * FB2 writer (Alexander Krotov):
+
+ + Add `unrecognised` genre to `<title-info>`
+ (Alexander Krotov). XML schema requires at least one genre.
+ + Remove `<annotation>` from `<body>`.
+
+ * CommonMark writer: fix strikethrough for `gfm` (#4038).
+
+ * Use texmath 0.10, which adds support for a wider range of
+ symbols and fixes default column alignments in MathML
+ and OMML.
+
+ * Highlighting fixes, using skylighting 0.4.3.2:
+
+ + Fix invalid CSS.
+ + Support `lineAnchors` (or `line-anchors`) in HTML code blocks.
+ + Ensure that code lines don't get duplicate identifiers (#4031).
+ The line identifiers are built using the code block's identifier
+ as a prefix. If the code block has null identifier, we use
+ `cb1`, `cb2`, etc.
+
+ * Added a few abbreviations to `data/abbreviations`,
+ and sorted the list (#3984, Wandmalfarbe).
+
+ * Improved support for columns in HTML writer (#4028).
+
+ + Remove `width` attribute from the `div`.
+ + Remove space between `<div class="column">` elements,
+ since this prevents columns whose widths sum to 100%
+ (the space takes up space).
+ + Move as much as possible of the CSS to the template.
+ + Ensure that all the HTML-based templates (including epub)
+ contain the CSS for columns.
+ + Columns default to 50% width unless they are given a width
+ attribute. So if you want two equal-width columns, you
+ can use a div with class `column` and no `width` attribute.
+
+ * SelfContained: use `base64` for css links with media attribute (#4026).
+ This fixes `--self-contained` with S5.
+
+ * Improve `pandoc-template-mode.el` (Vaclav Haisman).
+
+ * Issue INFO, not WARNING, when a .sty file cannot be
+ read in LaTeX reader. It is normally not an issue requiring
+ a fix from the user if .sty files are not found.
+
+ * INSTALL.md: MacOS instructions needed xar -f (adam234).
+
+ * MANUAL.txt:
+
+ + Clarify that --setext-headers doesn't affect gfm output (#4035).
+ + Clarify what is needed to open and close a div in `fenced_divs`
+ (#4039, Tristano Ajmone).
+ + Removed reference to `default.beamer` in docs (#4024).
+ Also added mention of other templates affecting PDF output
+ with different settings.
+
+pandoc (2.0.1)
+
+ * Fixed regression in parsing of HTML comments in markdown and other
+ non-HTML formats (`Text.Pandoc.Readers.HTML.htmlTag`) (#4019).
+ The parser stopped at the first `>` character, even if it wasn't
+ the end of the comment.
+
+ * Creole reader (Sascha Wilde):
+
+ + Fix some minor typos and formatting.
+ + Add additional test on nowiki-block after para.
+ + Fix lists with trailing white space.
+
+ * LaTeX reader: handle `%` comment right after command.
+ For example, `\emph%`.
+
+ * Markdown reader: make sure fenced div closers work in lists.
+ Previously the following failed:
+
+ ::: {.class}
+ 1. one
+ 2. two
+ :::
+
+ and you needed a blank line before the closing `:::`.
+
+ * Make `fenced_divs` affect the Markdown writer. If `fenced_divs` is
+ enabled, Divs will be rendered as fenced divs.
+
+ * LaTeX/Beamer writer: support "blocks" inside columns and other Divs
+ (#4016).
+
+ * HTML Writer: consistently use dashed class-names (Mauro Bieg, #3556).
+ Note: this change may require some changes in CSS rules.
+ `footnoteRef` has become `footnote-ref`, `titleslide` has
+ become `title-slide`, and `footnoteBack` has become `footnote-back`.
+
+ * JATS writer: Properly pass through author metadata (#4020).
+
+ * FB2 writer (Alexander Krotov):
+
+ + Write blocks outside of `<p>` in definitions.
+ + Make bullet lists consistent with ordered lists, repeating
+ the marker for the outer list rather than indenting sublists,
+ since indentation does not work in readers.
+ + Add new style FB2 tests.
+
+ * `Text.Pandoc.ImageSize`: Add `Millimeter` constructor to `Dimension`
+ (#4012) [API change]. Now sizes given in 'mm' are no longer converted
+ to 'cm'.
+
+ * Revise documentation of small caps syntax (Andrew Dunning, #4013).
+
+ * Fix broken reference links in manual (Andrew Dunning, #4014)
+
+ * Fixed example of slide columns structure in changelog (#4015).
+ Also documented this feature in MANUAL.txt.
+
+
+pandoc (2.0.0.1)
+
+ * EPUB writer:
+
+ + Fixed filepaths for nonstandard epub-subdirectory values.
+ + Ensure that epub2 is recognized as a non-text format,
+ so that a template is used.
+ + Don't include "prefix" attribute for ibooks for epub2.
+ It doesn't validate.
+ + Fix stylesheet paths; previously we had an incorrect
+ stylesheet path for the cover page and nav page.
+
+ * LaTeX reader:
+
+ + Insert space when needed in macro expansion (#4007).
+ Sometimes we need to insert a space after a control sequence
+ to prevent it merging with a following letter.
+ + Allow unbraced arguments for macros (#4007).
+ + Allow body of macro definition to be unbraced (#4007).
+
+ * Linux package build: ensure that pandoc-citeproc is statically linked.
+
+ * trypandoc: add native, ms.
+
+pandoc (2.0)
+
+ [new features]
-pandoc (1.19.2.2)
+ * New output format `ms` (groff ms). Complete support, including
+ tables, math, syntax highlighting, and PDF bookmarks. The writer uses
+ texmath's new eqn writer to convert math to eqn format, so a ms file
+ produced with this writer should be processed with `groff -ms -e` if
+ it contains math.
- * Fix build with GHC 8.2.1 (#3876, Peter Simons). Setup.hs does not
- compile with Cabal 2.x, so we require an earlier version via
- setup-depends. The following packages need newer versions with
- GHC 8.2.1 and had their constraints relaxed accordingly:
- executable-path, process, syb, and time.
+ * New output format `jats` (Journal Article Tag Suite). This is an XML
+ format used in archiving and publishing articles. Note that a
+ URI-encoded CSL stylesheet (`data/jats.csl`) is added automatically
+ unless a stylesheet is specified using `--css`.
-pandoc (1.19.2.1)
+ * New output format `gfm` (GitHub-flavored CommonMark) (#3841).
+ This uses bindings to GitHub's fork of cmark, so it should parse
+ gfm exactly as GitHub does (excepting certain postprocessing
+ steps, involving notifications, emojis, etc.). `markdown_github`
+ has been deprecated in favor of `gfm`.
+
+ * New output format `muse` (Emacs Muse) (Alexander Krotov, #3489).
+
+ * New input format `gfm` (GitHub-flavored CommonMark) (#3841).
+ This uses bindings to GitHub's fork of cmark. `markdown_github`
+ has been deprecated in favor of `gfm`.
+
+ * New input format `muse` (Emacs Muse) reader (Alexander Krotov, #3620).
+
+ * New input format `tikiwiki` (TikiWiki markup) (rlpowell, #3800).
+
+ * New input format `vimwiki` (Vimwiki markup) (Yuchen Pei, #3705).
+ Note that there is a new data file, `data/vimwiki.css`, which can
+ be used to display the HTML produced by this reader and
+ pandoc's HTML writer in the style of vimwiki's own HTML
+ export.
+
+ * New input format `creole` (Creole 1.0) (#3994, Sascha Wilde).
+
+ * New syntax for Divs, with `fenced_divs` extension enabled by
+ default (#168). This gives an attractive, plain-text way to create
+ containers for block-level content.
+
+ * Added new syntax for including raw content in any output format,
+ enabled by the `raw_attribute` extension (which is on by default
+ for `markdown` and `multimarkdown`). The syntax is the same as
+ for fenced code blocks or code inlines, only with `{=FORMAT}` for
+ attributes, where `FORMAT` is the name of the output format
+ (e.g., `ms`, `html`).
+
+ * Implement multicolumn support for slide formats (#1710).
+ The structure expected is:
+
+ :::::::::::::: {.columns}
+ ::: {.column width="40%"}
+ contents...
+ :::
+ ::: {.column width="60%"}
+ contents...
+ :::
+ ::::::::::::::
+
+ Support has been added for beamer and all HTML slide formats.
+
+ * Allows line comments in templates, beginning with `$--` (#3806).
+ (Requires doctemplates 0.2.1.)
+
+ * Add `--eol=crlf|lf|native` flag and writer option to control line endings
+ (Stefan Dresselhaus, #3663, #2097).
+
+ * Add `--log` option to save log messages in JSON format to a file (#3392).
+
+ * Add `--request-header` option, to set request headers when pandoc
+ makes HTTP requests to fetch external resources. For example:
+ `--request-header User-Agent:blah`.
+
+ * Added lua filters (Albert Krewinkel, #3514). The new `--lua-filter`
+ option works like `--filter` but takes pathnames of special lua filters
+ and uses the lua interpreter baked into pandoc, so that no external
+ interpreter is needed. Note that lua filters are all applied before
+ regular filters, regardless of their position on the command line.
+ For documentation of lua filters, see `doc/lua-filters.md`.
+
+ * Set `PANDOC_READER_OPTIONS` in environment where filters are run.
+ This contains a JSON representation of `ReaderOptions`, so filters
+ can access it.
+
+ * Support creation of pdf via groff `ms` and pdfroff.
+ `pandoc -t ms -o output.pdf input.txt`.
+
+ * Support for PDF generation via HTML and `weasyprint` or `prince`
+ (Mauro Bieg, #3909). `pandoc -t html5 -o output.pdf --pdf-engine=prince`.
+
+ * Added `--epub-subdirectory` option (#3720). This specifies the
+ subdirectory in the OCF container that holds the EPUB specific content.
+ We now put all EPUB related content in an `EPUB/` subdirectory by default
+ (later this will be configurable).
+
+ ```
+ mimetype
+ META-INF/
+ com.apple.ibooks.display-options.xml
+ container.xml
+ EPUB/ <<--configurable-->>
+ fonts/ <<--static-->>
+ font.otf
+ media/ <<--static-->>
+ cover.jpg
+ fig1.jpg
+ styles/ <<--static-->>
+ stylesheet.css
+ content.opf
+ toc.ncx
+ text/ <<--static-->>
+ ch001.xhtml
+ ```
+
+ * Added `--resource-path=SEARCHPATH` command line option (#852).
+ SEARCHPATH is separated by the usual character, depending on OS
+ (: on unix, ; on windows). Default resource path is just working
+ directory. However, the working directory must be explicitly
+ specified if the `--resource-path` option is used.
+
+ * Added --abbreviations=FILE option for custom abbreviations file
+ (#256). Default abbreviations file (`data/abbreviations`) contains
+ a list of strings that will be recognized by pandoc's
+ Markdown parser as abbreviations. (A nonbreaking space will
+ be inserted after the period, preventing a sentence space in
+ formats like LaTeX.) Users can override the default by putting a file
+ abbreviations in their user data directory (`~/.pandoc` on *nix).
+
+ * Allow a theme file as argument to `--highlight-style`.
+ Also include a sample, `default.theme`, in `data/`.
+
+ * Allow `--syntax-definition` option for dynamic loading of syntax
+ highlighting definitions (#3334).
+
+ * Lists in `markdown` by default now use the CommonMark variable
+ nesting rules (#3511). The indentation required for a block-level
+ item to be included in a list item is no longer fixed, but is
+ determined by the first line of the list item. To be included in
+ the list item, a block must be indented to the level of the first
+ non-space content after the list marker. Exception: if are 5 or more
+ spaces after the list marker, then the content is interpreted as an
+ indented code block, and continuation paragraphs must be indented
+ two spaces beyond the end of the list marker. See the CommonMark
+ spec for more details and examples.
+
+ Documents that adhere to the four-space rule should, in most cases,
+ be parsed the same way by the new rules. Here are some examples
+ of texts that will be parsed differently:
+
+ - a
+ - b
+
+ will be parsed as a list item with a sublist; under the four-space
+ rule, it would be a list with two items.
+
+ - a
+
+ code
+
+ Here we have an indented code block under the list item, even though it
+ is only indented six spaces from the margin, because it is four spaces
+ past the point where a continuation paragraph could begin. With the
+ four-space rule, this would be a regular paragraph rather than a code
+ block.
+
+ - a
+
+ code
+
+ Here the code block will start with two spaces, whereas under
+ the four-space rule, it would start with `code`. With the four-space
+ rule, indented code under a list item always must be indented eight
+ spaces from the margin, while the new rules require only that it
+ be indented four spaces from the beginning of the first non-space
+ text after the list marker (here, `a`).
+
+ This change was motivated by a slew of bug reports from people
+ who expected lists to work differently (#3125, #2367, #2575, #2210,
+ #1990, #1137, #744, #172, #137, #128) and by the growing prevalance
+ of CommonMark (now used by GitHub, for example). Those who
+ prefer the old behavior can use `-f markdown+four_space_rule`.
+
+ * Added `four_space_rule` extension. This triggers the old pandoc
+ parsing rule for content nested under list items (the "four space
+ rule").
+
+ * Added `spaced_reference_links` extension (#2602). It allows whitespace
+ between the two parts of a reference link: e.g.
+
+ [a] [b]
+
+ [b]: url
+
+ This was previously enabled by default; it is now forbidden by default.
+
+ * Add `space_in_atx_header` extension (#3512). This is enabled by default
+ in pandoc and GitHub markdown but not the other flavors.
+ This requires a space between the opening #'s and the header
+ text in ATX headers (as CommonMark does but many other implementations
+ do not). This is desirable to avoid falsely capturing things like
+
+ #hashtag
+
+ or
+
+ #5
+
+ * Add `sourcefile` and `outputfile` template variables (Roland Hieber,
+ #3431).
+
+ * Allow ibooks-specific metadata in epubs (#2693). You can now have
+ the following fields in your YAML metadata, and it will be treated
+ appropriately in the generated EPUB:
+
+ ```
+ ibooks:
+ version: 1.3.4
+ specified-fonts: false
+ ipad-orientation-lock: portrait-only
+ iphone-orientation-lock: landscape-only
+ binding: true
+ scroll-axis: vertical
+ ```
+
+
+ [behavior changes]
+
+ * Reader functions no longer presuppose that CRs have been
+ stripped from the input. (They strip CRs themselves, before
+ parsing, to simplify the parsers.)
+
+ * Added support for translations (localization) (#3559).
+ Currently this only affects the LaTeX reader, for things
+ like `\figurename`. Translation data files for 46 languages
+ can be found in `data/translations`.
+
+ * Make `--ascii` work with DocBook output too.
+
+ * Rename `--latex-engine` to `--pdf-engine`,
+ and `--latex-engine-opt` to `--pdf-engine-opt`.
+
+ * Removed `--parse-raw` and `readerParseRaw`. These were confusing.
+ Now we rely on the `+raw_tex` or `+raw_html` extension with latex or html
+ input. Thus, instead of `--parse-raw -f latex` we use `-f latex+raw_tex`,
+ and instead of `--parse-raw -f html` we use `-f html+raw_html`.
+
+ * With `--filter` R filters are now recognized, even if they are
+ not executable (#3940, #3941, Andrie de Vries).
+
+ * Support SVG in PDF output, converting with `rsvg2pdf` (#1793).
+
+ * Make epub an alias for epub3, not epub2.
+
+ * Removed `--epub-stylesheet`; use `--css` instead (#3472, #847).
+ Multiple stylesheets may be used. Stylesheets will be taken both from
+ `--css` and from the `stylesheet` metadata field (which can contain
+ either a file path or a list of them).
+
+ * `--mathml` and MathML in HTMLMathMethod no longer take an argument.
+ The argument was for a bridge JavaScript that used to be necessary
+ in 2004. We have removed the script already.
+
+ * `--katex` improvements. The latest version is used, and the
+ autoload script is loaded by default.
+
+ * Change MathJax CDN default since old one is shutting down (#3544).
+ Note: The new URL requires a version number, which we'll have
+ to update manually in subsequent pandoc releases in order to
+ take advantage of mathjax improvements.
+
+ * `--self-contained`: don't incorporate elements with `data-external="1"`
+ (#2656). You can leave an external link as it is by adding the attribute
+ data-external="1" to the element. Pandoc will then not try to
+ incorporate its content when `--self-contained` is used. This is
+ similar to a feature already supported by the EPUB writer.
+
+ * Allow `--extract-media` to work with non-binary input formats
+ (#1583, #2289). If `--extract-media` is supplied with a non-binary
+ input format, pandoc will attempt to extract the contents of all
+ linked images, whether in local files, data: uris, or external uris.
+ They will be named based on the sha1 hash of the contents.
+
+ * Make `papersize: a4` work regardless of the case of `a4`.
+ It is converted to `a4` in LaTeX and `A4` in ConTeXt.
+
+ * Make `east_asian_line_breaks` affect all readers/writers (#3703).
+
+ * Underlined elements are now treated consistently by readers
+ (#2270, hftf); they are always put in a Span with class `underline`.
+ This allows the user to treat them differently from other emphasis,
+ using a filter. Docx, Org, Textile, Txt2Tags, and HTML readers
+ have been changed.
+
+ * Improved behavior of `auto_identifiers` when there are explicit ids
+ (#1745). Previously only autogenerated ids were added to the list
+ of header identifiers in state, so explicit ids weren't taken
+ into account when generating unique identifiers. Duplicated
+ identifiers could result. This simple fix ensures that explicitly given
+ identifiers are also taken into account.
+
+ * Use `table-of-contents` for contents of toc, make `toc` a boolean
+ (#2872). Changed markdown, rtf, and HTML-based templates accordingly.
+ This allows you to set `toc: true` in the metadata; this
+ previously produced strange results in some output formats.
+ For backwards compatibility, `toc` is still set to the
+ toc contents. But it is recommended that you update templates
+ to use `table-of-contents` for the toc contents and `toc`
+ for a boolean flag.
+
+ * Change behavior with binary format output to stdout.
+ Previously, for binary formats, output to stdout was disabled
+ unless we could detect that the output was being piped (and not
+ sent to the terminal). Unfortunately, such detection is not
+ possible on Windows, leaving windows users no way to pipe binary
+ output. So we have changed the behavior in the following way:
+
+ + Output to stdout is allowed when it can be determined that
+ the output is being piped (on non-Windows platforms).
+ + If the `-o` option is not used, binary output is never sent
+ to stdout by default; instead, an error is raised.
+ + If `-o -` is used, binary output is sent to stdout, regardless
+ of whether it is being piped. This works on Windows too.
+
+ * Better error behavior: uses of `error` have been replaced by
+ raising of `PandocError`, which can be trapped and handled by the
+ calling program.
+
+ * Removed `hard_line_breaks` extension from `markdown_github` (#3594).
+ GitHub has two Markdown modes, one for long-form documents like READMEs
+ and one for short things like issue coments. In issue comments, a line
+ break is treated as a hard line break. In README, wikis, etc., it is
+ treated as a space as in regular Markdown. Since pandoc is more likely to
+ be used to convert long-form documents from GitHub Markdown,
+ `-hard_line_breaks` is a better default.
+
+ * Include `backtick_code_blocks` extension in `mardkown_mmd` (#3637).
+
+ * Escape `MetaString` values (as added with `-M/--metadata` flag) (#3792).
+ Previously they would be transmitted to the template without any
+ escaping. Note that `--M title='*foo*'` yields a different result from
+
+ ---
+ title: *foo*
+ ---
+
+ In the latter case, we have emphasis; in the former case, just
+ a string with literal asterisks (which will be escaped
+ in formats, like Markdown, that require it).
+
+ * Allow `em`, `cm`, `in` for image height/width in HTML, LaTeX (#3450).
+
+ * HTML writer: Insert `data-` in front of unsupported attributes. Thus,
+ a span with attribute `foo` gets written to HTML5 with `data-foo`, so
+ it is valid HTML5. HTML4 is not affected. This will allow us to use
+ custom attributes in pandoc without producing invalid HTML. (With help
+ from Wandmalfarbe, #3817.)
+
+ * Plain writer: improved super/subscript rendering. We now
+ handle more non-digit characters for which there are
+ sub/superscripted unicode characters. When unicode
+ sub/superscripted characters are not available, we use
+ `_(..)` or `^(..)` (#3518).
+
+ * Docbook, JATS, TEI writers: print INFO message when omitting interior
+ header (#3750). This only applies to section headers inside list items,
+ e.g., which were otherwise silently omitted.
+
+ * Change to `--reference-links` in Markdown writer (#3701). With
+ `--reference-location` of `section` or `block`, pandoc will now repeat
+ references that have been used in earlier sections. The Markdown
+ reader has also been modified, so that *exactly* repeated references
+ do not generate a warning, only references with the same label but
+ different targets. The idea is that, with references after every block,
+ one might want to repeat references sometimes.
+
+ * ODT/OpenDocument writer:
+
+ + Support `lang` attribute (#1667).
+ + Added support for `--toc` (#2836). Thanks to @anayrat.
+
+ * Docx writer:
+
+ + `lang` meta, see #1667 (Mauro Bieg, #3515).
+ + Change `FigureWithCaption` to `CaptionedFigure` (iandol, #3658).
+ + Use `Table` rather than `Table Normal` for table style (#3275).
+ `Table Normal` is the default table style and can't be modified.
+ + Pass through comments (#2994). We assume that comments are defined as
+ parsed by the docx reader:
+
+ I want <span class="comment-start" id="0" author="Jesse Rosenthal"
+ date="2016-05-09T16:13:00Z">I left a comment.</span>some text to
+ have a comment <span class="comment-end" id="0"></span>on it.
+
+ We assume also that the id attributes are unique and properly
+ matched between comment-start and comment-end.
+ + Bookmark improvements. Bookmark start/end now surrounds content rather
+ than preceding it. Bookmarks generated for Div with id
+ (jgm/pandoc-citeproc#205).
+ + Add `keywords` metadata to docx document properties (Ian).
+
+ * RST writer: support unknown interpreted text roles by
+ parsing them as `Span` with `role` attributes (#3407). This
+ way they can be manipulated in the AST.
+
+ * HTML writer:
+
+ + Line block: Use class instead of style attribute (#1623). We now
+ issue `<div class="line-block">` and include a default definition
+ for `line-block` in the default templates, instead of hard-coding a
+ `style` on the div.
+ + Add class `footnoteBack` to footnote back references (Timm Albers).
+ This allows for easier CSS styling.
+ + Render SmallCaps as span with smallcaps class (#1592), rather than
+ using a style attribute directly. This gives the user more flexibility
+ in styling small caps in CSS.
+ + With reveal.js we use `data-src` instead of `src` for images for
+ lazy loading.
+ + Special-case `.stretch` class for images in reveal.js (#1291).
+ Now in reveal.js, an image with class `stretch` in a paragraph
+ by itself will stretch to fill the whole screen, with no
+ caption or figure environment.
+
+ * Added warnings for non-rendered blocks to writers.
+
+ * Writers now raise an error on template failure.
+
+ * When creating a PDF via LaTeX, warn if the font is missing some
+ characters (#3742).
+
+ * Remove initial check for PDF-creating program (#3819).
+ Instead, just try running it and raise the exception if it
+ isn't found at that point. This improves things for users of Cygwin
+ on Windows, where the executable won't be found by `findExecutable`
+ unless `.exe` is added. The same exception is raised as before, but
+ at a later point.
+
+ * Readers issue warning for duplicate header identifiers (#1745).
+ Autogenerated header identifiers are given suffixes so as not to clash
+ with previously used header identifiers. But they may still coincide with
+ an explicit identifier that is given for a header later in the document,
+ or with an identifier on a div, span, link, or image. We now issue
+ a warning in this case, so users can supply an explicit identifier.
+
+ * CommonMark reader now supports `emoji`, `hard_line_breaks`, `smart`,
+ and `raw_html` extensions.
+
+ * Markdown reader:
+
+ + Don't allow backslash + newline to affect block structure (#3730).
+ Note that as a result of this change, the following, which formerly
+ produced a header with two lines separated by a line break, will
+ now produce a header followed by a paragraph:
+
+ # Hi\
+ there
+
+ This may affect some existing documents that relied on
+ this undocumented and unintended behavior. This change makes pandoc
+ more consistent with other Markdown implementations, and with itself
+ (since the two-space version of a line break doesn't work inside ATX
+ headers, and neither version works inside Setext headers).
+
+
+ * Org reader (Albert Krewinkel, unless noted):
+
+ + Support `table.el` tables (#3314).
+ + Support macros (#3401).
+ + Support the `#+INCLUDE:` file inclusion mechanism (#3510).
+ Recognized include types are `example`, `export`, `src`, and
+ normal org file inclusion. Advanced features like line numbers
+ and level selection are not implemented yet.
+ + Interpret more meta value as inlines. The values of the following
+ meta variables are now interpreted using org-markup instead of
+ treating them as pure strings: `keywords` (comma-separated list of
+ inlines), `subtitle` (inline values), `nocite` (inline values, can
+ be repeated).
+ + Support `\n` export option (#3940). This turns all newlines in the
+ text into hard linebreaks.
+
+ * RST reader:
+
+ + Improved admonition support (#223). We no longer add an
+ `admonition` class, we just use the class for the type of admonition,
+ `note` for example. We put the word corresponding to the label in
+ a paragraph inside a `Div` at the beginning of the admonition with
+ class `admonition-title`. This is about as close as we can get to
+ RST's own output.
+ + Initial support of `.. table` directive. This allows adding captions
+ to tables.
+ + Support `.. line-block` directive. This is deprecated but may still
+ be in older documents.
+ + Support scale and align attributes of images (#2662).
+ + Implemented implicit internal header links (#3475).
+ + Support RST-style citations (#853). The citations appear at the end
+ of the document as a definition list in a special div with id
+ `citations`. Citations link to the definitions.
+ + Recurse into bodies of unknown directives (#3432).
+ In most cases it's better to preserve the content than
+ to emit it. This isn't guaranteed to have good results;
+ it will fail spectacularly for unknown raw or verbatim directives.
+ + Handle chained link definitions (#262). For example,
+
+ .. _hello:
+ .. _goodbye: example.com
+
+ Here both `hello` and `goodbye` should link to `example.com`.
+ + Support anchors (#262). E.g.
+
+ `hello`
+
+ .. _hello:
+
+ paragraph
+
+ This is supported by putting "paragraph" in a `Div` with id `hello`.
+ + Support `:widths:` attribute for table directive.
+ + Implement csv-table directive (#3533). Most attributes are supported,
+ including `:file:` and `:url:`.
+ + Support unknown interpreted text roles by parsing them as Span
+ with "role" attributes (#3407). This way they can be manipulated in
+ the AST.
+
+ * HTML reader: parse a span with class `smallcaps` as `SmallCaps`.
+
+ * LaTeX reader:
+
+ + Implemented `\graphicspath` (#736).
+ + Properly handle column prefixes/suffixes. For example, in
+ `\begin{tabular}{>{$}l<{$}>{$}l<{$} >{$}l<{$}}`
+ each cell will be interpreted as if it has a `$`
+ before its content and a `$` after (math mode).
+ + Handle komascript `\dedication` (#1845). It now adds a
+ `dedication` field to metadata. It is up to the user to supply
+ a template that uses this variable.
+ + Support all `\textXX` commands, where XX = `rm`, `tt`, `up`, `md`,
+ `sf`, `bf` (#3488). Spans with a class are used when there is
+ nothing better.
+ + Expand `\newenvironment` macros (#987).
+ + Add support for LaTeX subfiles package (Marc Schreiber, #3530).
+ + Better support for subfigure package (#3577).
+ A figure with two subfigures turns into two pandoc
+ figures; the subcaptions are used and the main caption
+ ignored, unless there are no subcaptions.
+ + Add support for \vdots (Marc Schreiber, #3607).
+ + Add basic support for hyphenat package (Marc Schreiber, #3603).
+ + Add basic `\textcolor` support (Marc Schreiber).
+ + Add support for `tabularx` environment (Marc Schreiber, #3632).
+ + Better handling of comments inside math environments (#3113).
+ This solves a problem with commented out `\end{eqnarray}` inside
+ an eqnarray (among other things).
+ + Parse tikzpicture as raw verbatim environment if `raw_tex` extension
+ is selected (#3692). Otherwise skip with a warning. This is better
+ than trying to parse it as text!
+ + Add `\colorbox` support (Marc Schreiber).
+ + Set identifiers on Spans used for `\label`.
+ + Have `\setmainlanguage` set `lang` in metadata.
+ + Support etoolbox's `\ifstrequal`.
+ + Support `plainbreak`, `fancybreak` et al from the memoir class
+ (bucklereed, #3833).
+ + Support `\let`. Also, fix regular macros so they're expanded at the
+ point of use, and NOT also the point of definition. `\let` macros,
+ by contrast, are expanded at the point of definition. Added an
+ `ExpansionPoint` field to `Macro` to track this difference.
+ + Support simple `\def` macros. Note that we still don't support
+ macros with fancy parameter delimiters, like `\def\foo#1..#2{...}`.
+ + Support \chaptername, \partname, \abstractname, etc. (#3559,
+ obsoletes #3560).
+ + Put content of `\ref`, `\label`, `\eqref` commands into `Span` with
+ attributes, so they can be handled in filters (Marc Schreiber, #3639)
+ + Add Support for `glossaries` and `acronym` package (Marc Schreiber,
+ #3589). Acronyms are not resolved by the reader, but acronym and
+ glossary information is put into attributes on Spans so that they
+ can be processed in filters.
+ + Use `Link` instead of `Span` for `\ref`. This makes more sense
+ semantically and avoids unnecessary `Span [Link]` nestings when
+ references are resolved.
+ + Rudimentary support for `\hyperlink`.
+ + Support `\textquoteleft|right`, `\textquotedblleft|right` (#3849).
+ + Support `\lq`, `\rq`.
+ + Implement `\newtoggle`, `\iftoggle`, `\toggletrue|false` from etoolbox
+ (#3853).
+ + Support `\RN` and `\Rn`, from biblatex (bucklereed, #3854).
+ + Improved support for `\hyperlink`, `\hypertarget` (#2549).
+ + Support `\k` ogonek accent.
+ + Improve handling of accents. Handle ogonek, and fall back correctly
+ with forms like `\"{}`.
+ + Better support for ogonek accents.
+ + Support for `\faCheck` and `\faClose` (Marc Schreiber, #3727).
+ + Support for `xspace` (Marc Schreiber, #3797).
+ + Support `\setmainlanguage` or `\setdefaultlanguage` (polyglossia)
+ and `\figurename`.
+ + Better handling of `\part` in LaTeX (#1905). Now we parse chapters as
+ level 0 headers, and parts as level -1 headers. After parsing, we
+ check for the lowest header level, and if it's less than 1 we bump
+ everything up so that 1 is the lowest header level. So `\part` will
+ always produce a header; no command-line options are needed.
+ + Add block version of `\textcolor` (Marc Schreiber).
+ + `\textcolor` works as inline and block command (Marc Schreiber).
+ + `\textcolor` will be parse as span at the beginning of a paragraph
+ (Marc Schreiber).
+ + Read polyglossia/babel `\text(LANG){...}` (bucklereed)
+ + Improved handling of include files in LaTeX reader (#3971).
+ Previously `\include` wouldn't work if the included file
+ contained, e.g., a begin without a matching end.
+ + Support `\expandafter` (#3983).
+ + Handle `\DeclareRobustCommand` (#3983). Currently it's just treated
+ as a synonym for `\newcommand`.
+ + Handle `\lettrine` (Mauro Bieg).
+
+ * Math improvements due to updates in texmath:
+
+ + Improved handling of accents and upper/lower delimiters.
+ + Support for output in GNU eqn format (used with *roff).
+ + Allow `\boldsymbol` + a token without braces, and similarly
+ with other styling commands.
+ + Improve parsing of `\mathop` to allow multi-character operator names.
+ + Add thin space after math operators when "faking it with
+ unicode."
+
+ * `walk` is now used instead of `bottomUp` in the `ToJSONFilter`
+ instance for `a -> [a]` (pandoc-types). Note that behavior
+ will be slightly different, since `bottomUp`'s treatment of
+ a function `[a] -> [a]` is to apply it to each sublist of a
+ list, while walk applies it only to maximal sublists.
+ Usually the latter behavior is what is wanted, and the
+ former can be simulated when needed. But there may be
+ existing filters that need to be rewritten in light of the
+ new behavior. Performance should be improved.
+
+ * There are some changes to syntax highlighting due to revisions
+ in the `skylighting` library:
+
+ + Support for `powershell` has been added, and many syntax
+ definitions have been updated.
+ + Background colors have been added to the `kate` style.
+ + The way highlighted code blocks are formatted in HTML has
+ been changed (David Baynard), in ways that may require
+ changes in hard-coded CSS affecting highlighting.
+ (If you haven't included hard-coded highlighting CSS in
+ your template, you needn't change anything.)
+
+
+ [API changes]
+
+ * New module `Text.Pandoc.Class` (Jesse Rosenthal, John MacFarlane).
+ This contains definitions of the `PandocMonad` typeclass, the
+ `PandocIO` and `PandocPure` monads, and associated functions.
+
+ * Changed types of all writers and readers.
+
+ + We now use `Text` instead of `String` in the interface (#3731).
+ (We have not yet changed the internals of most readers to work
+ with `Text`, but making this change in the API now opens up a
+ path to doing that.)
+ + The result is now of form `m a` with constraint `PandocMonad m`.
+ Readers and writers can be combined to form monadic values which
+ can be run using either `runIO` or `runPure`. If `runIO` is used,
+ then both readers and writers will be able to do IO when needed
+ (for include files, for example); if `runPure` is used,
+ then the functions are pure and will not touch IO.
+ + Where previously you used
+ `writeRST def (readMarkdown def "[foo](url)")`, now you
+ would use
+ `runPure $ readMarkdown def (pack "[foo](url)") >>= writeRST def`.
+
+ * New module `Text.Pandoc.Readers` (Albert Krewinkel). This
+ contains reader helper functions formerly defined in the
+ top-level `Text.Pandoc` module.
+
+ + Changed `StringReader` -> `TextReader`.
+ + `getReader` now returns a pair of a reader and
+ `Extensions`, instead of building the extensions into the
+ reader (#3659). The calling code must explicitly set
+ `readerExtensions` using the `Extensions` returned. The
+ point of the change is to make it possible for the calling
+ code to determine what extensions are being used.
+
+ * New module `Text.Pandoc.Writers` (Albert Krewinkel).
+ This contains writer helper functions formerly defined in the
+ top-level `Text.Pandoc` module.
+
+ + Changed `StringWriter` -> `TextWriter`.
+ + `getWriter` now retuns a pair of a reader and
+ `Extensions`, instead of building the extensions into the
+ reader (#3659). The calling code must explicitly set
+ `readerExtensions` using the `Extensions` returned. The
+ point of the change is to make it possible for the calling
+ code to determine what extensions are being used.
+
+ * New module `Text.Pandoc.Lua`, exporting `runLuaFilter` (Albert Krewinkel,
+ #3514).
+
+ * New module `Text.Pandoc.App`. This abstracts out the functionality
+ of the command line program (`convertWithOpts`), so it can be reproduced
+ e.g. in a desktop or web application. Instead of exiting, we throw errors
+ (#3548), which are caught (leading to exit) in pandoc.hs, but allow other
+ users of `Text.Pandoc.App` to recover. `pandoc.hs` is now a 2-liner.
+ The module also exports some utility functions for parsing options
+ and running filters.
+
+ * New module `Text.Pandoc.Logging` (exported module) (#3392).
+ This now contains the `Verbosity` definition previously in
+ `Text.Pandoc.Options`, as well as a new `LogMessage` datatype that will
+ eventually be used instead of raw strings for warnings. This will enable
+ us, among other things, to provide machine-readable warnings if desired.
+ Include ToJSON instance and showLogMessage. This gives us the possibility
+ of both machine-readable and human-readable output for log messages.
+
+ * New module `Text.Pandoc.BCP47`, with `getLang`, `Lang(..)`, `parseBCP47`.
+
+ * New module `Text.Pandoc.Translations`, exporting `Term`,
+ `Translations`, `readTranslations`.
+
+ * New module `Text.Pandoc.Readers.LaTeX.Types', exporting `Macro`, `Tok`,
+ `TokType`, `Line`, `Column`.
+
+ * `Text.Pandoc.Error`: added many new constructors for `PandocError`.
+
+ * Expose some previously private modules (#3260). These are often
+ helpful to people writing their own reader or writer modules:
+
+ + `Text.Pandoc.Writers.Shared`
+ + `Text.Pandoc.Parsing`
+ + `Text.Pandoc.Asciify`
+ + `Text.Pandoc.Emoji`
+ + `Text.Pandoc.ImageSize`
+ + `Text.Pandoc.Highlighting`
+`
+ * New module `Text.Pandoc.Extensions` (Albert Krewinkel):
+ Extension parsing and processing functions were defined in the top-level
+ `Text.Pandoc` module. These functions are moved to the Extensions
+ submodule as to enable reuse in other submodules.
+
+ * Add `Ext_raw_attribute` constructor for `Extension`.
+
+ * Add `Ext_fenced_divs` constructor for `Extension'.
+
+ * Add `Ext_four_space_rule` constructor in `Extension`.
+
+ * Add `Ext_gfm_auto_identifiers` constructor for `Extension`.
+
+ * Add `Monoid` instance for `Extensions`.
+
+ * Add `Text.Pandoc.Writers.Ms`, exporting `writeMs`.
+
+ * Add `Text.Pandoc.Writers.JATS`, exporting `writeJATS`.
+
+ * Add `Text.Pandoc.Writers.Muse`, exporting `writeMuse`.
+
+ * Add `Text.Pandoc.Readers.Muse`, exporting `readMuse`.
+
+ * Add `Text.Pandoc.Readers.TikiWiki`, exporting `readTikiWiki`.
+
+ * Add `Text.Pandoc.Readers.Vimwiki`, exporting `readVimwiki`.
+
+ * Add `Text.Pandoc.Readers.Creole`, exporting `readCreole`.
+
+ * Export `setVerbosity` from `Text.Pandoc`.
+
+ * `Text.Pandoc.Pretty`: Add `Eq` instance for `Doc`.
+
+ * `Text.Pandoc.XML`: `toEntities`: changed type to `Text -> Text`.
+
+ * `Text.Pandoc.UTF8`:
+
+ + Export `fromText`, `fromTextLazy`, `toText`, `toTextLazy`.
+ Define `toString`, `toStringLazy` in terms of them.
+ + Add new functions parameterized on `Newline`: `writeFileWith`,
+ `putStrWith`, `putStrLnWith`, `hPutStrWith`, `hPutStrLnWith`.
+
+ * `Text.Pandoc.MediaBag`: removed `extractMediaBag`.
+
+ * `Text.Pandoc.Highlighting`:
+
+ + `highlighting` now returns an Either rather than Maybe.
+ This allows us to display error information returned by the skylighting
+ library. Display a warning if the highlighting library throws an error.
+ + Add parameter for `SyntaxMap` to `highlight`.
+
+ * `Text.Pandoc.Writers.Math`:
+
+ + Export `defaultMathJaxURL`, `defaultKaTeXURL`. This will ensure that
+ we only need to update these in one place.
+
+ * `Text.Pandoc.SelfContained`:
+
+ + Removed `WriterOptions` parameter from `makeSelfContained`.
+ + Put `makeSelfContained` in PandocMonad instead of IO. This removes
+ the need to pass MediaBag around and improves exceptions. It also
+ opens up the possibility of using makeSelfContained purely.
+ + Export `makeDataURI`.
+
+ * `Text.Pandoc.ImageSize`:
+
+ + Export `lengthToDim`, new function `scaleDimension`.
+ + Export `inEm` from ImageSize (#3450).
+ + Change `showFl` and `show` instance for `Dimension` so
+ extra decimal places are omitted.
+ + Added `Em` as a constructor of `Dimension`.
+ + Add `WriterOptions` parameter to `imageSize` signature (Mauro Bieg).
+
+ * `Text.Pandoc.Templates`:
+
+ + Change type of `renderTemplate'`. Now it runs in `PandocMonad`
+ and raises a proper `PandocTemplateError` if there are problems, rather
+ than failing with uncatchable `error`.
+ + Change signature of `getDefaultTemplate`. Now it runs in any instance
+ of `PandocMonad`, and returns a `String` rather than an `Either` value.
+ And it no longer takes a `datadir` parameter, since this can be
+ retrieved from `CommonState`.
+
+ * `Text.Pandoc.Options`:
+
+ + Added `writerEpubSubdirectory` to `WriterOptions` (#3720).
+ The EPUB writer now takes its EPUB subdirectory from this option.
+ + In `WriterOptions`, rename `writerLaTeXEngine` to `writerPdfEngine`
+ and `writerLaTeXArgs` to `writerPdfArgs` (Mauro Bieg, #3909).
+ + Add `writerSyntaxMap` to `WriterOptions`.
+ + Removed `writerEpubStylesheet` from `WriterOptions`.
+ + Remove `writerUserDataDir` from `WriterOptions`. It is now carried
+ in `CommonState` in `PandocMonad` instances. (And thus it can be used
+ by readers too.)
+ + Changed `writerEpubMetadata` to a `Maybe String`.
+ + Removed `readerApplyMacros` from `ReaderOptions`. Now we just check
+ the `latex_macros` reader extension.
+ + FromJSON/ToJSON instances for `ReaderOptions`.
+ + In `HTMLMathMethod`, the `KaTeX` contsructor now takes only
+ one string (for the KaTeX base URL), rather than two.
+ + Removed `writerSourceURL` from `WriterOptions`. We now use
+ `stSourceURL` in `CommonState`, which is set by `setInputFiles`.
+
+ * `Text.Pandoc.Shared`:
+
+ + `tabFilter` now takes a `Text`, not `String`.
+ + `openURL`: Changed type from an Either. Now it will just raise
+ an exception to be trapped later.
+ + Remove `normalizeSpaces` (#1530).
+ + Remove `warn`. (Use `report` from `Text.Pandoc.Class` instead.)
+ + Export a new function `crFilter`.
+ + Add `eastAsianLineBreakFilter` (previously in Markdown reader).
+ + Provide custom `isURI` that rejects unknown schemes.
+ (Albert Krewinkel, #2713). We also export the set of known
+ `schemes`. The new function replaces the function of the same name
+ from `Network.URI`, as the latter did not check whether a scheme is
+ well-known. All official IANA schemes (as of 2017-05-22) are
+ included in the set of known schemes. The four non-official schemes
+ `doi`, `isbn`, `javascript`, and `pmid` are kept.
+ + Remove `err`.
+ + Remove `readDataFile`, `readDefaultDataFile`, `getReferenceDocx`,
+ `getReferenceODT`. These now live in `Text.Pandoc.Class`,
+ where they are defined in terms of `PandocMonad`
+ primitives and have different signatures.
+ + Remove `openURL`. Use `openURL` from `Text.Pandoc.Class` instead.
+ + Add `underlineSpan`.
+
+ * `Text.Pandoc.Readers.HTML`: export new `NamedTag` class.
+
+ * `Text.Pandoc.Readers.Markdown`: remove `readDocxWithWarnings`.
+ With the new API one can simply use `getLog` after running
+ the reader.
+
+ * `Text.Pandoc.Readers.LaTeX`: Changed types for `rawLaTeXInline`
+ and `rawLaTeXBlock`. (Both now return a `String`, and they are
+ polymorphic in state.)
+
+
+ [bug fixes and under-the-hood improvements]
+
+ * TEI writer: Added identifiers on `<div>` elements.
+
+ * DokuWiki reader: Better handling for code block in list item (#3824).
+
+ * Custom writer: Remove old preprocesesor conditionals (Albert Krewinkel).
+
+ * ZimWiki writer: Removed internal formatting from note and table cells,
+ because ZimWiki does not support it (Alex Ivkin, #3446).
+
+ * MediaWiki writer:
+
+ + Updated list of syntax highlighting languages (#3461).
+ Now `r` gets you `<source>` rather than `<code>` (among others).
+ + Add display attribute on `<math>` tags (#3452). This allows display
+ math to be rendered properly.
+ + Remove newline before `</ref>` (#2652).
+ + Don't softbreak lines inside list items (#3531).
+
+ * Org writer:
+
+ + Reduce to two spaces after bullets (#3417, Albert Krewinkel).
+ + Add unit tests (Alexander Krotov).
+ + Stop using raw HTML to wrap divs (Albert Krewinkel, #3771).
+ + Do not strip `#` from Org anchor links (Alexander Krotov).
+
+ * CommonMark writer:
+
+ + Avoid excess blank lines at end of output.
+ + Prefer pipe tables to HTML tables even if it means losing relative
+ column width information (#3734).
+ + Support table, strikethrough extensions, when enabled (as with gfm).
+ Note that we bypass the commonmark writer from cmark and construct our
+ own pipe tables, with better results.
+ + Properly support `--wrap=none`.
+ + Use smallcaps class for `SmallCaps` (#1592).
+ + Omit "fig:" prefix in image titles. This is used internally to
+ indicate internal figures.
+
+ * RST writer:
+
+ + Properly handle table captions.
+ + Don't wrap lines in in definition list terms. Wrapping is not allowed.
+ + Implemented `+/-smart` and improved escaping with `+smart`.
+ + Add empty comments when needed to avoid including a blockquote
+ in the indented content of a preceding block (#3675).
+ + Improve grid table output, fix bug with empty rows (#3516).
+ Uses the new `gridTable` in Writers.Shared, which is here
+ improved to better handle 0-width cells.
+ + Remove space at beginning/end of RST code span (#3496). Otherwise
+ we get invalid RST. There seems to be no way to escape the space.
+ + Add header anchors when header has non-standard id (#3937).
+ + Correctly handle inline code containing backticks, using a `:literal:`
+ role (#3974).
+ + Don't backslash-escape word-internal punctuation (#3978).
+
+ * Markdown writer:
+
+ + Don't include variables in metadata blocks. Previously variables set
+ on the command line were included in e.g. YAML metadata, contrary to
+ documentation and intentions.
+ + Improved escaping with `+smart`.
+ + Fixed grid tables embedded in grid tables (#2834).
+ + Use span with class 'smallcaps' for SmallCaps, instead of a style
+ attribute as before (#1592).
+ + Escape initial `%` in a paragraph if the `pandoc_title_blocks`
+ extension is enabled (#3454). Otherwise in a document starting with
+ a literal `%` the first line is wrongly interpreted as a title.
+ + Fixed false ordered lists in YAML metadata (#3492, #1685). Now we
+ properly escape things that would otherwise start ordered lists,
+ such as
+
+ ---
+ title: 1. inline
+ ...
+ + Better handling of tables with empty columns (#3337). We now
+ calculate the number of columns based on the longest row (or the
+ length of aligns or widths).
+ + Escape unordered list markers at beginning of paragraph (#3497), to
+ avoid false interpretation as a list.
+ + Escape `|` appropriately.
+ + Ensure space before list at top level (#3487).
+ + Avoid spurious blanklines at end of document after tables and list,
+ for example.
+ + Fixed bugs in simple/multiline list output (#3384).
+ Previously we got overlong lists with `--wrap=none`. This is fixed.
+ Previously a multiline list could become a simple list (and would
+ always become one with `--wrap=none`).
+ + Don't emit a simple table if `simple_tables` disabled (#3529).
+ + Case-insensitive reference links (David A Roberts, #3616).
+ Ensure that we do not generate reference links whose labels differ only
+ by case. Also allow implicit reference links when the link
+ text and label are identical up to case.
+ + Put space before reference link definitions (Mauro Bieg, #3630).
+ + Better escaping for links (David A. Roberts, #3619). Previously the
+ Markdown writer would sometimes create links where there were none
+ in the source. This is now avoided by selectively escaping bracket
+ characters when they occur in a place where a link might be created.
+ + Added missing `\n` (David A. Roberts, #3647).
+ + Fixed duplicated reference links with `--reference-links`
+ and `--reference-location=section` (#3674). Also ensure that there
+ are no empty link references `[]`.
+ + Avoid inline surround-marking with empty content (#3715).
+ E.g. we don't want `<strong></strong>` to become `****`.
+ Similarly for emphasis, super/subscript, strikeout.
+ + Don't allow soft break in header (#3736).
+ + Make sure `plain`, `markdown_github`, etc. work for raw.
+ Previously only `markdown` worked. Note: currently a raw block labeled
+ `markdown_github` will be printed for any `markdown` format.
+ + Ensure that `+` and `-` are escaped properly so they don't cause
+ spurious lists (#3773). Previously they were only
+ if succeeded by a space, not if they were at end of line.
+ + Use pipe tables if `raw_html` disabled and `pipe_tables` enabled,
+ even if the table has relative width information (#3734).
+ + Markdown writer: don't crash on `Str ""`.
+ + Make `Span` with null attribute transparent. That is, we don't use
+ brackets or `<span>` tags to mark spans when there are no attributes;
+ we simply output the contents.
+ + Escape pipe characters when `pipe_tables` enabled (#3887).
+ + Better escaping of `<` and `>`. If `all_symbols_escapable` is set,
+ we backslash escape these. Otherwise we use entities as before.
+ + When writing plain, don't use `&nbsp;` to separate list and indented
+ code. There's no need for it in this context, since this isn't to be
+ interpreted using Markdown rules.
+ + Preserve classes in JS obfuscated links (Timm Albers, #2989).
+ HTML links containing classes originally now preserve them when using
+ JavaScript email obfuscation.
+ + Render `SmallCaps` as a native span when `native_spans` are enabled.
+ + Always write attributes with `bracketed_spans` (d-dorazio).
+
+ * Man writer:
+
+ + Fix handling of nested font commands (#3568). Previously pandoc emitted
+ incorrect markup for bold + italic, for example, or bold + code.
+ + Avoid error for definition lists with no definitions (#3832).
+
+ * DocBook writer:
+
+ + Fix internal links with `writerIdentifierPrefix opt`
+ (#3397, Mauro Bieg).
+
+ * Docx writer:
+
+ + Don't include bookmarks on headers unless non-null id (#3476).
+ + Support 9 levels of headers (#1642).
+ + Allow 9 list levels (#3519).
+ + Don't take `distArchive` from datadir (#3322). The docx writer takes
+ components from the distribution's version of `reference.docx` when it
+ can't find them in a user's custom `reference.docx`. Previously, we
+ allowed a `reference.docx` in the data directory (e.g. `~/.pandoc`)
+ to be used as the distribution's reference.docx. This led to a
+ bizarre situation where pandoc would produce a good docx using
+ `--template ~/.pandoc/ref.docx`, but if `ref.docx` were moved to
+ `~/.pandoc/reference.docx`, it would then produce a corrupted docx.
+ + Fixed handling of soft hyphen (0173) (#3691).
+ + Better handling of keywords (#3719).
+ + Cleaner code for handling dir and style attributes for `Div`.
+ + Use `Set` for dynamic styles to avoid duplicates.
+ + Removed redundant element from data/docx/word/numbering.xml.
+ The elements we need are generated when the document is
+ compiled; this didn't do anything.
+ + Activate `evenAndOddHeaders` from reference docx (#3901,
+ Augustín Martín Barbero).
+
+ * ODT/OpenDocument writer:
+
+ + Calculate aspect ratio for percentage-sized images (Mauro Bieg, #3239).
+ + Use more widely available bullet characters (#1400). The old
+ characters weren't available in some font sets. These seem to work
+ well on Windows and Linux versions of LibreOffice.
+ + Wider labels for lists (#2421). This avoids overly narrow labels for
+ ordered lists with `()` delimiters. However, arguably it creates
+ overly wide labels for bullets. Also, lists now start flush with
+ the margin, rather than indented.
+ + Fixed dropped elements in some ordered lists (#2434).
+
+ * FB2 writer:
+
+ + Don't render `RawBlock` as code.
+ + Don't fail with an error on interior headers (e.g. in list) (#3750).
+ Instead, omit them with an INFO message.
+ + Add support for "lang" metadata (Alexander Krotov, #3625).
+ + Format `LineBlock` as poem (Alexander Krotov). Previously writer
+ produced one paragraph with `<empty-line/>` elements, which are not
+ allowed inside `<p>` according to FB2 schema.
+ + Replace `concatMap` with `cMap` (Alexander Krotov).
+ + Write FB2 lists without nesting blocks inside `<p>` (Alexander
+ Krotov, #4004)
+
+ * HTML writer:
+
+ + Make sure `html4`, `html5` formats work for raw blocks/inlines.
+ + Render raw inline environments when `--mathjax` used (#3816).
+ We previously did this only with raw blocks, on the assumption
+ that math environments would always be raw blocks. This has changed
+ since we now parse them as inline environments.
+ + Ensure we don't get two style attributes for width and height.
+ + Report when not rendering raw inline/block.
+ + Issue warning if no title specified and template used (#3473).
+ + Info message if `lang` is unspecified (#3486).
+ + Removed unused parameter in `dimensionsToAttributeList`.
+ + Avoid two class attributes when adding `uri` class (#3716).
+ + Fix internal links with `writerIdentifierPrefix opt` (#3397, Mauro
+ Bieg).
+ + Use revealjs's math plugin for mathjax (#3743). This is a thin
+ wrapper around mathjax that makes math look better on revealjs.
+ + Slidy: use h1 for all slides, even if they were originally
+ level 2 headers (#3566). Otherwise the built-in table of contents
+ in Slidy breaks.
+
+ * LaTeX writer:
+
+ + Don't render LaTeX images with data: URIs (#3636). Note that
+ `--extract-media` can be used when the input contains data: URIs.
+ + Make highlighted code blocks work in footnotes (Timm Albers).
+ + Don't use figure inside table cell (#3836).
+ + Use proper code for list enumerators (#3891). This should fix problems
+ with lists that don't use arabic numerals.
+ + Always add hypertarget when there's a non-empty identifier (#2719).
+ Previously the hypertargets were only added when there was actually
+ a link to that identifier.
+ + Use `%` after hypertarget before code block.
+ + Add `\leavevmode` before hypertarget at start of paragraph (#2704,
+ fixes formatting problems in beamer citations).
+ + Don't use `lstinline` in \item[..] (#645). If you do, the contents
+ of item disappear or are misplaced. Use `\texttt` instead.
+ + Fix problem with escaping in `lstinline` (#1629). Previously the
+ LaTeX writer created invalid LaTeX when `--listings` was specified and
+ a code span occured inside emphasis or another construction.
+ + Fix error with line breaks after empty content (#2874). LaTeX
+ requires something before a line break, so we insert a `~` if no
+ printable content has yet been emitted.
+ + Use BCP47 parser.
+ + Fixed detection of otherlangs (#3770). We weren't recursing into
+ inline contexts.
+ + Handle language in inline code with `--listings` (#3422).
+ + Write euro symbol directly in LaTeX (Andrew Dunning, #3801).
+ The textcomp package allows pdfLaTeX to parse `€` directly, making the
+ `\euro` command unneeded.
+ + Fixed footnotes in table captions (#2378). Note that if the table has
+ a first page header and a continuation page header, the notes will
+ appear only on the first occurrence of the header.
+ + In `writeBeamer` output, allow hyperlinks to frames (#3220).
+ Previously you could link to a header above or below slide level but
+ not *to* slide level. This commit changes that. Hypertargets are
+ inserted inside frame titles; technically the reference is to just
+ after the title, but in normal use (where slides are viewed full
+ screen in a slide show), this does not matter.
+ + Remove `\strut` at beginning of table cells (#3436). This fixes a
+ problem with alignment of lists in table cells. The `\strut` at the
+ end seems to be enough to avoid the too-close spacing that motivated
+ addition of the strut in #1573.
+ + Add partial siunitx Support (Marc Schreiber, #3588).
+
+ * ConTeXt writer:
+
+ + Refactored to use BCP47 module.
+ + Remove unnecessary `$` (Alexander Krotov, #3482).
+ + Use header identifiers for chapters (#3968).
+
+ * EPUB writer:
+
+ + `title_page.xhtml` is now put in `text/`.
+ + Don't strip formatting in TOC (#1611).
+
+ * Textile reader:
+
+ + Fix bug for certain links in table cells (#3667).
+ + Allow 'pre' code in list item (#3916).
+
+ * HTML reader:
+
+ + Added warnings for ignored material (#3392).
+ + Better sanity checks to avoid parsing unintended things as
+ raw HTML in the Markdown reader (#3257).
+ + Revise treatment of `li` with `id` attribute (#3596). Previously we
+ always added an empty div before the list item, but this created
+ problems with spacing in tight lists. Now we do this: If the list
+ item contents begin with a `Plain` block, we modify the `Plain`
+ block by adding a `Span` around its contents. Otherwise, we add a
+ `Div` around the contents of the list item (instead of adding an
+ empty `Div` to the beginning, as before).
+ + Add `details` tag to list of block tags (#3694).
+ + Removed `button` from block tag list (#3717). It is already in the
+ `eitherBlockOrInlineTag` list, and should be both places.
+ + Use `Set`s instead of lists for block tag lookup.
+ + Rewrote to use `Text` throughout. Effect on memory usage is modest
+ (< 10%).
+ + Use the lang value of `<html>` to set the lang meta value (bucklereed,
+ #3765).
+ + Ensure that paragraphs are closed properly when the parent block
+ element closes, even without `</p>` (#3794).
+ + Parse `<figure>` and `<figcaption>` (Mauro Bieg, #3813).
+ + Parse `<main>` like `<div role=main>` (bucklereed, #3791).
+ `<main>` closes `<p>` and behaves like a block element generally
+ + Support column alignments (#1881). These can be set either
+ with a `width` attribute or with `text-width` in a `style` attribute.
+ + Modified state type to be an instance of `HasLogMessages`, so
+ `registerHeader` can issue warnings.
+ + `</td>` or `</th>` should close any open block tag (#3991).
+ + `<td>` should close an open `<th>` or `<td>`.
+ + `htmlTag` improvements (#3989). We previously failed on cases
+ where an attribute contained a `>` character. This patch fixes the
+ bug, which especially affects raw HTML in Markdown.
+
+ * Txt2Tags reader:
+
+ + Newline is not indentation (Alexander Krotov).
+
+ * MediaWiki reader:
+
+ + Allow extra hyphens after `|-` in tables (#2649).
+ + Allow blank line after table start (#2649).
+ + Fixed more table issues (#2649).
+ + Ensure that list starts begin at left margin (#2606). Including when
+ they're in tables or other list items.
+ + Make smart double quotes depend on `smart` extension (#3585).
+ + Don't do curly quotes inside `<tt>` contexts (#3585). Even if `+smart`.
+ + Modified state type to be an instance of `HasLogMessages`, so
+ `registerHeader` can issue warnings.
+
+ * TWiki reader (Alexander Krotov):
+
+ + Remove unnecessary `$` (#3597).
+ + Simplify `linkText` (#3605).
+
+ * EPUB reader:
+
+ + Minor refactoring, avoiding explicit MediaBag handling.
+ This all works behind the scenes in CommonState plumbing.
+
+ * Docx reader:
+
+ + Don't drop smartTag contents (#2242).
+ + Handle local namespace declarations (#3365). Previously we didn't
+ recognize math, for example, when the xmlns declaration occured on
+ the element and not the root.
+ + More efficient trimSps (#1530). Replacing `trimLineBreaks`. This
+ does the work of `normalizeSpaces` as well, so we avoid the need for
+ that function here.
+ + Avoid 0-level headers (Jesse Rosenthal, #3830). We used to parse
+ paragraphs styled with "HeadingN" as "nth-level header." But if a
+ document has a custom style named "Heading0", this will produce a
+ 0-level header, which shouldn't exist. We only parse this style
+ if N>0. Otherwise we treat it as a normal style name, and
+ follow its dependencies, if any.
+ + Add tests for avoiding zero-level header (Jesse Rosenthal).
+
+ * ODT reader:
+
+ + Replaced `collectRights` with Rights from `Data.Either`.
+ + Remove dead code (Albert Krewinkel).
+
+ * Org reader (Albert Krewinkel, unless noted).
+
+ + Don't allow tables inside list items (John MacFarlane, #3499).
+ + Disallow tables on list marker lines (#3499).
+ + Convert markup at beginning of footnotes (John MacFarlane, #3576).
+ + Allow emphasized text to be followed by `[` (#3577).
+ + Handle line numbering switch for src blocks.
+ The line-numbering switch that can be given to source blocks (`-n` with
+ an start number as an optional parameter) is parsed and translated to a
+ class/key-value combination used by highlighting and other readers and
+ writers.
+ + Stop adding rundoc prefix to src params. Source block parameter names
+ are no longer prefixed with `rundoc`. This was intended to simplify
+ working with the rundoc project, a babel runner. However, the rundoc
+ project is unmaintained, and adding those markers is not the reader's
+ job anyway. The original language that is specified for a source
+ element is now retained as the `data-org-language` attribute and only
+ added if it differs from the translated language.
+ + Allow multi-word arguments to src block params (#3477). The reader now
+ correctly parses src block parameter list even if parameter arguments
+ contain multiple words.
+ + Avoid creating `nullMeta` by applying `setMeta` directly
+ (Alexander Krotov).
+ + Replace `sequence . map` with `mapM`.
+ + Fix smart parsing behavior. Parsing of smart quotes and special
+ characters can either be enabled via the `smart` language extension or
+ the `'` and `-` export options. Smart parsing is active if either the
+ extension or export option is enabled. Only smart parsing of special
+ characters (like ellipses and en and em dashes) is enabled by default,
+ while smart quotes are disabled. Previously, all smart parsing was
+ disabled unless the language extension was enabled.
+ + Subject full doc tree to headline transformations (Albert Krewinkel,
+ #3695). Emacs parses org documents into a tree structure, which is
+ then post-processed during exporting. The reader is changed to do the
+ same, turning the document into a single tree of headlines starting
+ at level 0.
+ + Fix cite parsing behaviour (Herwig Stuetz). Until now, `org-ref`
+ cite keys included special characters also at the end. This caused
+ problems when citations occur right before colons or at the end of
+ a sentence. With this change, all non alphanumeric characters at
+ the end of a cite key are ignored. This also adds `,` to the list
+ of special characters that are legal in cite keys to better mirror
+ the behaviour of org-export.
+ + Fix module names in haddock comments. Copy-pasting had lead to
+ haddock module descriptions containing the wrong module names.
+ + Recognize babel result blocks with attributes (#3706). Babel
+ result blocks can have block attributes like captions and names.
+ Result blocks with attributes were not recognized and were parsed
+ as normal blocks without attributes.
+ + Include tags in headlines. The Emacs default is to include tags in the
+ headline when exporting. Instead of just empty spans, which contain the
+ tag name as attribute, tags are rendered as small caps and wrapped in
+ those spans. Non-breaking spaces serve as separators for multiple tags.
+ + Respect export option for tags (#3713). Tags are appended to
+ headlines by default, but will be omitted when the `tags` export option
+ is set to nil.
+ + Use `tag-name` attribute instead of `data-tag-name`.
+ + Use `org-language` attribute rather than `data-org-language`.
+ + Modified state type to be an instance of `HasLogMessages`, so
+ `registerHeader` can issue warnings.
+ + End footnotes after two blank lines. Footnotes can not only be
+ terminated by the start of a new footnote or a header, but also by two
+ consecutive blank lines.
+ + Update emphasis border chars (#3933). The org reader was updated to
+ match current org-mode behavior: the set of characters which are
+ acceptable to occur as the first or last character in an org emphasis
+ have been changed and now allows all non-whitespace chars at the
+ inner border of emphasized text (see `org-emphasis-regexp-components`).
+
+ * RST reader:
+
+ + Fixed small bug in list parsing (#3432). Previously the parser didn't
+ handle properly this case:
+
+ * - a
+ - b
+ * - c
+ - d
+ + Handle multiline cells in simple tables (#1166).
+ + Parse list table directive (Keiichiro Shikano, #3432).
+ + Make use of `anyLineNewline` (Alexander Krotov, #3686).
+ + Use `anyLineNewline` in `rawListItem` (Alexander Krotov, #3702).
+ + Reorganize block parsers for ~20% faster parsing.
+ + Fixed `..include::` directive (#3880).
+ + Handle blank lines correctly in line blocks (Alexander Krotov, #3881).
+ Previously pandoc would sometimes combine two line blocks separated
+ by blanks, and ignore trailing blank lines within the line block.
+ + Fix indirect hyperlink targets (#512).
+
+ * Markdown reader:
+
+ + Allow attributes in reference links to start on next line (#3674).
+ + Parse YAML metadata in a context that sees footnotes defined in
+ the body of the document (#1279).
+ + When splitting pipe table cells, skip tex math (#3481).
+ You might have a `|` character inside math. (Or for that matter
+ something that the parser might mistake for raw HTML.)
+ + Treat span with class `smallcaps` as SmallCaps.
+ This allows users to specify small caps in Markdown this way:
+ `[my text]{.smallcaps}` (#1592).
+ + Fixed internal header links (#2397).
+ This patch also adds `shortcut_reference_links` to the list
+ of mmd extensions.
+ + Treat certain environments as inline
+ when they occur without space surrounding them (#3309, #2171).
+ E.g. equation, math. This avoids incorrect vertical space
+ around equations.
+ + Optimized `nonindentSpaces`. Makes the benchmark go from 40 to 36 ms.
+ + Allow latex macro definitions indented 1-3 spaces.
+ Previously they only worked if nonindented.
+ + Improved parsing of indented raw HTML blocks (#1841).
+ Previously we inadvertently interpreted indented HTML as
+ code blocks. This was a regression. We now seek to determine the
+ indentation level of the contents of an HTML block, and (optionally)
+ skip that much indentation. As a side effect, indentation may be
+ stripped off of raw HTML blocks, if `markdown_in_html_blocks` is
+ used. This is better than having things interpreted as indented
+ code blocks.
+ + Fixed smart quotes after emphasis (#2228). E.g. in `*foo*'s 'foo'`.
+ + Warn for notes defined but not used (#1718).
+ + Use `anyLineNewline` (Alexander Krotov).
+ + Interpret YAML metadata as Inlines when possible (#3755). If
+ the metadata field is all on one line, we try to interpret it as
+ Inlines, and only try parsing as Blocks if that fails. If it
+ extends over one line (including possibly the `|` or `>` character
+ signaling an indented block), then we parse as Blocks. This was
+ motivated by some German users finding that `date: '22. Juin 2017'`
+ got parsed as an ordered list.
+ + Fixed spurious parsing as citation as reference def (#3840).
+ We now disallow reference keys starting with `@` if the
+ `citations` extension is enabled.
+ + Parse `-@roe` as suppress-author citation (pandoc-citeproc#237).
+ Previously only `[-@roe]` (with brackets) was recognized as
+ suppress-author, and `-@roe` was treated the same as `@roe`.
+ + Fixed parsing of fenced code after list when there is no intervening
+ blank line (#3733).
+ + Allow raw latex commands starting with `\start` (#3558). Previously
+ these weren't allowed because they were interpreted as starting
+ ConTeXt environments, even without a corresponding `\stop`...
+ + Added `inlines`, `inlines1`.
+ + Require nonempty alt text for `implicit_figures` (#2844).
+ A figure with an empty caption doesn't make sense.
+ + Removed texmath macro material; now all this is handled
+ in the LaTeX reader functions.
+ + Fixed bug with indented code following raw LaTeX (#3947).
+
+ * LaTeX reader:
+
+ + Rewrote LaTeX reader with proper tokenization (#1390,
+ #2118, #3236, #3779, #934, #982). This rewrite is primarily
+ motivated by the need to get macros working properly. A side benefit
+ is that the reader is significantly faster. We now tokenize the
+ input text, then parse the token stream. Macros modify the token
+ stream, so they should now be effective in any context, including
+ math. Thus, we no longer need the clunky macro processing
+ capacities of texmath.
+ + Parse `\,` to `\8198` (six-per-em space) (Henri Werth).
+ + Allow `\newcommand\foo{blah}` without braces.
+ + Support `\lstinputlisting` (#2116).
+ + Issue warnings when skipping unknown latex commands (#3392).
+ + Include contents of `\parbox`.
+ + Allow `\hspace` and `\vspace` to count as raw block or inline.
+ Previously we would refuse to parse anything as raw inline if
+ it was in the `blockCommands` list. Now we allow exceptions
+ if they're listed under ignoreInlines in inlineCommands.
+ This should make it easier e.g. to include an `\hspace`
+ between two side-by-side raw LaTeX tables.
+ + Don't drop contents of `\hypertarget`.
+ + Handle spaces before `\cite` arguments.
+ + Allow newpage, clearpage, pagebreak in inline contexts as well as
+ block contexts (#3494).
+ + Treat `{{xxx}}` the same as `{xxx}` (#2115).
+ + Use `pMacroDefinition` in macro (for more direct parsing).
+ Note that this means that `macro` will now parse one
+ macro at a time, rather than parsing a whole group together.
+ + Fixed failures on \ref{}, \label{} with `+raw_tex`. Now these
+ commands are parsed as raw if `+raw_tex`; otherwise, their argument
+ is parsed as a bracketed string.
+ + Don't crash on empty `enumerate` environment (#3707).
+ + Handle escaped `&` inside table cell (#3708).
+ + Handle block structure inside table cells (#3709). `minipage` is no
+ longer required.
+ + Handle some width specifiers on table columns (#3709). Currently
+ we only handle the form `0.9\linewidth`. Anything else would have
+ to be converted to a percentage, using some kind arbitrary assumptions
+ about line widths.
+ + Make sure `\write18` is parsed as raw LaTeX. The change is in the
+ LaTeX reader's treatment of raw commands, but it also affects the
+ Markdown reader.
+ + Fixed regression with starred environment names (#3803).
+ + Handle optional args in raw `\titleformat` (#3804).
+ + Improved heuristic for raw block/inline. An unknown command at the
+ beginning of the line that could be either block or inline is
+ treated as block if we have a sequence of block commands followed by
+ a newline or a `\startXXX` command (which might start a raw ConTeXt
+ environment).
+ + Don't remove macro definitions from the output, even if
+ `Ext_latex_macros` is set, so that macros will be applied.
+ Since they're only applied to math in Markdown, removing the macros
+ can have bad effects. Even for math macros, keeping them should be
+ harmless.
+ + Removed `macro`. It is no longer necessary, since the
+ `rawLaTeXBlock` parser will parse macro definitions. This also avoids
+ the need for a separate `latexMacro` parser in the Markdown reader.
+ + Use `label` instead of `data-label` for label in caption (#3639).
+ + Fixed space after \figurename etc.
+ + Resolve references to section numbers.
+ + Fix `\let\a=0` case, with single character token.
+ + Allow `@` as a letter in control sequences. `@` is commonly used
+ in macros using `\makeatletter`. Ideally we'd make the tokenizer
+ sensitive to `\makeatletter` and `\makeatother`, but until then this
+ seems a good change.
+ + Track header numbers and correlate with labels.
+ + Allow `]` inside group in option brackets (#3857).
+ + lstinline with braces can be used (verb cannot be used with braces)
+ (Marc Schreiber, #3535).
+ + Fix keyval funtion: pandoc did not parse options in braces correctly
+ (Marc Schreiber, #3642).
+ + When parsing raw LaTeX commands, include trailing space (#1773).
+ Otherwise things like `\noindent foo` break and turn into
+ `\noindentfoo`. Affects `-f latex+raw_tex` and `-f markdown` (and other
+ formats that allow `raw_tex`).
+ + Don't treat "..." as Quoted (#3958). This caused quotes to be omitted in
+ `\texttt` contexts.
+ + Add tests for existing `\includegraphics` behaviour (Ben Firshman).
+ + Allow space before `=` in bracketd options (Ben Firshman).
+ + Be more forgiving in parsing command options. This was needed, for
+ example, to make some minted options work.
+ + Strip off quotes in `\include` filenames.
+
+ * Added `Text.Pandoc.CSV`, simple (unexported) CSV parser.
+
+ * `Text.Pandoc.PDF`:
+
+ + Got `--resource-path` working with PDF output (#852).
+ + Fetch images when generating PDF via context (#3380).
+ To do this, we create the temp directory as a subdirectory
+ of the working directory. Since context mk IV by default looks
+ for images in the parent directory, this works.
+ + Use `report` instead of `warn`, make it sensitive to verbosity settings.
+ + Use `fillMediaBag` and `extractMedia` to extract media to temp dir.
+ This reduces code duplication.
+ + `html2pdf`: use stdin instead of intermediate HTML file
+ + Removed useless `TEXINPUTS` stuff for `context2pdf`. mkiv context
+ doesn't use `TEXINPUTS`.
+
+ * `Text.Pandoc.Pretty`:
+
+ + Simplified definition of `realLength`.
+ + Don't error for blocks of size < 1. Instead, resize to 1 (see #1785).
+
+ * `Text.Pandoc.MIME`:
+
+ + Use `application/javascript` (not `application/x-javascript`).
+ + Added `emf` to mimeTypes with type `application/x-msmetafile` (#1713).
+
+ * `Text.Pandoc.ImageSize`:
+
+ + Improve SVG image size code (Marc Schreiber, #3580).
+ + Make `imageSize` recognize basic SVG dimensions (Mauro Bieg, #3462).
+
+ * Use `Control.Monad.State.Strict` throughout. This gives 20-30% speedup
+ and reduction of memory usage in most of the writers.
+
+ * Use `foldrWithKey` instead of deprecated `foldWithKey`.
+
+ * `Text.Pandoc.SelfContained`:
+
+ + Fixed problem with embedded fonts (#3629).
+ + Refactored getData from `getDataURI` in `SelfContained`.
+ + Don't use data URIs for script or style (#3423). Instead, just use
+ script or style tags with the content inside. The old method with
+ data URIs prevents certain optimizations outside pandoc. Exception:
+ data URIs are still used when a script contains `</script>` or a
+ style contains `</`.
+ + SelfContained: Handle URL inside material retrieved from a URL
+ (#3629). This can happen e.g. with an @import of a google web font.
+ (What is imported is some CSS which contains an url reference
+ to the font itself.) Also, allow unescaped pipe (|) in URL.
+ + Load resources from `data-src` (needed for lazy loading in
+ reveal.js slide shows).
+ + Handle `data-background-image` attribute on section (#3979).
+
+ * `Text.Pandoc.Parsing`:
+
+ + Added `indentWith` (Alexander Krotov, #3687).
+ + Added `stateCitations` to `ParserState`.
+ + Removed `stateChapters` from `ParserState`.
+ + In `ParserState`, make `stateNotes'` a Map, add `stateNoteRefs`.
+ + Added `gobbleSpaces` and `gobbleAtMostSpaces`.
+ + Adjusted type of `insertIncludedFile` so it can be used with token
+ parser.
+ + Replace old texmath macro stuff from Parsing. Use Macro from
+ Text.Pandoc.Readers.LaTeX.Types instead.
+ + Export `insertIncludedFile`.
+ + Added `HasLogMessages`, `logMessage`, `reportLogMessages` (#3447).
+ + Replace partial with total function (Albert Krewinkel).
+ + Introduce `HasIncludeFiles` type class (Albert Krewinkel). The
+ `insertIncludeFile` function is generalized to work with all parser
+ states which are instances of that class.
+ + Add `insertIncludedFilesF` which returns F blocks (Albert Krewinkel).
+ The `insertIncludeFiles` function was generalized and renamed
+ to `insertIncludedFiles'`; the specialized versions are based on that.
+ + `many1Till`: Check for the end condition before parsing (Herwig
+ Stuetz). By not checking for the end condition before the first
+ parse, the parser was applied too often, consuming too much of the
+ input. This only affects `many1Till p end` where `p` matches on a
+ prefix of `end`.
+ + Provide `parseFromString` (#3690). This is a verison of
+ `parseFromString` specialied to ParserState, which resets
+ `stateLastStrPos` at the end. This is almost always what we want.
+ This fixes a bug where `_hi_` wasn't treated as emphasis in the
+ following, because pandoc got confused about the position of the
+ last word: `- [o] _hi_`.
+ + Added `takeP`, `takeWhileP` for efficient parsing of `[Char]`.
+ + Fix `blanklines` documentation (Alexander Krotov, #3843).
+ + Give less misleading line information with `parseWithString`.
+ Previously positions would be reported past the end of the chunk.
+ We now reset the source position within the chunk and report
+ positions "in chunk."
+ + Add `anyLineNewline` (Alexander Krotov).
+ + Provide shared F monad functions for Markdown and Org readers
+ (Albert Krewinkel). The `F` monads used for delayed evaluation
+ of certain values in the Markdown and Org readers are based on a
+ shared data type capturing the common pattern of both `F` types.
+ + Add `returnF` (Alexander Krotov).
+ + Avoid parsing `Notes:**` as a bare URI (#3570). This avoids parsing
+ bare URIs that start with a scheme + colon + `*`, `_`, or `]`.
+ + Added `readerAbbreviations` to `ParserState`. Markdown reader
+ now consults this to determine what is an abbreviation.
+ + Combine grid table parsers (Albert Krewinkel, #3638). The grid table
+ parsers for markdown and rst was combined into one single
+ parser `gridTable`, slightly changing parsing behavior of both
+ parsers: (1) The markdown parser now compactifies block content
+ cell-wise: pure text blocks in cells are now treated as paragraphs
+ only if the cell contains multiple paragraphs, and as plain blocks
+ otherwise. Before, this was true only for single-column tables. (2)
+ The rst parser now accepts newlines and multiple blocks in header
+ cells.
+ + Generalize tableWith, gridTableWith (Albert Krewinkel).
+ The parsing functions `tableWith` and `gridTableWith` are generalized
+ to work with more parsers. The parser state only has to be an
+ instance of the `HasOptions` class instead of requiring a concrete
+ type. Block parsers are required to return blocks wrapped into a
+ monad, as this makes it possible to use parsers returning results
+ wrapped in `Future`s.
+
+ * `Text.Pandoc.Shared`:
+
+ + Simplify `toRomanNumeral` using guards (Alexander Krotov, #3445)
+ + `stringify`: handle Quoted better (#3958). Previously we were losing
+ the quotation marks in Quoted elements.
+
+ * `Text.Pandoc.Writers.Shared`:
+
+ + Export `metaToJSON'`, `addVariablesToJSON` (#3439).
+ This allows us to add the variables AFTER using the metadata
+ to generate a YAML header (in the Markdown writer).
+ + Added `unsmartify` (previously in RST writer).
+ Undo literal double curly quotes. Previously we left these.
+ + Generalize type of `metaToJSON` so it can take a Text. Previously a
+ String was needed as argument; now any ToJSON instance will do.
+ + Added `gridTable` (previously in Markdown writer).
+ + `gridTable`: Refactored to use widths in chars.
+ + `gridTable`: remove unnecessary extra space in cells.
+ + Fixed `addVariablesToJSON`. It was previously not allowing multiple
+ values to become lists.
+ + Pipe tables: impose minimum cell size (see #3526).
+
+
+ [default template changes]
+
+ * HTML templates (including EPUB and HTML slide show templates):
+
+ + Make default.html5 polyglot markup conformant (John Luke Bentley,
+ #3473). Polyglot markup is HTML5 that is also valid XHTML. See
+ <https://www.w3.org/TR/html-polyglot>. With this change, pandoc's
+ html5 writer creates HTML that is both valid HTML5 and valid XHTML.
+ + Regularized CSS in html/epub/html slide templates (#3485).
+ All templates now include `code{white-space: pre-wrap}`
+ and CSS for `q` if `--html-q-tags` is used. Previously some templates
+ had `pre` and others `pre-wrap`; the `q` styles were only sometimes
+ included.
+ + CSS for `.smallcaps`, (Mauro Bieg, #1592)
+ + `default.revealjs`: make `history` default to true.
+ + `default.revealjs`: use lazy loading (#2283).
+ + `default.revealjs`: add `mathjax` variable and some conditional code
+ to use the MathJaX plugin.
+ + `default.slidy` uses `https` instead of `http` (ickc, #3848).
+ + `default.dzslides`: Load Google Font using HTTPS by default
+ (Yoan Blanc).
+
+ * DocBook5 template: Use `lang` and `subtitle` variables (Jens Getreu,
+ #3855).
+
+ * LaTeX/Beamer template:
+
+ + Combine LaTeX/Beamer templates (Andrew Dunning, #3878).
+ `default.beamer` has been removed; beamer now uses the
+ `default.latex` template. Beamer-specific parts are conditional
+ on the `beamer` variable set by the writer. Note that
+ `pandoc -D beamer` will return this (combined) template.
+ + Use `xcolor` for `colorlinks` option (Andrew Dunning, #3877).
+ Beamer loads `xcolor` rather than `color`, and thus the
+ `dvipsnames` option doesn't take effect. This also provides a wider
+ range of colour selections with the `svgnames` option.
+ + Use starred versions of `xcolor` names (Andrew Dunning).
+ Prevents changes to documents defined using the `dvipsnames` list (e.g.
+ `Blue` gives a different result with svgnames enabled).
+ + Load `polyglossia` after header-includes (#3898). It needs to be
+ loaded as late as possible.
+ + Use `unicode-math` (Vaclav Haisman). Use `mathspec` with only
+ XeLaTeX on request.
+ + Don't load `fontspec` before `unicode-math` (over there).
+ The `unicode-math` package loads `fontspec` so explict loading of
+ `fontspec` before `unicode-math` is not necessary.
+ + Use `unicode-math` by default in default.latex template. mathspec will
+ be used in xelatex if the `mathspec` variable is set; otherwise
+ unicode-math will be used (Václav Haisman).
+ + Use `dvipsnames` options when `colorlinks` specified (otherwise
+ we get an error for `maroon`) (Thomas Hodgson).
+ + Added beamer `titlegraphic` and `logo` variables (Thomas Hodgson).
+ + Fix typo in fix for notes in tables (#2378, zeeMonkeez).
+ + Fix `hyperref` options clash (Andrew Dunning, #3847) Avoids an options
+ clash when loading a package (e.g. `tufte-latex`) that uses
+ `hyperref` settings different from those in the template.
+ + Add `natbiboptions` variable (#3768).
+ + Fix links inside captions in LaTeX output with links-as-notes
+ (Václav Haisman, #3651). Declare our redefined `\href` robust.
+ + Load `parskip` before `hyperref` (Václav Haisman, #3654).
+ + Allow setting Japanese fonts when using LuaLaTeX (Václav Haisman,
+ #3873). by using the `luatexja-fontspec` and `luatexja-preset`
+ packages. Use existing `CJKmainfont` and `CJKoptions` template
+ variables. Add `luatexjafontspecoptions` for `luatexja-fontspec`
+ and `luatexjapresetoptions` for `luatexja-preset`.
+ + Added `aspectratio` variable to beamer template (Václav Haisman,
+ #3723).
+ + Modified template.latex to fix XeLaTex being used with tables
+ (lwolfsonkin, #3661). Reordered `lang` variable handling to
+ immediately before `bidi`.
+
+ * ConTeXt template: Improved font handling: `simplefonts` is now
+ obsolete in ConTeXt (Pablo Rodríguez).
+
+
+ [documentation improvements]
+
+ * MANUAL.txt:
+
+ + Add URL for Prince HTML > PDF engine (Ian, #3919).
+ + Document that content above slide-level will be omitted in
+ slide shows. See #3460, #2265.
+ + Explain `--webtex` SVG url (Mauro Bieg, #3471)
+ + Small clarification in YAML metadata section.
+ + Document that html4 is technically XHTML 1.0 transitional.
+ + Remove refs to highlighting-kate (#3672).
+ + Document ibooks specific epub metadata.
+ + Clarify that mathml is used for ODT math.
+ + Mention limitations of Literate Haskell Support (#3410,
+ Joachim Breitner).
+ + Add documentation of limitations of grid tables (Stephen
+ McDowell, #3864).
+ + Clarify that meta-json contains transformed values (Jakob Voß,
+ #3491) Make clear that template variable `meta-json` does not
+ contain plain text values or JSON output format but field values
+ transformed to the selected output format.
+
+ * COPYRIGHT:
+
+ + Clarify that templates are dual-licensed.
+ + Clarify that pandoc-types is BSD3 licensed.
+ + List new files not written by jgm (Albert Krewinkel).
+ + Update dates in copyright notices (Albert Krewinkel). This follows
+ the suggestions given by the FSF for GPL licensed software.
+ <https://www.gnu.org/prep/maintain/html_node/Copyright-Notices.html>
+
+ * INSTALL.md:
+
+ + Improved instructions for tests with patterns.
+ + Put RPM-based distros on separate point (Mauro Bieg, #3449)
+
+ * CONTRIBUTING.md:
+
+ + Fixed typos (Wandmalfarbe, #3479).
+ + Add "ask on pandoc-discuss" (Mauro Bieg).
+
+ * Add lua filter documentation in `doc/lua-filters.md`. Note that the
+ end of this document is autogenerated from `data/pandoc.lua`
+ using `make doc/lua-filters.md`, which uses `tools/ldoc.ltp`
+ (Albert Krewinkel).
+
+ * Add `doc/filters.md`. This is the old scripting tutorial from
+ the website.
+
+ * Add `doc/using-the-pandoc-api.md` (#3289). This gives an introduction
+ to using pandoc as a Haskell library.
+
+
+ [build infrastructure improvements]
+
+ * Removed `data/templates` submodule. Templates are now a subtree
+ in `data/templates`. This removes the need to do `git submodule
+ update`.
+
+ * Renamed `tests` -> `test`.
+
+ * Remove `https` flag. Always build with HTTPS support.
+
+ * Use `file-embed` instead of `hsb2hs` to embed data files when
+ `embed_data_files` flag is set. `file-embed` gives us better dependency
+ tracking: if a data file changes, ghc/stack/cabal know to recompile
+ the Data module. This also removes `hsb2hs` as a build dependency.
+
+ * Add `custom-setup` stanza to pandoc, lowercase field names.
+
+ * Add `static` Cabal flag.
+
+ * Name change OSX -> MacOS. Add a -MacOS suffix to mac package rather
+ than -OSX. Changed local names from osx to macos.
+
+ * make_macos_package.sh - Use strip to reduce executable size.
+
+ * Revised binary linux package. Now a completely static executable
+ is created, using Docker and alpine. We create both a deb and a
+ tarball. The old `deb` directory has been replaced with a `linux`
+ directory. Running `make` in the `linux` directory should
+ perform the build, putting the binary packages in `artifacts/`.
+
+ * `linux/control.in`: add `Replaces:`, so existing pandoc-citeproc and
+ pandoc-data packages will be uninstalled; this package provides
+ both (#3822). Add latex packages as 'suggested', update
+ description.
+
+ * Remove cpphs build requirement -- it is no longer needed.
+
+ * Replaced `{deb,macos,windows}/stack.yaml` with `stack.pkg.yaml`.
+
+ * Name change OSX -> macOS (ickc, #3869).
+
+ * Fix casing of Linux, UNIX, and Windows (ickc).
+
+ * `.travis.yml`: create a source dist and do cabal build and test there.
+ That way we catch errors due to files missing from the data
+ section of pandoc.cabal.
+
+ * Makefile:
+
+ + Split `make haddock` from `make full`.
+ + Add BRANCH variable for winpkg.
+ + Add `lint` target.
+ + Improve `make full`. Disable optimizations.
+ Build everything, inc. trypandoc and benchmarks. Use parallel build.
+ + Allow `make test` to take `TESTARGS`.
+
+ * Added new command tests (`Tests.Command`), using small text files
+ in `test/command/`. Any files added in this directory will be treated
+ as shell tests (see smart.md for an example). This makes it very easy
+ to add regression tests etc.
+
+ * Test fixes so we can find data files. In old tests & command tests,
+ we now set the environment variable `pandoc_datadir`. In lua tests,
+ we set the datadir explicitly.
+
+ * Refactored `compareOutput` in docx writer test.
+
+ * Consolidated some common functions in `Tests.Helper`.
+
+ * Small change to unbalanced bracket test to speed up test suite.
+
+ * Speed up Native writer quickcheck tests.
+
+ * Use tasty for tests rather than test-framework.
+
+ * Add simple Emacs mode to help with Pandoc templates editing.
+ (Václav Haisman, #3889). `tools/pandoc-template-mode.el`
- * Require skylighting >= 0.1.1.4.
- * Adjust test output for skylighting version.
- * Relax upper bounds on blaze-html and blaze-markup.
pandoc (1.19.2)
@@ -319,11 +3545,11 @@ pandoc (1.19)
3. does some postprocessing of the paragraphs that combines tables
followed immediately by captions
- The ODT writer used the `TableCaption` style for the caption
- paragraph. This commit follows the OpenOffice approach which allows
- for appending captions to table but uses a built-in style named
- `Table` instead of `TableCaption`. Users of a custom `reference.odt`
- should change the style's name from `TableCaption` to `Table`.
+ The ODT writer used the `TableCaption` style for the caption
+ paragraph. This commit follows the OpenOffice approach which allows
+ for appending captions to table but uses a built-in style named
+ `Table` instead of `TableCaption`. Users of a custom `reference.odt`
+ should change the style's name from `TableCaption` to `Table`.
* ODT reader: Infer tables' header props from rows (#3199,
Hubert Plociniczak). ODT reader simply provided an empty header list
@@ -3274,7 +6500,7 @@ pandoc (1.13.2.1)
pandoc (1.13.2)
- * TWiki Reader: add new new twiki reader (API chaneg, Alexander Sulfrian).
+ * TWiki Reader: add new new twiki reader (API change, Alexander Sulfrian).
* Markdown reader:
@@ -3552,23 +6778,23 @@ pandoc (1.13.2)
Now we still support those, but also support the format recommended
for epub metadata in the pandoc README:
- ---
- title:
- - type: main
- text: My Book
- - type: subtitle
- text: An investigation of metadata
- creator:
- - role: author
- text: John Smith
- - role: editor
- text: Sarah Jones
- identifier:
- - scheme: DOI
- text: doi:10.234234.234/33
- publisher: My Press
- rights: (c) 2007 John Smith, CC BY-NC
- ...
+ ---
+ title:
+ - type: main
+ text: My Book
+ - type: subtitle
+ text: An investigation of metadata
+ creator:
+ - role: author
+ text: John Smith
+ - role: editor
+ text: Sarah Jones
+ identifier:
+ - scheme: DOI
+ text: doi:10.234234.234/33
+ publisher: My Press
+ rights: (c) 2007 John Smith, CC BY-NC
+ ...
* `Text.Pandoc.Templates.getDefaultTemplate`:
don't fail when called with "fb2" (#1660).
@@ -5291,6 +8517,8 @@ pandoc (1.12)
+ Export `varListToJSON`.
* `Text.Pandoc.PDF` exports `makePDF` instead of `tex2pdf`.
+ The signature of `makePDF` has changed and now contains
+ an additional argument for pdf engine options.
* `Text.Pandoc`:
@@ -5313,6 +8541,8 @@ pandoc (1.12)
+ All bibliography-related fields have been removed from
`ReaderOptions` and `WriterOptions`: `writerBiblioFiles`,
`readerReferences`, `readerCitationStyle`.
+ + Removed `writerPdfArgs` from `WriterOptions`. These are now
+ passed in as a parameter to `makePDF`.
* The `Text.Pandoc.Biblio` module has been removed. Users of the
pandoc library who want citation support will need to use
@@ -8564,7 +11794,7 @@ pandoc (1.5)
* Added Maybe datadir parameter to readDataFile, saveOpenDocumentAsODT,
latexMathMLScript, s5HeaderIncludes, and getDefaultTemplate. If
- Nothing, no user directory is searched for an override.
+ Nothing, no user directory is searched for an override.
* Added 'plain' output format. This is similar to markdown, but
removes links, pictures, inline formatting, and most anything that
@@ -8678,8 +11908,8 @@ pandoc (1.5)
+ Allow footnotes to be indented < 4 spaces.
This fixes a regression. A test case has been added.
+ Escape spaces in URLs as %20. Previously they were incorrectly
- escaped as +, which is appropriate only for the query part of
- a URL. Resolves Issue #220.
+ escaped as +, which is appropriate only for the query part of
+ a URL. Resolves Issue #220.
+ Require two spaces after capital letter + period for list item.
Otherwise "E. coli" starts a list. This might change the semantics
of some existing documents, since previously the two-space
@@ -8806,7 +12036,7 @@ pandoc (1.4)
* Pandoc no longer requires Template Haskell. Resolves Issue #186.
+ Removed need for TH in ODT module. Instead get reference.odt from
- data file at run time.
+ data file at run time.
+ Removed TH dependency from S5 module. S5 module now exports
s5HeaderIncludes, which pandoc.hs includes if writer is s5 and
standalone.
@@ -8823,7 +12053,7 @@ pandoc (1.4)
on unix), or, if not found there, from the system data
directory ($CABALDIR/shared/pandoc-VERSION/). All data
files, including templates, LaTeXMathML.js, s5 styles,
- and reference.odt, can be overridden by the user.
+ and reference.odt, can be overridden by the user.
* s5 files moved from data/ui/default to s5/default.
@@ -8848,7 +12078,7 @@ pandoc (1.4)
* Added --reference-odt option, so users may customize the styles
used in pandoc-generated ODT files. Users may also place a
- default reference.odt in the ~\.pandoc directory.
+ default reference.odt in the ~\.pandoc directory.
* ODT writer:
+ Indented and line-broke styles.xml so it can be modified more easily.
@@ -8932,8 +12162,8 @@ pandoc (1.3)
* Treat a backslash followed by a newline as a hard line break
in markdown. Resolves Issue #154. This is a nice alternative
- to markdown's "invisible" way of indicating hardline breaks
- using lines that end with two spaces.
+ to markdown's "invisible" way of indicating hardline breaks
+ using lines that end with two spaces.
* Improved performance of markdown reader by ~10% by eliminating the
need for a separate parsing pass for notes. Raw notes are now stored
@@ -8944,7 +12174,7 @@ pandoc (1.3)
* In markdown reader, treat 4 or more * or _ in a row as literal
text. (Trying to parse long strings of * or _ as strong or emph
- leads to exponential performance problems.)
+ leads to exponential performance problems.)
* Markdown reader: Use + rather than %20 for spaces in URLs.
@@ -8962,8 +12192,8 @@ pandoc (1.3)
* Modified html+lhs output to use "haskell" highlighter instead
of "literateHaskell". The highlighting module now adds bird tracks
- after highlighting (for HTML output), if the code block has the
- "literate" class. This gives better results, because kate's
+ after highlighting (for HTML output), if the code block has the
+ "literate" class. This gives better results, because kate's
haskell highlighter is much better than the literateHaskell
highlighter.
@@ -9084,7 +12314,7 @@ pandoc (1.2.1)
explicit marker. For example:
A. my list
- #. continued
+ #. continued
Resolves Issue #140.
+ Allow continuation lines in line blocks. Also added test cases for
@@ -9117,7 +12347,7 @@ pandoc (1.2.1)
* Added new Haskell version of markdown2pdf, due to
Paulo Tanimoto. This should be more portable than the old
- shell script.
+ shell script.
* Made 'pandoc -v' more explicit about compiler options.
Resolves Issue #139.
@@ -9267,7 +12497,7 @@ pandoc (1.1)
* Text.Pandoc.Shared: Modified wrappedTeX to eliminate the line break
between a footnote and immediately following nonspace characters in
LaTeX and ConTeXt output. (This gets interpreted as a space, which
- is not desired in cases like "text^[note]---".) Resolves Issue #93.
+ is not desired in cases like `text^[note]---`.) Resolves Issue #93.
* Windows installer: Don't require admin privileges to run
installer. Modified pandoc-setup.iss, and changed modpath.iss to
@@ -10773,8 +14003,8 @@ pandoc (0.3) unstable; urgency=low
* Revised footnote syntax. (See README for full details.) The
'[^1]' format now standard in markdown extensions is supported,
- as are inline footnotes with this syntax: '^[My note.]'.
- The earlier footnote syntax '^(1)' is no longer supported.
+ as are inline footnotes with this syntax: `^[My note.]`.
+ The earlier footnote syntax `^(1)` is no longer supported.
* Improved HTML representation of footnotes. All footnotes
are now auto-numbered and appear in an ordered list at the
diff --git a/data/abbreviations b/data/abbreviations
new file mode 100644
index 000000000..7be63d891
--- /dev/null
+++ b/data/abbreviations
@@ -0,0 +1,50 @@
+al.
+Apr.
+Aug.
+Bros.
+Capt.
+cf.
+ch.
+Co.
+Corp.
+cp.
+Dec.
+Dr.
+e.g.
+esp.
+Feb.
+Gen.
+Gov.
+Hon.
+i.e.
+Inc.
+Jan.
+Jr.
+Jul.
+Jun.
+Ltd.
+M.A.
+M.D.
+Mar.
+Mr.
+Mrs.
+Ms.
+No.
+Nov.
+Oct.
+p.
+Ph.D.
+pp.
+Pres.
+Prof.
+Rep.
+Rev.
+sec.
+Sen.
+Sep.
+Sept.
+Sgt.
+Sr.
+St.
+vol.
+vs.
diff --git a/data/bash_completion.tpl b/data/bash_completion.tpl
index 317fd5095..c9145c06c 100644
--- a/data/bash_completion.tpl
+++ b/data/bash_completion.tpl
@@ -29,8 +29,8 @@ _pandoc()
COMPREPLY=( $(compgen -W "references javascript none" -- ${cur}) )
return 0
;;
- --latex-engine)
- COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex" -- ${cur}) )
+ --pdf-engine)
+ COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex wkhtmltopdf weasyprint prince context pdfroff" -- ${cur}) )
return 0
;;
--print-default-data-file)
diff --git a/data/docx/[Content_Types].xml b/data/docx/[Content_Types].xml
index 9c5756aed..1e888dff9 100644
--- a/data/docx/[Content_Types].xml
+++ b/data/docx/[Content_Types].xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
-<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="xml" ContentType="application/xml" /><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" /><Override PartName="/word/webSettings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml" /><Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" /><Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" /><Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml" /><Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" /><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" /><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml" /><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" /><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" /><Override PartName="/word/footnotes.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" /></Types>
+<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="xml" ContentType="application/xml" /><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" /><Override PartName="/word/webSettings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml" /><Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" /><Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" /><Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml" /><Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" /><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" /><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml" /><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" /><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" /><Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" /><Override PartName="/word/footnotes.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" /></Types>
diff --git a/data/docx/docProps/core.xml b/data/docx/docProps/core.xml
index 2274766e4..bc61390b0 100644
--- a/data/docx/docProps/core.xml
+++ b/data/docx/docProps/core.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
-<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:title></dc:title><dc:creator></dc:creator></cp:coreProperties> \ No newline at end of file
+<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:title>Title</dc:title><dc:creator>Author</dc:creator><cp:keywords></cp:keywords><dcterms:created xsi:type="dcterms:W3CDTF">2017-12-27T05:22:50Z</dcterms:created><dcterms:modified xsi:type="dcterms:W3CDTF">2017-12-27T05:22:50Z</dcterms:modified></cp:coreProperties> \ No newline at end of file
diff --git a/data/docx/word/_rels/document.xml.rels b/data/docx/word/_rels/document.xml.rels
index ca0c57b63..f01e07658 100644
--- a/data/docx/word/_rels/document.xml.rels
+++ b/data/docx/word/_rels/document.xml.rels
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
-<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Id="rId1" Target="numbering.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Id="rId2" Target="styles.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Id="rId3" Target="settings.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Id="rId4" Target="webSettings.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Id="rId5" Target="fontTable.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Id="rId6" Target="theme/theme1.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Id="rId7" Target="footnotes.xml" /></Relationships>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Id="rId1" Target="numbering.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Id="rId2" Target="styles.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Id="rId3" Target="settings.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Id="rId4" Target="webSettings.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Id="rId5" Target="fontTable.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Id="rId6" Target="theme/theme1.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Id="rId7" Target="footnotes.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" Id="rId8" Target="comments.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Id="rId30" Target="http://example.com" TargetMode="External" /></Relationships>
diff --git a/data/docx/word/_rels/footnotes.xml.rels b/data/docx/word/_rels/footnotes.xml.rels
index be7e70853..81d529a4c 100644
--- a/data/docx/word/_rels/footnotes.xml.rels
+++ b/data/docx/word/_rels/footnotes.xml.rels
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
-<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships" /> \ No newline at end of file
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Id="rId30" Target="http://example.com" TargetMode="External" /></Relationships> \ No newline at end of file
diff --git a/data/docx/word/comments.xml b/data/docx/word/comments.xml
new file mode 100644
index 000000000..ca80aa7fe
--- /dev/null
+++ b/data/docx/word/comments.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:comments xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" /> \ No newline at end of file
diff --git a/data/docx/word/document.xml b/data/docx/word/document.xml
index 7199034da..f74c3f56e 100644
--- a/data/docx/word/document.xml
+++ b/data/docx/word/document.xml
@@ -1,2 +1,398 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"><w:body><w:p><w:r><w:t xml:space="preserve">Hello world.</w:t></w:r></w:p></w:body></w:document>
+<?xml version="1.0" encoding="utf-8"?>
+<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
+xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
+xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+xmlns:o="urn:schemas-microsoft-com:office:office"
+xmlns:v="urn:schemas-microsoft-com:vml"
+xmlns:w10="urn:schemas-microsoft-com:office:word"
+xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
+xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"
+xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">
+
+ <w:body>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Title" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Title
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Subtitle" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Subtitle
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Author" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Author
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Date" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Date
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Compact" />
+ <w:pStyle w:val="Abstract" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Abstract
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading1" />
+ </w:pPr>
+ <w:bookmarkStart w:id="21" w:name="heading-1" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 1
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="21" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading2" />
+ </w:pPr>
+ <w:bookmarkStart w:id="22" w:name="heading-2" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 2
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="22" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading3" />
+ </w:pPr>
+ <w:bookmarkStart w:id="23" w:name="heading-3" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 3
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="23" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading4" />
+ </w:pPr>
+ <w:bookmarkStart w:id="24" w:name="heading-4" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 4
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="24" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading5" />
+ </w:pPr>
+ <w:bookmarkStart w:id="25" w:name="heading-5" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 5
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="25" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading6" />
+ </w:pPr>
+ <w:bookmarkStart w:id="26" w:name="heading-6" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 6
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="26" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading7" />
+ </w:pPr>
+ <w:bookmarkStart w:id="27" w:name="heading-7" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 7
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="27" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading8" />
+ </w:pPr>
+ <w:bookmarkStart w:id="28" w:name="heading-8" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 8
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="28" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Heading9" />
+ </w:pPr>
+ <w:bookmarkStart w:id="29" w:name="heading-9" />
+ <w:r>
+ <w:t xml:space="preserve">
+Heading 9
+</w:t>
+ </w:r>
+ <w:bookmarkEnd w:id="29" />
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="FirstParagraph" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+First Paragraph.
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="BodyText" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Body Text. Body Text Char.
+</w:t>
+ </w:r>
+ <w:r>
+ <w:t xml:space="preserve">
+
+</w:t>
+ </w:r>
+ <w:r>
+ <w:rPr>
+ <w:rStyle w:val="VerbatimChar" />
+ </w:rPr>
+ <w:t xml:space="preserve">
+Verbatim Char
+</w:t>
+ </w:r>
+ <w:r>
+ <w:t xml:space="preserve">
+.
+</w:t>
+ </w:r>
+ <w:r>
+ <w:t xml:space="preserve">
+
+</w:t>
+ </w:r>
+ <w:hyperlink r:id="rId30">
+ <w:r>
+ <w:rPr>
+ <w:rStyle w:val="Hyperlink" />
+ </w:rPr>
+ <w:t xml:space="preserve">
+Hyperlink
+</w:t>
+ </w:r>
+ </w:hyperlink>
+ <w:r>
+ <w:t xml:space="preserve">
+.
+</w:t>
+ </w:r>
+ <w:r>
+ <w:t xml:space="preserve">
+
+</w:t>
+ </w:r>
+ <w:r>
+ <w:t xml:space="preserve">
+Footnote.
+</w:t>
+ </w:r>
+ <w:r>
+ <w:rPr>
+ <w:rStyle w:val="FootnoteReference" />
+ </w:rPr>
+ <w:footnoteReference w:id="31" />
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="BlockText" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Block Text.
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="TableCaption" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Table caption.
+</w:t>
+ </w:r>
+ </w:p>
+ <w:tbl>
+ <w:tblPr>
+ <w:tblStyle w:val="Table" />
+ <w:tblW w:type="pct" w:w="0.0" />
+ <w:tblLook w:firstRow="1" />
+ <w:tblCaption w:val="Table caption." />
+ </w:tblPr>
+ <w:tblGrid />
+ <w:tr>
+ <w:trPr>
+ <w:cnfStyle w:firstRow="1" />
+ </w:trPr>
+ <w:tc>
+ <w:tcPr>
+ <w:tcBorders>
+ <w:bottom w:val="single" />
+ </w:tcBorders>
+ <w:vAlign w:val="bottom" />
+ </w:tcPr>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Compact" />
+ <w:jc w:val="left" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Table
+</w:t>
+ </w:r>
+ </w:p>
+ </w:tc>
+ <w:tc>
+ <w:tcPr>
+ <w:tcBorders>
+ <w:bottom w:val="single" />
+ </w:tcBorders>
+ <w:vAlign w:val="bottom" />
+ </w:tcPr>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Compact" />
+ <w:jc w:val="left" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Table
+</w:t>
+ </w:r>
+ </w:p>
+ </w:tc>
+ </w:tr>
+ <w:tr>
+ <w:tc>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Compact" />
+ <w:jc w:val="left" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+1
+</w:t>
+ </w:r>
+ </w:p>
+ </w:tc>
+ <w:tc>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Compact" />
+ <w:jc w:val="left" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+2
+</w:t>
+ </w:r>
+ </w:p>
+ </w:tc>
+ </w:tr>
+ </w:tbl>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="ImageCaption" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Image Caption
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="DefinitionTerm" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+DefinitionTerm
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Definition" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Definition
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="DefinitionTerm" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+DefinitionTerm
+</w:t>
+ </w:r>
+ </w:p>
+ <w:p>
+ <w:pPr>
+ <w:pStyle w:val="Definition" />
+ </w:pPr>
+ <w:r>
+ <w:t xml:space="preserve">
+Definition
+</w:t>
+ </w:r>
+ </w:p>
+ <w:sectPr />
+ </w:body>
+</w:document>
diff --git a/data/docx/word/footnotes.xml b/data/docx/word/footnotes.xml
index db82d9462..2a150e026 100644
--- a/data/docx/word/footnotes.xml
+++ b/data/docx/word/footnotes.xml
@@ -1,26 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
-<w:footnotes xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
-xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
-xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
-xmlns:o="urn:schemas-microsoft-com:office:office"
-xmlns:v="urn:schemas-microsoft-com:vml"
-xmlns:w10="urn:schemas-microsoft-com:office:word"
-xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
-xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"
-xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">
-
- <w:footnote w:type="continuationSeparator" w:id="0">
- <w:p>
- <w:r>
- <w:continuationSeparator />
- </w:r>
- </w:p>
- </w:footnote>
- <w:footnote w:type="separator" w:id="-1">
- <w:p>
- <w:r>
- <w:separator />
- </w:r>
- </w:p>
- </w:footnote>
-</w:footnotes>
+<?xml version="1.0" encoding="UTF-8"?>
+<w:footnotes xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"><w:footnote w:type="continuationSeparator" w:id="0"><w:p><w:r><w:continuationSeparator /></w:r></w:p></w:footnote><w:footnote w:type="separator" w:id="-1"><w:p><w:r><w:separator /></w:r></w:p></w:footnote><w:footnote w:id="31"><w:p><w:pPr><w:pStyle w:val="FootnoteText" /></w:pPr><w:r>
+ <w:rPr>
+ <w:rStyle w:val="FootnoteReference" />
+ </w:rPr>
+ <w:footnoteRef />
+</w:r><w:r><w:t xml:space="preserve"> </w:t></w:r><w:r><w:t xml:space="preserve">Footnote Text.</w:t></w:r></w:p></w:footnote></w:footnotes> \ No newline at end of file
diff --git a/data/docx/word/numbering.xml b/data/docx/word/numbering.xml
index b9e91371b..2df923f28 100644
--- a/data/docx/word/numbering.xml
+++ b/data/docx/word/numbering.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
-<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:abstractNum w:abstractNumId="0"><w:nsid w:val="e17f69ba" /><w:multiLevelType w:val="multilevel" /><w:lvl w:ilvl="0"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="0" /></w:tabs><w:ind w:left="480" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="1"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="720" /></w:tabs><w:ind w:left="1200" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="2"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="1440" /></w:tabs><w:ind w:left="1920" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="3"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="2160" /></w:tabs><w:ind w:left="2640" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="4"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="2880" /></w:tabs><w:ind w:left="3360" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="5"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="3600" /></w:tabs><w:ind w:left="4080" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="6"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="4320" /></w:tabs><w:ind w:left="4800" w:hanging="480" /></w:pPr></w:lvl></w:abstractNum><w:num w:numId="1"><w:abstractNumId w:val="0" /></w:num></w:numbering> \ No newline at end of file
+<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:abstractNum w:abstractNumId="990"><w:nsid w:val="170cd2de" /><w:multiLevelType w:val="multilevel" /><w:lvl w:ilvl="0"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="0" /></w:tabs><w:ind w:left="480" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="1"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="720" /></w:tabs><w:ind w:left="1200" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="2"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="1440" /></w:tabs><w:ind w:left="1920" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="3"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="2160" /></w:tabs><w:ind w:left="2640" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="4"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="2880" /></w:tabs><w:ind w:left="3360" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="5"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="3600" /></w:tabs><w:ind w:left="4080" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="6"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="4320" /></w:tabs><w:ind w:left="4800" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="7"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="5040" /></w:tabs><w:ind w:left="5520" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="8"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="5760" /></w:tabs><w:ind w:left="6240" w:hanging="480" /></w:pPr></w:lvl></w:abstractNum><w:num w:numId="1000"><w:abstractNumId w:val="990" /></w:num></w:numbering> \ No newline at end of file
diff --git a/data/docx/word/settings.xml b/data/docx/word/settings.xml
index 425e6f7b5..afa0199c9 100644
--- a/data/docx/word/settings.xml
+++ b/data/docx/word/settings.xml
@@ -44,4 +44,4 @@
<w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink" />
<w:decimalSymbol w:val="." />
<w:listSeparator w:val="," />
-</w:settings>
+</w:settings> \ No newline at end of file
diff --git a/data/docx/word/styles.xml b/data/docx/word/styles.xml
index d19c4c7fb..130a55a63 100644
--- a/data/docx/word/styles.xml
+++ b/data/docx/word/styles.xml
@@ -251,6 +251,66 @@
<w:szCs w:val="24" />
</w:rPr>
</w:style>
+ <w:style w:type="paragraph" w:styleId="Heading7">
+ <w:name w:val="Heading 7" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="200" w:after="0" />
+ <w:outlineLvl w:val="6" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ <w:sz w:val="24" />
+ <w:szCs w:val="24" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Heading8">
+ <w:name w:val="Heading 8" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="200" w:after="0" />
+ <w:outlineLvl w:val="7" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ <w:sz w:val="24" />
+ <w:szCs w:val="24" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Heading9">
+ <w:name w:val="Heading 9" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="200" w:after="0" />
+ <w:outlineLvl w:val="8" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ <w:sz w:val="24" />
+ <w:szCs w:val="24" />
+ </w:rPr>
+ </w:style>
<w:style w:type="paragraph" w:styleId="BlockText">
<w:name w:val="Block Text" />
<w:basedOn w:val="BodyText" />
@@ -282,8 +342,9 @@
<w:semiHidden />
<w:unhideWhenUsed />
</w:style>
- <w:style w:type="table" w:default="1" w:styleId="TableNormal">
- <w:name w:val="Normal Table" />
+ <w:style w:type="table" w:default="1" w:styleId="Table">
+ <w:name w:val="Table" />
+ <w:basedOn w:val="TableNormal" />
<w:semiHidden />
<w:unhideWhenUsed />
<w:qFormat />
@@ -340,8 +401,8 @@
<w:name w:val="Figure" />
<w:basedOn w:val="Normal" />
</w:style>
- <w:style w:type="paragraph" w:customStyle="1" w:styleId="FigureWithCaption">
- <w:name w:val="Figure with Caption" />
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="CaptionedFigure">
+ <w:name w:val="Captioned Figure" />
<w:basedOn w:val="Figure" />
<w:pPr>
<w:keepNext />
@@ -389,8 +450,7 @@
<w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
<w:b w:val="0" />
<w:bCs w:val="0" />
- <w:color w:val="365F91" w:themeColor="accent1"
- w:themeShade="BF" />
+ <w:color w:val="365F91" w:themeColor="accent1" w:themeShade="BF" />
</w:rPr>
</w:style>
</w:styles>
diff --git a/data/epub.css b/data/epub.css
index 594a1e01e..34835ced4 100644
--- a/data/epub.css
+++ b/data/epub.css
@@ -12,7 +12,7 @@ h2.author { }
h3.date { }
ol.toc { padding: 0; margin-left: 1em; }
ol.toc li { list-style-type: none; margin: 0; padding: 0; }
-a.footnoteRef { vertical-align: super; }
+a.footnote-ref { vertical-align: super; }
em, em em em, em em em em em { font-style: italic;}
em em, em em em em { font-style: normal; }
diff --git a/data/init.lua b/data/init.lua
new file mode 100644
index 000000000..ed39dd294
--- /dev/null
+++ b/data/init.lua
@@ -0,0 +1,7 @@
+-- This Lua script is run every time the Lua interpreter is started when running
+-- a Lua filter. It can be customized to load additional modules or to alter the
+-- default modules.
+
+pandoc = require 'pandoc'
+pandoc.mediabag = require 'pandoc.mediabag'
+pandoc.utils = require 'pandoc.utils'
diff --git a/data/jats.csl b/data/jats.csl
new file mode 100644
index 000000000..dc1f154a8
--- /dev/null
+++ b/data/jats.csl
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" default-locale="en-US">
+ <info>
+ <title>Journal Article Tag Suite</title>
+ <title-short>JATS</title-short>
+ <id>http://www.zotero.org/styles/journal-article-tag-suite</id>
+ <link href="https://github.com/MartinPaulEve/JATS-CSL/blob/master/jats.csl" rel="self"/>
+ <link rel="documentation" href="http://jats.nlm.nih.gov/archiving/tag-library/1.0/index.html"/>
+ <author>
+ <name>Martin Paul Eve</name>
+ <email>martin@martineve.com</email>
+ </author>
+ <category citation-format="numeric"/>
+ <category field="medicine"/>
+ <category field="biology"/>
+ <summary>Use this style to generate bibliographic data in Journal Article Tagging Suite (JATS) 1.0 XML format</summary>
+ <updated>2014-06-21T17:41:26+00:00</updated>
+ <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License. Originally by Martin Fenner.</rights>
+ </info>
+ <locale xml:lang="en">
+ <terms>
+ <term name="et-al">{{jats}}&lt;etal/&gt;{{/jats}}</term>
+ </terms>
+ </locale>
+ <macro name="citation-number">
+ <text variable="citation-number" prefix="{{jats}}id=&quot;ref-{{/jats}}" suffix="{{jats}}&quot;&gt;{{/jats}}"/>
+ </macro>
+ <macro name="author">
+ <names variable="author">
+ <name prefix="{{jats}}&lt;name&gt;{{/jats}}" suffix="{{jats}}&lt;/name&gt;{{/jats}}" name-as-sort-order="all" sort-separator="">
+ <name-part name="family" text-case="capitalize-first" prefix="{{jats}}&lt;surname&gt;{{/jats}}" suffix="{{jats}}&lt;/surname&gt;{{/jats}}"/>
+ <name-part name="given" text-case="capitalize-first" prefix="{{jats}}&lt;given-names&gt;{{/jats}}" suffix="{{jats}}&lt;/given-names&gt;{{/jats}}"/>
+ </name>
+ <substitute>
+ <names variable="editor"/>
+ </substitute>
+ </names>
+ </macro>
+
+ <macro name="editor">
+ <names variable="editor" prefix="{{jats}}&lt;person-group person-group-type=&quot;editor&quot;&gt;{{/jats}}" suffix="{{jats}}&lt;/person-group&gt;{{/jats}}">
+ <name prefix="{{jats}}&lt;name&gt;{{/jats}}" suffix="{{jats}}&lt;/name&gt;{{/jats}}" name-as-sort-order="all" sort-separator="">
+ <name-part name="family" text-case="capitalize-first" prefix="{{jats}}&lt;surname&gt;{{/jats}}" suffix="{{jats}}&lt;/surname&gt;{{/jats}}"/>
+ <name-part name="given" text-case="capitalize-first" prefix="{{jats}}&lt;given-names&gt;{{/jats}}" suffix="{{jats}}&lt;/given-names&gt;{{/jats}}"/>
+ </name>
+ <substitute>
+ <names variable="editor"/>
+ </substitute>
+ </names>
+ </macro>
+
+ <macro name="editor">
+ <group delimiter=": ">
+ <names variable="editor">
+ <name prefix="{{jats}}&lt;name&gt;{{/jats}}" suffix="{{jats}}&lt;/name&gt;{{/jats}}" name-as-sort-order="all" sort-separator="">
+ <name-part name="family" text-case="capitalize-first" prefix="{{jats}}&lt;surname&gt;{{/jats}}" suffix="{{jats}}&lt;/surname&gt;{{/jats}}"/>
+ <name-part name="given" text-case="capitalize-first" prefix="{{jats}}&lt;given-names&gt;{{/jats}}" suffix="{{jats}}&lt;given-names&gt;{{/jats}}"/>
+ </name>
+ </names>
+ </group>
+ </macro>
+ <macro name="title">
+ <choose>
+ <if type="book" match="any">
+ <group prefix="{{jats}}&lt;source&gt;{{/jats}}" suffix="{{jats}}&lt;/source&gt;{{/jats}}">
+ <text variable="title"/>
+ </group>
+ </if>
+ <else>
+ <group prefix="{{jats}}&lt;article-title&gt;{{/jats}}" suffix="{{jats}}&lt;/article-title&gt;{{/jats}}">
+ <text variable="title"/>
+ </group>
+ </else>
+ </choose>
+ </macro>
+ <macro name="container-title">
+ <text variable="container-title" form="short" prefix="{{jats}}&lt;source&gt;{{/jats}}" suffix="{{jats}}&lt;/source&gt;{{/jats}}"/>
+ </macro>
+ <macro name="publisher">
+ <text variable="publisher" prefix="{{jats}}&lt;publisher-name&gt;{{/jats}}" suffix="{{jats}}&lt;/publisher-name&gt;{{/jats}}"/>
+ <text variable="publisher-place" prefix="{{jats}}&lt;publisher-loc&gt;{{/jats}}" suffix="{{jats}}&lt;/publisher-loc&gt;{{/jats}}"/>
+ </macro>
+ <macro name="link">
+ <choose>
+ <if match="any" variable="DOI">
+ <group prefix="{{jats}}&lt;pub-id pub-id-type=&quot;doi&quot;&gt;{{/jats}}" suffix="{{jats}}&lt;/pub-id&gt;{{/jats}}">
+ <text variable="DOI"/>
+ </group>
+ </if>
+ </choose>
+ <choose>
+ <if match="any" variable="PMID">
+ <group prefix="{{jats}}&lt;ext-link ext-link-type=&quot;pmid&quot; {{/jats}}" suffix="{{jats}}&lt;/ext-link&gt;{{/jats}}">
+ <text variable="PMID" prefix="{{jats}}xlink:href=&quot;http://www.ncbi.nlm.nih.gov/pubmed/{{/jats}}" suffix="{{jats}}&quot; xlink:type=&quot;simple&quot;&gt;{{/jats}}"/>
+ <text variable="PMID"/>
+ </group>
+ </if>
+ </choose>
+ <choose>
+ <if variable="URL" match="any">
+ <text variable="URL" />
+ </if>
+ </choose>
+ </macro>
+ <macro name="date">
+ <choose>
+ <if type="article-journal article-magazine article-newspaper report patent book" match="any">
+ <group prefix="{{jats}}&lt;date&gt;{{/jats}}" suffix="{{jats}}&lt;/date&gt;{{/jats}}">
+ <date variable="issued">
+ <date-part name="day" form="numeric-leading-zeros" prefix="{{jats}}&lt;day&gt;{{/jats}}" suffix="{{jats}}&lt;/day&gt;{{/jats}}"/>
+ <date-part name="month" form="numeric-leading-zeros" prefix="{{jats}}&lt;month&gt;{{/jats}}" suffix="{{jats}}&lt;/month&gt;{{/jats}}"/>
+ <date-part name="year" prefix="{{jats}}&lt;year&gt;{{/jats}}" suffix="{{jats}}&lt;/year&gt;{{/jats}}"/>
+ </date>
+ </group>
+ </if>
+ <else>
+ <group prefix="{{jats}}&lt;date-in-citation content-type=&quot;access-date&quot;{{/jats}}" suffix="{{jats}}&lt;/date-in-citation&gt;{{/jats}}">
+ <date variable="accessed" prefix="{{jats}} iso-8601-date=&quot;{{/jats}}" suffix="{{jats}}&quot;&gt;{{/jats}}">
+ <date-part name="year"/>
+ <date-part name="month" form="numeric-leading-zeros" prefix="{{jats}}-{{/jats}}"/>
+ <date-part name="day" form="numeric-leading-zeros" prefix="{{jats}}-{{/jats}}"/>
+ </date>
+ <date variable="accessed">
+ <date-part name="day" prefix="{{jats}}&lt;day&gt;{{/jats}}" suffix="{{jats}}&lt;/day&gt;{{/jats}}"/>
+ <date-part name="month" form="numeric-leading-zeros" prefix="{{jats}}&lt;month&gt;{{/jats}}" suffix="{{jats}}&lt;/month&gt;{{/jats}}"/>
+ <date-part name="year" prefix="{{jats}}&lt;year&gt;{{/jats}}" suffix="{{jats}}&lt;/year&gt;{{/jats}}"/>
+ </date>
+ </group>
+ </else>
+ </choose>
+ </macro>
+ <macro name="location">
+ <choose>
+ <if type="article-journal article-magazine" match="any">
+ <text variable="volume" prefix="{{jats}}&lt;volume&gt;{{/jats}}" suffix="{{jats}}&lt;/volume&gt;{{/jats}}"/>
+ <text variable="issue" prefix="{{jats}}&lt;issue&gt;{{/jats}}" suffix="{{jats}}&lt;/issue&gt;{{/jats}}"/>
+ </if>
+ </choose>
+ <choose>
+ <if type="article-journal article-magazine article-newspaper chapter" match="any">
+ <text variable="page-first" prefix="{{jats}}&lt;fpage&gt;{{/jats}}" suffix="{{jats}}&lt;/fpage&gt;{{/jats}}"/>
+ </if>
+ </choose>
+ </macro>
+ <macro name="publication-type">
+ <group prefix="{{jats}} publication-type=&quot;{{/jats}}" suffix="{{jats}}&quot;&gt;{{/jats}}">
+ <choose>
+ <if type="article-journal article-magazine article-newspaper" match="any">
+ <text value="journal"/>
+ </if>
+ <else-if type="book" match="any">
+ <text value="book"/>
+ </else-if>
+ <else-if type="chapter" match="any">
+ <text value="bookchapter"/>
+ </else-if>
+ <else-if type="dataset" match="any">
+ <text value="dataset"/>
+ </else-if>
+ <else-if type="patent" match="any">
+ <text value="patent"/>
+ </else-if>
+ <else-if type="report" match="any">
+ <text value="report"/>
+ </else-if>
+ <else-if type="review" match="any">
+ <text value="review"/>
+ </else-if>
+ <else>
+ <text value="standard"/>
+ </else>
+ </choose>
+ </group>
+ </macro>
+ <citation collapse="citation-number">
+ <sort>
+ <key variable="citation-number"/>
+ </sort>
+ <layout delimiter=",">
+ <group prefix="{{jats}}&lt;xref ref-type=&quot;bibr&quot; rid=&quot;{{/jats}}" suffix="{{jats}}&lt;/xref&gt;{{/jats}}">
+ <text variable="citation-number" prefix="{{jats}}ref-{{/jats}}" suffix="{{jats}}&quot;&gt;{{/jats}}"/>
+ <text variable="citation-number"/>
+ </group>
+ </layout>
+ </citation>
+ <bibliography sort-separator="">
+ <layout>
+ <group prefix="{{jats}}&lt;ref {{/jats}}" suffix="{{jats}}&lt;/ref&gt;{{/jats}}">
+ <text macro="citation-number"/>
+ <group prefix="{{jats}}&lt;element-citation{{/jats}}" suffix="{{jats}}&lt;/element-citation&gt;{{/jats}}">
+ <text macro="publication-type"/>
+ <text macro="author" prefix="{{jats}}&lt;person-group person-group-type=&quot;author&quot;&gt;{{/jats}}" suffix="{{jats}}&lt;/person-group&gt;{{/jats}}"/>
+ <text macro="title" />
+ <text macro="container-title"/>
+ <text macro="editor"/>
+ <text macro="publisher"/>
+ <text macro="date"/>
+ <text macro="location"/>
+ <text macro="link"/>
+ </group>
+ </group>
+ </layout>
+ </bibliography>
+</style>
+
diff --git a/data/pandoc.List.lua b/data/pandoc.List.lua
new file mode 100644
index 000000000..6b3188a65
--- /dev/null
+++ b/data/pandoc.List.lua
@@ -0,0 +1,120 @@
+--[[
+List.lua
+
+Copyright © 2017–2018 Albert Krewinkel
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+]]
+
+--- Pandoc's List type and helper methods
+-- @classmod pandoc.List
+-- @author Albert Krewinkel
+-- @copyright © 2017–2018 Albert Krewinkel
+-- @license MIT
+local List = {
+ _VERSION = "0.1.0"
+}
+
+function List:new (o)
+ o = o or {}
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+function List:__call (o)
+ return self:new(o)
+end
+
+--- Concatenates two lists.
+-- @param list second list concatenated to the first
+-- @return a new list containing all elements from list1 and list2
+function List:__concat (list)
+ local res = List.clone(self)
+ List.extend(res, list)
+ return res
+end
+
+--- Returns a (shallow) copy of the list.
+function List:clone ()
+ local lst = setmetatable({}, getmetatable(self))
+ List.extend(lst, self)
+ return lst
+end
+
+--- Checks if the list has an item equal to the given needle.
+-- @param needle item to search for
+-- @param init index at which the search is started
+-- @return true if a list item is equal to the needle, false otherwise
+function List:includes (needle, init)
+ return not (List.find(self, needle, init) == nil)
+end
+
+--- Returns the value and index of the first occurrence of the given item.
+-- @param needle item to search for
+-- @param init index at which the search is started
+-- @return first item equal to the needle, or nil if no such item exists.
+-- @return index of that element
+function List:find (needle, init)
+ return List.find_if(self, function(x) return x == needle end, init)
+end
+
+--- Returns the value and index of the first element for which the predicate
+--- holds true.
+-- @param pred the predicate function
+-- @param init index at which the search is started
+-- @return first item for which `test` succeeds, or nil if no such item exists.
+-- @return index of that element
+function List:find_if (pred, init)
+ init = (init == nil and 1) or (init < 0 and #self - init) or init
+ for i = init, #self do
+ if pred(self[i], i) then
+ return self[i], i
+ end
+ end
+ return nil
+end
+
+--- Adds the given list to the end of this list.
+-- @param list list to appended
+function List:extend (list)
+ for i = 1, #list do
+ self[#self + 1] = list[i]
+ end
+end
+
+--- Returns a copy of the current list by applying the given function to all
+-- elements.
+-- @param fn function which is applied to all list items.
+function List:map (fn)
+ local res = setmetatable({}, getmetatable(self))
+ for i = 1, #self do
+ res[i] = fn(self[i], i)
+ end
+ return res
+end
+
+--- Returns a new list containing all items satisfying a given condition.
+-- @param pred condition items must satisfy.
+-- @return a new list containing all items for which `test` was true.
+function List:filter (pred)
+ local res = setmetatable({}, getmetatable(self))
+ for i = 1, #self do
+ if pred(self[i], i) then
+ res[#res + 1] = self[i]
+ end
+ end
+ return res
+end
+
+return List
diff --git a/data/pandoc.lua b/data/pandoc.lua
new file mode 100644
index 000000000..512b2919c
--- /dev/null
+++ b/data/pandoc.lua
@@ -0,0 +1,945 @@
+--[[
+pandoc.lua
+
+Copyright © 2017–2018 Albert Krewinkel
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+]]
+
+---
+-- Lua functions for pandoc scripts.
+--
+-- @author Albert Krewinkel
+-- @copyright © 2017–2018 Albert Krewinkel
+-- @license MIT
+local M = {}
+
+local List = require 'pandoc.List'
+
+------------------------------------------------------------------------
+-- Accessor objects
+--
+-- Create metatables which allow to access numerical indices via accessor
+-- methods.
+-- @section
+-- @local
+
+--- Create a new indexing function.
+-- @param template function template
+-- @param indices list of indices, starting with the most deeply nested
+-- @return newly created function
+-- @local
+function make_indexing_function(template, indices)
+ local loadstring = loadstring or load
+ local bracketed = {}
+ for i = 1, #indices do
+ bracketed[i] = string.format('[%d]', indices[#indices - i + 1])
+ end
+ local fnstr = string.format('return ' .. template, table.concat(bracketed))
+ return assert(loadstring(fnstr))()
+end
+
+--- Create accessor functions using a function template.
+-- @param fn_template function template in which '%s' is replacd with indices
+-- @param accessors list of accessors
+-- @return mapping from accessor names to accessor functions
+-- @local
+local function create_accessor_functions (fn_template, accessors)
+ local res = {}
+ function add_accessors(acc, ...)
+ if type(acc) == 'string' then
+ res[acc] = make_indexing_function(fn_template, {...})
+ elseif type(acc) == 'table' and #acc == 0 and next(acc) then
+ local name, substructure = next(acc)
+ res[name] = make_indexing_function(fn_template, {...})
+ add_accessors(substructure, ...)
+ else
+ for i = 1, #(acc or {}) do
+ add_accessors(acc[i], i, ...)
+ end
+ end
+ end
+ add_accessors(accessors)
+ return res
+end
+
+--- Create a new table which allows to access numerical indices via accessor
+-- functions.
+-- @local
+local function create_accessor_behavior (tag, accessors)
+ local behavior = {tag = tag}
+ behavior.getters = create_accessor_functions(
+ 'function (x) return x.c%s end',
+ accessors
+ )
+ behavior.setters = create_accessor_functions(
+ 'function (x, v) x.c%s = v end',
+ accessors
+ )
+ behavior.__index = function(t, k)
+ if getmetatable(t).getters[k] then
+ return getmetatable(t).getters[k](t)
+ elseif k == "t" then
+ return getmetatable(t)["tag"]
+ else
+ return getmetatable(t)[k]
+ end
+ end
+ behavior.__newindex = function(t, k, v)
+ if getmetatable(t).setters[k] then
+ getmetatable(t).setters[k](t, v)
+ else
+ rawset(t, k, v)
+ end
+ end
+ return behavior
+end
+
+
+------------------------------------------------------------------------
+-- The base class for types
+-- @type Type
+-- @local
+local Type = {}
+Type.name = 'Type'
+Type.__index = Type
+Type.behavior = {
+ __type = Type,
+ new = function (obj)
+ obj = obj or {}
+ setmetatable(obj, self)
+ return obj
+ end
+}
+Type.behavior.__index = Type.behavior
+
+--- Set a new behavior for the type, inheriting that of the parent type if none
+--- is specified explicitely
+-- @param behavior the behavior object for this type.
+-- @local
+function Type:set_behavior (behavior)
+ behavior = behavior or {}
+ behavior.__index = rawget(behavior, '__index') or behavior
+ behavior.__type = self
+ if not getmetatable(behavior) and getmetatable(self) then
+ setmetatable(behavior, getmetatable(self).behavior)
+ end
+ self.behavior = behavior
+end
+
+--- Create a new subtype, using the given table as base.
+-- @param name name of the new type
+-- @param[opt] behavior behavioral object for the new type.
+-- @return a new type
+-- @local
+function Type:make_subtype(name, behavior)
+ local newtype = setmetatable({}, self)
+ newtype.name = name
+ newtype.__index = newtype
+ newtype:set_behavior(behavior)
+ return newtype
+end
+
+
+------------------------------------------------------------------------
+-- The base class for pandoc's AST elements.
+-- @type AstElement
+-- @local
+local AstElement = Type:make_subtype 'AstElement'
+AstElement.__call = function(t, ...)
+ local success, ret = pcall(t.new, t, ...)
+ if success then
+ return setmetatable(ret, t.behavior)
+ else
+ error(string.format('Constructor for %s failed: %s\n', t.name, ret))
+ end
+end
+
+--- Make a new subtype which constructs a new value when called.
+-- @local
+function AstElement:make_subtype(...)
+ local newtype = Type.make_subtype(self, ...)
+ newtype.__call = self.__call
+ return newtype
+end
+
+--- Create a new constructor
+-- @local
+-- @param tag Tag used to identify the constructor
+-- @param fn Function to be called when constructing a new element
+-- @param accessors names to use as accessors for numerical fields
+-- @return function that constructs a new element
+function AstElement:create_constructor(tag, fn, accessors)
+ local constr = self:make_subtype(tag, create_accessor_behavior(tag, accessors))
+ function constr:new(...)
+ return setmetatable(fn(...), self.behavior)
+ end
+ self.constructor = self.constructor or {}
+ self.constructor[tag] = constr
+ return constr
+end
+
+--- Convert AstElement input into a list if necessary.
+-- @local
+local function ensureList (x)
+ if x.tag then
+ -- Lists are not tagged, but all elements are
+ return List:new{x}
+ else
+ return List:new(x)
+ end
+end
+
+--- Ensure a given object is an Inline element, or convert it into one.
+-- @local
+local function ensureInlineList (x)
+ if type(x) == 'string' then
+ return List:new{M.Str(x)}
+ else
+ return ensureList(x)
+ end
+end
+
+------------------------------------------------------------------------
+--- Pandoc Document
+-- @section document
+
+--- A complete pandoc document
+-- @function Pandoc
+-- @tparam {Block,...} blocks document content
+-- @tparam[opt] Meta meta document meta data
+M.Pandoc = AstElement:make_subtype'Pandoc'
+function M.Pandoc:new (blocks, meta)
+ return {
+ blocks = ensureList(blocks),
+ meta = meta or {},
+ }
+end
+
+-- DEPRECATED synonym:
+M.Doc = M.Pandoc
+
+------------------------------------------------------------------------
+-- Meta
+-- @section Meta
+
+--- Create a new Meta object. It sets the metatable of the given table to
+--- `Meta`.
+-- @function Meta
+-- @tparam meta table table containing document meta information
+M.Meta = AstElement:make_subtype'Meta'
+function M.Meta:new (meta) return meta end
+
+
+------------------------------------------------------------------------
+-- MetaValue
+-- @section MetaValue
+M.MetaValue = AstElement:make_subtype('MetaValue')
+
+--- Meta blocks
+-- @function MetaBlocks
+-- @tparam {Block,...} blocks blocks
+M.MetaBlocks = M.MetaValue:create_constructor(
+ 'MetaBlocks',
+ function (content) return ensureList(content) end
+)
+
+--- Meta inlines
+-- @function MetaInlines
+-- @tparam {Inline,...} inlines inlines
+M.MetaInlines = M.MetaValue:create_constructor(
+ 'MetaInlines',
+ function (content) return ensureInlineList(content) end
+)
+
+--- Meta list
+-- @function MetaList
+-- @tparam {MetaValue,...} meta_values list of meta values
+M.MetaList = M.MetaValue:create_constructor(
+ 'MetaList',
+ function (content) return ensureList(content) end
+)
+
+--- Meta map
+-- @function MetaMap
+-- @tparam table key_value_map a string-indexed map of meta values
+M.MetaMap = M.MetaValue:create_constructor(
+ "MetaMap",
+ function (mm) return mm end
+)
+
+--- Creates string to be used in meta data.
+-- Does nothing, lua strings are meta strings.
+-- @function MetaString
+-- @tparam string str string value
+function M.MetaString(str)
+ return str
+end
+
+--- Creates boolean to be used in meta data.
+-- Does nothing, lua booleans are meta booleans.
+-- @function MetaBool
+-- @tparam boolean bool boolean value
+function M.MetaBool(bool)
+ return bool
+end
+
+------------------------------------------------------------------------
+-- Blocks
+-- @section Block
+
+--- Block elements
+M.Block = AstElement:make_subtype'Block'
+
+--- Creates a block quote element
+-- @function BlockQuote
+-- @tparam {Block,...} content block content
+-- @treturn Block block quote element
+M.BlockQuote = M.Block:create_constructor(
+ "BlockQuote",
+ function(content) return {c = ensureList(content)} end,
+ "content"
+)
+
+--- Creates a bullet (i.e. unordered) list.
+-- @function BulletList
+-- @tparam {{Block,...},...} content list of items
+-- @treturn Block bullet list element
+M.BulletList = M.Block:create_constructor(
+ "BulletList",
+ function(content) return {c = ensureList(content)} end,
+ "content"
+)
+
+--- Creates a code block element
+-- @function CodeBlock
+-- @tparam string text code string
+-- @tparam[opt] Attr attr element attributes
+-- @treturn Block code block element
+M.CodeBlock = M.Block:create_constructor(
+ "CodeBlock",
+ function(text, attr) return {c = {attr or M.Attr(), text}} end,
+ {{attr = {"identifier", "classes", "attributes"}}, "text"}
+)
+
+--- Creates a definition list, containing terms and their explanation.
+-- @function DefinitionList
+-- @tparam {{{Inline,...},{Block,...}},...} content list of items
+-- @treturn Block definition list element
+M.DefinitionList = M.Block:create_constructor(
+ "DefinitionList",
+ function(content) return {c = ensureList(content)} end,
+ "content"
+)
+
+--- Creates a div element
+-- @function Div
+-- @tparam {Block,...} content block content
+-- @tparam[opt] Attr attr element attributes
+-- @treturn Block div element
+M.Div = M.Block:create_constructor(
+ "Div",
+ function(content, attr)
+ return {c = {attr or M.Attr(), ensureList(content)}}
+ end,
+ {{attr = {"identifier", "classes", "attributes"}}, "content"}
+)
+
+--- Creates a header element.
+-- @function Header
+-- @tparam int level header level
+-- @tparam {Inline,...} content inline content
+-- @tparam[opt] Attr attr element attributes
+-- @treturn Block header element
+M.Header = M.Block:create_constructor(
+ "Header",
+ function(level, content, attr)
+ return {c = {level, attr or M.Attr(), ensureInlineList(content)}}
+ end,
+ {"level", {attr = {"identifier", "classes", "attributes"}}, "content"}
+)
+
+--- Creates a horizontal rule.
+-- @function HorizontalRule
+-- @treturn Block horizontal rule
+M.HorizontalRule = M.Block:create_constructor(
+ "HorizontalRule",
+ function() return {} end
+)
+
+--- Creates a line block element.
+-- @function LineBlock
+-- @tparam {{Inline,...},...} content inline content
+-- @treturn Block line block element
+M.LineBlock = M.Block:create_constructor(
+ "LineBlock",
+ function(content) return {c = ensureList(content)} end,
+ "content"
+)
+
+--- Creates a null element.
+-- @function Null
+-- @treturn Block null element
+M.Null = M.Block:create_constructor(
+ "Null",
+ function() return {} end
+)
+
+--- Creates an ordered list.
+-- @function OrderedList
+-- @tparam {{Block,...},...} items list items
+-- @param[opt] listAttributes list parameters
+-- @treturn Block ordered list element
+M.OrderedList = M.Block:create_constructor(
+ "OrderedList",
+ function(items, listAttributes)
+ listAttributes = listAttributes or {1, M.DefaultStyle, M.DefaultDelim}
+ return {c = {listAttributes, ensureList(items)}}
+ end,
+ {{listAttributes = {"start", "style", "delimiter"}}, "content"}
+)
+
+--- Creates a para element.
+-- @function Para
+-- @tparam {Inline,...} content inline content
+-- @treturn Block paragraph element
+M.Para = M.Block:create_constructor(
+ "Para",
+ function(content) return {c = ensureInlineList(content)} end,
+ "content"
+)
+
+--- Creates a plain element.
+-- @function Plain
+-- @tparam {Inline,...} content inline content
+-- @treturn Block plain element
+M.Plain = M.Block:create_constructor(
+ "Plain",
+ function(content) return {c = ensureInlineList(content)} end,
+ "content"
+)
+
+--- Creates a raw content block of the specified format.
+-- @function RawBlock
+-- @tparam string format format of content
+-- @tparam string text string content
+-- @treturn Block raw block element
+M.RawBlock = M.Block:create_constructor(
+ "RawBlock",
+ function(format, text) return {c = {format, text}} end,
+ {"format", "text"}
+)
+
+--- Creates a table element.
+-- @function Table
+-- @tparam {Inline,...} caption table caption
+-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
+-- @tparam {int,...} widths column widths
+-- @tparam {Block,...} headers header row
+-- @tparam {{Block,...}} rows table rows
+-- @treturn Block table element
+M.Table = M.Block:create_constructor(
+ "Table",
+ function(caption, aligns, widths, headers, rows)
+ return {
+ c = {
+ ensureInlineList(caption),
+ List:new(aligns),
+ List:new(widths),
+ List:new(headers),
+ List:new(rows)
+ }
+ }
+ end,
+ {"caption", "aligns", "widths", "headers", "rows"}
+)
+
+
+------------------------------------------------------------------------
+-- Inline
+-- @section Inline
+
+--- Inline element class
+M.Inline = AstElement:make_subtype'Inline'
+
+--- Creates a Cite inline element
+-- @function Cite
+-- @tparam {Inline,...} content List of inlines
+-- @tparam {Citation,...} citations List of citations
+-- @treturn Inline citations element
+M.Cite = M.Inline:create_constructor(
+ "Cite",
+ function(content, citations)
+ return {c = {ensureList(citations), ensureInlineList(content)}}
+ end,
+ {"citations", "content"}
+)
+
+--- Creates a Code inline element
+-- @function Code
+-- @tparam string text brief image description
+-- @tparam[opt] Attr attr additional attributes
+-- @treturn Inline code element
+M.Code = M.Inline:create_constructor(
+ "Code",
+ function(text, attr) return {c = {attr or M.Attr(), text}} end,
+ {{attr = {"identifier", "classes", "attributes"}}, "text"}
+)
+
+--- Creates an inline element representing emphasised text.
+-- @function Emph
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline emphasis element
+M.Emph = M.Inline:create_constructor(
+ "Emph",
+ function(content) return {c = ensureInlineList(content)} end,
+ "content"
+)
+
+--- Creates a Image inline element
+-- @function Image
+-- @tparam {Inline,..} caption text used to describe the image
+-- @tparam string src path to the image file
+-- @tparam[opt] string title brief image description
+-- @tparam[opt] Attr attr additional attributes
+-- @treturn Inline image element
+M.Image = M.Inline:create_constructor(
+ "Image",
+ function(caption, src, title, attr)
+ title = title or ""
+ attr = attr or M.Attr()
+ return {c = {attr, ensureInlineList(caption), {src, title}}}
+ end,
+ {{attr = {"identifier", "classes", "attributes"}}, "caption", {"src", "title"}}
+)
+
+--- Create a LineBreak inline element
+-- @function LineBreak
+-- @treturn Inline linebreak element
+M.LineBreak = M.Inline:create_constructor(
+ "LineBreak",
+ function() return {} end
+)
+
+--- Creates a link inline element, usually a hyperlink.
+-- @function Link
+-- @tparam {Inline,..} content text for this link
+-- @tparam string target the link target
+-- @tparam[opt] string title brief link description
+-- @tparam[opt] Attr attr additional attributes
+-- @treturn Inline image element
+M.Link = M.Inline:create_constructor(
+ "Link",
+ function(content, target, title, attr)
+ title = title or ""
+ attr = attr or M.Attr()
+ return {c = {attr, ensureInlineList(content), {target, title}}}
+ end,
+ {{attr = {"identifier", "classes", "attributes"}}, "content", {"target", "title"}}
+)
+
+--- Creates a Math element, either inline or displayed.
+-- @function Math
+-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
+-- @tparam string text Math content
+-- @treturn Inline Math element
+M.Math = M.Inline:create_constructor(
+ "Math",
+ function(mathtype, text)
+ return {c = {mathtype, text}}
+ end,
+ {"mathtype", "text"}
+)
+--- Creates a DisplayMath element (DEPRECATED).
+-- @function DisplayMath
+-- @tparam string text Math content
+-- @treturn Inline Math element
+M.DisplayMath = M.Inline:create_constructor(
+ "DisplayMath",
+ function(text) return M.Math("DisplayMath", text) end,
+ {"mathtype", "text"}
+)
+--- Creates an InlineMath inline element (DEPRECATED).
+-- @function InlineMath
+-- @tparam string text Math content
+-- @treturn Inline Math element
+M.InlineMath = M.Inline:create_constructor(
+ "InlineMath",
+ function(text) return M.Math("InlineMath", text) end,
+ {"mathtype", "text"}
+)
+
+--- Creates a Note inline element
+-- @function Note
+-- @tparam {Block,...} content footnote block content
+M.Note = M.Inline:create_constructor(
+ "Note",
+ function(content) return {c = ensureList(content)} end,
+ "content"
+)
+
+--- Creates a Quoted inline element given the quote type and quoted content.
+-- @function Quoted
+-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline quoted element
+M.Quoted = M.Inline:create_constructor(
+ "Quoted",
+ function(quotetype, content) return {c = {quotetype, ensureInlineList(content)}} end,
+ {"quotetype", "content"}
+)
+--- Creates a single-quoted inline element (DEPRECATED).
+-- @function SingleQuoted
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline quoted element
+-- @see Quoted
+M.SingleQuoted = M.Inline:create_constructor(
+ "SingleQuoted",
+ function(content) return M.Quoted(M.SingleQuote, content) end,
+ {"quotetype", "content"}
+)
+--- Creates a single-quoted inline element (DEPRECATED).
+-- @function DoubleQuoted
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline quoted element
+-- @see Quoted
+M.DoubleQuoted = M.Inline:create_constructor(
+ "DoubleQuoted",
+ function(content) return M.Quoted("DoubleQuote", content) end,
+ {"quotetype", "content"}
+)
+
+--- Creates a RawInline inline element
+-- @function RawInline
+-- @tparam string format format of the contents
+-- @tparam string text string content
+-- @treturn Inline raw inline element
+M.RawInline = M.Inline:create_constructor(
+ "RawInline",
+ function(format, text) return {c = {format, text}} end,
+ {"format", "text"}
+)
+
+--- Creates text rendered in small caps
+-- @function SmallCaps
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline smallcaps element
+M.SmallCaps = M.Inline:create_constructor(
+ "SmallCaps",
+ function(content) return {c = ensureInlineList(content)} end,
+ "content"
+)
+
+--- Creates a SoftBreak inline element.
+-- @function SoftBreak
+-- @treturn Inline softbreak element
+M.SoftBreak = M.Inline:create_constructor(
+ "SoftBreak",
+ function() return {} end
+)
+
+--- Create a Space inline element
+-- @function Space
+-- @treturn Inline space element
+M.Space = M.Inline:create_constructor(
+ "Space",
+ function() return {} end
+)
+
+--- Creates a Span inline element
+-- @function Span
+-- @tparam {Inline,..} content inline content
+-- @tparam[opt] Attr attr additional attributes
+-- @treturn Inline span element
+M.Span = M.Inline:create_constructor(
+ "Span",
+ function(content, attr)
+ return {c = {attr or M.Attr(), ensureInlineList(content)}}
+ end,
+ {{attr = {"identifier", "classes", "attributes"}}, "content"}
+)
+
+--- Creates a Str inline element
+-- @function Str
+-- @tparam string text content
+-- @treturn Inline string element
+M.Str = M.Inline:create_constructor(
+ "Str",
+ function(text) return {c = text} end,
+ "text"
+)
+
+--- Creates text which is striked out.
+-- @function Strikeout
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline strikeout element
+M.Strikeout = M.Inline:create_constructor(
+ "Strikeout",
+ function(content) return {c = ensureInlineList(content)} end,
+ "content"
+)
+
+--- Creates a Strong element, whose text is usually displayed in a bold font.
+-- @function Strong
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline strong element
+M.Strong = M.Inline:create_constructor(
+ "Strong",
+ function(content) return {c = ensureInlineList(content)} end,
+ "content"
+)
+
+--- Creates a Subscript inline element
+-- @function Subscript
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline subscript element
+M.Subscript = M.Inline:create_constructor(
+ "Subscript",
+ function(content) return {c = ensureInlineList(content)} end,
+ "content"
+)
+
+--- Creates a Superscript inline element
+-- @function Superscript
+-- @tparam {Inline,..} content inline content
+-- @treturn Inline strong element
+M.Superscript = M.Inline:create_constructor(
+ "Superscript",
+ function(content) return {c = ensureInlineList(content)} end,
+ "content"
+)
+
+
+------------------------------------------------------------------------
+-- Element components
+-- @section components
+
+--- Check if the first element of a pair matches the given value.
+-- @param x key value to be checked
+-- @return function returning true iff first element of its argument matches x
+-- @local
+local function assoc_key_equals (x)
+ return function (y) return y[1] == x end
+end
+
+--- Lookup a value in an associative list
+-- @function lookup
+-- @local
+-- @tparam {{key, value},...} alist associative list
+-- @param key key for which the associated value is to be looked up
+local function lookup(alist, key)
+ return (List.find_if(alist, assoc_key_equals(key)) or {})[2]
+end
+
+--- Return an iterator which returns key-value pairs of an associative list.
+-- @function apairs
+-- @local
+-- @tparam {{key, value},...} alist associative list
+local apairs = function (alist)
+ local i = 1
+ local cur
+ function nxt ()
+ cur = rawget(alist, i)
+ if cur then
+ i = i + 1
+ return cur[1], cur[2]
+ end
+ return nil
+ end
+ return nxt, nil, nil
+end
+
+--- AttributeList, a metatable to allow table-like access to attribute lists
+-- represented by associative lists.
+-- @local
+local AttributeList = {
+ __index = function (t, k)
+ if type(k) == "number" then
+ return rawget(t, k)
+ else
+ return lookup(t, k)
+ end
+ end,
+
+ __newindex = function (t, k, v)
+ local cur, idx = List.find_if(t, assoc_key_equals(k))
+ if v == nil then
+ table.remove(t, idx)
+ elseif cur then
+ cur[2] = v
+ elseif type(k) == "number" then
+ rawset(t, k, v)
+ else
+ rawset(t, #t + 1, {k, v})
+ end
+ end,
+
+ __pairs = apairs
+}
+
+--- Convert a table to an associative list. The order of key-value pairs in the
+-- alist is undefined. The table should either contain no numeric keys or
+-- already be an associative list.
+-- @local
+-- @tparam table tbl associative list or table without numeric keys.
+-- @treturn table associative list
+local to_alist = function (tbl)
+ if #tbl ~= 0 or next(tbl) == nil then
+ -- probably already an alist
+ return tbl
+ end
+ local alist = {}
+ local i = 1
+ for k, v in pairs(tbl) do
+ alist[i] = {k, v}
+ i = i + 1
+ end
+ return alist
+end
+
+-- Attr
+
+--- Create a new set of attributes (Attr).
+-- @function Attr
+-- @tparam[opt] string identifier element identifier
+-- @tparam[opt] {string,...} classes element classes
+-- @tparam[opt] table attributes table containing string keys and values
+-- @return element attributes
+M.Attr = AstElement:make_subtype'Attr'
+function M.Attr:new (identifier, classes, attributes)
+ identifier = identifier or ''
+ classes = ensureList(classes or {})
+ attributes = setmetatable(to_alist(attributes or {}), AttributeList)
+ return {identifier, classes, attributes}
+end
+M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3}
+M.Attr.behavior.__index = function(t, k)
+ return rawget(t, getmetatable(t)._field_names[k]) or
+ getmetatable(t)[k]
+end
+M.Attr.behavior.__newindex = function(t, k, v)
+ if getmetatable(t)._field_names[k] then
+ rawset(t, getmetatable(t)._field_names[k], v)
+ else
+ rawset(t, k, v)
+ end
+end
+
+-- Citation
+M.Citation = AstElement:make_subtype'Citation'
+
+--- Creates a single citation.
+-- @function Citation
+-- @tparam string id citation identifier (like a bibtex key)
+-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
+-- @tparam[opt] {Inline,...} prefix citation prefix
+-- @tparam[opt] {Inline,...} suffix citation suffix
+-- @tparam[opt] int note_num note number
+-- @tparam[opt] int hash hash number
+function M.Citation:new (id, mode, prefix, suffix, note_num, hash)
+ return {
+ id = id,
+ mode = mode,
+ prefix = ensureList(prefix or {}),
+ suffix = ensureList(suffix or {}),
+ note_num = note_num or 0,
+ hash = hash or 0,
+ }
+end
+
+
+------------------------------------------------------------------------
+-- Constants
+-- @section constants
+
+--- Author name is mentioned in the text.
+-- @see Citation
+-- @see Cite
+M.AuthorInText = "AuthorInText"
+
+--- Author name is suppressed.
+-- @see Citation
+-- @see Cite
+M.SuppressAuthor = "SuppressAuthor"
+
+--- Default citation style is used.
+-- @see Citation
+-- @see Cite
+M.NormalCitation = "NormalCitation"
+
+--- Table cells aligned left.
+-- @see Table
+M.AlignLeft = "AlignLeft"
+
+--- Table cells right-aligned.
+-- @see Table
+M.AlignRight = "AlignRight"
+
+--- Table cell content is centered.
+-- @see Table
+M.AlignCenter = "AlignCenter"
+
+--- Table cells are alignment is unaltered.
+-- @see Table
+M.AlignDefault = "AlignDefault"
+
+--- Default list number delimiters are used.
+-- @see OrderedList
+M.DefaultDelim = "DefaultDelim"
+
+--- List numbers are delimited by a period.
+-- @see OrderedList
+M.Period = "Period"
+
+--- List numbers are delimited by a single parenthesis.
+-- @see OrderedList
+M.OneParen = "OneParen"
+
+--- List numbers are delimited by a double parentheses.
+-- @see OrderedList
+M.TwoParens = "TwoParens"
+
+--- List are numbered in the default style
+-- @see OrderedList
+M.DefaultStyle = "DefaultStyle"
+
+--- List items are numbered as examples.
+-- @see OrderedList
+M.Example = "Example"
+
+--- List are numbered using decimal integers.
+-- @see OrderedList
+M.Decimal = "Decimal"
+
+--- List are numbered using lower-case roman numerals.
+-- @see OrderedList
+M.LowerRoman = "LowerRoman"
+
+--- List are numbered using upper-case roman numerals
+-- @see OrderedList
+M.UpperRoman = "UpperRoman"
+
+--- List are numbered using lower-case alphabetic characters.
+-- @see OrderedList
+M.LowerAlpha = "LowerAlpha"
+
+--- List are numbered using upper-case alphabetic characters.
+-- @see OrderedList
+M.UpperAlpha = "UpperAlpha"
+
+------------------------------------------------------------------------
+-- Functions which have moved to different modules
+local utils = require 'pandoc.utils'
+M.sha1 = utils.sha1
+
+return M
diff --git a/data/pptx/[Content_Types].xml b/data/pptx/[Content_Types].xml
new file mode 100644
index 000000000..8a33c28c1
--- /dev/null
+++ b/data/pptx/[Content_Types].xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/><Override PartName="/ppt/slideMasters/slideMaster1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"/><Override PartName="/ppt/slides/slide1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/><Override PartName="/ppt/slides/slide2.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/><Override PartName="/ppt/notesMasters/notesMaster1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml"/><Override PartName="/ppt/presProps.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presProps+xml"/><Override PartName="/ppt/viewProps.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml"/><Override PartName="/ppt/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/ppt/tableStyles.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml"/><Override PartName="/ppt/slideLayouts/slideLayout1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout2.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout3.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout4.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout5.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout6.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout7.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout8.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout9.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout10.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/slideLayouts/slideLayout11.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/theme/theme2.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/ppt/notesSlides/notesSlide1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml"/><Override PartName="/ppt/notesSlides/notesSlide2.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types> \ No newline at end of file
diff --git a/data/pptx/_rels/.rels b/data/pptx/_rels/.rels
new file mode 100644
index 000000000..27ca98f00
--- /dev/null
+++ b/data/pptx/_rels/.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="ppt/presentation.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/docProps/app.xml b/data/pptx/docProps/app.xml
new file mode 100644
index 000000000..e052fdfaf
--- /dev/null
+++ b/data/pptx/docProps/app.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><TotalTime>1</TotalTime><Words>26</Words><Application>Microsoft Office PowerPoint</Application><PresentationFormat>On-screen Show (4:3)</PresentationFormat><Paragraphs>10</Paragraphs><Slides>2</Slides><Notes>2</Notes><HiddenSlides>0</HiddenSlides><MMClips>0</MMClips><ScaleCrop>false</ScaleCrop><HeadingPairs><vt:vector size="6" baseType="variant"><vt:variant><vt:lpstr>Fonts Used</vt:lpstr></vt:variant><vt:variant><vt:i4>2</vt:i4></vt:variant><vt:variant><vt:lpstr>Theme</vt:lpstr></vt:variant><vt:variant><vt:i4>1</vt:i4></vt:variant><vt:variant><vt:lpstr>Slide Titles</vt:lpstr></vt:variant><vt:variant><vt:i4>2</vt:i4></vt:variant></vt:vector></HeadingPairs><TitlesOfParts><vt:vector size="5" baseType="lpstr"><vt:lpstr>Arial</vt:lpstr><vt:lpstr>Calibri</vt:lpstr><vt:lpstr>Office Theme</vt:lpstr><vt:lpstr>Title</vt:lpstr><vt:lpstr>Slide Title</vt:lpstr></vt:vector></TitlesOfParts><Company></Company><LinksUpToDate>false</LinksUpToDate><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>15.0000</AppVersion></Properties> \ No newline at end of file
diff --git a/data/pptx/docProps/core.xml b/data/pptx/docProps/core.xml
new file mode 100644
index 000000000..f7a0a8ace
--- /dev/null
+++ b/data/pptx/docProps/core.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:title>Title</dc:title><dc:creator>Jesse Rosenthal</dc:creator><cp:lastModifiedBy>KSAS-IT</cp:lastModifiedBy><cp:revision>3</cp:revision><dcterms:created xsi:type="dcterms:W3CDTF">2017-06-05T14:10:58Z</dcterms:created><dcterms:modified xsi:type="dcterms:W3CDTF">2018-02-17T16:21:08Z</dcterms:modified></cp:coreProperties> \ No newline at end of file
diff --git a/data/pptx/docProps/thumbnail.jpeg b/data/pptx/docProps/thumbnail.jpeg
new file mode 100644
index 000000000..07aa48f19
--- /dev/null
+++ b/data/pptx/docProps/thumbnail.jpeg
Binary files differ
diff --git a/data/pptx/ppt/_rels/presentation.xml.rels b/data/pptx/ppt/_rels/presentation.xml.rels
new file mode 100644
index 000000000..4c297d869
--- /dev/null
+++ b/data/pptx/ppt/_rels/presentation.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableStyles" Target="tableStyles.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide2.xml"/><Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide1.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="slideMasters/slideMaster1.xml"/><Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/viewProps" Target="viewProps.xml"/><Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/presProps" Target="presProps.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster" Target="notesMasters/notesMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/notesMasters/_rels/notesMaster1.xml.rels b/data/pptx/ppt/notesMasters/_rels/notesMaster1.xml.rels
new file mode 100644
index 000000000..53a3df379
--- /dev/null
+++ b/data/pptx/ppt/notesMasters/_rels/notesMaster1.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="../theme/theme2.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/notesMasters/notesMaster1.xml b/data/pptx/ppt/notesMasters/notesMaster1.xml
new file mode 100644
index 000000000..9b72dd7a3
--- /dev/null
+++ b/data/pptx/ppt/notesMasters/notesMaster1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:notesMaster xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:cSld><p:bg><p:bgRef idx="1001"><a:schemeClr val="bg1"/></p:bgRef></p:bg><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Header Placeholder 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="hdr" sz="quarter"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="2971800" cy="458788"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0"/><a:lstStyle><a:lvl1pPr algn="l"><a:defRPr sz="1200"/></a:lvl1pPr></a:lstStyle><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Date Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="3884613" y="0"/><a:ext cx="2971800" cy="458788"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0"/><a:lstStyle><a:lvl1pPr algn="r"><a:defRPr sz="1200"/></a:lvl1pPr></a:lstStyle><a:p><a:fld id="{0F9C1CCF-B725-44A7-AA57-5E433BD85C9F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Slide Image Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1" noRot="1" noChangeAspect="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldImg" idx="2"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="1371600" y="1143000"/><a:ext cx="4114800" cy="3086100"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln w="12700"><a:solidFill><a:prstClr val="black"/></a:solidFill></a:ln></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0" anchor="ctr"/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Notes Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" sz="quarter" idx="3"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="685800" y="4400550"/><a:ext cx="5486400" cy="3600450"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0"/><a:lstStyle/><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Footer Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="4"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="0" y="8685213"/><a:ext cx="2971800" cy="458787"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0" anchor="b"/><a:lstStyle><a:lvl1pPr algn="l"><a:defRPr sz="1200"/></a:lvl1pPr></a:lstStyle><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="7" name="Slide Number Placeholder 6"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="5"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="3884613" y="8685213"/><a:ext cx="2971800" cy="458787"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0" anchor="b"/><a:lstStyle><a:lvl1pPr algn="r"><a:defRPr sz="1200"/></a:lvl1pPr></a:lstStyle><a:p><a:fld id="{18BDFEC3-8487-43E8-A154-7C12CBC1FFF2}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="3782709779"/></p:ext></p:extLst></p:cSld><p:clrMap bg1="lt1" tx1="dk1" bg2="lt2" tx2="dk2" accent1="accent1" accent2="accent2" accent3="accent3" accent4="accent4" accent5="accent5" accent6="accent6" hlink="hlink" folHlink="folHlink"/><p:notesStyle><a:lvl1pPr marL="0" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl1pPr><a:lvl2pPr marL="457200" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl2pPr><a:lvl3pPr marL="914400" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl3pPr><a:lvl4pPr marL="1371600" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl4pPr><a:lvl5pPr marL="1828800" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl5pPr><a:lvl6pPr marL="2286000" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl6pPr><a:lvl7pPr marL="2743200" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl7pPr><a:lvl8pPr marL="3200400" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl8pPr><a:lvl9pPr marL="3657600" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl9pPr></p:notesStyle></p:notesMaster> \ No newline at end of file
diff --git a/data/pptx/ppt/notesSlides/_rels/notesSlide1.xml.rels b/data/pptx/ppt/notesSlides/_rels/notesSlide1.xml.rels
new file mode 100644
index 000000000..75bee32f4
--- /dev/null
+++ b/data/pptx/ppt/notesSlides/_rels/notesSlide1.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="../slides/slide1.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster" Target="../notesMasters/notesMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/notesSlides/_rels/notesSlide2.xml.rels b/data/pptx/ppt/notesSlides/_rels/notesSlide2.xml.rels
new file mode 100644
index 000000000..7c700efea
--- /dev/null
+++ b/data/pptx/ppt/notesSlides/_rels/notesSlide2.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="../slides/slide2.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster" Target="../notesMasters/notesMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/notesSlides/notesSlide1.xml b/data/pptx/ppt/notesSlides/notesSlide1.xml
new file mode 100644
index 000000000..c088f25da
--- /dev/null
+++ b/data/pptx/ppt/notesSlides/notesSlide1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:notes xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Slide Image Placeholder 1"/><p:cNvSpPr><a:spLocks noGrp="1" noRot="1" noChangeAspect="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldImg"/></p:nvPr></p:nvSpPr><p:spPr/></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Notes Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" idx="1"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" dirty="0" smtClean="0"/><a:t>Here</a:t></a:r><a:r><a:rPr lang="en-US" baseline="0" dirty="0" smtClean="0"/><a:t> is a note</a:t></a:r></a:p><a:p><a:endParaRPr lang="en-US" baseline="0" dirty="0" smtClean="0"/></a:p><a:p><a:r><a:rPr lang="en-US" baseline="0" dirty="0" smtClean="0"/><a:t>With another paragraph.</a:t></a:r><a:endParaRPr lang="en-US" dirty="0"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Slide Number Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{18BDFEC3-8487-43E8-A154-7C12CBC1FFF2}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>1</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="3171319170"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:notes> \ No newline at end of file
diff --git a/data/pptx/ppt/notesSlides/notesSlide2.xml b/data/pptx/ppt/notesSlides/notesSlide2.xml
new file mode 100644
index 000000000..33a6d7b08
--- /dev/null
+++ b/data/pptx/ppt/notesSlides/notesSlide2.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:notes xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Slide Image Placeholder 1"/><p:cNvSpPr><a:spLocks noGrp="1" noRot="1" noChangeAspect="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldImg"/></p:nvPr></p:nvSpPr><p:spPr/></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Notes Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" idx="1"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" dirty="0" smtClean="0"/><a:t>A</a:t></a:r><a:r><a:rPr lang="en-US" baseline="0" dirty="0" smtClean="0"/><a:t> speaker note on </a:t></a:r><a:r><a:rPr lang="en-US" baseline="0" smtClean="0"/><a:t>this slide too.</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Slide Number Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{18BDFEC3-8487-43E8-A154-7C12CBC1FFF2}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>2</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="3016900036"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:notes> \ No newline at end of file
diff --git a/data/pptx/ppt/presProps.xml b/data/pptx/ppt/presProps.xml
new file mode 100644
index 000000000..5a041b0ee
--- /dev/null
+++ b/data/pptx/ppt/presProps.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:presentationPr xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:extLst><p:ext uri="{E76CE94A-603C-4142-B9EB-6D1370010A27}"><p14:discardImageEditData xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="0"/></p:ext><p:ext uri="{D31A062A-798A-4329-ABDD-BBA856620510}"><p14:defaultImageDpi xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="0"/></p:ext><p:ext uri="{FD5EFAAD-0ECE-453E-9831-46B23BE46B34}"><p15:chartTrackingRefBased xmlns:p15="http://schemas.microsoft.com/office/powerpoint/2012/main" val="0"/></p:ext></p:extLst></p:presentationPr> \ No newline at end of file
diff --git a/data/pptx/ppt/presentation.xml b/data/pptx/ppt/presentation.xml
new file mode 100644
index 000000000..a07ea53e5
--- /dev/null
+++ b/data/pptx/ppt/presentation.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:presentation xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" saveSubsetFonts="1" autoCompressPictures="0"><p:sldMasterIdLst><p:sldMasterId id="2147483648" r:id="rId1"/></p:sldMasterIdLst><p:notesMasterIdLst><p:notesMasterId r:id="rId4"/></p:notesMasterIdLst><p:sldIdLst><p:sldId id="256" r:id="rId2"/><p:sldId id="257" r:id="rId3"/></p:sldIdLst><p:sldSz cx="9144000" cy="6858000" type="screen4x3"/><p:notesSz cx="6858000" cy="9144000"/><p:defaultTextStyle><a:defPPr><a:defRPr lang="en-US"/></a:defPPr><a:lvl1pPr marL="0" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl1pPr><a:lvl2pPr marL="457200" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl2pPr><a:lvl3pPr marL="914400" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl3pPr><a:lvl4pPr marL="1371600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl4pPr><a:lvl5pPr marL="1828800" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl5pPr><a:lvl6pPr marL="2286000" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl6pPr><a:lvl7pPr marL="2743200" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl7pPr><a:lvl8pPr marL="3200400" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl8pPr><a:lvl9pPr marL="3657600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl9pPr></p:defaultTextStyle><p:extLst><p:ext uri="{EFAFB233-063F-42B5-8137-9DF3F51BA10A}"><p15:sldGuideLst xmlns:p15="http://schemas.microsoft.com/office/powerpoint/2012/main"><p15:guide id="1" orient="horz" pos="2160"><p15:clr><a:srgbClr val="A4A3A4"/></p15:clr></p15:guide><p15:guide id="2" pos="2880"><p15:clr><a:srgbClr val="A4A3A4"/></p15:clr></p15:guide></p15:sldGuideLst></p:ext></p:extLst></p:presentation> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels b/data/pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels
new file mode 100644
index 000000000..0ab2c475a
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout1.xml b/data/pptx/ppt/slideLayouts/slideLayout1.xml
new file mode 100644
index 000000000..c70a75bf9
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="title" preserve="1"><p:cSld name="Title Slide"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ctrTitle"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="685800" y="2130425"/><a:ext cx="7772400" cy="1470025"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Subtitle 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="subTitle" idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="1371600" y="3886200"/><a:ext cx="6400800" cy="1752600"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr marL="0" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl1pPr><a:lvl2pPr marL="457200" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl2pPr><a:lvl3pPr marL="914400" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl3pPr><a:lvl4pPr marL="1371600" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl4pPr><a:lvl5pPr marL="1828800" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl5pPr><a:lvl6pPr marL="2286000" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl6pPr><a:lvl7pPr marL="2743200" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl7pPr><a:lvl8pPr marL="3200400" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl8pPr><a:lvl9pPr marL="3657600" indent="0" algn="ctr"><a:buNone/><a:defRPr><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl9pPr></a:lstStyle><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master subtitle style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Date Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Footer Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Slide Number Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="1444357513"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout10.xml b/data/pptx/ppt/slideLayouts/slideLayout10.xml
new file mode 100644
index 000000000..e07b6ec38
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout10.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="vertTx" preserve="1"><p:cSld name="Title and Vertical Text"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Vertical Text Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" orient="vert" idx="1"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr vert="eaVert"/><a:lstStyle/><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Date Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Footer Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Slide Number Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="313914798"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout11.xml b/data/pptx/ppt/slideLayouts/slideLayout11.xml
new file mode 100644
index 000000000..aa98083cd
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout11.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="vertTitleAndTx" preserve="1"><p:cSld name="Vertical Title and Text"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Vertical Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title" orient="vert"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="6629400" y="274638"/><a:ext cx="2057400" cy="5851525"/></a:xfrm></p:spPr><p:txBody><a:bodyPr vert="eaVert"/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Vertical Text Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" orient="vert" idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="274638"/><a:ext cx="6019800" cy="5851525"/></a:xfrm></p:spPr><p:txBody><a:bodyPr vert="eaVert"/><a:lstStyle/><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Date Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Footer Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Slide Number Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="2581529045"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout2.xml b/data/pptx/ppt/slideLayouts/slideLayout2.xml
new file mode 100644
index 000000000..b44d10c54
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout2.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="obj" preserve="1"><p:cSld name="Title and Content"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Content Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph idx="1"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Date Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Footer Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Slide Number Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="338346009"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout3.xml b/data/pptx/ppt/slideLayouts/slideLayout3.xml
new file mode 100644
index 000000000..f8b39fc3d
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout3.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="secHead" preserve="1"><p:cSld name="Section Header"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="722313" y="4406900"/><a:ext cx="7772400" cy="1362075"/></a:xfrm></p:spPr><p:txBody><a:bodyPr anchor="t"/><a:lstStyle><a:lvl1pPr algn="l"><a:defRPr sz="4000" b="1" cap="all"/></a:lvl1pPr></a:lstStyle><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Text Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="722313" y="2906713"/><a:ext cx="7772400" cy="1500187"/></a:xfrm></p:spPr><p:txBody><a:bodyPr anchor="b"/><a:lstStyle><a:lvl1pPr marL="0" indent="0"><a:buNone/><a:defRPr sz="2000"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl1pPr><a:lvl2pPr marL="457200" indent="0"><a:buNone/><a:defRPr sz="1800"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl2pPr><a:lvl3pPr marL="914400" indent="0"><a:buNone/><a:defRPr sz="1600"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl3pPr><a:lvl4pPr marL="1371600" indent="0"><a:buNone/><a:defRPr sz="1400"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl4pPr><a:lvl5pPr marL="1828800" indent="0"><a:buNone/><a:defRPr sz="1400"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl5pPr><a:lvl6pPr marL="2286000" indent="0"><a:buNone/><a:defRPr sz="1400"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl6pPr><a:lvl7pPr marL="2743200" indent="0"><a:buNone/><a:defRPr sz="1400"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl7pPr><a:lvl8pPr marL="3200400" indent="0"><a:buNone/><a:defRPr sz="1400"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl8pPr><a:lvl9pPr marL="3657600" indent="0"><a:buNone/><a:defRPr sz="1400"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Date Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Footer Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Slide Number Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="1073069076"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout4.xml b/data/pptx/ppt/slideLayouts/slideLayout4.xml
new file mode 100644
index 000000000..e2179e2fa
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout4.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="twoObj" preserve="1"><p:cSld name="Two Content"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Content Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph sz="half" idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="1600200"/><a:ext cx="4038600" cy="4525963"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr><a:defRPr sz="2800"/></a:lvl1pPr><a:lvl2pPr><a:defRPr sz="2400"/></a:lvl2pPr><a:lvl3pPr><a:defRPr sz="2000"/></a:lvl3pPr><a:lvl4pPr><a:defRPr sz="1800"/></a:lvl4pPr><a:lvl5pPr><a:defRPr sz="1800"/></a:lvl5pPr><a:lvl6pPr><a:defRPr sz="1800"/></a:lvl6pPr><a:lvl7pPr><a:defRPr sz="1800"/></a:lvl7pPr><a:lvl8pPr><a:defRPr sz="1800"/></a:lvl8pPr><a:lvl9pPr><a:defRPr sz="1800"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Content Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph sz="half" idx="2"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="4648200" y="1600200"/><a:ext cx="4038600" cy="4525963"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr><a:defRPr sz="2800"/></a:lvl1pPr><a:lvl2pPr><a:defRPr sz="2400"/></a:lvl2pPr><a:lvl3pPr><a:defRPr sz="2000"/></a:lvl3pPr><a:lvl4pPr><a:defRPr sz="1800"/></a:lvl4pPr><a:lvl5pPr><a:defRPr sz="1800"/></a:lvl5pPr><a:lvl6pPr><a:defRPr sz="1800"/></a:lvl6pPr><a:lvl7pPr><a:defRPr sz="1800"/></a:lvl7pPr><a:lvl8pPr><a:defRPr sz="1800"/></a:lvl8pPr><a:lvl9pPr><a:defRPr sz="1800"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Date Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Footer Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="7" name="Slide Number Placeholder 6"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="2619886245"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout5.xml b/data/pptx/ppt/slideLayouts/slideLayout5.xml
new file mode 100644
index 000000000..118704803
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout5.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="twoTxTwoObj" preserve="1"><p:cSld name="Comparison"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr><a:defRPr/></a:lvl1pPr></a:lstStyle><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Text Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="1535113"/><a:ext cx="4040188" cy="639762"/></a:xfrm></p:spPr><p:txBody><a:bodyPr anchor="b"/><a:lstStyle><a:lvl1pPr marL="0" indent="0"><a:buNone/><a:defRPr sz="2400" b="1"/></a:lvl1pPr><a:lvl2pPr marL="457200" indent="0"><a:buNone/><a:defRPr sz="2000" b="1"/></a:lvl2pPr><a:lvl3pPr marL="914400" indent="0"><a:buNone/><a:defRPr sz="1800" b="1"/></a:lvl3pPr><a:lvl4pPr marL="1371600" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl4pPr><a:lvl5pPr marL="1828800" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl5pPr><a:lvl6pPr marL="2286000" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl6pPr><a:lvl7pPr marL="2743200" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl7pPr><a:lvl8pPr marL="3200400" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl8pPr><a:lvl9pPr marL="3657600" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Content Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph sz="half" idx="2"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="2174875"/><a:ext cx="4040188" cy="3951288"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr><a:defRPr sz="2400"/></a:lvl1pPr><a:lvl2pPr><a:defRPr sz="2000"/></a:lvl2pPr><a:lvl3pPr><a:defRPr sz="1800"/></a:lvl3pPr><a:lvl4pPr><a:defRPr sz="1600"/></a:lvl4pPr><a:lvl5pPr><a:defRPr sz="1600"/></a:lvl5pPr><a:lvl6pPr><a:defRPr sz="1600"/></a:lvl6pPr><a:lvl7pPr><a:defRPr sz="1600"/></a:lvl7pPr><a:lvl8pPr><a:defRPr sz="1600"/></a:lvl8pPr><a:lvl9pPr><a:defRPr sz="1600"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Text Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" sz="quarter" idx="3"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="4645025" y="1535113"/><a:ext cx="4041775" cy="639762"/></a:xfrm></p:spPr><p:txBody><a:bodyPr anchor="b"/><a:lstStyle><a:lvl1pPr marL="0" indent="0"><a:buNone/><a:defRPr sz="2400" b="1"/></a:lvl1pPr><a:lvl2pPr marL="457200" indent="0"><a:buNone/><a:defRPr sz="2000" b="1"/></a:lvl2pPr><a:lvl3pPr marL="914400" indent="0"><a:buNone/><a:defRPr sz="1800" b="1"/></a:lvl3pPr><a:lvl4pPr marL="1371600" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl4pPr><a:lvl5pPr marL="1828800" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl5pPr><a:lvl6pPr marL="2286000" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl6pPr><a:lvl7pPr marL="2743200" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl7pPr><a:lvl8pPr marL="3200400" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl8pPr><a:lvl9pPr marL="3657600" indent="0"><a:buNone/><a:defRPr sz="1600" b="1"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Content Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph sz="quarter" idx="4"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="4645025" y="2174875"/><a:ext cx="4041775" cy="3951288"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr><a:defRPr sz="2400"/></a:lvl1pPr><a:lvl2pPr><a:defRPr sz="2000"/></a:lvl2pPr><a:lvl3pPr><a:defRPr sz="1800"/></a:lvl3pPr><a:lvl4pPr><a:defRPr sz="1600"/></a:lvl4pPr><a:lvl5pPr><a:defRPr sz="1600"/></a:lvl5pPr><a:lvl6pPr><a:defRPr sz="1600"/></a:lvl6pPr><a:lvl7pPr><a:defRPr sz="1600"/></a:lvl7pPr><a:lvl8pPr><a:defRPr sz="1600"/></a:lvl8pPr><a:lvl9pPr><a:defRPr sz="1600"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="7" name="Date Placeholder 6"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="8" name="Footer Placeholder 7"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="9" name="Slide Number Placeholder 8"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="2535793967"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout6.xml b/data/pptx/ppt/slideLayouts/slideLayout6.xml
new file mode 100644
index 000000000..3edced81e
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout6.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="titleOnly" preserve="1"><p:cSld name="Title Only"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Date Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Footer Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Slide Number Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="3472721253"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout7.xml b/data/pptx/ppt/slideLayouts/slideLayout7.xml
new file mode 100644
index 000000000..b4d3bc475
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout7.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="blank" preserve="1"><p:cSld name="Blank"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Date Placeholder 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Footer Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Slide Number Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="2130901097"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout8.xml b/data/pptx/ppt/slideLayouts/slideLayout8.xml
new file mode 100644
index 000000000..7a8457653
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout8.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="objTx" preserve="1"><p:cSld name="Content with Caption"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="273050"/><a:ext cx="3008313" cy="1162050"/></a:xfrm></p:spPr><p:txBody><a:bodyPr anchor="b"/><a:lstStyle><a:lvl1pPr algn="l"><a:defRPr sz="2000" b="1"/></a:lvl1pPr></a:lstStyle><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Content Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="3575050" y="273050"/><a:ext cx="5111750" cy="5853113"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr><a:defRPr sz="3200"/></a:lvl1pPr><a:lvl2pPr><a:defRPr sz="2800"/></a:lvl2pPr><a:lvl3pPr><a:defRPr sz="2400"/></a:lvl3pPr><a:lvl4pPr><a:defRPr sz="2000"/></a:lvl4pPr><a:lvl5pPr><a:defRPr sz="2000"/></a:lvl5pPr><a:lvl6pPr><a:defRPr sz="2000"/></a:lvl6pPr><a:lvl7pPr><a:defRPr sz="2000"/></a:lvl7pPr><a:lvl8pPr><a:defRPr sz="2000"/></a:lvl8pPr><a:lvl9pPr><a:defRPr sz="2000"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Text Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" sz="half" idx="2"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="1435100"/><a:ext cx="3008313" cy="4691063"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr marL="0" indent="0"><a:buNone/><a:defRPr sz="1400"/></a:lvl1pPr><a:lvl2pPr marL="457200" indent="0"><a:buNone/><a:defRPr sz="1200"/></a:lvl2pPr><a:lvl3pPr marL="914400" indent="0"><a:buNone/><a:defRPr sz="1000"/></a:lvl3pPr><a:lvl4pPr marL="1371600" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl4pPr><a:lvl5pPr marL="1828800" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl5pPr><a:lvl6pPr marL="2286000" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl6pPr><a:lvl7pPr marL="2743200" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl7pPr><a:lvl8pPr marL="3200400" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl8pPr><a:lvl9pPr marL="3657600" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Date Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Footer Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="7" name="Slide Number Placeholder 6"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="3540895647"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideLayouts/slideLayout9.xml b/data/pptx/ppt/slideLayouts/slideLayout9.xml
new file mode 100644
index 000000000..34a172ae3
--- /dev/null
+++ b/data/pptx/ppt/slideLayouts/slideLayout9.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="picTx" preserve="1"><p:cSld name="Picture with Caption"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="1792288" y="4800600"/><a:ext cx="5486400" cy="566738"/></a:xfrm></p:spPr><p:txBody><a:bodyPr anchor="b"/><a:lstStyle><a:lvl1pPr algn="l"><a:defRPr sz="2000" b="1"/></a:lvl1pPr></a:lstStyle><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Picture Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="pic" idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="1792288" y="612775"/><a:ext cx="5486400" cy="4114800"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr marL="0" indent="0"><a:buNone/><a:defRPr sz="3200"/></a:lvl1pPr><a:lvl2pPr marL="457200" indent="0"><a:buNone/><a:defRPr sz="2800"/></a:lvl2pPr><a:lvl3pPr marL="914400" indent="0"><a:buNone/><a:defRPr sz="2400"/></a:lvl3pPr><a:lvl4pPr marL="1371600" indent="0"><a:buNone/><a:defRPr sz="2000"/></a:lvl4pPr><a:lvl5pPr marL="1828800" indent="0"><a:buNone/><a:defRPr sz="2000"/></a:lvl5pPr><a:lvl6pPr marL="2286000" indent="0"><a:buNone/><a:defRPr sz="2000"/></a:lvl6pPr><a:lvl7pPr marL="2743200" indent="0"><a:buNone/><a:defRPr sz="2000"/></a:lvl7pPr><a:lvl8pPr marL="3200400" indent="0"><a:buNone/><a:defRPr sz="2000"/></a:lvl8pPr><a:lvl9pPr marL="3657600" indent="0"><a:buNone/><a:defRPr sz="2000"/></a:lvl9pPr></a:lstStyle><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Text Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" sz="half" idx="2"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="1792288" y="5367338"/><a:ext cx="5486400" cy="804862"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr marL="0" indent="0"><a:buNone/><a:defRPr sz="1400"/></a:lvl1pPr><a:lvl2pPr marL="457200" indent="0"><a:buNone/><a:defRPr sz="1200"/></a:lvl2pPr><a:lvl3pPr marL="914400" indent="0"><a:buNone/><a:defRPr sz="1000"/></a:lvl3pPr><a:lvl4pPr marL="1371600" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl4pPr><a:lvl5pPr marL="1828800" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl5pPr><a:lvl6pPr marL="2286000" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl6pPr><a:lvl7pPr marL="2743200" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl7pPr><a:lvl8pPr marL="3200400" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl8pPr><a:lvl9pPr marL="3657600" indent="0"><a:buNone/><a:defRPr sz="900"/></a:lvl9pPr></a:lstStyle><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Date Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="10"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Footer Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="11"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="7" name="Slide Number Placeholder 6"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="3566899855"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sldLayout> \ No newline at end of file
diff --git a/data/pptx/ppt/slideMasters/_rels/slideMaster1.xml.rels b/data/pptx/ppt/slideMasters/_rels/slideMaster1.xml.rels
new file mode 100644
index 000000000..6a191ab98
--- /dev/null
+++ b/data/pptx/ppt/slideMasters/_rels/slideMaster1.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout8.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout3.xml"/><Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout7.xml"/><Relationship Id="rId12" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="../theme/theme1.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout2.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout1.xml"/><Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout6.xml"/><Relationship Id="rId11" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout11.xml"/><Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout5.xml"/><Relationship Id="rId10" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout10.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout4.xml"/><Relationship Id="rId9" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout9.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slideMasters/slideMaster1.xml b/data/pptx/ppt/slideMasters/slideMaster1.xml
new file mode 100644
index 000000000..1eb3595f6
--- /dev/null
+++ b/data/pptx/ppt/slideMasters/slideMaster1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sldMaster xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:cSld><p:bg><p:bgRef idx="1001"><a:schemeClr val="bg1"/></p:bgRef></p:bg><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title Placeholder 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="274638"/><a:ext cx="8229600" cy="1143000"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0" anchor="ctr"><a:normAutofit/></a:bodyPr><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master title style</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Text Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="body" idx="1"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="1600200"/><a:ext cx="8229600" cy="4525963"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0"><a:normAutofit/></a:bodyPr><a:lstStyle/><a:p><a:pPr lvl="0"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Click to edit Master text styles</a:t></a:r></a:p><a:p><a:pPr lvl="1"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Second level</a:t></a:r></a:p><a:p><a:pPr lvl="2"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Third level</a:t></a:r></a:p><a:p><a:pPr lvl="3"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fourth level</a:t></a:r></a:p><a:p><a:pPr lvl="4"/><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>Fifth level</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="4" name="Date Placeholder 3"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="dt" sz="half" idx="2"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="457200" y="6356350"/><a:ext cx="2133600" cy="365125"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0" anchor="ctr"/><a:lstStyle><a:lvl1pPr algn="l"><a:defRPr sz="1200"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl1pPr></a:lstStyle><a:p><a:fld id="{241EB5C9-1307-BA42-ABA2-0BC069CD8E7F}" type="datetimeFigureOut"><a:rPr lang="en-US" smtClean="0"/><a:t>2/17/2018</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="5" name="Footer Placeholder 4"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ftr" sz="quarter" idx="3"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="3124200" y="6356350"/><a:ext cx="2895600" cy="365125"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0" anchor="ctr"/><a:lstStyle><a:lvl1pPr algn="ctr"><a:defRPr sz="1200"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl1pPr></a:lstStyle><a:p><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="6" name="Slide Number Placeholder 5"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="4"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="6553200" y="6356350"/><a:ext cx="2133600" cy="365125"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0" anchor="ctr"/><a:lstStyle><a:lvl1pPr algn="r"><a:defRPr sz="1200"><a:solidFill><a:schemeClr val="tx1"><a:tint val="75000"/></a:schemeClr></a:solidFill></a:defRPr></a:lvl1pPr></a:lstStyle><a:p><a:fld id="{C5EF2332-01BF-834F-8236-50238282D533}" type="slidenum"><a:rPr lang="en-US" smtClean="0"/><a:t>‹#›</a:t></a:fld><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="3676200875"/></p:ext></p:extLst></p:cSld><p:clrMap bg1="lt1" tx1="dk1" bg2="lt2" tx2="dk2" accent1="accent1" accent2="accent2" accent3="accent3" accent4="accent4" accent5="accent5" accent6="accent6" hlink="hlink" folHlink="folHlink"/><p:sldLayoutIdLst><p:sldLayoutId id="2147483649" r:id="rId1"/><p:sldLayoutId id="2147483650" r:id="rId2"/><p:sldLayoutId id="2147483651" r:id="rId3"/><p:sldLayoutId id="2147483652" r:id="rId4"/><p:sldLayoutId id="2147483653" r:id="rId5"/><p:sldLayoutId id="2147483654" r:id="rId6"/><p:sldLayoutId id="2147483655" r:id="rId7"/><p:sldLayoutId id="2147483656" r:id="rId8"/><p:sldLayoutId id="2147483657" r:id="rId9"/><p:sldLayoutId id="2147483658" r:id="rId10"/><p:sldLayoutId id="2147483659" r:id="rId11"/></p:sldLayoutIdLst><p:txStyles><p:titleStyle><a:lvl1pPr algn="ctr" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="0"/></a:spcBef><a:buNone/><a:defRPr sz="4400" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mj-lt"/><a:ea typeface="+mj-ea"/><a:cs typeface="+mj-cs"/></a:defRPr></a:lvl1pPr></p:titleStyle><p:bodyStyle><a:lvl1pPr marL="342900" indent="-342900" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="•"/><a:defRPr sz="3200" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl1pPr><a:lvl2pPr marL="742950" indent="-285750" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="–"/><a:defRPr sz="2800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl2pPr><a:lvl3pPr marL="1143000" indent="-228600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="•"/><a:defRPr sz="2400" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl3pPr><a:lvl4pPr marL="1600200" indent="-228600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="–"/><a:defRPr sz="2000" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl4pPr><a:lvl5pPr marL="2057400" indent="-228600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="»"/><a:defRPr sz="2000" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl5pPr><a:lvl6pPr marL="2514600" indent="-228600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="•"/><a:defRPr sz="2000" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl6pPr><a:lvl7pPr marL="2971800" indent="-228600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="•"/><a:defRPr sz="2000" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl7pPr><a:lvl8pPr marL="3429000" indent="-228600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="•"/><a:defRPr sz="2000" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl8pPr><a:lvl9pPr marL="3886200" indent="-228600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:spcBef><a:spcPct val="20000"/></a:spcBef><a:buFont typeface="Arial"/><a:buChar char="•"/><a:defRPr sz="2000" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl9pPr></p:bodyStyle><p:otherStyle><a:defPPr><a:defRPr lang="en-US"/></a:defPPr><a:lvl1pPr marL="0" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl1pPr><a:lvl2pPr marL="457200" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl2pPr><a:lvl3pPr marL="914400" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl3pPr><a:lvl4pPr marL="1371600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl4pPr><a:lvl5pPr marL="1828800" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl5pPr><a:lvl6pPr marL="2286000" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl6pPr><a:lvl7pPr marL="2743200" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl7pPr><a:lvl8pPr marL="3200400" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl8pPr><a:lvl9pPr marL="3657600" algn="l" defTabSz="457200" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1"><a:defRPr sz="1800" kern="1200"><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:latin typeface="+mn-lt"/><a:ea typeface="+mn-ea"/><a:cs typeface="+mn-cs"/></a:defRPr></a:lvl9pPr></p:otherStyle></p:txStyles></p:sldMaster> \ No newline at end of file
diff --git a/data/pptx/ppt/slides/_rels/slide1.xml.rels b/data/pptx/ppt/slides/_rels/slide1.xml.rels
new file mode 100644
index 000000000..c8628ebbd
--- /dev/null
+++ b/data/pptx/ppt/slides/_rels/slide1.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide" Target="../notesSlides/notesSlide1.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout1.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slides/_rels/slide2.xml.rels b/data/pptx/ppt/slides/_rels/slide2.xml.rels
new file mode 100644
index 000000000..89a9f5a77
--- /dev/null
+++ b/data/pptx/ppt/slides/_rels/slide2.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide" Target="../notesSlides/notesSlide2.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout2.xml"/></Relationships> \ No newline at end of file
diff --git a/data/pptx/ppt/slides/slide1.xml b/data/pptx/ppt/slides/slide1.xml
new file mode 100644
index 000000000..2d1863312
--- /dev/null
+++ b/data/pptx/ppt/slides/slide1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="ctrTitle"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" dirty="0" smtClean="0"/><a:t>Title</a:t></a:r><a:endParaRPr lang="en-US" dirty="0"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Subtitle 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="subTitle" idx="1"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" dirty="0" smtClean="0"/><a:t>Subtitle</a:t></a:r><a:endParaRPr lang="en-US" dirty="0"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="392669009"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sld> \ No newline at end of file
diff --git a/data/pptx/ppt/slides/slide2.xml b/data/pptx/ppt/slides/slide2.xml
new file mode 100644
index 000000000..7e1aa0d84
--- /dev/null
+++ b/data/pptx/ppt/slides/slide2.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" dirty="0" smtClean="0"/><a:t>Slide Title</a:t></a:r><a:endParaRPr lang="en-US" dirty="0"/></a:p></p:txBody></p:sp><p:sp><p:nvSpPr><p:cNvPr id="3" name="Content Placeholder 2"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph idx="1"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:pPr marL="0" indent="0"><a:buNone/></a:pPr><a:r><a:rPr lang="en-US" dirty="0" smtClean="0"/><a:t>Hello</a:t></a:r><a:r><a:rPr lang="en-US" smtClean="0"/><a:t>, world.</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree><p:extLst><p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}"><p14:creationId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="572707455"/></p:ext></p:extLst></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sld> \ No newline at end of file
diff --git a/data/pptx/ppt/tableStyles.xml b/data/pptx/ppt/tableStyles.xml
new file mode 100644
index 000000000..ecd5f7a01
--- /dev/null
+++ b/data/pptx/ppt/tableStyles.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<a:tblStyleLst xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" def="{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"/> \ No newline at end of file
diff --git a/data/pptx/ppt/theme/theme1.xml b/data/pptx/ppt/theme/theme1.xml
new file mode 100644
index 000000000..d4f11e794
--- /dev/null
+++ b/data/pptx/ppt/theme/theme1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme"><a:themeElements><a:clrScheme name="Office"><a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1><a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1><a:dk2><a:srgbClr val="1F497D"/></a:dk2><a:lt2><a:srgbClr val="EEECE1"/></a:lt2><a:accent1><a:srgbClr val="4F81BD"/></a:accent1><a:accent2><a:srgbClr val="C0504D"/></a:accent2><a:accent3><a:srgbClr val="9BBB59"/></a:accent3><a:accent4><a:srgbClr val="8064A2"/></a:accent4><a:accent5><a:srgbClr val="4BACC6"/></a:accent5><a:accent6><a:srgbClr val="F79646"/></a:accent6><a:hlink><a:srgbClr val="0000FF"/></a:hlink><a:folHlink><a:srgbClr val="800080"/></a:folHlink></a:clrScheme><a:fontScheme name="Office"><a:majorFont><a:latin typeface="Calibri"/><a:ea typeface=""/><a:cs typeface=""/><a:font script="Jpan" typeface="MS Pゴシック"/><a:font script="Hang" typeface="맑은 고딕"/><a:font script="Hans" typeface="宋体"/><a:font script="Hant" typeface="新細明體"/><a:font script="Arab" typeface="Times New Roman"/><a:font script="Hebr" typeface="Times New Roman"/><a:font script="Thai" typeface="Angsana New"/><a:font script="Ethi" typeface="Nyala"/><a:font script="Beng" typeface="Vrinda"/><a:font script="Gujr" typeface="Shruti"/><a:font script="Khmr" typeface="MoolBoran"/><a:font script="Knda" typeface="Tunga"/><a:font script="Guru" typeface="Raavi"/><a:font script="Cans" typeface="Euphemia"/><a:font script="Cher" typeface="Plantagenet Cherokee"/><a:font script="Yiii" typeface="Microsoft Yi Baiti"/><a:font script="Tibt" typeface="Microsoft Himalaya"/><a:font script="Thaa" typeface="MV Boli"/><a:font script="Deva" typeface="Mangal"/><a:font script="Telu" typeface="Gautami"/><a:font script="Taml" typeface="Latha"/><a:font script="Syrc" typeface="Estrangelo Edessa"/><a:font script="Orya" typeface="Kalinga"/><a:font script="Mlym" typeface="Kartika"/><a:font script="Laoo" typeface="DokChampa"/><a:font script="Sinh" typeface="Iskoola Pota"/><a:font script="Mong" typeface="Mongolian Baiti"/><a:font script="Viet" typeface="Times New Roman"/><a:font script="Uigh" typeface="Microsoft Uighur"/><a:font script="Geor" typeface="Sylfaen"/></a:majorFont><a:minorFont><a:latin typeface="Calibri"/><a:ea typeface=""/><a:cs typeface=""/><a:font script="Jpan" typeface="MS Pゴシック"/><a:font script="Hang" typeface="맑은 고딕"/><a:font script="Hans" typeface="宋体"/><a:font script="Hant" typeface="新細明體"/><a:font script="Arab" typeface="Arial"/><a:font script="Hebr" typeface="Arial"/><a:font script="Thai" typeface="Cordia New"/><a:font script="Ethi" typeface="Nyala"/><a:font script="Beng" typeface="Vrinda"/><a:font script="Gujr" typeface="Shruti"/><a:font script="Khmr" typeface="DaunPenh"/><a:font script="Knda" typeface="Tunga"/><a:font script="Guru" typeface="Raavi"/><a:font script="Cans" typeface="Euphemia"/><a:font script="Cher" typeface="Plantagenet Cherokee"/><a:font script="Yiii" typeface="Microsoft Yi Baiti"/><a:font script="Tibt" typeface="Microsoft Himalaya"/><a:font script="Thaa" typeface="MV Boli"/><a:font script="Deva" typeface="Mangal"/><a:font script="Telu" typeface="Gautami"/><a:font script="Taml" typeface="Latha"/><a:font script="Syrc" typeface="Estrangelo Edessa"/><a:font script="Orya" typeface="Kalinga"/><a:font script="Mlym" typeface="Kartika"/><a:font script="Laoo" typeface="DokChampa"/><a:font script="Sinh" typeface="Iskoola Pota"/><a:font script="Mong" typeface="Mongolian Baiti"/><a:font script="Viet" typeface="Arial"/><a:font script="Uigh" typeface="Microsoft Uighur"/><a:font script="Geor" typeface="Sylfaen"/></a:minorFont></a:fontScheme><a:fmtScheme name="Office"><a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs><a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="16200000" scaled="1"/></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="100000"/><a:shade val="100000"/><a:satMod val="130000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="50000"/><a:shade val="100000"/><a:satMod val="350000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="16200000" scaled="0"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w="9525" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"><a:shade val="95000"/><a:satMod val="105000"/></a:schemeClr></a:solidFill><a:prstDash val="solid"/></a:ln><a:ln w="25400" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln><a:ln w="38100" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="38000"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr></a:outerShdw></a:effectLst><a:scene3d><a:camera prst="orthographicFront"><a:rot lat="0" lon="0" rev="0"/></a:camera><a:lightRig rig="threePt" dir="t"><a:rot lat="0" lon="0" rev="1200000"/></a:lightRig></a:scene3d><a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs><a:gs pos="40000"><a:schemeClr val="phClr"><a:tint val="45000"/><a:shade val="99000"/><a:satMod val="350000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs></a:gsLst><a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs></a:gsLst><a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults><a:spDef><a:spPr/><a:bodyPr/><a:lstStyle/><a:style><a:lnRef idx="1"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="3"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="2"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="lt1"/></a:fontRef></a:style></a:spDef><a:lnDef><a:spPr/><a:bodyPr/><a:lstStyle/><a:style><a:lnRef idx="2"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="0"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="1"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="tx1"/></a:fontRef></a:style></a:lnDef></a:objectDefaults><a:extraClrSchemeLst/></a:theme> \ No newline at end of file
diff --git a/data/pptx/ppt/theme/theme2.xml b/data/pptx/ppt/theme/theme2.xml
new file mode 100644
index 000000000..0d1c2a234
--- /dev/null
+++ b/data/pptx/ppt/theme/theme2.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme"><a:themeElements><a:clrScheme name="Office"><a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1><a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1><a:dk2><a:srgbClr val="44546A"/></a:dk2><a:lt2><a:srgbClr val="E7E6E6"/></a:lt2><a:accent1><a:srgbClr val="5B9BD5"/></a:accent1><a:accent2><a:srgbClr val="ED7D31"/></a:accent2><a:accent3><a:srgbClr val="A5A5A5"/></a:accent3><a:accent4><a:srgbClr val="FFC000"/></a:accent4><a:accent5><a:srgbClr val="4472C4"/></a:accent5><a:accent6><a:srgbClr val="70AD47"/></a:accent6><a:hlink><a:srgbClr val="0563C1"/></a:hlink><a:folHlink><a:srgbClr val="954F72"/></a:folHlink></a:clrScheme><a:fontScheme name="Office"><a:majorFont><a:latin typeface="Calibri Light" panose="020F0302020204030204"/><a:ea typeface=""/><a:cs typeface=""/><a:font script="Jpan" typeface="MS Pゴシック"/><a:font script="Hang" typeface="맑은 고딕"/><a:font script="Hans" typeface="宋体"/><a:font script="Hant" typeface="新細明體"/><a:font script="Arab" typeface="Times New Roman"/><a:font script="Hebr" typeface="Times New Roman"/><a:font script="Thai" typeface="Angsana New"/><a:font script="Ethi" typeface="Nyala"/><a:font script="Beng" typeface="Vrinda"/><a:font script="Gujr" typeface="Shruti"/><a:font script="Khmr" typeface="MoolBoran"/><a:font script="Knda" typeface="Tunga"/><a:font script="Guru" typeface="Raavi"/><a:font script="Cans" typeface="Euphemia"/><a:font script="Cher" typeface="Plantagenet Cherokee"/><a:font script="Yiii" typeface="Microsoft Yi Baiti"/><a:font script="Tibt" typeface="Microsoft Himalaya"/><a:font script="Thaa" typeface="MV Boli"/><a:font script="Deva" typeface="Mangal"/><a:font script="Telu" typeface="Gautami"/><a:font script="Taml" typeface="Latha"/><a:font script="Syrc" typeface="Estrangelo Edessa"/><a:font script="Orya" typeface="Kalinga"/><a:font script="Mlym" typeface="Kartika"/><a:font script="Laoo" typeface="DokChampa"/><a:font script="Sinh" typeface="Iskoola Pota"/><a:font script="Mong" typeface="Mongolian Baiti"/><a:font script="Viet" typeface="Times New Roman"/><a:font script="Uigh" typeface="Microsoft Uighur"/><a:font script="Geor" typeface="Sylfaen"/></a:majorFont><a:minorFont><a:latin typeface="Calibri" panose="020F0502020204030204"/><a:ea typeface=""/><a:cs typeface=""/><a:font script="Jpan" typeface="MS Pゴシック"/><a:font script="Hang" typeface="맑은 고딕"/><a:font script="Hans" typeface="宋体"/><a:font script="Hant" typeface="新細明體"/><a:font script="Arab" typeface="Arial"/><a:font script="Hebr" typeface="Arial"/><a:font script="Thai" typeface="Cordia New"/><a:font script="Ethi" typeface="Nyala"/><a:font script="Beng" typeface="Vrinda"/><a:font script="Gujr" typeface="Shruti"/><a:font script="Khmr" typeface="DaunPenh"/><a:font script="Knda" typeface="Tunga"/><a:font script="Guru" typeface="Raavi"/><a:font script="Cans" typeface="Euphemia"/><a:font script="Cher" typeface="Plantagenet Cherokee"/><a:font script="Yiii" typeface="Microsoft Yi Baiti"/><a:font script="Tibt" typeface="Microsoft Himalaya"/><a:font script="Thaa" typeface="MV Boli"/><a:font script="Deva" typeface="Mangal"/><a:font script="Telu" typeface="Gautami"/><a:font script="Taml" typeface="Latha"/><a:font script="Syrc" typeface="Estrangelo Edessa"/><a:font script="Orya" typeface="Kalinga"/><a:font script="Mlym" typeface="Kartika"/><a:font script="Laoo" typeface="DokChampa"/><a:font script="Sinh" typeface="Iskoola Pota"/><a:font script="Mong" typeface="Mongolian Baiti"/><a:font script="Viet" typeface="Arial"/><a:font script="Uigh" typeface="Microsoft Uighur"/><a:font script="Geor" typeface="Sylfaen"/></a:minorFont></a:fontScheme><a:fmtScheme name="Office"><a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:lumMod val="110000"/><a:satMod val="105000"/><a:tint val="67000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:lumMod val="105000"/><a:satMod val="103000"/><a:tint val="73000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:lumMod val="105000"/><a:satMod val="109000"/><a:tint val="81000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:satMod val="103000"/><a:lumMod val="102000"/><a:tint val="94000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:satMod val="110000"/><a:lumMod val="100000"/><a:shade val="100000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:lumMod val="99000"/><a:satMod val="120000"/><a:shade val="78000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w="6350" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln><a:ln w="12700" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln><a:ln w="19050" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="57150" dist="19050" dir="5400000" algn="ctr" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="63000"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:solidFill><a:schemeClr val="phClr"><a:tint val="95000"/><a:satMod val="170000"/></a:schemeClr></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="93000"/><a:satMod val="150000"/><a:shade val="98000"/><a:lumMod val="102000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:tint val="98000"/><a:satMod val="130000"/><a:shade val="90000"/><a:lumMod val="103000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="63000"/><a:satMod val="120000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults/><a:extraClrSchemeLst/><a:extLst><a:ext uri="{05A4C25C-085E-4340-85A3-A5531E510DB2}"><thm15:themeFamily xmlns:thm15="http://schemas.microsoft.com/office/thememl/2012/main" name="Office Theme" id="{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}" vid="{4A3C46E8-61CC-4603-A589-7422A47A8E4A}"/></a:ext></a:extLst></a:theme> \ No newline at end of file
diff --git a/data/pptx/ppt/viewProps.xml b/data/pptx/ppt/viewProps.xml
new file mode 100644
index 000000000..932dcd50d
--- /dev/null
+++ b/data/pptx/ppt/viewProps.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<p:viewPr xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:normalViewPr><p:restoredLeft sz="15633" autoAdjust="0"/><p:restoredTop sz="94711" autoAdjust="0"/></p:normalViewPr><p:slideViewPr><p:cSldViewPr snapToGrid="0" snapToObjects="1"><p:cViewPr varScale="1"><p:scale><a:sx n="93" d="100"/><a:sy n="93" d="100"/></p:scale><p:origin x="102" y="120"/></p:cViewPr><p:guideLst><p:guide orient="horz" pos="2160"/><p:guide pos="2880"/></p:guideLst></p:cSldViewPr></p:slideViewPr><p:outlineViewPr><p:cViewPr><p:scale><a:sx n="33" d="100"/><a:sy n="33" d="100"/></p:scale><p:origin x="0" y="0"/></p:cViewPr></p:outlineViewPr><p:notesTextViewPr><p:cViewPr><p:scale><a:sx n="100" d="100"/><a:sy n="100" d="100"/></p:scale><p:origin x="0" y="0"/></p:cViewPr></p:notesTextViewPr><p:gridSpacing cx="76200" cy="76200"/></p:viewPr> \ No newline at end of file
diff --git a/data/sample.lua b/data/sample.lua
index 1e3a08731..6c09442b5 100644
--- a/data/sample.lua
+++ b/data/sample.lua
@@ -242,14 +242,12 @@ function OrderedList(items)
return "<ol>\n" .. table.concat(buffer, "\n") .. "\n</ol>"
end
--- Revisit association list STackValue instance.
function DefinitionList(items)
local buffer = {}
for _,item in pairs(items) do
- for k, v in pairs(item) do
- table.insert(buffer,"<dt>" .. k .. "</dt>\n<dd>" ..
- table.concat(v,"</dd>\n<dd>") .. "</dd>")
- end
+ local k, v = next(item)
+ table.insert(buffer, "<dt>" .. k .. "</dt>\n<dd>" ..
+ table.concat(v, "</dd>\n<dd>") .. "</dd>")
end
return "<dl>\n" .. table.concat(buffer, "\n") .. "\n</dl>"
end
@@ -288,7 +286,7 @@ function Table(caption, aligns, widths, headers, rows)
end
if widths and widths[1] ~= 0 then
for _, w in pairs(widths) do
- add('<col width="' .. string.format("%d%%", w * 100) .. '" />')
+ add('<col width="' .. string.format("%.0f%%", w * 100) .. '" />')
end
end
local header_row = {}
diff --git a/data/templates/default.beamer b/data/templates/default.beamer
deleted file mode 100644
index 680a4121d..000000000
--- a/data/templates/default.beamer
+++ /dev/null
@@ -1,278 +0,0 @@
-\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(handout)$handout,$endif$$if(beamer)$ignorenonframetext,$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$}
-\setbeamertemplate{caption}[numbered]
-\setbeamertemplate{caption label separator}{: }
-\setbeamercolor{caption name}{fg=normal text.fg}
-\beamertemplatenavigationsymbols$if(navigation)$$navigation$$else$empty$endif$
-$if(fontfamily)$
-\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
-$else$
-\usepackage{lmodern}
-$endif$
-\usepackage{amssymb,amsmath}
-\usepackage{ifxetex,ifluatex}
-\usepackage{fixltx2e} % provides \textsubscript
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
- \usepackage[utf8]{inputenc}
-$if(euro)$
- \usepackage{eurosym}
-$endif$
-\else % if luatex or xelatex
- \ifxetex
- \usepackage{mathspec}
- \else
- \usepackage{fontspec}
- \fi
- \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
-$for(fontfamilies)$
- \newfontfamily{$fontfamilies.name$}[$fontfamilies.options$]{$fontfamilies.font$}
-$endfor$
-$if(euro)$
- \newcommand{\euro}{€}
-$endif$
-$if(mainfont)$
- \setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
-$endif$
-$if(sansfont)$
- \setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$}
-$endif$
-$if(monofont)$
- \setmonofont[Mapping=tex-ansi$if(monofontoptions)$,$for(monofontoptions)$$monofontoptions$$sep$,$endfor$$endif$]{$monofont$}
-$endif$
-$if(mathfont)$
- \setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
-$endif$
-$if(CJKmainfont)$
- \usepackage{xeCJK}
- \setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
-$endif$
-\fi
-$if(theme)$
-\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
-$endif$
-$if(colortheme)$
-\usecolortheme{$colortheme$}
-$endif$
-$if(fonttheme)$
-\usefonttheme{$fonttheme$}
-$endif$
-$if(mainfont)$
-\usefonttheme{serif} % use mainfont rather than sansfont for slide text
-$endif$
-$if(innertheme)$
-\useinnertheme{$innertheme$}
-$endif$
-$if(outertheme)$
-\useoutertheme{$outertheme$}
-$endif$
-% use upquote if available, for straight quotes in verbatim environments
-\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
-% use microtype if available
-\IfFileExists{microtype.sty}{%
-\usepackage{microtype}
-\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
-}{}
-$if(lang)$
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
-$if(babel-newcommands)$
- $babel-newcommands$
-$endif$
-\else
- \usepackage{polyglossia}
- \setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$}
-$for(polyglossia-otherlangs)$
- \setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$}
-$endfor$
-\fi
-$endif$
-\newif\ifbibliography
-$if(natbib)$
-\usepackage{natbib}
-\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
-$endif$
-$if(biblatex)$
-\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
-$for(bibliography)$
-\addbibresource{$bibliography$}
-$endfor$
-$endif$
-$if(verbatim-in-note)$
-\usepackage{fancyvrb}
-$endif$
-\hypersetup{
-$if(title-meta)$
- pdftitle={$title-meta$},
-$endif$
-$if(author-meta)$
- pdfauthor={$author-meta$},
-$endif$
-$if(keywords)$
- pdfkeywords={$for(keywords)$$keywords$$sep$, $endfor$},
-$endif$
-$if(colorlinks)$
- colorlinks=true,
- linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$,
- citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$,
- urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$,
-$else$
- pdfborder={0 0 0},
-$endif$
- breaklinks=true}
-\urlstyle{same} % don't use monospace font for urls
-$if(verbatim-in-note)$
-\VerbatimFootnotes % allows verbatim text in footnotes
-$endif$
-$if(listings)$
-\usepackage{listings}
-$endif$
-$if(lhs)$
-\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
-$endif$
-$if(highlighting-macros)$
-$highlighting-macros$
-$endif$
-$if(tables)$
-\usepackage{longtable,booktabs}
-\usepackage{caption}
-% These lines are needed to make table captions work with longtable:
-\makeatletter
-\def\fnum@table{\tablename~\thetable}
-\makeatother
-$endif$
-$if(graphics)$
-\usepackage{graphicx,grffile}
-\makeatletter
-\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
-\def\maxheight{\ifdim\Gin@nat@height>\textheight0.8\textheight\else\Gin@nat@height\fi}
-\makeatother
-% Scale images if necessary, so that they will not overflow the page
-% margins by default, and it is still possible to overwrite the defaults
-% using explicit options in \includegraphics[width, height, ...]{}
-\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
-$endif$
-
-% Prevent slide breaks in the middle of a paragraph:
-\widowpenalties 1 10000
-\raggedbottom
-
-$if(section-titles)$
-\AtBeginPart{
- \let\insertpartnumber\relax
- \let\partname\relax
- \frame{\partpage}
-}
-\AtBeginSection{
- \ifbibliography
- \else
- \let\insertsectionnumber\relax
- \let\sectionname\relax
- \frame{\sectionpage}
- \fi
-}
-\AtBeginSubsection{
- \let\insertsubsectionnumber\relax
- \let\subsectionname\relax
- \frame{\subsectionpage}
-}
-$endif$
-
-$if(links-as-notes)$
-% Make links footnotes instead of hotlinks:
-\renewcommand{\href}[2]{#2\footnote{\url{#1}}}
-$endif$
-$if(strikeout)$
-\usepackage[normalem]{ulem}
-% avoid problems with \sout in headers with hyperref:
-\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
-$endif$
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-\setlength{\emergencystretch}{3em} % prevent overfull lines
-\providecommand{\tightlist}{%
- \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-$if(numbersections)$
-\setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
-$else$
-\setcounter{secnumdepth}{0}
-$endif$
-$if(dir)$
-\ifxetex
- % load bidi as late as possible as it modifies e.g. graphicx
- $if(latex-dir-rtl)$
- \usepackage[RTLdocument]{bidi}
- $else$
- \usepackage{bidi}
- $endif$
-\fi
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \TeXXeTstate=1
- \newcommand{\RL}[1]{\beginR #1\endR}
- \newcommand{\LR}[1]{\beginL #1\endL}
- \newenvironment{RTL}{\beginR}{\endR}
- \newenvironment{LTR}{\beginL}{\endL}
-\fi
-$endif$
-$for(header-includes)$
-$header-includes$
-$endfor$
-
-$if(title)$
-\title{$title$}
-$endif$
-$if(subtitle)$
-\subtitle{$subtitle$}
-$endif$
-$if(author)$
-\author{$for(author)$$author$$sep$ \and $endfor$}
-$endif$
-$if(institute)$
-\institute{$for(institute)$$institute$$sep$ \and $endfor$}
-$endif$
-\date{$date$}
-
-\begin{document}
-$if(title)$
-\frame{\titlepage}
-$endif$
-
-$for(include-before)$
-$include-before$
-
-$endfor$
-$if(toc)$
-\begin{frame}
-\tableofcontents[hideallsubsections]
-\end{frame}
-
-$endif$
-$body$
-
-$if(natbib)$
-$if(bibliography)$
-$if(biblio-title)$
-$if(book-class)$
-\renewcommand\bibname{$biblio-title$}
-$else$
-\renewcommand\refname{$biblio-title$}
-$endif$
-$endif$
-\begin{frame}[allowframebreaks]{$biblio-title$}
-\bibliographytrue
-\bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
-\end{frame}
-
-$endif$
-$endif$
-$if(biblatex)$
-\begin{frame}[allowframebreaks]{$biblio-title$}
-\bibliographytrue
-\printbibliography[heading=none]
-\end{frame}
-
-$endif$
-$for(include-after)$
-$include-after$
-
-$endfor$
-\end{document}
diff --git a/data/templates/default.commonmark b/data/templates/default.commonmark
index 95d7e52cc..9f6ca96de 100644
--- a/data/templates/default.commonmark
+++ b/data/templates/default.commonmark
@@ -11,7 +11,7 @@ $include-before$
$endfor$
$if(toc)$
-$toc$
+$table-of-contents$
$endif$
$body$
diff --git a/data/templates/default.context b/data/templates/default.context
index 4a3457934..56f4e9cf7 100644
--- a/data/templates/default.context
+++ b/data/templates/default.context
@@ -23,6 +23,7 @@ $endif$
style=$linkstyle$,
color=$linkcolor$,
contrastcolor=$linkcontrastcolor$]
+
% make chapter, section bookmarks visible when opening document
\placebookmarks[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][chapter, section]
\setupinteractionscreen[option=bookmark]
@@ -37,26 +38,22 @@ $endif$
$if(pagenumbering)$
\setuppagenumbering[$for(pagenumbering)$$pagenumbering$$sep$,$endfor$]
$endif$
+
% use microtypography
\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
\setupalign[hz,hanging]
\setupitaliccorrection[global, always]
+
\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
-\usemodule[simplefonts$if(fontsize)$,$fontsize$$endif$]
-\setmainfontfallback[DejaVu Serif][range={greekandcoptic, greekextended}, force=yes, rscale=auto]
-$if(mainfont)$
-\setmainfont[$mainfont$]
-$endif$
-$if(sansfont)$
-\setsansfont[$sansfont$][rscale=auto]
-$endif$
-$if(monofont)$
-\setmonofont[$monofont$][features=none, rscale=auto]
-$endif$
-$if(mathfont)$
-\setmathfont[$mathfont$][rscale=auto]
-$endif$
+
+\definefallbackfamily[mainface][rm][DejaVu Serif][preset=range:greek, force=yes]
+\definefontfamily[mainface][rm][$if(mainfont)$$mainfont$$else$Latin Modern Roman$endif$]
+\definefontfamily[mainface][mm][$if(mathfont)$$mathfont$$else$Latin Modern Math$endif$]
+\definefontfamily[mainface][ss][$if(sansfont)$$sansfont$$else$Latin Modern Sans$endif$]
+\definefontfamily[mainface][tt][$if(monofont)$$monofont$$else$Latin Modern Typewriter$endif$][features=none]
+\setupbodyfont[mainface$if(fontsize)$,$fontsize$$endif$]
+
\setupwhitespace[$if(whitespace)$$whitespace$$else$medium$endif$]
$if(indenting)$
\setupindenting[$for(indenting)$$indenting$$sep$,$endfor$]
@@ -95,6 +92,11 @@ $endif$
\setupthinrules[width=15em] % width of horizontal rules
+\setupxtable[frame=off]
+\setupxtable[head][topframe=on,bottomframe=on]
+\setupxtable[body][]
+\setupxtable[foot][bottomframe=on]
+
$for(header-includes)$
$header-includes$
$endfor$
diff --git a/data/templates/default.docbook b/data/templates/default.docbook4
index 5313c4083..5313c4083 100644
--- a/data/templates/default.docbook
+++ b/data/templates/default.docbook4
diff --git a/data/templates/default.docbook5 b/data/templates/default.docbook5
index 415ccf9c3..b2c407903 100644
--- a/data/templates/default.docbook5
+++ b/data/templates/default.docbook5
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE article>
<article
+$if(lang)$
+ xml:lang="$lang$"
+$endif$
xmlns="http://docbook.org/ns/docbook" version="5.0"
$if(mathml)$
xmlns:mml="http://www.w3.org/1998/Math/MathML"
@@ -8,6 +11,9 @@ $endif$
xmlns:xlink="http://www.w3.org/1999/xlink" >
<info>
<title>$title$</title>
+$if(subtitle)$
+ <subtitle>$subtitle$</subtitle>
+$endif$
$if(author)$
<authorgroup>
$for(author)$
diff --git a/data/templates/default.dzslides b/data/templates/default.dzslides
index 97d518931..892a434cb 100644
--- a/data/templates/default.dzslides
+++ b/data/templates/default.dzslides
@@ -12,10 +12,15 @@ $if(keywords)$
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$">
$endif$
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
- <style type="text/css">code{white-space: pre-wrap;}</style>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
$if(quotes)$
- <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
+ q { quotes: "“" "”" "‘" "’"; }
$endif$
+ </style>
$if(highlighting-css)$
<style type="text/css">
$highlighting-css$
@@ -26,7 +31,7 @@ $for(css)$
<link rel="stylesheet" href="$css$">
$endfor$
$else$
-<link href='http://fonts.googleapis.com/css?family=Oswald' rel='stylesheet'>
+<link href='https://fonts.googleapis.com/css?family=Oswald' rel='stylesheet'>
<style>
html, .view body { background-color: black; counter-reset: slideidx; }
@@ -183,7 +188,7 @@ $endif$
$endif$
$if(toc)$
<section id="$idprefix$TOC">
-$toc$
+$table-of-contents$
</section>
$endif$
$for(include-before)$
diff --git a/data/templates/default.epub b/data/templates/default.epub
deleted file mode 100644
index afcf96a3e..000000000
--- a/data/templates/default.epub
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"$if(lang)$ xml:lang="$lang$"$endif$>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="Content-Style-Type" content="text/css" />
- <meta name="generator" content="pandoc" />
- <title>$pagetitle$</title>
-$if(highlighting-css)$
- <style type="text/css">
-$highlighting-css$
- </style>
-$endif$
-$for(css)$
- <link rel="stylesheet" type="text/css" href="$css$" />
-$endfor$
-$for(header-includes)$
- $header-includes$
-$endfor$
-</head>
-<body$if(coverpage)$ id="cover"$endif$>
-$if(titlepage)$
-$for(title)$
-$if(title.text)$
- <h1 class="$title.type$">$title.text$</h1>
-$else$
- <h1 class="title">$title$</h1>
-$endif$
-$endfor$
-$if(subtitle)$
- <p class="subtitle">$subtitle$</p>
-$endif$
-$for(author)$
- <p class="author">$author$</p>
-$endfor$
-$for(creator)$
- <p class="$creator.role$">$creator.text$</p>
-$endfor$
-$if(publisher)$
- <p class="publisher">$publisher$</p>
-$endif$
-$if(date)$
- <p class="date">$date$</p>
-$endif$
-$if(rights)$
- <div class="rights">$rights$</div>
-$endif$
-$else$
-$for(include-before)$
-$include-before$
-$endfor$
-$body$
-$for(include-after)$
-$include-after$
-$endfor$
-$endif$
-</body>
-</html>
-
diff --git a/data/templates/default.epub2 b/data/templates/default.epub2
new file mode 100644
index 000000000..cca9fcf6f
--- /dev/null
+++ b/data/templates/default.epub2
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"$if(lang)$ xml:lang="$lang$"$endif$>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <meta name="generator" content="pandoc" />
+ <title>$pagetitle$</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+$if(quotes)$
+ q { quotes: "“" "”" "‘" "’"; }
+$endif$
+ </style>
+$if(highlighting-css)$
+ <style type="text/css">
+$highlighting-css$
+ </style>
+$endif$
+$for(css)$
+ <link rel="stylesheet" type="text/css" href="$css$" />
+$endfor$
+$for(header-includes)$
+ $header-includes$
+$endfor$
+</head>
+<body$if(coverpage)$ id="cover"$endif$>
+$if(titlepage)$
+$for(title)$
+$if(title.text)$
+ <h1 class="$title.type$">$title.text$</h1>
+$else$
+ <h1 class="title">$title$</h1>
+$endif$
+$endfor$
+$if(subtitle)$
+ <p class="subtitle">$subtitle$</p>
+$endif$
+$for(author)$
+ <p class="author">$author$</p>
+$endfor$
+$for(creator)$
+ <p class="$creator.role$">$creator.text$</p>
+$endfor$
+$if(publisher)$
+ <p class="publisher">$publisher$</p>
+$endif$
+$if(date)$
+ <p class="date">$date$</p>
+$endif$
+$if(rights)$
+ <div class="rights">$rights$</div>
+$endif$
+$else$
+$for(include-before)$
+$include-before$
+$endfor$
+$body$
+$for(include-after)$
+$include-after$
+$endfor$
+$endif$
+</body>
+</html>
+
diff --git a/data/templates/default.epub3 b/data/templates/default.epub3
index 8a12e0fb3..b22714963 100644
--- a/data/templates/default.epub3
+++ b/data/templates/default.epub3
@@ -5,11 +5,15 @@
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<title>$pagetitle$</title>
-$if(quotes)$
<style type="text/css">
- q { quotes: "“" "”" "‘" "’"; }
- </style>
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+$if(quotes)$
+ q { quotes: "“" "”" "‘" "’"; }
$endif$
+ </style>
$if(highlighting-css)$
<style type="text/css">
$highlighting-css$
diff --git a/data/templates/default.html b/data/templates/default.html
deleted file mode 100644
index 8caea26c8..000000000
--- a/data/templates/default.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"$if(lang)$ lang="$lang$" xml:lang="$lang$"$endif$$if(dir)$ dir="$dir$"$endif$>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="Content-Style-Type" content="text/css" />
- <meta name="generator" content="pandoc" />
-$for(author-meta)$
- <meta name="author" content="$author-meta$" />
-$endfor$
-$if(date-meta)$
- <meta name="date" content="$date-meta$" />
-$endif$
-$if(keywords)$
- <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
-$endif$
- <title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
- <style type="text/css">code{white-space: pre;}</style>
-$if(quotes)$
- <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
-$endif$
-$if(highlighting-css)$
- <style type="text/css">
-$highlighting-css$
- </style>
-$endif$
-$for(css)$
- <link rel="stylesheet" href="$css$" type="text/css" />
-$endfor$
-$if(math)$
- $math$
-$endif$
-$for(header-includes)$
- $header-includes$
-$endfor$
-</head>
-<body>
-$for(include-before)$
-$include-before$
-$endfor$
-$if(title)$
-<div id="$idprefix$header">
-<h1 class="title">$title$</h1>
-$if(subtitle)$
-<h1 class="subtitle">$subtitle$</h1>
-$endif$
-$for(author)$
-<h2 class="author">$author$</h2>
-$endfor$
-$if(date)$
-<h3 class="date">$date$</h3>
-$endif$
-</div>
-$endif$
-$if(toc)$
-<div id="$idprefix$TOC">
-$toc$
-</div>
-$endif$
-$body$
-$for(include-after)$
-$include-after$
-$endfor$
-</body>
-</html>
diff --git a/data/templates/default.html4 b/data/templates/default.html4
new file mode 100644
index 000000000..714b3ff2e
--- /dev/null
+++ b/data/templates/default.html4
@@ -0,0 +1,69 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"$if(lang)$ lang="$lang$" xml:lang="$lang$"$endif$$if(dir)$ dir="$dir$"$endif$>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <meta name="generator" content="pandoc" />
+$for(author-meta)$
+ <meta name="author" content="$author-meta$" />
+$endfor$
+$if(date-meta)$
+ <meta name="date" content="$date-meta$" />
+$endif$
+$if(keywords)$
+ <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
+$endif$
+ <title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+$if(quotes)$
+ q { quotes: "“" "”" "‘" "’"; }
+$endif$
+ </style>
+$if(highlighting-css)$
+ <style type="text/css">
+$highlighting-css$
+ </style>
+$endif$
+$for(css)$
+ <link rel="stylesheet" href="$css$" type="text/css" />
+$endfor$
+$if(math)$
+ $math$
+$endif$
+$for(header-includes)$
+ $header-includes$
+$endfor$
+</head>
+<body>
+$for(include-before)$
+$include-before$
+$endfor$
+$if(title)$
+<div id="$idprefix$header">
+<h1 class="title">$title$</h1>
+$if(subtitle)$
+<h1 class="subtitle">$subtitle$</h1>
+$endif$
+$for(author)$
+<h2 class="author">$author$</h2>
+$endfor$
+$if(date)$
+<h3 class="date">$date$</h3>
+$endif$
+</div>
+$endif$
+$if(toc)$
+<div id="$idprefix$TOC">
+$table-of-contents$
+</div>
+$endif$
+$body$
+$for(include-after)$
+$include-after$
+$endfor$
+</body>
+</html>
diff --git a/data/templates/default.html5 b/data/templates/default.html5
index 5641ecb80..5c484f376 100644
--- a/data/templates/default.html5
+++ b/data/templates/default.html5
@@ -1,23 +1,28 @@
<!DOCTYPE html>
-<html$if(lang)$ lang="$lang$"$endif$$if(dir)$ dir="$dir$"$endif$>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
<head>
- <meta charset="utf-8">
- <meta name="generator" content="pandoc">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
+ <meta charset="utf-8" />
+ <meta name="generator" content="pandoc" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
$for(author-meta)$
- <meta name="author" content="$author-meta$">
+ <meta name="author" content="$author-meta$" />
$endfor$
$if(date-meta)$
- <meta name="dcterms.date" content="$date-meta$">
+ <meta name="dcterms.date" content="$date-meta$" />
$endif$
$if(keywords)$
- <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$">
+ <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
$endif$
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
- <style type="text/css">code{white-space: pre;}</style>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
$if(quotes)$
- <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
+ q { quotes: "“" "”" "‘" "’"; }
$endif$
+ </style>
$if(highlighting-css)$
<style type="text/css">
$highlighting-css$
@@ -56,7 +61,7 @@ $endif$
$endif$
$if(toc)$
<nav id="$idprefix$TOC">
-$toc$
+$table-of-contents$
</nav>
$endif$
$body$
diff --git a/data/templates/default.jats b/data/templates/default.jats
new file mode 100644
index 000000000..228a0636a
--- /dev/null
+++ b/data/templates/default.jats
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="utf-8" ?>
+$if(xml-stylesheet)$
+<?xml-stylesheet type="text/xsl" href="$xml-stylesheet$"?>
+$endif$
+<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD v1.0 20120330//EN"
+ "JATS-journalpublishing1.dtd">
+$if(article.type)$
+<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.0" article-type="$article.type$">
+$else$
+<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.0" article-type="other">
+$endif$
+<front>
+<journal-meta>
+$if(journal.publisher-id)$
+<journal-id journal-id-type="publisher-id">$journal.publisher-id$</journal-id>
+$endif$
+$if(journal.nlm-ta)$
+<journal-id journal-id-type="nlm-ta">$journal.nlm-ta$</journal-id>
+$endif$
+$if(journal.pmc)$
+<journal-id journal-id-type="pmc">$journal.pmc$</journal-id>
+$endif$
+<journal-title-group>
+$if(journal.title)$
+<journal-title>$journal.title$</journal-title>
+$endif$
+$if(journal.abbrev-title)$
+<abbrev-journal-title>$journal.abbrev-title$</abbrev-journal-title>
+$endif$
+</journal-title-group>
+$if(journal.pissn)$
+<issn pub-type="ppub">$journal.pissn$</issn>
+$endif$
+$if(journal.eissn)$
+<issn pub-type="epub">$journal.eissn$</issn>
+$endif$
+<publisher>
+<publisher-name>$journal.publisher-name$</publisher-name>
+$if(journal.publisher-loc)$
+<publisher-loc>$journal.publisher-loc$</publisher-loc>
+$endif$
+</publisher>
+</journal-meta>
+<article-meta>
+$if(article.publisher-id)$
+<article-id pub-id-type="publisher-id">$article.publisher-id$</article-id>
+$endif$
+$if(article.doi)$
+<article-id pub-id-type="doi">$article.doi$</article-id>
+$endif$
+$if(article.pmid)$
+<article-id pub-id-type="pmid">$article.pmid$</article-id>
+$endif$
+$if(article.pmcid)$
+<article-id pub-id-type="pmcid">$article.pmcid$</article-id>
+$endif$
+$if(article.art-access-id)$
+<article-id pub-id-type="art-access-id">$article.art-access-id$</article-id>
+$endif$
+$if(article.heading)$
+<article-categories>
+<subj-group subj-group-type="heading">
+<subject>$article.heading$</subject>
+</subj-group>
+$if(article.categories)$
+<subj-group subj-group-type="categories">
+$for(article.categories)$
+<subject>$article.categories$</subject>
+$endfor$
+</subj-group>
+$endif$
+</article-categories>
+$endif$
+$if(title)$
+<title-group>
+<article-title>$title$</article-title>
+</title-group>
+$endif$
+$if(author)$
+<contrib-group>
+$for(author)$
+<contrib contrib-type="author">
+$if(author.orcid)$
+<contrib-id contrib-id-type="orcid">$author.orcid$</contrib-id>
+$endif$
+<name>
+$if(author.surname)$
+<surname>$author.surname$</surname>
+<given-names>$author.given-names$</given-names>
+$else$
+<string-name>$author$</string-name>
+$endif$
+</name>
+$if(author.email)$
+<email>$author.email$</email>
+$endif$
+$if(author.aff-id)$
+<xref ref-type="aff" rid="aff-$contrib.aff-id$"/>
+$endif$
+$if(author.cor-id)$
+<xref ref-type="corresp" rid="cor-$author.cor-id$"><sup>*</sup></xref>
+$endif$
+</contrib>
+$endfor$
+</contrib-group>
+$endif$
+$if(article.author-notes)$
+<author-notes>
+$if(article.author-notes.corresp)$
+$for(article.author-notes.corresp)$
+<corresp id="cor-$article.author-notes.corresp.id$">* E-mail: <email>$article.author-notes.corresp.email$</email></corresp>
+$endfor$
+$endif$
+$if(article.author-notes.conflict)$
+<fn fn-type="conflict"><p>$article.author-notes.conflict$</p></fn>
+$endif$
+$if(article.author-notes.con)$
+<fn fn-type="con"><p>$article.author-notes.con$</p></fn>
+$endif$
+</author-notes>
+$endif$
+$if(date)$
+$if(date.iso-8601)$
+<pub-date pub-type="epub" iso-8601-date="$date.iso-8601$">
+$else$
+<pub-date pub-type="epub">
+$endif$
+$if(date.day)$
+<day>$pub-date.day$</day>
+$endif$
+$if(date.month)$
+<month>$pub-date.month$</month>
+$endif$
+$if(date.year)$
+<year>$pub-date.year$</year>
+$else$
+<string-date>$date$</string-date>
+$endif$
+</pub-date>
+$endif$
+$if(article.volume)$
+<volume>$article.volume$</volume>
+$endif$
+$if(article.issue)$
+<issue>$article.issue$</issue>
+$endif$
+$if(article.fpage)$
+<fpage>$article.fpage$</fpage>
+$endif$
+$if(article.lpage)$
+<lpage>$article.lpage$</lpage>
+$endif$
+$if(article.elocation-id)$
+<elocation-id>$article.elocation-id$</elocation-id>
+$endif$
+$if(history)$
+<history>
+</history>
+$endif$
+$if(copyright)$
+<permissions>
+$if(copyright.statement)$
+<copyright-statement>$copyright.statement$</copyright-statement>
+$endif$
+$if(copyright.year)$
+<copyright-year>$copyright.year$</copyright-year>
+$endif$
+$if(copyright.holder)$
+<copyright-holder>$copyright.holder$</copyright-holder>
+$endif$
+$if(copyright.text)$
+<license license-type="$copyright.type$" xlink:href="$copyright.link$">
+<license-p>$copyright.text$</license-p>
+</license>
+</permissions>
+$endif$
+$endif$
+$if(tags)$
+<kwd-group kwd-group-type="author">
+$for(tags)$
+<kwd>$tags$</kwd>
+$endfor$
+</kwd-group>
+$endif$
+$if(article.funding-statement)$
+<funding-group>
+<funding-statement>$article.funding-statement$</funding-statement>
+</funding-group>
+$endif$
+</article-meta>
+$if(notes)$
+<notes>$notes$</notes>
+$endif$
+</front>
+<body>
+$body$
+</body>
+<back>
+$if(back)$
+$back$
+$endif$
+</back>
+</article>
diff --git a/data/templates/default.latex b/data/templates/default.latex
index 128f79d8d..c36bf8576 100644
--- a/data/templates/default.latex
+++ b/data/templates/default.latex
@@ -1,4 +1,16 @@
-\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(papersize)$$papersize$paper,$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$}
+\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+\PassOptionsToPackage{hyphens}{url}
+$if(colorlinks)$
+\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
+$endif$
+%
+\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$}
+$if(beamer)$
+\setbeamertemplate{caption}[numbered]
+\setbeamertemplate{caption label separator}{: }
+\setbeamercolor{caption name}{fg=normal text.fg}
+\beamertemplatenavigationsymbols$if(navigation)$$navigation$$else$empty$endif$
+$endif$
$if(beamerarticle)$
\usepackage{beamerarticle} % needs to be loaded first
$endif$
@@ -17,22 +29,21 @@ $endif$
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
\usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
\usepackage[utf8]{inputenc}
-$if(euro)$
- \usepackage{eurosym}
-$endif$
+ \usepackage{textcomp} % provides euro and other symbols
\else % if luatex or xelatex
+$if(mathspec)$
\ifxetex
\usepackage{mathspec}
\else
- \usepackage{fontspec}
+ \usepackage{unicode-math}
\fi
+$else$
+ \usepackage{unicode-math}
+$endif$
\defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
$for(fontfamilies)$
\newfontfamily{$fontfamilies.name$}[$fontfamilies.options$]{$fontfamilies.font$}
$endfor$
-$if(euro)$
- \newcommand{\euro}{€}
-$endif$
$if(mainfont)$
\setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
$endif$
@@ -43,13 +54,54 @@ $if(monofont)$
\setmonofont[Mapping=tex-ansi$if(monofontoptions)$,$for(monofontoptions)$$monofontoptions$$sep$,$endfor$$endif$]{$monofont$}
$endif$
$if(mathfont)$
+$if(mathspec)$
+ \ifxetex
\setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+ \else
+ \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+ \fi
+$else$
+ \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+$endif$
$endif$
$if(CJKmainfont)$
+ \ifxetex
\usepackage{xeCJK}
\setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+ \fi
+$endif$
+$if(luatexjapresetoptions)$
+ \ifluatex
+ \usepackage[$for(luatexjapresetoptions)$$luatexjapresetoptions$$sep$,$endfor$]{luatexja-preset}
+ \fi
+$endif$
+$if(CJKmainfont)$
+ \ifluatex
+ \usepackage[$for(luatexjafontspecoptions)$$luatexjafontspecoptions$$sep$,$endfor$]{luatexja-fontspec}
+ \setmainjfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+ \fi
$endif$
\fi
+$if(beamer)$
+$if(theme)$
+\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
+$endif$
+$if(colortheme)$
+\usecolortheme{$colortheme$}
+$endif$
+$if(fonttheme)$
+\usefonttheme{$fonttheme$}
+$endif$
+$if(mainfont)$
+\usefonttheme{serif} % use mainfont rather than sansfont for slide text
+$endif$
+$if(innertheme)$
+\useinnertheme{$innertheme$}
+$endif$
+$if(outertheme)$
+\useoutertheme{$outertheme$}
+$endif$
+$endif$
% use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
% use microtype if available
@@ -57,14 +109,22 @@ $endif$
\usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
-\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
+$if(indent)$
+$else$
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
+$endif$
$if(verbatim-in-note)$
\usepackage{fancyvrb}
$endif$
-\usepackage[unicode=true]{hyperref}
$if(colorlinks)$
-\PassOptionsToPackage{usenames,dvipsnames}{color} % color is loaded by hyperref
+\usepackage{xcolor}
$endif$
+\usepackage{hyperref}
\hypersetup{
$if(title-meta)$
pdftitle={$title-meta$},
@@ -91,32 +151,12 @@ $endif$
$if(geometry)$
\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
$endif$
-$if(lang)$
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
-$if(babel-newcommands)$
- $babel-newcommands$
-$endif$
-\else
- \usepackage{polyglossia}
- \setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$}
-$for(polyglossia-otherlangs)$
- \setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$}
-$endfor$
-\fi
-$endif$
-$if(natbib)$
-\usepackage{natbib}
-\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
-$endif$
-$if(biblatex)$
-\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
-$for(bibliography)$
-\addbibresource{$bibliography$}
-$endfor$
+$if(beamer)$
+\newif\ifbibliography
$endif$
$if(listings)$
\usepackage{listings}
+\newcommand{\passthrough}[1]{#1}
$endif$
$if(lhs)$
\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
@@ -126,8 +166,16 @@ $highlighting-macros$
$endif$
$if(tables)$
\usepackage{longtable,booktabs}
+$if(beamer)$
+\usepackage{caption}
+% These lines are needed to make table captions work with longtable:
+\makeatletter
+\def\fnum@table{\tablename~\thetable}
+\makeatother
+$else$
% Fix footnotes in tables (requires footnote package)
-\IfFileExists{footnote.sty}{\usepackage{footnote}\makesavenoteenv{long table}}{}
+\IfFileExists{footnote.sty}{\usepackage{footnote}\makesavenoteenv{longtable}}{}
+$endif$
$endif$
$if(graphics)$
\usepackage{graphicx,grffile}
@@ -140,24 +188,52 @@ $if(graphics)$
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
$endif$
+$if(beamer)$
+% Prevent slide breaks in the middle of a paragraph:
+\widowpenalties 1 10000
+\raggedbottom
+$if(section-titles)$
+\setbeamertemplate{part page}{
+\centering
+\begin{beamercolorbox}[sep=16pt,center]{part title}
+ \usebeamerfont{part title}\insertpart\par
+\end{beamercolorbox}
+}
+\setbeamertemplate{section page}{
+\centering
+\begin{beamercolorbox}[sep=12pt,center]{part title}
+ \usebeamerfont{section title}\insertsection\par
+\end{beamercolorbox}
+}
+\setbeamertemplate{subsection page}{
+\centering
+\begin{beamercolorbox}[sep=8pt,center]{part title}
+ \usebeamerfont{subsection title}\insertsubsection\par
+\end{beamercolorbox}
+}
+\AtBeginPart{
+ \frame{\partpage}
+}
+\AtBeginSection{
+ \ifbibliography
+ \else
+ \frame{\sectionpage}
+ \fi
+}
+\AtBeginSubsection{
+ \frame{\subsectionpage}
+}
+$endif$
+$endif$
$if(links-as-notes)$
% Make links footnotes instead of hotlinks:
-\renewcommand{\href}[2]{#2\footnote{\url{#1}}}
+\DeclareRobustCommand{\href}[2]{#2\footnote{\url{#1}}}
$endif$
$if(strikeout)$
\usepackage[normalem]{ulem}
% avoid problems with \sout in headers with hyperref:
\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
$endif$
-$if(indent)$
-$else$
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
-$endif$
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
@@ -166,6 +242,8 @@ $if(numbersections)$
$else$
\setcounter{secnumdepth}{0}
$endif$
+$if(beamer)$
+$else$
$if(subparagraph)$
$else$
% Redefines (sub)paragraphs to behave more like sections
@@ -178,6 +256,34 @@ $else$
\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
\fi
$endif$
+$endif$
+$if(pagestyle)$
+\pagestyle{$pagestyle$}
+$endif$
+
+% set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+
+$for(header-includes)$
+$header-includes$
+$endfor$
+$if(lang)$
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+ \usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
+$if(babel-newcommands)$
+ $babel-newcommands$
+$endif$
+\else
+ % load polyglossia as late as possible as it *could* call bidi if RTL lang (e.g. Hebrew or Arabic)
+ \usepackage{polyglossia}
+ \setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$}
+$for(polyglossia-otherlangs)$
+ \setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$}
+$endfor$
+\fi
+$endif$
$if(dir)$
\ifxetex
% load bidi as late as possible as it modifies e.g. graphicx
@@ -195,15 +301,16 @@ $if(dir)$
\newenvironment{LTR}{\beginL}{\endL}
\fi
$endif$
-
-% set default figure placement to htbp
-\makeatletter
-\def\fps@figure{htbp}
-\makeatother
-
-$for(header-includes)$
-$header-includes$
+$if(natbib)$
+\usepackage[$natbiboptions$]{natbib}
+\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
+$endif$
+$if(biblatex)$
+\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
+$for(bibliography)$
+\addbibresource{$bibliography$}
$endfor$
+$endif$
$if(title)$
\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
@@ -220,9 +327,20 @@ $if(institute)$
\institute{$for(institute)$$institute$$sep$ \and $endfor$}
$endif$
\date{$date$}
+$if(beamer)$
+$if(titlegraphic)$
+\titlegraphic{\includegraphics{$titlegraphic$}}
+$endif$
+$if(logo)$
+\logo{\includegraphics{$logo$}}
+$endif$
+$endif$
\begin{document}
$if(title)$
+$if(beamer)$
+\frame{\titlepage}
+$else$
\maketitle
$endif$
$if(abstract)$
@@ -230,20 +348,27 @@ $if(abstract)$
$abstract$
\end{abstract}
$endif$
+$endif$
$for(include-before)$
$include-before$
$endfor$
$if(toc)$
+$if(beamer)$
+\begin{frame}
+\tableofcontents[hideallsubsections]
+\end{frame}
+$else$
{
$if(colorlinks)$
-\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$black$endif$}
+\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$$endif$}
$endif$
\setcounter{tocdepth}{$toc-depth$}
\tableofcontents
}
$endif$
+$endif$
$if(lot)$
\listoftables
$endif$
@@ -261,12 +386,26 @@ $else$
\renewcommand\refname{$biblio-title$}
$endif$
$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+\bibliographytrue
+$endif$
\bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
+$if(beamer)$
+\end{frame}
+$endif$
$endif$
$endif$
$if(biblatex)$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+\bibliographytrue
+\printbibliography[heading=none]
+\end{frame}
+$else$
\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
+$endif$
$endif$
$for(include-after)$
diff --git a/data/templates/default.markdown b/data/templates/default.markdown
index 95d7e52cc..9f6ca96de 100644
--- a/data/templates/default.markdown
+++ b/data/templates/default.markdown
@@ -11,7 +11,7 @@ $include-before$
$endfor$
$if(toc)$
-$toc$
+$table-of-contents$
$endif$
$body$
diff --git a/data/templates/default.ms b/data/templates/default.ms
new file mode 100644
index 000000000..f4204338a
--- /dev/null
+++ b/data/templates/default.ms
@@ -0,0 +1,112 @@
+.\" **** Custom macro definitions *********************************
+.\" * Super/subscript
+.\" (https://lists.gnu.org/archive/html/groff/2012-07/msg00046.html)
+.ds { \v'-0.3m'\\s[\\n[.s]*9u/12u]
+.ds } \s0\v'0.3m'
+.ds < \v'0.3m'\s[\\n[.s]*9u/12u]
+.ds > \s0\v'-0.3m'
+.\" * Horizontal line
+.de HLINE
+.LP
+.ce
+\l'20'
+..
+$if(highlighting-macros)$
+.\" * Syntax highlighting macros
+$highlighting-macros$
+$endif$
+.\" **** Settings *************************************************
+.\" text width
+.nr LL 5.5i
+.\" left margin
+.nr PO 1.25i
+.\" top margin
+.nr HM 1.25i
+.\" bottom margin
+.nr FM 1.25i
+.\" header/footer width
+.nr LT \n[LL]
+.\" point size
+.nr PS $if(pointsize)$$pointsize$$else$10p$endif$
+.\" line height
+.nr VS $if(lineheight)$$lineheight$$else$12p$endif$
+.\" font family: A, BM, H, HN, N, P, T, ZCM
+.fam $if(fontfamily)$$fontfamily$$else$T$endif$
+.\" paragraph indent
+.nr PI $if(indent)$$indent$$else$2m$endif$
+.\" interparagraph space
+.nr PD 0.33v
+.\" footnote width
+.nr FL \n[LL]
+.\" footnote point size
+.nr FPS (\n[PS] - 2000)
+$if(papersize)$
+.\" paper size
+.ds paper $papersize$
+$endif$
+.\" color used for strikeout
+.defcolor strikecolor rgb 0.7 0.7 0.7
+.\" color for links (rgb)
+.ds PDFHREF.COLOUR 0.35 0.00 0.60
+.\" border for links (default none)
+.ds PDFHREF.BORDER 0 0 0
+.\" point size difference between heading levels
+.nr PSINCR 1p
+.\" heading level above which point size no longer changes
+.nr GROWPS 2
+.\" comment these out if you want a dot after section numbers:
+.als SN SN-NO-DOT
+.als SN-STYLE SN-NO-DOT
+.\" pdf outline fold level
+.nr PDFOUTLINE.FOLDLEVEL 3
+.\" start out in outline view
+.pdfview /PageMode /UseOutlines
+.\" ***************************************************************
+.\" PDF metadata
+.pdfinfo /Title "$title-meta$"
+.pdfinfo /Author "$author-meta$"
+$if(adjusting)$
+.ad $adjusting$
+$endif$
+$if(hyphenate)$
+.hy
+$else$
+.nh \" Turn off hyphenation by default.
+$endif$
+$if(has-inline-math)$
+.EQ
+delim @@
+.EN
+$endif$
+$for(header-includes)$
+$header-includes$
+$endfor$
+$if(title)$
+.TL
+$title$
+$endif$
+$for(author)$
+.AU
+$author$
+$endfor$
+$if(date)$
+.ND "$date$"
+$endif$
+$if(abstract)$
+.AB
+$abstract$
+.AE
+$endif$
+.\" 1 column (use .2C for two column)
+.1C
+$for(include-before)$
+$include-before$
+$endfor$
+$body$
+$if(toc)$
+.TC
+$endif$
+$for(include-after)$
+$include-after$
+$endfor$
+.pdfsync
diff --git a/data/templates/default.muse b/data/templates/default.muse
new file mode 100644
index 000000000..05534adef
--- /dev/null
+++ b/data/templates/default.muse
@@ -0,0 +1,44 @@
+$if(author)$
+#author $author$
+$endif$
+$if(title)$
+#title $title$
+$endif$
+$if(lang)$
+#lang $lang$
+$endif$
+$if(LISTtitle)$
+#LISTtitle $LISTtitle$
+$endif$
+$if(subtitle)$
+#subtitle $subtitle$
+$endif$
+$if(SORTauthors)$
+#SORTauthors $SORTauthors$
+$endif$
+$if(SORTtopics)$
+#SORTtopics $SORTtopics$
+$endif$
+$if(date)$
+#date $date$
+$endif$
+$if(notes)$
+#notes $notes$
+$endif$
+$if(source)$
+#source $source$
+$endif$
+
+$for(header-includes)$
+$header-includes$
+
+$endfor$
+$for(include-before)$
+$include-before$
+
+$endfor$
+$body$
+$for(include-after)$
+
+$include-after$
+$endfor$
diff --git a/data/templates/default.opendocument b/data/templates/default.opendocument
index bb01d4bbb..e0bc5c1d3 100644
--- a/data/templates/default.opendocument
+++ b/data/templates/default.opendocument
@@ -23,6 +23,135 @@ $endif$
$for(include-before)$
$include-before$
$endfor$
+$if(toc)$
+<text:table-of-content>
+ <text:table-of-content-source text:outline-level="10">
+ <text:index-title-template text:style-name="Contents_20_Heading">
+ $toc-title$
+ </text:index-title-template>
+ <text:table-of-content-entry-template text:outline-level="1"
+ text:style-name="Contents_20_1">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="2"
+ text:style-name="Contents_20_2">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="3"
+ text:style-name="Contents_20_3">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="4"
+ text:style-name="Contents_20_4">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="5"
+ text:style-name="Contents_20_5">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="6"
+ text:style-name="Contents_20_6">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="7"
+ text:style-name="Contents_20_7">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="8"
+ text:style-name="Contents_20_8">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="9"
+ text:style-name="Contents_20_9">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="10"
+ text:style-name="Contents_20_10">
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-chapter />
+ <text:index-entry-text />
+ <text:index-entry-link-end />
+ <text:index-entry-tab-stop style:type="right"
+ style:leader-char="." />
+ <text:index-entry-link-start text:style-name="Internet_20_link" />
+ <text:index-entry-page-number />
+ <text:index-entry-link-end />
+ </text:table-of-content-entry-template>
+ </text:table-of-content-source>
+</text:table-of-content>
+$endif$
$body$
$for(include-after)$
$include-after$
diff --git a/data/templates/default.plain b/data/templates/default.plain
index 95d7e52cc..9f6ca96de 100644
--- a/data/templates/default.plain
+++ b/data/templates/default.plain
@@ -11,7 +11,7 @@ $include-before$
$endfor$
$if(toc)$
-$toc$
+$table-of-contents$
$endif$
$body$
diff --git a/data/templates/default.revealjs b/data/templates/default.revealjs
index 1d356ef8d..65ab09049 100644
--- a/data/templates/default.revealjs
+++ b/data/templates/default.revealjs
@@ -17,10 +17,15 @@ $endif$
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="$revealjs-url$/css/reveal.css">
- <style type="text/css">code{white-space: pre;}</style>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
$if(quotes)$
- <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
+ q { quotes: "“" "”" "‘" "’"; }
$endif$
+ </style>
$if(highlighting-css)$
<style type="text/css">
$highlighting-css$
@@ -60,7 +65,7 @@ $endfor$
<div class="slides">
$if(title)$
-<section>
+<section id="$idprefix$title-slide">
<h1 class="title">$title$</h1>
$if(subtitle)$
<p class="subtitle">$subtitle$</p>
@@ -75,7 +80,7 @@ $endif$
$endif$
$if(toc)$
<section id="$idprefix$TOC">
-$toc$
+$table-of-contents$
</section>
$endif$
@@ -103,9 +108,11 @@ $if(slideNumber)$
// Display the page number of the current slide
slideNumber: $slideNumber$,
$endif$
-$if(history)$
// Push each slide change to the browser history
+$if(history)$
history: $history$,
+$else$
+ history: true,
$endif$
$if(keyboard)$
// Enable keyboard shortcuts for navigation
@@ -223,15 +230,36 @@ $endif$
$if(maxScale)$
maxScale: $maxScale$,
$endif$
+$if(mathjax)$
+ math: {
+ mathjax: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js',
+ config: 'TeX-AMS_HTML-full',
+ tex2jax: {
+ inlineMath: [['\\(','\\)']],
+ displayMath: [['\\[','\\]']],
+ balanceBraces: true,
+ processEscapes: false,
+ processRefs: true,
+ processEnvironments: true,
+ preview: 'TeX',
+ skipTags: ['script','noscript','style','textarea','pre','code'],
+ ignoreClass: 'tex2jax_ignore',
+ processClass: 'tex2jax_process'
+ },
+ },
+$endif$
// Optional reveal.js plugins
dependencies: [
{ src: '$revealjs-url$/lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: '$revealjs-url$/plugin/zoom-js/zoom.js', async: true },
- $if(notes-server)$
+$if(notes-server)$
{ src: '$revealjs-url$/socket.io/socker.io.js', async: true },
{ src: '$revealjs-url$/plugin/notes-server/client.js', async: true },
- $endif$
+$endif$
+$if(mathjax)$
+ { src: '$revealjs-url$/plugin/math/math.js', async: true },
+$endif$
{ src: '$revealjs-url$/plugin/notes/notes.js', async: true }
]
});
diff --git a/data/templates/default.rst b/data/templates/default.rst
index 30005d19b..e9c0dc203 100644
--- a/data/templates/default.rst
+++ b/data/templates/default.rst
@@ -15,12 +15,6 @@ $if(date)$
$endif$
$endif$
-$if(math)$
-.. role:: math(raw)
- :format: html latex
-..
-
-$endif$
$if(rawtex)$
.. role:: raw-latex(raw)
:format: latex
diff --git a/data/templates/default.rtf b/data/templates/default.rtf
index 59e132b3f..a7f79376d 100644
--- a/data/templates/default.rtf
+++ b/data/templates/default.rtf
@@ -18,7 +18,7 @@ $if(spacer)$
{\pard \ql \f0 \sa180 \li0 \fi0 \par}
$endif$
$if(toc)$
-$toc$
+$table-of-contents$
$endif$
$for(include-before)$
$include-before$
diff --git a/data/templates/default.s5 b/data/templates/default.s5
index 6ab482864..e9c36b4d4 100644
--- a/data/templates/default.s5
+++ b/data/templates/default.s5
@@ -15,13 +15,18 @@ $if(keywords)$
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
$endif$
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
- <style type="text/css">code{white-space: pre;}</style>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+$if(quotes)$
+ q { quotes: "“" "”" "‘" "’"; }
+$endif$
+ </style>
<!-- configuration parameters -->
<meta name="defaultView" content="slideshow" />
<meta name="controlVis" content="hidden" />
-$if(quotes)$
- <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
-$endif$
$if(highlighting-css)$
<style type="text/css">
$highlighting-css$
@@ -59,7 +64,7 @@ $endfor$
</div>
<div class="presentation">
$if(title)$
-<div class="titleslide slide">
+<div class="title-slide slide">
<h1 class="title">$title$</h1>
$if(subtitle)$
<h2 class="subtitle">$subtitle$</h2>
@@ -74,7 +79,7 @@ $endif$
$endif$
$if(toc)$
<div class="slide" id="$idprefix$TOC">
-$toc$
+$table-of-contents$
</div>
$endif$
$body$
diff --git a/data/templates/default.slideous b/data/templates/default.slideous
index 30c93567d..ad58272ae 100644
--- a/data/templates/default.slideous
+++ b/data/templates/default.slideous
@@ -16,10 +16,15 @@ $if(keywords)$
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
$endif$
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
- <style type="text/css">code{white-space: pre;}</style>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
$if(quotes)$
- <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
+ q { quotes: "“" "”" "‘" "’"; }
$endif$
+ </style>
$if(highlighting-css)$
<style type="text/css">
$highlighting-css$
@@ -79,7 +84,7 @@ $endif$
$endif$
$if(toc)$
<div class="slide" id="$idprefix$TOC">
-$toc$
+$table-of-contents$
</div>
$endif$
$body$
diff --git a/data/templates/default.slidy b/data/templates/default.slidy
index cccf3537d..98b8d669d 100644
--- a/data/templates/default.slidy
+++ b/data/templates/default.slidy
@@ -16,10 +16,15 @@ $if(keywords)$
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
$endif$
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
- <style type="text/css">code{white-space: pre;}</style>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
$if(quotes)$
- <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
+ q { quotes: "“" "”" "‘" "’"; }
$endif$
+ </style>
$if(highlighting-css)$
<style type="text/css">
$highlighting-css$
@@ -65,7 +70,7 @@ $endif$
$endif$
$if(toc)$
<div class="slide" id="$idprefix$TOC">
-$toc$
+$table-of-contents$
</div>
$endif$
$body$
diff --git a/data/translations/am.yaml b/data/translations/am.yaml
new file mode 100644
index 000000000..4c8169302
--- /dev/null
+++ b/data/translations/am.yaml
@@ -0,0 +1,20 @@
+Abstract: አኅጽተሮ ጽሁፍ
+Appendix: መድበል
+Bibliography: ቢዋ መጽሃፍት
+Cc: ግልባጭ
+Chapter: ክፍል
+Contents: ይዘት
+Encl: አባሪዎች
+Figure: ሥዕል
+Index: ምህጻር ቃል
+ListOfFigures: የሥዕችሎ ማውጫ
+ListOfTables: የሰንጠዥረ ማውጫ
+Page: ገጽ
+Part: ንዑስ ክፍል
+Preface: መቅድም
+Proof: ማረጋገጫ
+References: የነሥ ጹሁፍ ምንጭ
+See: ይመልከቱ
+SeeAlso: ይህምን ይመልከቱ
+Table: ሰንጠረዥ
+To: ለ
diff --git a/data/translations/ar.yaml b/data/translations/ar.yaml
new file mode 100644
index 000000000..6b9110a60
--- /dev/null
+++ b/data/translations/ar.yaml
@@ -0,0 +1,20 @@
+Preface: ﻡﺪﺨﻟ
+References: ﺎﻠﻣﺭﺎﺠﻋ
+Abstract: ﻢﻠﺨﺻ
+Bibliography: ﺎﻠﻤﺻﺍﺩﺭ
+Chapter: ﺏﺎﺑ
+Appendix: ﺎﻠﻣﻼﺤﻗ
+Contents: ﺎﻠﻤﺤﺗﻮﻳﺎﺗ
+ListOfFigures: ﻕﺎﺌﻣﺓ ﺍﻸﺸﻛﺎﻟ
+ListOfTables: ﻕﺎﺌﻣﺓ ﺎﻠﺟﺩﺍﻮﻟ
+Index: ﺎﻠﻔﻫﺮﺳ
+Figure: ﺶﻜﻟ
+Table: ﺝﺩﻮﻟ
+Part: ﺎﻠﻘﺴﻣ
+Encl: ﺎﻠﻣﺮﻔﻗﺎﺗ
+To: ﺈﻟﻯ
+Page: ﺺﻔﺣﺓ
+See: ﺭﺎﺠﻋ
+SeeAlso: ﺭﺎﺠﻋ ﺄﻴﺿًﺍ
+Proof: ﺏﺮﻫﺎﻧ
+Glossary: ﻕﺎﻣﻮﺳ
diff --git a/data/translations/bg.yaml b/data/translations/bg.yaml
new file mode 100644
index 000000000..7851caa97
--- /dev/null
+++ b/data/translations/bg.yaml
@@ -0,0 +1,19 @@
+Abstract: Абстракт
+Appendix: Приложение
+Bibliography: Библиография
+Cc: копия
+Chapter: Глава
+Contents: Съдържание
+Encl: Приложения
+Figure: Фигура
+Glossary: Glossary
+Index: Азбучен указател
+ListOfFigures: Списък на фигурите
+ListOfTables: Списък на таблиците
+Page: Стр.
+Preface: Предговор
+Proof: Proof
+References: Литература
+See: вж.
+SeeAlso: вж. също и
+Table: Таблица
diff --git a/data/translations/bn.yaml b/data/translations/bn.yaml
new file mode 100644
index 000000000..5f66be85a
--- /dev/null
+++ b/data/translations/bn.yaml
@@ -0,0 +1,21 @@
+Abstract: সারসংক্ষেপ
+Appendix: পরিশিষ্ট
+Bibliography: তথ্যবিবরণ
+Cc: অনুলিপি
+Chapter: অধ্যায়
+Contents: সূচীপত্র
+Encl: সংযুক্তি
+Figure: ছবি/নকশা
+Glossary: পরিভাষার শব্দসম্ভার
+Index: সূচক/নির্দেশক
+ListOfFigures: ছবি/নকশা সমূহের তালিকা
+ListOfTables: তালিকাসারণী
+Page: পৃষ্ঠা
+Part: খন্ড
+Preface: পূর্বকথা
+Proof: প্রমাণ
+References: তথ্যসুত্রসমূহ
+See: দেখুন
+SeeAlso: আরও দেখুন
+Table: সারনী
+To: প্রতি
diff --git a/data/translations/ca.yaml b/data/translations/ca.yaml
new file mode 100644
index 000000000..b7a0c618e
--- /dev/null
+++ b/data/translations/ca.yaml
@@ -0,0 +1,21 @@
+Abstract: Resum
+Appendix: Apèndix
+Bibliography: Bibliografia
+Cc: Còpies a
+Chapter: Capítol
+Contents: Índex
+Encl: Adjunt
+Figure: Figura
+Glossary: Glossari
+Index: Índex alfabètic
+ListOfFigures: Índex de figures
+ListOfTables: Índex de taules
+Page: Pàgina
+Part: Part
+Preface: Pròleg
+Proof: Demostració
+References: Referències
+See: Vegeu
+SeeAlso: Vegeu també
+Table: Taula
+To: A
diff --git a/data/translations/cs.yaml b/data/translations/cs.yaml
new file mode 100644
index 000000000..e69110181
--- /dev/null
+++ b/data/translations/cs.yaml
@@ -0,0 +1,21 @@
+Abstract: Abstrakt
+Appendix: Dodatek
+Bibliography: Literatura
+Cc: Na vědomí:
+Chapter: Kapitola
+Contents: Obsah
+Encl: Příloha
+Figure: Obrázek
+Glossary: Slovník
+Index: Index
+ListOfFigures: Seznam obrázků
+ListOfTables: Seznam tabulek
+Page: Strana
+Part: Část
+Preface: Předmluva
+Proof: Důkaz
+References: Reference
+See: viz
+SeeAlso: viz
+Table: Tabulka
+To: Komu
diff --git a/data/translations/da.yaml b/data/translations/da.yaml
new file mode 100644
index 000000000..483670d00
--- /dev/null
+++ b/data/translations/da.yaml
@@ -0,0 +1,21 @@
+Abstract: Resumé
+Appendix: Bilag
+Bibliography: Litteratur
+Cc: Kopi til}
+Chapter: Kapitel
+Contents: Indhold
+Encl: Vedlagt
+Figure: Figur
+Glossary: Gloseliste
+Index: Indeks
+ListOfFigures: Figurer
+ListOfTables: Tabeller
+Page: Side
+Part: Del
+Preface: Forord
+Proof: Bevis
+References: Litteratur
+See: Se
+SeeAlso: Se også
+Table: Tabel
+To: Til}
diff --git a/data/translations/de.yaml b/data/translations/de.yaml
new file mode 100644
index 000000000..df519ef83
--- /dev/null
+++ b/data/translations/de.yaml
@@ -0,0 +1,21 @@
+Abstract: Zusammenfassung
+Appendix: Anhang
+Bibliography: Literaturverzeichnis
+Cc: Verteiler
+Chapter: Kapitel
+Contents: Inhaltsverzeichnis
+Encl: Anlage(n)
+Figure: Abbildung
+Glossary: Glossar
+Index: Index
+ListOfFigures: Abbildungsverzeichnis
+ListOfTables: Tabellenverzeichnis
+Page: Seite
+Part: Teil
+Preface: Vorwort
+Proof: Beweis
+References: Literatur
+See: siehe
+SeeAlso: siehe auch
+Table: Tabelle
+To: An
diff --git a/data/translations/el.yaml b/data/translations/el.yaml
new file mode 100644
index 000000000..4aa0468ee
--- /dev/null
+++ b/data/translations/el.yaml
@@ -0,0 +1,21 @@
+Abstract: Περίληψη
+Appendix: Παράρτημα
+Bibliography: Βιβλιογραφία
+Cc: Κοινοποίηση
+Chapter: Κεφάλαιο
+Contents: Περιεχόμενα
+Encl: Συνημμένα
+Figure: Σχήμα
+Glossary: Γλωσσάρι
+Index: Ευρετήριο
+ListOfFigures: Κατάλογος σχημάτων
+ListOfTables: Κατάλογος πινάκων
+Page: Σελίδα
+Part: Μέρος
+Preface: Πρόλογος
+Proof: Απόδειξη
+References: Αναφορές
+See: βλέπε
+SeeAlso: βλέπε επίσης
+Table: Πίνακας
+To: Προς
diff --git a/data/translations/en.yaml b/data/translations/en.yaml
new file mode 100644
index 000000000..bd2599ec8
--- /dev/null
+++ b/data/translations/en.yaml
@@ -0,0 +1,22 @@
+Abstract: Abstract
+Appendix: Appendix
+Bibliography: Bibliography
+Cc: cc
+Chapter: Chapter
+Contents: Contents
+Encl: encl
+Figure: Figure
+Glossary: Glossary
+Index: Index
+ListOfFigures: ListOfFigures
+ListOfTables: ListOfTables
+Page: page
+Part: Part
+Preface: Preface
+Proof: Proof
+References: References
+See: see
+SeeAlso: see also
+Table: Table
+To: To
+Listing: Listing
diff --git a/data/translations/eo.yaml b/data/translations/eo.yaml
new file mode 100644
index 000000000..3393f5a35
--- /dev/null
+++ b/data/translations/eo.yaml
@@ -0,0 +1,20 @@
+Abstract: Resumo
+Appendix: Apendico
+Bibliography: Bibliografio
+Cc: Kopie al
+Chapter: Ĉapitro
+Contents: Enhavo
+Encl: Aldono(j)
+Figure: Figuro
+Glossary: Glosaro
+Index: Indekso
+ListOfFigures: Listo de figuroj
+ListOfTables: Listo de tabeloj
+Page: Paĝo
+Preface: Antaŭparolo
+Proof: Pruvo
+References: Citaĵoj
+See: vidu
+SeeAlso: Parto
+Table: Tabelo
+To: Al
diff --git a/data/translations/es.yaml b/data/translations/es.yaml
new file mode 100644
index 000000000..ad227b7d2
--- /dev/null
+++ b/data/translations/es.yaml
@@ -0,0 +1,21 @@
+Abstract: Resumen
+Appendix: Apéndice
+Bibliography: Bibliografía
+Cc: Copia a
+Chapter: Capítulo
+Contents: Índice general
+Encl: Adjunto(s)
+Figure: Figura
+Glossary: Glosario
+Index: Índice alfabético
+ListOfFigures: Índice de figuras
+ListOfTables: Índice de cuadros
+Page: Página
+Part: Parte
+Preface: Prefacio
+Proof: Prueba
+References: Referencias
+See: véase
+SeeAlso: véase también
+Table: Cuadro
+To: A
diff --git a/data/translations/et.yaml b/data/translations/et.yaml
new file mode 100644
index 000000000..0dde73380
--- /dev/null
+++ b/data/translations/et.yaml
@@ -0,0 +1,20 @@
+Abstract: Kokkuvõte
+Appendix: Lisa
+Bibliography: Kirjandus
+Cc: Koopia(d)
+Chapter: Peatükk
+Contents: Sisukord
+Encl: Lisa(d)
+Figure: Joonis
+Glossary: Glossary
+Index: Indeks
+ListOfFigures: Joonised
+ListOfTables: Tabelid
+Page: Lk.
+Part: Osa
+Preface: Sissejuhatus
+Proof: Korrektuur
+References: Viited
+See: vt.
+SeeAlso: vt. ka
+Table: Tabel
diff --git a/data/translations/eu.yaml b/data/translations/eu.yaml
new file mode 100644
index 000000000..901a64bd6
--- /dev/null
+++ b/data/translations/eu.yaml
@@ -0,0 +1,21 @@
+Abstract: Laburpena
+Appendix: Eranskina
+Bibliography: Bibliografia
+Cc: Kopia
+Chapter: Kapitulua
+Contents: Gaien Aurkibidea
+Encl: Erantsia
+Figure: Irudia
+Glossary: Glosarioa
+Index: Kontzeptuen Aurkibidea
+ListOfFigures: Irudien Zerrenda
+ListOfTables: Taulen Zerrenda
+Page: Orria
+Part: Atala
+Preface: Hitzaurrea
+Proof: Frogapena
+References: Erreferentziak
+See: Ikusi
+SeeAlso: Ikusi, halaber
+Table: Taula
+To: Nori
diff --git a/data/translations/fa.yaml b/data/translations/fa.yaml
new file mode 100644
index 000000000..aa7661859
--- /dev/null
+++ b/data/translations/fa.yaml
@@ -0,0 +1,21 @@
+Abstract: چکیﺪﻫ
+Appendix: پیﻮﺴﺗ
+Bibliography: کﺕﺎﺑc>ﻧﺎﻤﻫ
+Cc: ﺭﻮﻧﻮﺸﺗ
+Chapter: ﻒﺼﻟ
+Contents: ﻒﻫﺮﺴﺗ ﻢﻃﺎﻠﺑ
+Encl: پیﻮﺴﺗ
+Figure: ﺶﻜﻟ
+Glossary: ﺩﺎﻨﺷc>ﻧﺎﻤﻫ
+Index: ﻦﻣﺍیﻩ
+ListOfFigures: ﻝیﺲﺗ ﺖﺻﺍﻭیﺭ
+ListOfTables: ﻝیﺲﺗ ﺝﺩﺍﻮﻟ
+Page: ﺺﻔﺣﺓ
+Part: ﺐﺨﺷ
+Preface: پیﺵگﻒﺗﺍﺭ
+Proof: ﺏﺮﻫﺎﻧ
+References: ﻡﺭﺎﺠﻋ
+See: ﺐﺑیﻥیﺩ
+SeeAlso: ﻥیﺯ ﺐﺑیﻥیﺩ
+Table: ﺝﺩﻮﻟ
+To: ﺐﻫ
diff --git a/data/translations/fi.yaml b/data/translations/fi.yaml
new file mode 100644
index 000000000..37589a4d0
--- /dev/null
+++ b/data/translations/fi.yaml
@@ -0,0 +1,21 @@
+Abstract: Tiivistelmä
+Appendix: Liite
+Bibliography: Kirjallisuutta
+Cc: Jakelu
+Chapter: Luku
+Contents: Sisältö
+Encl: Liitteet
+Figure: Kuva
+Glossary: Sanasto
+Index: Hakemisto
+ListOfFigures: Kuvat
+ListOfTables: Taulukot
+Page: Sivu
+Part: Osa
+Preface: Esipuhe
+Proof: Todistus
+References: Viitteet
+See: katso
+SeeAlso: katso myös
+Table: Taulukko
+To: Vastaanottaja
diff --git a/data/translations/fr.yaml b/data/translations/fr.yaml
new file mode 100644
index 000000000..4b75da6f4
--- /dev/null
+++ b/data/translations/fr.yaml
@@ -0,0 +1,20 @@
+Abstract: Résumé
+Appendix: Annexe
+Bibliography: Bibliographie
+Cc: Copie à
+Chapter: Chaptire
+Contents: Table des matières
+Figure: Fig.
+Glossary:
+Index: Index
+ListOfFigures: Table des figures
+ListOfTables: Liste des tableaux
+Page: page
+Part: partie
+Preface: Préface
+Proof: Démonstration
+References: Références
+See: voir
+SeeAlso: voir aussi
+Table: Tab.
+To:
diff --git a/data/translations/he.yaml b/data/translations/he.yaml
new file mode 100644
index 000000000..b3019255f
--- /dev/null
+++ b/data/translations/he.yaml
@@ -0,0 +1,22 @@
+Abstract: תקציר
+Appendix: נספח
+Bibliography: ביבליוגרפיה
+Cc: העתקים
+Chapter: פרק
+Contents: תוכן העניינים
+Encl: רצ"ב
+Figure: איור
+Glossary: מילון מונחים}
+Index: מפתח
+ListOfFigures: רשימת האיורים
+ListOfTables: רשימת הטבלאות
+Page: עמוד
+Part: חלק
+Preface: מבוא
+Proof: הוכחה}
+Ps: נ.ב.
+References: מקורות
+See: ראה
+SeeAlso: ראה גם}
+Table: טבלה
+To: אל
diff --git a/data/translations/hi.yaml b/data/translations/hi.yaml
new file mode 100644
index 000000000..5dbf6e046
--- /dev/null
+++ b/data/translations/hi.yaml
@@ -0,0 +1,20 @@
+Abstract: सारांश
+Appendix: परिशिष्ट
+Bibliography: संदर ग्रन्थ}
+Cc:
+Chapter: अध्याय
+Contents: विषय सूची
+Encl:
+Figure: चित्र}
+Headpage: पृषठ
+Index: सूची
+ListOfFigures: चित्रों की सूची
+ListOfTables: तालिकाओं की सूची
+Page: पृषठ
+Part: खणड
+Preface: प्रस्तावना}
+References: हवाले
+See: देखिए
+SeeAlso: और देखिए
+Table: तालिका
+To:
diff --git a/data/translations/hr.yaml b/data/translations/hr.yaml
new file mode 100644
index 000000000..389433511
--- /dev/null
+++ b/data/translations/hr.yaml
@@ -0,0 +1,21 @@
+Abstract: Sažetak
+Appendix: Dodatak
+Bibliography: Bibliografija
+Cc: Kopija
+Chapter: Poglavlje
+Contents: Sadržaj
+Encl: Prilozi
+Figure: Slika
+Glossary: Pojmovnik
+Index: Kazalo
+ListOfFigures: Popis slika
+ListOfTables: Popis tablica
+Page: Stranica
+Part: Dio
+Preface: Predgovor
+Proof: Dokaz
+References: Literatura
+See: Vidjeti
+SeeAlso: Također vidjeti
+Table: Tablica
+To: Prima
diff --git a/data/translations/hu.yaml b/data/translations/hu.yaml
new file mode 100644
index 000000000..93c079089
--- /dev/null
+++ b/data/translations/hu.yaml
@@ -0,0 +1,21 @@
+Abstract: Kivonat
+Appendix: Függelék
+Bibliography: Irodalomjegyzék
+Cc: Körlevél–címzettek
+Chapter: fejezet
+Contents: Tartalomjegyzék
+Encl: Melléklet
+Figure: ábra
+Glossary: Szójegyzék
+Index: Tárgymutató
+ListOfFigures: Ábrák jegyzéke
+ListOfTables: Táblázatok jegyzéke
+Page: oldal
+Part: rész
+Preface: Előszó
+Proof: Bizonyítás
+References: Hivatkozások
+See: lásd
+SeeAlso: lásd még
+Table: táblázat
+To: Címzett
diff --git a/data/translations/is.yaml b/data/translations/is.yaml
new file mode 100644
index 000000000..a64c46a81
--- /dev/null
+++ b/data/translations/is.yaml
@@ -0,0 +1,21 @@
+Abstract: Útdráttur
+Appendix: Viðauki
+Bibliography: Heimildir
+Cc: Samrit
+Chapter: Kafli
+Contents: Efnisyfirlit
+Encl: Hjálagt
+Figure: Mynd
+Glossary: Orðalisti
+Index: Atriðisorðaskrá
+ListOfFigures: Myndaskrá
+ListOfTables: Töfluskrá
+Page: Blaðsíða
+Part: Hluti
+Preface: Formáli
+Proof: Sönnun
+References: Heimildir
+See: Sjá
+SeeAlso: Sjá einnig
+Table: Tafla
+To: Til:
diff --git a/data/translations/it.yaml b/data/translations/it.yaml
new file mode 100644
index 000000000..70eca5341
--- /dev/null
+++ b/data/translations/it.yaml
@@ -0,0 +1,21 @@
+Abstract: Sommario
+Appendix: Appendice
+Bibliography: Bibliografia
+Cc: e p. c.
+Chapter: Capitolo
+Contents: Indice
+Encl: Allegati
+Figure: Figura
+Glossary: Glossario
+Index: Indice analitico
+ListOfFigures: Elenco delle figure
+ListOfTables: Elenco delle tabelle
+Page: Pag.
+Part: Parte
+Preface: Prefazione
+Proof: Dimostrazione
+References: Riferimenti bibliografici
+See: vedi
+SeeAlso: vedi anche
+Table: Tabella
+To: Per
diff --git a/data/translations/km.yaml b/data/translations/km.yaml
new file mode 100644
index 000000000..85143735a
--- /dev/null
+++ b/data/translations/km.yaml
@@ -0,0 +1,21 @@
+Abstract: សង្ខេប
+Appendix: សេចក្ដីបន្ថែម
+Bibliography: គន្ថនិទ្ទេស
+Cc: ចម្លងជួន
+Chapter: ជំពូក
+Contents: មាតិការ
+Encl: ឯកសារភ្ជាប់
+Figure: រូប
+Glossary: សទានុក្រម
+Index: សន្ទស្សន៍
+ListOfFigures: បញ្ជីរូបភាព
+ListOfTables: បញ្ជីតារាង
+Page: ទំព័រ
+Part: ផ្នែក
+Preface: អារម្ភកថា
+Proof: សម្រាយ
+References: ឯកសារយោង
+See: មើល
+SeeAlso: មើលបន្ថែម
+Table: តារាង
+To: ផ្ញើរទៅ
diff --git a/data/translations/ko.yaml b/data/translations/ko.yaml
new file mode 100644
index 000000000..15f0a7914
--- /dev/null
+++ b/data/translations/ko.yaml
@@ -0,0 +1,17 @@
+Abstract: 요약
+Appendix: 부록
+Bibliography: 참고문헌
+Cc: 사본
+Chapter: 장
+Contents: 차례
+Encl: 동봉
+Figure: 그림
+Index: 찾아보기
+ListOfFigures: 그림 차례
+ListOfTables: 표 차례
+Page: 페이지
+Preface: 서문
+Proof: 증명
+References: 참고문헌
+Table: 표
+To: 수신:
diff --git a/data/translations/lo.yaml b/data/translations/lo.yaml
new file mode 100644
index 000000000..47b271e56
--- /dev/null
+++ b/data/translations/lo.yaml
@@ -0,0 +1,21 @@
+Abstract: ບົດຫຍໍ້ຄວາມ
+Appendix: ພາກຄັດຕິດ
+Bibliography: ເອກະສານອ້າງອີງ
+Cc: ສໍາເນົາເຖິງ
+Chapter: ບົດທີ
+Contents: ສາລະບານ
+Encl: ເອກະສານປະກອບ
+Figure: ຮູບທີ
+Glossary: ປະມວນສັບ
+Index: ດັດຊະນີ
+ListOfFigures: ສາລະບານຮູບ
+ListOfTables: ສາລະບານຕາຕະລາງ
+Page: ໜ້າ
+Part: ພາກ
+Preface: ຄໍານໍາ
+Proof: ຂໍ້ພິສູດ
+References: ໜັງສືອ້າງອີງ
+See: ອ່ານ
+SeeAlso: ອ່ານເພີ່ມ
+Table: ຕາຕະລາງທີ
+To: ຮຽນ
diff --git a/data/translations/lt.yaml b/data/translations/lt.yaml
new file mode 100644
index 000000000..35190751b
--- /dev/null
+++ b/data/translations/lt.yaml
@@ -0,0 +1,21 @@
+Abstract: Santrauka
+Appendix: Priedas
+Bibliography: Literatūra
+Cc: Kopijos
+Chapter: Skyrius
+Contents: Turinys
+Encl: Įdėta
+Figure: pav.
+Glossary: Terminų žodynas
+Index: Rodyklė
+ListOfFigures: Iliustracijų sąrašas
+ListOfTables: Lentelių sąrašas
+Page: puslapis
+Part: Dalis
+Preface: Pratarmė
+Proof: Įrodymas
+References: Literatūra
+See: žiūrėk
+SeeAlso: taip pat
+Table: lentelė
+To: Kam
diff --git a/data/translations/lv.yaml b/data/translations/lv.yaml
new file mode 100644
index 000000000..3e224100f
--- /dev/null
+++ b/data/translations/lv.yaml
@@ -0,0 +1,20 @@
+Abstract: Anotācija
+Appendix: Pielikums
+Bibliography: Literatūra
+Cc: cc
+Chapter: Nodaļa
+Contents: Saturs
+Encl: encl
+Figure: Att.
+Index: Index
+ListOfFigures: Attēlu saraksts
+ListOfTables: Tabulu saraksts
+Page: lpp.
+Part: Daļa
+Preface: Priekšvārds
+Proof: Pierādījums
+References: Literatūras saraksts
+See: sk.
+SeeAlso: sk. arī
+Table: Tabula
+To: To
diff --git a/data/translations/nl.yaml b/data/translations/nl.yaml
new file mode 100644
index 000000000..2c21901d9
--- /dev/null
+++ b/data/translations/nl.yaml
@@ -0,0 +1,21 @@
+Abstract: Samenvatting
+Appendix: Bijlage
+Bibliography: Bibliografie
+Cc: cc
+Chapter: Hoofdstuk
+Contents: Inhoudsopgave
+Encl: Bijlage(n)
+Figure: Figuur
+Glossary: Verklarende woordenlijst
+Index: Index
+ListOfFigures: Lijst van figuren
+ListOfTables: Lijst van tabellen
+Page: Pagina
+Part: Deel
+Preface: Voorwoord
+Proof: Bewijs
+References: Referenties
+See: zie
+SeeAlso: zie ook
+Table: Tabel
+To: Aan
diff --git a/data/translations/no.yaml b/data/translations/no.yaml
new file mode 100644
index 000000000..bc715a020
--- /dev/null
+++ b/data/translations/no.yaml
@@ -0,0 +1,21 @@
+Abstract: Sammendrag
+Appendix: Tillegg
+Bibliography: Bibliografi
+Cc: Kopi sendt
+Chapter: Kapittel
+Contents: Innhold
+Encl: Vedlegg
+Figure: Figur
+Glossary: Ordliste
+Index: Register
+ListOfFigures: Figurer
+ListOfTables: Tabeller
+Page: Side
+Part: Del
+Preface: Forord
+Proof: Bevis
+References: Referanser
+See: Se
+SeeAlso: Se også
+Table: Tabell
+To: Til
diff --git a/data/translations/pl.yaml b/data/translations/pl.yaml
new file mode 100644
index 000000000..160e67641
--- /dev/null
+++ b/data/translations/pl.yaml
@@ -0,0 +1,21 @@
+Abstract: Streszczenie
+Appendix: Dodatek
+Bibliography: Bibliografia
+Cc: Kopie:
+Chapter: Rozdział
+Contents: Spis treści
+Encl: Załącznik
+Figure: Rysunek
+Glossary: Glossary
+Index: Indeks
+ListOfFigures: Spis rysunków
+ListOfTables: Spis tabel
+Page: Strona
+Part: Część
+Preface: Przedmowa
+Proof: Dowód
+References: Literatura
+See: Zobacz
+SeeAlso: Zobacz też
+Table: Tabela
+To: Do
diff --git a/data/translations/pt.yaml b/data/translations/pt.yaml
new file mode 100644
index 000000000..eea2eeae3
--- /dev/null
+++ b/data/translations/pt.yaml
@@ -0,0 +1,21 @@
+Abstract: Resumo
+Appendix: Apêndice
+Bibliography: Bibliografia
+Cc: Com cópia a
+Chapter: Capítulo
+Contents: Conteúdo
+Encl: Anexo
+Figure: Figura
+Glossary: Glossário
+Index: Índice
+ListOfFigures: Lista de Figuras
+ListOfTables: Lista de Tabelas
+Page: Página
+Part: Parte
+Preface: Prefácio
+Proof: Demonstração
+References: Referências
+See: ver
+SeeAlso: ver também
+Table: Tabela
+To: Para
diff --git a/data/translations/rm.yaml b/data/translations/rm.yaml
new file mode 100644
index 000000000..f7f556197
--- /dev/null
+++ b/data/translations/rm.yaml
@@ -0,0 +1,21 @@
+Abstract: Recapitulaziun
+Appendix: Appendix
+Bibliography: Index bibliografic
+Cc: Copia a
+Chapter: Chapitel
+Contents: Tavla dal cuntegn
+Encl: Agiunta(s)
+Figure: Figura
+Glossary: Glossari
+Index: Register da materias
+ListOfFigures: Tavla da las figuras
+ListOfTables: Tavla da las tabellas
+Page: pagina
+Part: Part
+Preface: Prefaziun
+Proof: Demonstraziun
+References: Bibliografia
+See: vesair
+SeeAlso: vesair era
+Table: Tabella
+To: A
diff --git a/data/translations/ro.yaml b/data/translations/ro.yaml
new file mode 100644
index 000000000..d4bb866f6
--- /dev/null
+++ b/data/translations/ro.yaml
@@ -0,0 +1,21 @@
+Abstract: Rezumat
+Appendix: Anexa
+Bibliography: Bibliografie
+Cc: Copie
+Chapter: Capitolul
+Contents: Cuprins
+Encl: Anexă
+Figure: Figura
+Glossary: Glosar
+Index: Glosar
+ListOfFigures: Listă de figuri
+ListOfTables: Listă de tabele
+Page: Pagina
+Part: Partea
+Preface: Prefață
+Proof: Demonstrație
+References: Bibliografie
+See: Vezi
+SeeAlso: Vezi de asemenea
+Table: Tabela
+To: Pentru
diff --git a/data/translations/ru.yaml b/data/translations/ru.yaml
new file mode 100644
index 000000000..6012c3e19
--- /dev/null
+++ b/data/translations/ru.yaml
@@ -0,0 +1,21 @@
+Abstract: Аннотація
+Appendix: Приложеніе
+Author: Именной указатель
+Bibliography: Библіографія
+Cc: исх.
+Chapter: Глава
+Contents: Оглавленіе
+Encl: вкл.
+Figure: Рис.
+Index: Предмѣтный указатель
+ListOfFigures: Списокъ иллюстрацій
+ListOfTables: Списокъ таблицъ
+Page: с.
+Part: Часть
+Preface: Предисловіе
+Proof: Доказательство
+References: Примѣчанія
+See: см.
+SeeAlso: см. также
+Table: Таблица
+To: вх.
diff --git a/data/translations/sk.yaml b/data/translations/sk.yaml
new file mode 100644
index 000000000..b07212f85
--- /dev/null
+++ b/data/translations/sk.yaml
@@ -0,0 +1,21 @@
+Abstract: Abstrakt
+Appendix: Dodatok
+Bibliography: Literatúra
+Cc: cc.
+Chapter: Kapitola
+Contents: Obsah
+Encl: Prílohy
+Figure: Obrázok
+Glossary: Slovník
+Index: Index
+ListOfFigures: Zoznam obrázkov
+ListOfTables: Zoznam tabuliek
+Page: Strana
+Part: Časť
+Preface: Úvod
+Proof: Dôkaz
+References: Referencie
+See: viď
+SeeAlso: viď tiež
+Table: Tabuľka
+To: Pre
diff --git a/data/translations/sl.yaml b/data/translations/sl.yaml
new file mode 100644
index 000000000..3e735dfd0
--- /dev/null
+++ b/data/translations/sl.yaml
@@ -0,0 +1,21 @@
+Abstract: Povzetek
+Appendix: Dodatek
+Bibliography: Literatura
+Cc: Kopije
+Chapter: Poglavje
+Contents: Kazalo
+Encl: Priloge
+Figure: Slika
+Glossary: Slovar
+Index: Stvarno kazalo
+ListOfFigures: Slike
+ListOfTables: Tabele
+Page: Stran
+Part: Del
+Preface: Predgovor
+Proof: Dokaz
+References: Literatura
+See: glej
+SeeAlso: glej tudi
+Table: Tabela
+To: Prejme
diff --git a/data/translations/sq.yaml b/data/translations/sq.yaml
new file mode 100644
index 000000000..e8647489d
--- /dev/null
+++ b/data/translations/sq.yaml
@@ -0,0 +1,18 @@
+Abstract: Përmbledhja
+Appendix: Shtesa
+Bibliography: Bibliografia
+Chapter: Kapitulli
+Contents: Përmbajta
+Figure: Figura
+Glossary: Përhasja e Fjalëve
+Index: Indeksi
+ListOfFigures: Figurat
+ListOfTables: Tabelat
+Page: Faqe
+Part: Pjesa
+Preface: Parathenia
+Proof: Vërtetim
+References: Referencat
+See: shiko
+SeeAlso: shiko dhe
+Table: Tabela
diff --git a/data/translations/sr-cyrl.yaml b/data/translations/sr-cyrl.yaml
new file mode 100644
index 000000000..3ce57ddda
--- /dev/null
+++ b/data/translations/sr-cyrl.yaml
@@ -0,0 +1,21 @@
+Abstract: Сажетак
+Appendix: Додатак
+Bibliography: Литература
+Cc: Копије
+Chapter: Глава
+Contents: Садржај
+Encl: Прилози
+Figure: Слика
+Glossary: Речник непознатих речи
+Index: Регистар
+ListOfFigures: Списак слика
+ListOfTables: Списак табела
+Page: Страна
+Part: Део
+Preface: Предговор
+Proof: Доказ
+References: Библиографија
+See: Види
+SeeAlso: Види такође
+Table: Табела
+To: Прима
diff --git a/data/translations/sr.yaml b/data/translations/sr.yaml
new file mode 100644
index 000000000..461d463c0
--- /dev/null
+++ b/data/translations/sr.yaml
@@ -0,0 +1,21 @@
+Abstract: Sažetak
+Appendix: Dodatak
+Bibliography: Literatura
+Cc: Kopije
+Chapter: Glava
+Contents: Sadržaj
+Encl: Prilozi
+Figure: Slika
+Glossary: Rečnik nepoznatih reči
+Index: Registar
+ListOfFigures: Spisak slika
+ListOfTables: Spisak tabela
+Page: Strana
+Part: Deo
+Preface: Predgovor
+Proof: Dokaz
+References: Bibliografija
+See: Vidi
+SeeAlso: Vidi takođe
+Table: Tabela
+To: Prima
diff --git a/data/translations/sv.yaml b/data/translations/sv.yaml
new file mode 100644
index 000000000..af183466a
--- /dev/null
+++ b/data/translations/sv.yaml
@@ -0,0 +1,21 @@
+Abstract: Sammanfattning
+Appendix: Bilaga
+Bibliography: Litteraturförteckning
+Cc: Kopia för kännedom
+Chapter: Kapitel
+Contents: Innehåll
+Encl: Bil.
+Figure: Figur
+Glossary: Ordlista
+Index: Sakregister
+ListOfFigures: Figurer
+ListOfTables: Tabeller
+Page: Sida
+Part: Del
+Preface: Förord
+Proof: Bevis
+References: Referenser
+See: se
+SeeAlso: se även
+Table: Tabell
+To: Till
diff --git a/data/translations/th.yaml b/data/translations/th.yaml
new file mode 100644
index 000000000..f8443f622
--- /dev/null
+++ b/data/translations/th.yaml
@@ -0,0 +1,20 @@
+Abstract: บทคัดย่อ
+Appendix: ภาคผนวก
+Bibliography: บรรณานุกรม
+Cc: สำเนาถึง
+Chapter: บทที่
+Contents: สารบัญ
+Encl: สิ่งที่แนบมาด้วย
+Figure: รูปที่
+Index: ดรรชนี
+ListOfFigures: สารบัญรูป
+ListOfTables: สารบัญตาราง
+Page: หน้า
+Part: ภาค
+Preface: คำนำ
+Proof: พิสูจน์
+References: หนังสืออ้างอิง
+See: ดู
+SeeAlso: ดูเพิ่มเติม
+Table: ตารางที่
+To: เรียน
diff --git a/data/translations/tr.yaml b/data/translations/tr.yaml
new file mode 100644
index 000000000..6275a9822
--- /dev/null
+++ b/data/translations/tr.yaml
@@ -0,0 +1,22 @@
+Abstract: Özet
+Appendix: Ek
+Bibliography: Kaynakça
+Cc: Diğer Alıcılar
+Chapter: Bölüm
+Contents: İçindekiler
+Encl: İlişik
+Figure: Şekil
+Glossary: Lügatçe
+Index: Dizin
+ListOfFigures: Şekil Listesi
+ListOfTables: Tablo Listesi
+Page: Sayfa
+Part: Kısım
+Preface: Önsöz
+Proof: Kanıt
+References: Kaynaklar
+See: bkz.
+SeeAlso: ayrıca bkz.
+Subject: İlgili
+Table: Tablo
+To: Alıcı
diff --git a/data/translations/uk.yaml b/data/translations/uk.yaml
new file mode 100644
index 000000000..69b7b560e
--- /dev/null
+++ b/data/translations/uk.yaml
@@ -0,0 +1,22 @@
+Abstract: Анотація
+Appendix: Додаток
+Author: Іменний покажчик}% babel has "Їменний покажчик"
+Bibliography: Бібліоґрафія
+Cc: копія
+Chapter: Розділ
+Contents: Зміст
+Encl: вкладка
+Figure: Рис.
+Glossary: Словник термінів
+Index: Покажчик
+ListOfFigures: Перелік ілюстрацій
+ListOfTables: Перелік таблиць
+Page: с.
+Part: Частина
+Preface: Вступ
+Proof: Доведення
+References: Література
+See: див.
+SeeAlso: див. також
+Table: Табл.
+To: До
diff --git a/data/translations/ur.yaml b/data/translations/ur.yaml
new file mode 100644
index 000000000..991e69f5d
--- /dev/null
+++ b/data/translations/ur.yaml
@@ -0,0 +1,22 @@
+Abstract: ﻢﻠﺨّﺻ
+Appendix: ﺾﻣیﻡہ
+Bibliography: کﺕﺎﺑیﺎﺗ
+Cc: ﻦﻘﻟ
+Chapter: ﺏﺎﺑ
+Contents: ﻑہﺮﺴﺗ ﻊﻧﻭﺎﻧﺎﺗ
+Encl: ﻢﻨﺴﻟک
+Figure: ﺶﻜﻟ
+Glossary: ﻞﻐﺗ
+Index: ﺎﺷﺍﺭیہ
+ListOfFigures: ﻑہﺮﺴﺗ ﺎﺷکﺎﻟ
+ListOfTables: ﻑہﺮﺴﺗ ﺝﺩﺍﻮﻟ
+Page: ﺺﻔﺣہ
+Part: ﺢﺻّہ
+Preface: ﺩیﺏﺍچہ
+Proof: ﺚﺑﻮﺗ
+References: ﺡﻭﺎﻟہ ﺝﺎﺗ
+Section: ﻒﺼﻟ
+See: ﻡﻼﺤﻇہ ہﻭ
+SeeAlso: ﺍیﺽﺍً
+Table: ﺝﺩﻮﻟ
+To: ﺐﻣﻼﺤﻇہ
diff --git a/data/translations/vi.yaml b/data/translations/vi.yaml
new file mode 100644
index 000000000..ee8dfb736
--- /dev/null
+++ b/data/translations/vi.yaml
@@ -0,0 +1,21 @@
+Abstract: Tóm tắt nội dung
+Also: Xem thêm
+Appendix: Phụ lục
+Bib: Tài liệu tham khảo
+Cc: Cùng gửi
+Chapter: Chương
+Contents: Mục lục
+Encl: Kèm theo
+Figure: Hình
+Glossary: Từ điển chú giải
+Headto: Gửi
+Index: Chỉ mục
+Listfigure: Danh sách hình vẽ
+Listtable: Danh sách bẳng
+Page: Trang
+Part: Phần
+Preface: Lời nói đầu
+Proof: Chứng minh
+References: Tài liệu
+See: Xem
+Table: Bẳng
diff --git a/man/capitalizeHeaders.hs b/man/capitalizeHeaders.hs
deleted file mode 100644
index 863381c1f..000000000
--- a/man/capitalizeHeaders.hs
+++ /dev/null
@@ -1,20 +0,0 @@
-import Text.Pandoc.JSON
-import Text.Pandoc.Walk
-import Data.Char (toUpper)
-
-main :: IO ()
-main = toJSONFilter capitalizeHeaders
-
-capitalizeHeaders :: Block -> Block
-capitalizeHeaders (Header 1 attr xs) = Header 1 attr $ walk capitalize xs
-capitalizeHeaders x = x
-
-capitalize :: Inline -> Inline
-capitalize (Str xs) = Str $ map toUpper xs
-capitalize x = x
-
-{-
-capitalizeHeaderLinks :: Inline -> Inline
-capitalizeHeaderLinks (Link xs t@('#':_,_)) = Link (walk capitalize xs) t
-capitalizeHeaderLinks x = x
--}
diff --git a/man/manfilter.lua b/man/manfilter.lua
new file mode 100644
index 000000000..c6bbd02c4
--- /dev/null
+++ b/man/manfilter.lua
@@ -0,0 +1,22 @@
+-- we use preloaded text to get a UTF-8 aware 'upper' function
+local text = require('text')
+
+-- capitalize level 1 headers
+function Header(el)
+ if el.level == 1 then
+ return pandoc.walk_block(el, {
+ Str = function(el)
+ return pandoc.Str(text.upper(el.text))
+ end })
+ end
+end
+
+-- replace links with link text
+function Link(el)
+ return el.content
+end
+
+-- remove notes
+function Note(el)
+ return {}
+end
diff --git a/man/pandoc.1 b/man/pandoc.1
index 104458b06..7cac72ebd 100644
--- a/man/pandoc.1
+++ b/man/pandoc.1
@@ -1,63 +1,63 @@
.\"t
-.TH PANDOC 1 "January 29, 2017" "pandoc 1.19.2.4"
+.TH PANDOC 1 "March 2, 2018" "pandoc 2.1.2"
.SH NAME
pandoc - general markup converter
.SH SYNOPSIS
.PP
-\f[C]pandoc\f[] [\f[I]options\f[]] [\f[I]input\-file\f[]]\&...
+\f[C]pandoc\f[] [\f[I]options\f[]] [\f[I]input\-file\f[]]...
.SH DESCRIPTION
.PP
Pandoc is a Haskell library for converting from one markup format to
another, and a command\-line tool that uses this library.
-It can read Markdown, CommonMark, PHP Markdown Extra, GitHub\-Flavored
-Markdown, MultiMarkdown, and (subsets of) Textile, reStructuredText,
-HTML, LaTeX, MediaWiki markup, TWiki markup, Haddock markup, OPML, Emacs
-Org mode, DocBook, txt2tags, EPUB, ODT and Word docx; and it can write
-plain text, Markdown, CommonMark, PHP Markdown Extra, GitHub\-Flavored
-Markdown, MultiMarkdown, reStructuredText, XHTML, HTML5, LaTeX
-(including \f[C]beamer\f[] slide shows), ConTeXt, RTF, OPML, DocBook,
-OpenDocument, ODT, Word docx, GNU Texinfo, MediaWiki markup, DokuWiki
-markup, ZimWiki markup, Haddock markup, EPUB (v2 or v3), FictionBook2,
-Textile, groff man pages, Emacs Org mode, AsciiDoc, InDesign ICML, TEI
-Simple, and Slidy, Slideous, DZSlides, reveal.js or S5 HTML slide shows.
-It can also produce PDF output on systems where LaTeX, ConTeXt, or
-\f[C]wkhtmltopdf\f[] is installed.
-.PP
-Pandoc's enhanced version of Markdown includes syntax for footnotes,
-tables, flexible ordered lists, definition lists, fenced code blocks,
-superscripts and subscripts, strikeout, metadata blocks, automatic
-tables of contents, embedded LaTeX math, citations, and Markdown inside
-HTML block elements.
-(These enhancements, described further under Pandoc's Markdown, can be
-disabled using the \f[C]markdown_strict\f[] input or output format.)
-.PP
-In contrast to most existing tools for converting Markdown to HTML,
-which use regex substitutions, pandoc has a modular design: it consists
-of a set of readers, which parse text in a given format and produce a
-native representation of the document, and a set of writers, which
-convert this native representation into a target format.
+.PP
+Pandoc can read Markdown, CommonMark, PHP Markdown Extra,
+GitHub\-Flavored Markdown, MultiMarkdown, and (subsets of) Textile,
+reStructuredText, HTML, LaTeX, MediaWiki markup, TWiki markup, TikiWiki
+markup, Creole 1.0, Haddock markup, OPML, Emacs Org mode, DocBook, JATS,
+Muse, txt2tags, Vimwiki, EPUB, ODT, and Word docx.
+.PP
+Pandoc can write plain text, Markdown, CommonMark, PHP Markdown Extra,
+GitHub\-Flavored Markdown, MultiMarkdown, reStructuredText, XHTML,
+HTML5, LaTeX (including \f[C]beamer\f[] slide shows), ConTeXt, RTF,
+OPML, DocBook, JATS, OpenDocument, ODT, Word docx, GNU Texinfo,
+MediaWiki markup, DokuWiki markup, ZimWiki markup, Haddock markup, EPUB
+(v2 or v3), FictionBook2, Textile, groff man, groff ms, Emacs Org mode,
+AsciiDoc, InDesign ICML, TEI Simple, Muse, PowerPoint slide shows and
+Slidy, Slideous, DZSlides, reveal.js or S5 HTML slide shows.
+It can also produce PDF output on systems where LaTeX, ConTeXt,
+\f[C]pdfroff\f[], \f[C]wkhtmltopdf\f[], \f[C]prince\f[], or
+\f[C]weasyprint\f[] is installed.
+.PP
+Pandoc\[aq]s enhanced version of Markdown includes syntax for tables,
+definition lists, metadata blocks, \f[C]Div\f[] blocks, footnotes and
+citations, embedded LaTeX (including math), Markdown inside HTML block
+elements, and much more.
+These enhancements, described further under Pandoc\[aq]s Markdown, can
+be disabled using the \f[C]markdown_strict\f[] format.
+.PP
+Pandoc has a modular design: it consists of a set of readers, which
+parse text in a given format and produce a native representation of the
+document (like an \f[I]abstract syntax tree\f[] or AST), and a set of
+writers, which convert this native representation into a target format.
Thus, adding an input or output format requires only adding a reader or
writer.
+Users can also run custom pandoc filters to modify the intermediate AST.
.PP
-Because pandoc's intermediate representation of a document is less
+Because pandoc\[aq]s intermediate representation of a document is less
expressive than many of the formats it converts between, one should not
expect perfect conversions between every format and every other.
Pandoc attempts to preserve the structural elements of a document, but
not formatting details such as margin size.
And some document elements, such as complex tables, may not fit into
-pandoc's simple document model.
-While conversions from pandoc's Markdown to all formats aspire to be
-perfect, conversions from formats more expressive than pandoc's Markdown
-can be expected to be lossy.
+pandoc\[aq]s simple document model.
+While conversions from pandoc\[aq]s Markdown to all formats aspire to be
+perfect, conversions from formats more expressive than pandoc\[aq]s
+Markdown can be expected to be lossy.
.SS Using \f[C]pandoc\f[]
.PP
-If no \f[I]input\-file\f[] is specified, input is read from
+If no \f[I]input\-files\f[] are specified, input is read from
\f[I]stdin\f[].
-Otherwise, the \f[I]input\-files\f[] are concatenated (with a blank line
-between each) and used as input.
-Output goes to \f[I]stdout\f[] by default (though output to
-\f[I]stdout\f[] is disabled for the \f[C]odt\f[], \f[C]docx\f[],
-\f[C]epub\f[], and \f[C]epub3\f[] output formats).
+Output goes to \f[I]stdout\f[] by default.
For output to a file, use the \f[C]\-o\f[] option:
.IP
.nf
@@ -66,10 +66,10 @@ pandoc\ \-o\ output.html\ input.txt
\f[]
.fi
.PP
-By default, pandoc produces a document fragment, not a standalone
-document with a proper header and footer.
-To produce a standalone document, use the \f[C]\-s\f[] or
-\f[C]\-\-standalone\f[] flag:
+By default, pandoc produces a document fragment.
+To produce a standalone document (e.g.
+a valid HTML file including \f[C]<head>\f[] and \f[C]<body>\f[]), use
+the \f[C]\-s\f[] or \f[C]\-\-standalone\f[] flag:
.IP
.nf
\f[C]
@@ -78,27 +78,17 @@ pandoc\ \-s\ \-o\ output.html\ input.txt
.fi
.PP
For more information on how standalone documents are produced, see
-Templates, below.
-.PP
-Instead of a file, an absolute URI may be given.
-In this case pandoc will fetch the content using HTTP:
-.IP
-.nf
-\f[C]
-pandoc\ \-f\ html\ \-t\ markdown\ http://www.fsf.org
-\f[]
-.fi
+Templates below.
.PP
If multiple input files are given, \f[C]pandoc\f[] will concatenate them
all (with blank lines between them) before parsing.
-This feature is disabled for binary input formats such as \f[C]EPUB\f[],
-\f[C]odt\f[], and \f[C]docx\f[].
+(Use \f[C]\-\-file\-scope\f[] to parse files individually.)
+.SS Specifying formats
.PP
The format of the input and output can be specified explicitly using
command\-line options.
-The input format can be specified using the \f[C]\-r/\-\-read\f[] or
-\f[C]\-f/\-\-from\f[] options, the output format using the
-\f[C]\-w/\-\-write\f[] or \f[C]\-t/\-\-to\f[] options.
+The input format can be specified using the \f[C]\-f/\-\-from\f[]
+option, the output format using the \f[C]\-t/\-\-to\f[] option.
Thus, to convert \f[C]hello.txt\f[] from Markdown to LaTeX, you could
type:
.IP
@@ -116,17 +106,15 @@ pandoc\ \-f\ html\ \-t\ markdown\ hello.html
\f[]
.fi
.PP
-Supported output formats are listed below under the \f[C]\-t/\-\-to\f[]
-option.
-Supported input formats are listed below under the \f[C]\-f/\-\-from\f[]
-option.
-Note that the \f[C]rst\f[], \f[C]textile\f[], \f[C]latex\f[], and
-\f[C]html\f[] readers are not complete; there are some constructs that
-they do not parse.
+Supported input and output formats are listed below under Options (see
+\f[C]\-f\f[] for input formats and \f[C]\-t\f[] for output formats).
+You can also use \f[C]pandoc\ \-\-list\-input\-formats\f[] and
+\f[C]pandoc\ \-\-list\-output\-formats\f[] to print lists of supported
+formats.
.PP
If the input or output format is not specified explicitly,
\f[C]pandoc\f[] will attempt to guess it from the extensions of the
-input and output filenames.
+filenames.
Thus, for example,
.IP
.nf
@@ -137,11 +125,12 @@ pandoc\ \-o\ hello.tex\ hello.txt
.PP
will convert \f[C]hello.txt\f[] from Markdown to LaTeX.
If no output file is specified (so that output goes to \f[I]stdout\f[]),
-or if the output file's extension is unknown, the output format will
+or if the output file\[aq]s extension is unknown, the output format will
default to HTML.
If no input file is specified (so that input comes from \f[I]stdin\f[]),
-or if the input files' extensions are unknown, the input format will be
-assumed to be Markdown unless explicitly specified.
+or if the input files\[aq] extensions are unknown, the input format will
+be assumed to be Markdown.
+.SS Character encoding
.PP
Pandoc uses the UTF\-8 character encoding for both input and output.
If your local character encoding is not UTF\-8, you should pipe input
@@ -160,8 +149,7 @@ the \f[C]\-s/\-\-standalone\f[] option.
.SS Creating a PDF
.PP
To produce a PDF, specify an output file with a \f[C]\&.pdf\f[]
-extension.
-By default, pandoc will use LaTeX to convert it to PDF:
+extension:
.IP
.nf
\f[C]
@@ -169,67 +157,96 @@ pandoc\ test.txt\ \-o\ test.pdf
\f[]
.fi
.PP
-Production of a PDF requires that a LaTeX engine be installed (see
-\f[C]\-\-latex\-engine\f[], below), and assumes that the following LaTeX
-packages are available: \f[C]amsfonts\f[], \f[C]amsmath\f[],
-\f[C]lm\f[], \f[C]ifxetex\f[], \f[C]ifluatex\f[], \f[C]eurosym\f[],
-\f[C]listings\f[] (if the \f[C]\-\-listings\f[] option is used),
-\f[C]fancyvrb\f[], \f[C]longtable\f[], \f[C]booktabs\f[],
-\f[C]graphicx\f[] and \f[C]grffile\f[] (if the document contains
-images), \f[C]hyperref\f[], \f[C]ulem\f[], \f[C]geometry\f[] (with the
+By default, pandoc will use LaTeX to create the PDF, which requires that
+a LaTeX engine be installed (see \f[C]\-\-pdf\-engine\f[] below).
+.PP
+Alternatively, pandoc can use ConTeXt, \f[C]pdfroff\f[], or any of the
+following HTML/CSS\-to\-PDF\-engines, to create a PDF:
+\f[C]wkhtmltopdf\f[], \f[C]weasyprint\f[] or \f[C]prince\f[].
+To do this, specify an output file with a \f[C]\&.pdf\f[] extension, as
+before, but add the \f[C]\-\-pdf\-engine\f[] option or
+\f[C]\-t\ context\f[], \f[C]\-t\ html\f[], or \f[C]\-t\ ms\f[] to the
+command line (\f[C]\-t\ html\f[] defaults to
+\f[C]\-\-pdf\-engine=wkhtmltopdf\f[]).
+.PP
+PDF output can be controlled using variables for LaTeX (if LaTeX is
+used) and variables for ConTeXt (if ConTeXt is used).
+When using an HTML/CSS\-to\-PDF\-engine, \f[C]\-\-css\f[] affects the
+output.
+If \f[C]wkhtmltopdf\f[] is used, then the variables
+\f[C]margin\-left\f[], \f[C]margin\-right\f[], \f[C]margin\-top\f[],
+\f[C]margin\-bottom\f[], \f[C]footer\-html\f[], \f[C]header\-html\f[]
+and \f[C]papersize\f[] will affect the output.
+.PP
+To debug the PDF creation, it can be useful to look at the intermediate
+representation: instead of \f[C]\-o\ test.pdf\f[], use for example
+\f[C]\-s\ \-o\ test.tex\f[] to output the generated LaTeX.
+You can then test it with \f[C]pdflatex\ test.tex\f[].
+.PP
+When using LaTeX, the following packages need to be available (they are
+included with all recent versions of TeX Live): \f[C]amsfonts\f[],
+\f[C]amsmath\f[], \f[C]lm\f[], \f[C]unicode\-math\f[], \f[C]ifxetex\f[],
+\f[C]ifluatex\f[], \f[C]listings\f[] (if the \f[C]\-\-listings\f[]
+option is used), \f[C]fancyvrb\f[], \f[C]longtable\f[],
+\f[C]booktabs\f[], \f[C]graphicx\f[] and \f[C]grffile\f[] (if the
+document contains images), \f[C]hyperref\f[], \f[C]xcolor\f[] (with
+\f[C]colorlinks\f[]), \f[C]ulem\f[], \f[C]geometry\f[] (with the
\f[C]geometry\f[] variable set), \f[C]setspace\f[] (with
\f[C]linestretch\f[]), and \f[C]babel\f[] (with \f[C]lang\f[]).
The use of \f[C]xelatex\f[] or \f[C]lualatex\f[] as the LaTeX engine
-requires \f[C]fontspec\f[]; \f[C]xelatex\f[] uses \f[C]mathspec\f[],
-\f[C]polyglossia\f[] (with \f[C]lang\f[]), \f[C]xecjk\f[], and
-\f[C]bidi\f[] (with the \f[C]dir\f[] variable set).
+requires \f[C]fontspec\f[].
+\f[C]xelatex\f[] uses \f[C]polyglossia\f[] (with \f[C]lang\f[]),
+\f[C]xecjk\f[], and \f[C]bidi\f[] (with the \f[C]dir\f[] variable set).
+If the \f[C]mathspec\f[] variable is set, \f[C]xelatex\f[] will use
+\f[C]mathspec\f[] instead of \f[C]unicode\-math\f[].
The \f[C]upquote\f[] and \f[C]microtype\f[] packages are used if
-available, and \f[C]csquotes\f[] will be used for smart punctuation if
-added to the template or included in any header file.
+available, and \f[C]csquotes\f[] will be used for typography if added to
+the template or included in any header file.
The \f[C]natbib\f[], \f[C]biblatex\f[], \f[C]bibtex\f[], and
\f[C]biber\f[] packages can optionally be used for citation rendering.
-These are included with all recent versions of TeX Live.
+.SS Reading from the Web
.PP
-Alternatively, pandoc can use ConTeXt or \f[C]wkhtmltopdf\f[] to create
-a PDF.
-To do this, specify an output file with a \f[C]\&.pdf\f[] extension, as
-before, but add \f[C]\-t\ context\f[] or \f[C]\-t\ html5\f[] to the
-command line.
+Instead of an input file, an absolute URI may be given.
+In this case pandoc will fetch the content using HTTP:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ html\ \-t\ markdown\ http://www.fsf.org
+\f[]
+.fi
.PP
-PDF output can be controlled using variables for LaTeX (if LaTeX is
-used) and variables for ConTeXt (if ConTeXt is used).
-If \f[C]wkhtmltopdf\f[] is used, then the variables
-\f[C]margin\-left\f[], \f[C]margin\-right\f[], \f[C]margin\-top\f[],
-\f[C]margin\-bottom\f[], and \f[C]papersize\f[] will affect the output,
-as will \f[C]\-\-css\f[].
+It is possible to supply a custom User\-Agent string or other header
+when requesting a document from a URL:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ html\ \-t\ markdown\ \-\-request\-header\ User\-Agent:"Mozilla/5.0"\ \\
+\ \ http://www.fsf.org
+\f[]
+.fi
.SH OPTIONS
.SS General options
.TP
.B \f[C]\-f\f[] \f[I]FORMAT\f[], \f[C]\-r\f[] \f[I]FORMAT\f[], \f[C]\-\-from=\f[]\f[I]FORMAT\f[], \f[C]\-\-read=\f[]\f[I]FORMAT\f[]
Specify input format.
\f[I]FORMAT\f[] can be \f[C]native\f[] (native Haskell), \f[C]json\f[]
-(JSON version of native AST), \f[C]markdown\f[] (pandoc's extended
+(JSON version of native AST), \f[C]markdown\f[] (pandoc\[aq]s extended
Markdown), \f[C]markdown_strict\f[] (original unextended Markdown),
-\f[C]markdown_phpextra\f[] (PHP Markdown Extra),
-\f[C]markdown_github\f[] (GitHub\-Flavored Markdown),
-\f[C]markdown_mmd\f[] (MultiMarkdown), \f[C]commonmark\f[] (CommonMark
-Markdown), \f[C]textile\f[] (Textile), \f[C]rst\f[] (reStructuredText),
-\f[C]html\f[] (HTML), \f[C]docbook\f[] (DocBook), \f[C]t2t\f[]
-(txt2tags), \f[C]docx\f[] (docx), \f[C]odt\f[] (ODT), \f[C]epub\f[]
-(EPUB), \f[C]opml\f[] (OPML), \f[C]org\f[] (Emacs Org mode),
-\f[C]mediawiki\f[] (MediaWiki markup), \f[C]twiki\f[] (TWiki markup),
-\f[C]haddock\f[] (Haddock markup), or \f[C]latex\f[] (LaTeX).
-If \f[C]+lhs\f[] is appended to \f[C]markdown\f[], \f[C]rst\f[],
-\f[C]latex\f[], or \f[C]html\f[], the input will be treated as literate
-Haskell source: see Literate Haskell support, below.
-Markdown syntax extensions can be individually enabled or disabled by
-appending \f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format
-name.
-So, for example, \f[C]markdown_strict+footnotes+definition_lists\f[] is
-strict Markdown with footnotes and definition lists enabled, and
-\f[C]markdown\-pipe_tables+hard_line_breaks\f[] is pandoc's Markdown
-without pipe tables and with hard line breaks.
-See Pandoc's Markdown, below, for a list of extensions and their names.
+\f[C]markdown_phpextra\f[] (PHP Markdown Extra), \f[C]markdown_mmd\f[]
+(MultiMarkdown), \f[C]gfm\f[] (GitHub\-Flavored Markdown),
+\f[C]commonmark\f[] (CommonMark Markdown), \f[C]textile\f[] (Textile),
+\f[C]rst\f[] (reStructuredText), \f[C]html\f[] (HTML), \f[C]docbook\f[]
+(DocBook), \f[C]t2t\f[] (txt2tags), \f[C]docx\f[] (docx), \f[C]odt\f[]
+(ODT), \f[C]epub\f[] (EPUB), \f[C]opml\f[] (OPML), \f[C]org\f[] (Emacs
+Org mode), \f[C]mediawiki\f[] (MediaWiki markup), \f[C]twiki\f[] (TWiki
+markup), \f[C]tikiwiki\f[] (TikiWiki markup), \f[C]creole\f[] (Creole
+1.0), \f[C]haddock\f[] (Haddock markup), or \f[C]latex\f[] (LaTeX).
+(\f[C]markdown_github\f[] provides deprecated and less accurate support
+for Github\-Flavored Markdown; please use \f[C]gfm\f[] instead, unless
+you need to use extensions other than \f[C]smart\f[].) Extensions can be
+individually enabled or disabled by appending \f[C]+EXTENSION\f[] or
+\f[C]\-EXTENSION\f[] to the format name.
+See Extensions below, for a list of extensions and their names.
See \f[C]\-\-list\-input\-formats\f[] and \f[C]\-\-list\-extensions\f[],
below.
.RS
@@ -239,38 +256,39 @@ below.
Specify output format.
\f[I]FORMAT\f[] can be \f[C]native\f[] (native Haskell), \f[C]json\f[]
(JSON version of native AST), \f[C]plain\f[] (plain text),
-\f[C]markdown\f[] (pandoc's extended Markdown), \f[C]markdown_strict\f[]
-(original unextended Markdown), \f[C]markdown_phpextra\f[] (PHP Markdown
-Extra), \f[C]markdown_github\f[] (GitHub\-Flavored Markdown),
-\f[C]markdown_mmd\f[] (MultiMarkdown), \f[C]commonmark\f[] (CommonMark
-Markdown), \f[C]rst\f[] (reStructuredText), \f[C]html\f[] (XHTML),
-\f[C]html5\f[] (HTML5), \f[C]latex\f[] (LaTeX), \f[C]beamer\f[] (LaTeX
-beamer slide show), \f[C]context\f[] (ConTeXt), \f[C]man\f[] (groff
-man), \f[C]mediawiki\f[] (MediaWiki markup), \f[C]dokuwiki\f[] (DokuWiki
-markup), \f[C]zimwiki\f[] (ZimWiki markup), \f[C]textile\f[] (Textile),
+\f[C]markdown\f[] (pandoc\[aq]s extended Markdown),
+\f[C]markdown_strict\f[] (original unextended Markdown),
+\f[C]markdown_phpextra\f[] (PHP Markdown Extra), \f[C]markdown_mmd\f[]
+(MultiMarkdown), \f[C]gfm\f[] (GitHub\-Flavored Markdown),
+\f[C]commonmark\f[] (CommonMark Markdown), \f[C]rst\f[]
+(reStructuredText), \f[C]html4\f[] (XHTML 1.0 Transitional),
+\f[C]html\f[] or \f[C]html5\f[] (HTML5/XHTML polyglot markup),
+\f[C]latex\f[] (LaTeX), \f[C]beamer\f[] (LaTeX beamer slide show),
+\f[C]context\f[] (ConTeXt), \f[C]man\f[] (groff man), \f[C]mediawiki\f[]
+(MediaWiki markup), \f[C]dokuwiki\f[] (DokuWiki markup),
+\f[C]zimwiki\f[] (ZimWiki markup), \f[C]textile\f[] (Textile),
\f[C]org\f[] (Emacs Org mode), \f[C]texinfo\f[] (GNU Texinfo),
-\f[C]opml\f[] (OPML), \f[C]docbook\f[] (DocBook 4), \f[C]docbook5\f[]
-(DocBook 5), \f[C]opendocument\f[] (OpenDocument), \f[C]odt\f[]
-(OpenOffice text document), \f[C]docx\f[] (Word docx), \f[C]haddock\f[]
-(Haddock markup), \f[C]rtf\f[] (rich text format), \f[C]epub\f[] (EPUB
-v2 book), \f[C]epub3\f[] (EPUB v3), \f[C]fb2\f[] (FictionBook2 e\-book),
-\f[C]asciidoc\f[] (AsciiDoc), \f[C]icml\f[] (InDesign ICML),
+\f[C]opml\f[] (OPML), \f[C]docbook\f[] or \f[C]docbook4\f[] (DocBook 4),
+\f[C]docbook5\f[] (DocBook 5), \f[C]jats\f[] (JATS XML),
+\f[C]opendocument\f[] (OpenDocument), \f[C]odt\f[] (OpenOffice text
+document), \f[C]docx\f[] (Word docx), \f[C]haddock\f[] (Haddock markup),
+\f[C]rtf\f[] (rich text format), \f[C]epub2\f[] (EPUB v2 book),
+\f[C]epub\f[] or \f[C]epub3\f[] (EPUB v3), \f[C]fb2\f[] (FictionBook2
+e\-book), \f[C]asciidoc\f[] (AsciiDoc), \f[C]icml\f[] (InDesign ICML),
\f[C]tei\f[] (TEI Simple), \f[C]slidy\f[] (Slidy HTML and JavaScript
slide show), \f[C]slideous\f[] (Slideous HTML and JavaScript slide
show), \f[C]dzslides\f[] (DZSlides HTML5 + JavaScript slide show),
\f[C]revealjs\f[] (reveal.js HTML5 + JavaScript slide show), \f[C]s5\f[]
-(S5 HTML and JavaScript slide show), or the path of a custom lua writer
-(see Custom writers, below).
-Note that \f[C]odt\f[], \f[C]epub\f[], and \f[C]epub3\f[] output will
-not be directed to \f[I]stdout\f[]; an output filename must be specified
-using the \f[C]\-o/\-\-output\f[] option.
-If \f[C]+lhs\f[] is appended to \f[C]markdown\f[], \f[C]rst\f[],
-\f[C]latex\f[], \f[C]beamer\f[], \f[C]html\f[], or \f[C]html5\f[], the
-output will be rendered as literate Haskell source: see Literate Haskell
-support, below.
-Markdown syntax extensions can be individually enabled or disabled by
-appending \f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format
-name, as described above under \f[C]\-f\f[].
+(S5 HTML and JavaScript slide show), \f[C]pptx\f[] (PowerPoint slide
+show) or the path of a custom lua writer (see Custom writers, below).
+(\f[C]markdown_github\f[] provides deprecated and less accurate support
+for Github\-Flavored Markdown; please use \f[C]gfm\f[] instead, unless
+you use extensions that do not work with \f[C]gfm\f[].) Note that
+\f[C]odt\f[], \f[C]docx\f[], and \f[C]epub\f[] output will not be
+directed to \f[I]stdout\f[] unless forced with \f[C]\-o\ \-\f[].
+Extensions can be individually enabled or disabled by appending
+\f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format name.
+See Extensions below, for a list of extensions and their names.
See \f[C]\-\-list\-output\-formats\f[] and
\f[C]\-\-list\-extensions\f[], below.
.RS
@@ -278,9 +296,9 @@ See \f[C]\-\-list\-output\-formats\f[] and
.TP
.B \f[C]\-o\f[] \f[I]FILE\f[], \f[C]\-\-output=\f[]\f[I]FILE\f[]
Write output to \f[I]FILE\f[] instead of \f[I]stdout\f[].
-If \f[I]FILE\f[] is \f[C]\-\f[], output will go to \f[I]stdout\f[].
-(Exception: if the output format is \f[C]odt\f[], \f[C]docx\f[],
-\f[C]epub\f[], or \f[C]epub3\f[], output to stdout is disabled.)
+If \f[I]FILE\f[] is \f[C]\-\f[], output will go to \f[I]stdout\f[], even
+if a non\-textual format (\f[C]docx\f[], \f[C]odt\f[], \f[C]epub2\f[],
+\f[C]epub3\f[]) is specified.
.RS
.RE
.TP
@@ -288,7 +306,7 @@ If \f[I]FILE\f[] is \f[C]\-\f[], output will go to \f[I]stdout\f[].
Specify the user data directory to search for pandoc data files.
If this option is not specified, the default user data directory will be
used.
-This is, in Unix:
+This is, in UNIX:
.RS
.IP
.nf
@@ -317,7 +335,7 @@ You can find the default user data directory on your system by looking
at the output of \f[C]pandoc\ \-\-version\f[].
A \f[C]reference.odt\f[], \f[C]reference.docx\f[], \f[C]epub.css\f[],
\f[C]templates\f[], \f[C]slidy\f[], \f[C]slideous\f[], or \f[C]s5\f[]
-directory placed in this directory will override pandoc's normal
+directory placed in this directory will override pandoc\[aq]s normal
defaults.
.RE
.TP
@@ -329,7 +347,7 @@ To enable bash completion with pandoc, add this to your
.IP
.nf
\f[C]
-\ eval\ "$(pandoc\ \-\-bash\-completion)"
+eval\ "$(pandoc\ \-\-bash\-completion)"
\f[]
.fi
.RE
@@ -340,6 +358,23 @@ Currently this only has an effect with PDF output.
.RS
.RE
.TP
+.B \f[C]\-\-quiet\f[]
+Suppress warning messages.
+.RS
+.RE
+.TP
+.B \f[C]\-\-fail\-if\-warnings\f[]
+Exit with error status if there are any warnings.
+.RS
+.RE
+.TP
+.B \f[C]\-\-log=\f[]\f[I]FILE\f[]
+Write log messages in machine\-readable JSON format to \f[I]FILE\f[].
+All messages above DEBUG level will be written, regardless of verbosity
+settings (\f[C]\-\-verbose\f[], \f[C]\-\-quiet\f[]).
+.RS
+.RE
+.TP
.B \f[C]\-\-list\-input\-formats\f[]
List supported input formats, one per line.
.RS
@@ -350,10 +385,12 @@ List supported output formats, one per line.
.RS
.RE
.TP
-.B \f[C]\-\-list\-extensions\f[]
-List supported Markdown extensions, one per line, followed by a
-\f[C]+\f[] or \f[C]\-\f[] indicating whether it is enabled by default in
-pandoc's Markdown.
+.B \f[C]\-\-list\-extensions\f[][\f[C]=\f[]\f[I]FORMAT\f[]]
+List supported extensions, one per line, preceded by a \f[C]+\f[] or
+\f[C]\-\f[] indicating whether it is enabled by default in
+\f[I]FORMAT\f[].
+If \f[I]FORMAT\f[] is not specified, defaults for pandoc\[aq]s Markdown
+are given.
.RS
.RE
.TP
@@ -379,48 +416,21 @@ Show usage message.
.RE
.SS Reader options
.TP
-.B \f[C]\-R\f[], \f[C]\-\-parse\-raw\f[]
-Parse untranslatable HTML codes and LaTeX environments as raw HTML or
-LaTeX, instead of ignoring them.
-Affects only HTML and LaTeX input.
-Raw HTML can be printed in Markdown, reStructuredText, Emacs Org mode,
-HTML, Slidy, Slideous, DZSlides, reveal.js, and S5 output; raw LaTeX can
-be printed in Markdown, reStructuredText, Emacs Org mode, LaTeX, and
-ConTeXt output.
-The default is for the readers to omit untranslatable HTML codes and
-LaTeX environments.
-(The LaTeX reader does pass through untranslatable LaTeX
-\f[I]commands\f[], even if \f[C]\-R\f[] is not specified.)
-.RS
-.RE
-.TP
-.B \f[C]\-S\f[], \f[C]\-\-smart\f[]
-Produce typographically correct output, converting straight quotes to
-curly quotes, \f[C]\-\-\-\f[] to em\-dashes, \f[C]\-\-\f[] to
-en\-dashes, and \f[C]\&...\f[] to ellipses.
-Nonbreaking spaces are inserted after certain abbreviations, such as
-\[lq]Mr.\[rq] (Note: This option is selected automatically when the
-output format is \f[C]latex\f[] or \f[C]context\f[], unless
-\f[C]\-\-no\-tex\-ligatures\f[] is used.
-It has no effect for \f[C]latex\f[] input.)
-.RS
-.RE
-.TP
-.B \f[C]\-\-old\-dashes\f[]
-Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes:
-\f[C]\-\f[] before a numeral is an en\-dash, and \f[C]\-\-\f[] is an
-em\-dash.
-This option is selected automatically for \f[C]textile\f[] input.
+.B \f[C]\-\-base\-header\-level=\f[]\f[I]NUMBER\f[]
+Specify the base level for headers (defaults to 1).
.RS
.RE
.TP
-.B \f[C]\-\-base\-header\-level=\f[]\f[I]NUMBER\f[]
-Specify the base level for headers (defaults to 1).
+.B \f[C]\-\-strip\-empty\-paragraphs\f[]
+\f[I]Deprecated. Use the \f[CI]+empty_paragraphs\f[I] extension
+instead.\f[] Ignore paragraphs with no content.
+This option is useful for converting word processing documents where
+users have used empty paragraphs to create inter\-paragraph space.
.RS
.RE
.TP
.B \f[C]\-\-indented\-code\-classes=\f[]\f[I]CLASSES\f[]
-Specify classes to use for indented code blocks\[en]for example,
+Specify classes to use for indented code blocks\-\-for example,
\f[C]perl,numberLines\f[] or \f[C]haskell\f[].
Multiple classes may be separated by spaces or commas.
.RS
@@ -448,7 +458,7 @@ Reading binary files (docx, odt, epub) implies \f[C]\-\-file\-scope\f[].
Specify an executable to be used as a filter transforming the pandoc AST
after the input is parsed and before the output is written.
The executable should read JSON from stdin and write JSON to stdout.
-The JSON must be formatted like pandoc's own JSON input and output.
+The JSON must be formatted like pandoc\[aq]s own JSON input and output.
The name of the output format will be passed to the filter as the first
argument.
Hence,
@@ -476,15 +486,52 @@ writing filters in Haskell.
Those who would prefer to write filters in python can use the module
\f[C]pandocfilters\f[], installable from PyPI.
There are also pandoc filter libraries in PHP, perl, and
-javascript/node.js.
+JavaScript/node.js.
.PP
In order of preference, pandoc will look for filters in
.IP "1." 3
a specified full or relative path (executable or non\-executable)
.IP "2." 3
-\f[C]$DATADIR/filters\f[] (executable or non\-executable)
+\f[C]$DATADIR/filters\f[] (executable or non\-executable) where
+\f[C]$DATADIR\f[] is the user data directory (see
+\f[C]\-\-data\-dir\f[], above).
.IP "3." 3
\f[C]$PATH\f[] (executable only)
+.PP
+Filters and lua\-filters are applied in the order specified on the
+command line.
+.RE
+.TP
+.B \f[C]\-\-lua\-filter=\f[]\f[I]SCRIPT\f[]
+Transform the document in a similar fashion as JSON filters (see
+\f[C]\-\-filter\f[]), but use pandoc\[aq]s build\-in lua filtering
+system.
+The given lua script is expected to return a list of lua filters which
+will be applied in order.
+Each lua filter must contain element\-transforming functions indexed by
+the name of the AST element on which the filter function should be
+applied.
+.RS
+.PP
+The \f[C]pandoc\f[] lua module provides helper functions for element
+creation.
+It is always loaded into the script\[aq]s lua environment.
+.PP
+The following is an example lua script for macro\-expansion:
+.IP
+.nf
+\f[C]
+function\ expand_hello_world(inline)
+\ \ if\ inline.c\ ==\ \[aq]{{helloworld}}\[aq]\ then
+\ \ \ \ return\ pandoc.Emph{\ pandoc.Str\ "Hello,\ World"\ }
+\ \ else
+\ \ \ \ return\ inline
+\ \ end
+end
+
+return\ {{Str\ =\ expand_hello_world}}
+\f[]
+.fi
.RE
.TP
.B \f[C]\-M\f[] \f[I]KEY\f[][\f[C]=\f[]\f[I]VAL\f[]], \f[C]\-\-metadata=\f[]\f[I]KEY\f[][\f[C]:\f[]\f[I]VAL\f[]]
@@ -501,13 +548,6 @@ and may be printed in some output formats).
.RS
.RE
.TP
-.B \f[C]\-\-normalize\f[]
-Normalize the document after reading: merge adjacent \f[C]Str\f[] or
-\f[C]Emph\f[] elements, for example, and remove repeated
-\f[C]Space\f[]s.
-.RS
-.RE
-.TP
.B \f[C]\-p\f[], \f[C]\-\-preserve\-tabs\f[]
Preserve tabs instead of converting them to spaces (the default).
Note that this will only affect tabs in literal code spans and code
@@ -522,7 +562,7 @@ Specify the number of spaces per tab (default is 4).
.TP
.B \f[C]\-\-track\-changes=accept\f[]|\f[C]reject\f[]|\f[C]all\f[]
Specifies what to do with insertions, deletions, and comments produced
-by the MS Word \[lq]Track Changes\[rq] feature.
+by the MS Word "Track Changes" feature.
\f[C]accept\f[] (the default), inserts all insertions, and ignores all
deletions.
\f[C]reject\f[] inserts all deletions and ignores insertions.
@@ -534,22 +574,45 @@ respectively.
The author and time of change is included.
\f[C]all\f[] is useful for scripting: only accepting changes from a
certain reviewer, say, or before a certain date.
+If a paragraph is inserted or deleted, \f[C]track\-changes=all\f[]
+produces a span with the class
+\f[C]paragraph\-insertion\f[]/\f[C]paragraph\-deletion\f[] before the
+affected paragraph break.
This option only affects the docx reader.
.RS
.RE
.TP
.B \f[C]\-\-extract\-media=\f[]\f[I]DIR\f[]
-Extract images and other media contained in a docx or epub container to
-the path \f[I]DIR\f[], creating it if necessary, and adjust the images
-references in the document so they point to the extracted files.
-This option only affects the docx and epub readers.
+Extract images and other media contained in or linked from the source
+document to the path \f[I]DIR\f[], creating it if necessary, and adjust
+the images references in the document so they point to the extracted
+files.
+If the source format is a binary container (docx, epub, or odt), the
+media is extracted from the container and the original filenames are
+used.
+Otherwise the media is read from the file system or downloaded, and new
+filenames are constructed based on SHA1 hashes of the contents.
+.RS
+.RE
+.TP
+.B \f[C]\-\-abbreviations=\f[]\f[I]FILE\f[]
+Specifies a custom abbreviations file, with abbreviations one to a line.
+If this option is not specified, pandoc will read the data file
+\f[C]abbreviations\f[] from the user data directory or fall back on a
+system default.
+To see the system default, use
+\f[C]pandoc\ \-\-print\-default\-data\-file=abbreviations\f[].
+The only use pandoc makes of this list is in the Markdown reader.
+Strings ending in a period that are found in this list will be followed
+by a nonbreaking space, so that the period will not produce
+sentence\-ending space in formats like LaTeX.
.RS
.RE
.SS General writer options
.TP
.B \f[C]\-s\f[], \f[C]\-\-standalone\f[]
-Produce output with an appropriate header and footer (e.g.\ a standalone
-HTML, LaTeX, TEI, or RTF file, not a fragment).
+Produce output with an appropriate header and footer (e.g.
+a standalone HTML, LaTeX, TEI, or RTF file, not a fragment).
This option is set automatically for \f[C]pdf\f[], \f[C]epub\f[],
\f[C]epub3\f[], \f[C]fb2\f[], \f[C]docx\f[], and \f[C]odt\f[] output.
.RS
@@ -595,6 +658,14 @@ Files in the user data directory are ignored.
.RS
.RE
.TP
+.B \f[C]\-\-eol=crlf\f[]|\f[C]lf\f[]|\f[C]native\f[]
+Manually specify line endings: \f[C]crlf\f[] (Windows), \f[C]lf\f[]
+(macOS/Linux/UNIX), or \f[C]native\f[] (line endings appropriate to the
+OS on which pandoc is being run).
+The default is \f[C]native\f[].
+.RS
+.RE
+.TP
.B \f[C]\-\-dpi\f[]=\f[I]NUMBER\f[]
Specify the dpi (dots per inch) value for conversion from pixels to
inch/centimeters and vice versa.
@@ -617,11 +688,6 @@ Automatic wrapping does not currently work in HTML output.
.RS
.RE
.TP
-.B \f[C]\-\-no\-wrap\f[]
-Deprecated synonym for \f[C]\-\-wrap=none\f[].
-.RS
-.RE
-.TP
.B \f[C]\-\-columns=\f[]\f[I]NUMBER\f[]
Specify length of lines in characters.
This affects text wrapping in the generated source code (see
@@ -633,11 +699,11 @@ Tables below).
.TP
.B \f[C]\-\-toc\f[], \f[C]\-\-table\-of\-contents\f[]
Include an automatically generated table of contents (or, in the case of
-\f[C]latex\f[], \f[C]context\f[], \f[C]docx\f[], and \f[C]rst\f[], an
-instruction to create one) in the output document.
-This option has no effect on \f[C]man\f[], \f[C]docbook\f[],
-\f[C]docbook5\f[], \f[C]slidy\f[], \f[C]slideous\f[], \f[C]s5\f[], or
-\f[C]odt\f[] output.
+\f[C]latex\f[], \f[C]context\f[], \f[C]docx\f[], \f[C]odt\f[],
+\f[C]opendocument\f[], \f[C]rst\f[], or \f[C]ms\f[], an instruction to
+create one) in the output document.
+This option has no effect on \f[C]man\f[], \f[C]docbook4\f[],
+\f[C]docbook5\f[], or \f[C]jats\f[] output.
.RS
.RE
.TP
@@ -649,13 +715,21 @@ listed in the contents).
.RS
.RE
.TP
+.B \f[C]\-\-strip\-comments\f[]
+Strip out HTML comments in the Markdown or Textile source, rather than
+passing them on to Markdown, Textile or HTML output as raw HTML.
+This does not apply to HTML comments inside raw HTML blocks when the
+\f[C]markdown_in_html_blocks\f[] extension is not set.
+.RS
+.RE
+.TP
.B \f[C]\-\-no\-highlight\f[]
Disables syntax highlighting for code blocks and inlines, even when a
language attribute is given.
.RS
.RE
.TP
-.B \f[C]\-\-highlight\-style=\f[]\f[I]STYLE\f[]
+.B \f[C]\-\-highlight\-style=\f[]\f[I]STYLE\f[]|\f[I]FILE\f[]
Specifies the coloring style to be used in highlighted source code.
Options are \f[C]pygments\f[] (the default), \f[C]kate\f[],
\f[C]monochrome\f[], \f[C]breezeDark\f[], \f[C]espresso\f[],
@@ -664,6 +738,29 @@ For more information on syntax highlighting in pandoc, see Syntax
highlighting, below.
See also \f[C]\-\-list\-highlight\-styles\f[].
.RS
+.PP
+Instead of a \f[I]STYLE\f[] name, a JSON file with extension
+\f[C]\&.theme\f[] may be supplied.
+This will be parsed as a KDE syntax highlighting theme and (if valid)
+used as the highlighting style.
+.PP
+To generate the JSON version of an existing style, use
+\f[C]\-\-print\-highlight\-style\f[].
+.RE
+.TP
+.B \f[C]\-\-print\-highlight\-style=\f[]\f[I]STYLE\f[]|\f[I]FILE\f[]
+Prints a JSON version of a highlighting style, which can be modified,
+saved with a \f[C]\&.theme\f[] extension, and used with
+\f[C]\-\-highlight\-style\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-\-syntax\-definition=\f[]\f[I]FILE\f[]
+Instructs pandoc to load a KDE XML syntax definition file, which will be
+used for syntax highlighting of appropriately marked code blocks.
+This can be used to add support for new languages or to use altered
+syntax definitions for existing languages.
+.RS
.RE
.TP
.B \f[C]\-H\f[] \f[I]FILE\f[], \f[C]\-\-include\-in\-header=\f[]\f[I]FILE\f[]
@@ -679,8 +776,9 @@ Implies \f[C]\-\-standalone\f[].
.TP
.B \f[C]\-B\f[] \f[I]FILE\f[], \f[C]\-\-include\-before\-body=\f[]\f[I]FILE\f[]
Include contents of \f[I]FILE\f[], verbatim, at the beginning of the
-document body (e.g.\ after the \f[C]<body>\f[] tag in HTML, or the
-\f[C]\\begin{document}\f[] command in LaTeX).
+document body (e.g.
+after the \f[C]<body>\f[] tag in HTML, or the \f[C]\\begin{document}\f[]
+command in LaTeX).
This can be used to include navigation bars or banners in HTML
documents.
This option can be used repeatedly to include multiple files.
@@ -698,28 +796,52 @@ They will be included in the order specified.
Implies \f[C]\-\-standalone\f[].
.RS
.RE
+.TP
+.B \f[C]\-\-resource\-path=\f[]\f[I]SEARCHPATH\f[]
+List of paths to search for images and other resources.
+The paths should be separated by \f[C]:\f[] on Linux, UNIX, and macOS
+systems, and by \f[C];\f[] on Windows.
+If \f[C]\-\-resource\-path\f[] is not specified, the default resource
+path is the working directory.
+Note that, if \f[C]\-\-resource\-path\f[] is specified, the working
+directory must be explicitly listed or it will not be searched.
+For example: \f[C]\-\-resource\-path=.:test\f[] will search the working
+directory and the \f[C]test\f[] subdirectory, in that order.
+.RS
+.RE
+.TP
+.B \f[C]\-\-request\-header=\f[]\f[I]NAME\f[]\f[C]:\f[]\f[I]VAL\f[]
+Set the request header \f[I]NAME\f[] to the value \f[I]VAL\f[] when
+making HTTP requests (for example, when a URL is given on the command
+line, or when resources used in a document must be downloaded).
+.RS
+.RE
.SS Options affecting specific writers
.TP
.B \f[C]\-\-self\-contained\f[]
Produce a standalone HTML file with no external dependencies, using
\f[C]data:\f[] URIs to incorporate the contents of linked scripts,
stylesheets, images, and videos.
-The resulting file should be \[lq]self\-contained,\[rq] in the sense
-that it needs no external files and no net access to be displayed
-properly by a browser.
+Implies \f[C]\-\-standalone\f[].
+The resulting file should be "self\-contained," in the sense that it
+needs no external files and no net access to be displayed properly by a
+browser.
This option works only with HTML output formats, including
-\f[C]html\f[], \f[C]html5\f[], \f[C]html+lhs\f[], \f[C]html5+lhs\f[],
+\f[C]html4\f[], \f[C]html5\f[], \f[C]html+lhs\f[], \f[C]html5+lhs\f[],
\f[C]s5\f[], \f[C]slidy\f[], \f[C]slideous\f[], \f[C]dzslides\f[], and
\f[C]revealjs\f[].
Scripts, images, and stylesheets at absolute URLs will be downloaded;
those at relative URLs will be sought relative to the working directory
(if the first source file is local) or relative to the base URL (if the
first source file is remote).
+Elements with the attribute \f[C]data\-external="1"\f[] will be left
+alone; the documents they link to will not be incorporated in the
+document.
Limitation: resources that are loaded dynamically through JavaScript
cannot be incorporated; as a result, \f[C]\-\-self\-contained\f[] does
-not work with \f[C]\-\-mathjax\f[], and some advanced features (
-e.g.\ zoom or speaker notes) may not work in an offline
-\[lq]self\-contained\[rq] \f[C]reveal.js\f[] slide show.
+not work with \f[C]\-\-mathjax\f[], and some advanced features (e.g.
+zoom or speaker notes) may not work in an offline "self\-contained"
+\f[C]reveal.js\f[] slide show.
.RS
.RE
.TP
@@ -730,8 +852,8 @@ Use \f[C]<q>\f[] tags for quotes in HTML.
.TP
.B \f[C]\-\-ascii\f[]
Use only ASCII characters in output.
-Currently supported only for HTML output (which uses numerical entities
-instead of UTF\-8 when this option is selected).
+Currently supported only for HTML and DocBook output (which uses
+numerical entities instead of UTF\-8 when this option is selected).
.RS
.RE
.TP
@@ -757,11 +879,7 @@ Currently only affects the markdown writer.
Use ATX\-style headers in Markdown and AsciiDoc output.
The default is to use setext\-style headers for levels 1\-2, and then
ATX headers.
-.RS
-.RE
-.TP
-.B \f[C]\-\-chapters\f[]
-Deprecated synonym for \f[C]\-\-top\-level\-division=chapter\f[].
+(Note: for \f[C]gfm\f[] output, ATX headers are always used.)
.RS
.RE
.TP
@@ -790,40 +908,20 @@ Sections with class \f[C]unnumbered\f[] will never be numbered, even if
.RS
.RE
.TP
-.B \f[C]\-\-number\-offset=\f[]\f[I]NUMBER\f[][\f[C],\f[]\f[I]NUMBER\f[]\f[C],\f[]\f[I]\&...\f[]]
+.B \f[C]\-\-number\-offset=\f[]\f[I]NUMBER\f[][\f[C],\f[]\f[I]NUMBER\f[]\f[C],\f[]\f[I]...\f[]]
Offset for section headings in HTML output (ignored in other output
formats).
The first number is added to the section number for top\-level headers,
the second for second\-level headers, and so on.
So, for example, if you want the first top\-level header in your
-document to be numbered \[lq]6\[rq], specify
-\f[C]\-\-number\-offset=5\f[].
+document to be numbered "6", specify \f[C]\-\-number\-offset=5\f[].
If your document starts with a level\-2 header which you want to be
-numbered \[lq]1.5\[rq], specify \f[C]\-\-number\-offset=1,4\f[].
+numbered "1.5", specify \f[C]\-\-number\-offset=1,4\f[].
Offsets are 0 by default.
Implies \f[C]\-\-number\-sections\f[].
.RS
.RE
.TP
-.B \f[C]\-\-no\-tex\-ligatures\f[]
-Do not use the TeX ligatures for quotation marks, apostrophes, and
-dashes (\f[C]`...\[aq]\f[], \f[C]``..\[aq]\[aq]\f[], \f[C]\-\-\f[],
-\f[C]\-\-\-\f[]) when writing or reading LaTeX or ConTeXt.
-In reading LaTeX, parse the characters \f[C]`\f[], \f[C]\[aq]\f[], and
-\f[C]\-\f[] literally, rather than parsing ligatures for quotation marks
-and dashes.
-In writing LaTeX or ConTeXt, print unicode quotation mark and dash
-characters literally, rather than converting them to the standard ASCII
-TeX ligatures.
-Note: normally \f[C]\-\-smart\f[] is selected automatically for LaTeX
-and ConTeXt output, but it must be specified explicitly if
-\f[C]\-\-no\-tex\-ligatures\f[] is selected.
-If you use literal curly quotes, dashes, and ellipses in your source,
-then you may want to use \f[C]\-\-no\-tex\-ligatures\f[] without
-\f[C]\-\-smart\f[].
-.RS
-.RE
-.TP
.B \f[C]\-\-listings\f[]
Use the \f[C]listings\f[] package for LaTeX code blocks
.RS
@@ -842,15 +940,17 @@ Specifies that headers with the specified level create slides (for
Headers above this level in the hierarchy are used to divide the slide
show into sections; headers below this level create subheads within a
slide.
+Note that content that is not contained under slide\-level headers will
+not appear in the slide show.
The default is to set the slide level based on the contents of the
document; see Structuring the slide show.
.RS
.RE
.TP
.B \f[C]\-\-section\-divs\f[]
-Wrap sections in \f[C]<div>\f[] tags (or \f[C]<section>\f[] tags in
-HTML5), and attach identifiers to the enclosing \f[C]<div>\f[] (or
-\f[C]<section>\f[]) rather than the header itself.
+Wrap sections in \f[C]<section>\f[] tags (or \f[C]<div>\f[] tags for
+\f[C]html4\f[]), and attach identifiers to the enclosing
+\f[C]<section>\f[] (or \f[C]<div>\f[]) rather than the header itself.
See Header identifiers, below.
.RS
.RE
@@ -867,8 +967,9 @@ The default is \f[C]none\f[].
.RE
.TP
.B \f[C]\-\-id\-prefix=\f[]\f[I]STRING\f[]
-Specify a prefix to be added to all automatically generated identifiers
-in HTML and DocBook output, and to footnote numbers in Markdown output.
+Specify a prefix to be added to all identifiers and internal links in
+HTML and DocBook output, and to footnote numbers in Markdown and Haddock
+output.
This is useful for preventing duplicate identifiers when generating
fragments to be included in other pages.
.RS
@@ -887,29 +988,20 @@ Link to a CSS style sheet.
This option can be used repeatedly to include multiple files.
They will be included in the order specified.
.RS
+.PP
+A stylesheet is required for generating EPUB.
+If none is provided using this option (or the \f[C]stylesheet\f[]
+metadata field), pandoc will look for a file \f[C]epub.css\f[] in the
+user data directory (see \f[C]\-\-data\-dir\f[]).
+If it is not found there, sensible defaults will be used.
.RE
.TP
-.B \f[C]\-\-reference\-odt=\f[]\f[I]FILE\f[]
-Use the specified file as a style reference in producing an ODT.
-For best results, the reference ODT should be a modified version of an
-ODT produced using pandoc.
-The contents of the reference ODT are ignored, but its stylesheets are
-used in the new ODT.
-If no reference ODT is specified on the command line, pandoc will look
-for a file \f[C]reference.odt\f[] in the user data directory (see
-\f[C]\-\-data\-dir\f[]).
-If this is not found either, sensible defaults will be used.
+.B \f[C]\-\-reference\-doc=\f[]\f[I]FILE\f[]
+Use the specified file as a style reference in producing a docx or ODT
+file.
.RS
-.PP
-To produce a custom \f[C]reference.odt\f[], first get a copy of the
-default \f[C]reference.odt\f[]:
-\f[C]pandoc\ \-\-print\-default\-data\-file\ reference.odt\ >\ custom\-reference.odt\f[].
-Then open \f[C]custom\-reference.docx\f[] in LibreOffice, modify the
-styles as you wish, and save the file.
-.RE
.TP
-.B \f[C]\-\-reference\-docx=\f[]\f[I]FILE\f[]
-Use the specified file as a style reference in producing a docx file.
+.B Docx
For best results, the reference docx should be a modified version of a
docx file produced using pandoc.
The contents of the reference docx are ignored, but its stylesheets and
@@ -930,19 +1022,58 @@ For best results, do not make changes to this file other than modifying
the styles used by pandoc: [paragraph] Normal, Body Text, First
Paragraph, Compact, Title, Subtitle, Author, Date, Abstract,
Bibliography, Heading 1, Heading 2, Heading 3, Heading 4, Heading 5,
-Heading 6, Block Text, Footnote Text, Definition Term, Definition,
-Caption, Table Caption, Image Caption, Figure, Figure With Caption, TOC
-Heading; [character] Default Paragraph Font, Body Text Char, Verbatim
-Char, Footnote Reference, Hyperlink; [table] Normal Table.
+Heading 6, Heading 7, Heading 8, Heading 9, Block Text, Footnote Text,
+Definition Term, Definition, Caption, Table Caption, Image Caption,
+Figure, Captioned Figure, TOC Heading; [character] Default Paragraph
+Font, Body Text Char, Verbatim Char, Footnote Reference, Hyperlink;
+[table] Table.
.RE
.TP
-.B \f[C]\-\-epub\-stylesheet=\f[]\f[I]FILE\f[]
-Use the specified CSS file to style the EPUB.
-If no stylesheet is specified, pandoc will look for a file
-\f[C]epub.css\f[] in the user data directory (see
+.B ODT
+For best results, the reference ODT should be a modified version of an
+ODT produced using pandoc.
+The contents of the reference ODT are ignored, but its stylesheets are
+used in the new ODT.
+If no reference ODT is specified on the command line, pandoc will look
+for a file \f[C]reference.odt\f[] in the user data directory (see
\f[C]\-\-data\-dir\f[]).
-If it is not found there, sensible defaults will be used.
+If this is not found either, sensible defaults will be used.
.RS
+.PP
+To produce a custom \f[C]reference.odt\f[], first get a copy of the
+default \f[C]reference.odt\f[]:
+\f[C]pandoc\ \-\-print\-default\-data\-file\ reference.odt\ >\ custom\-reference.odt\f[].
+Then open \f[C]custom\-reference.odt\f[] in LibreOffice, modify the
+styles as you wish, and save the file.
+.RE
+.TP
+.B PowerPoint
+Any template included with a recent install of Microsoft PowerPoint
+(either with \f[C]\&.pptx\f[] or \f[C]\&.potx\f[] extension) should
+work, as will most templates derived from these.
+.RS
+.PP
+The specific requirement is that the template should contain the
+following four layouts as its first four layouts:
+.IP "1." 3
+Title Slide
+.IP "2." 3
+Title and Content
+.IP "3." 3
+Section Header
+.IP "4." 3
+Two Content
+.PP
+All templates included with a recent version of MS PowerPoint will fit
+these criteria.
+(You can click on \f[C]Layout\f[] under the \f[C]Home\f[] menu to
+check.)
+.PP
+You can also modify the default \f[C]reference.pptx\f[]: first run
+\f[C]pandoc\ \-\-print\-default\-data\-file\ reference.pptx\ >\ custom\-reference.pptx\f[],
+and then modify \f[C]custom\-reference.pptx\f[] in MS PowerPoint (pandoc
+will use the first four layout slides, as mentioned above).
+.RE
.RE
.TP
.B \f[C]\-\-epub\-cover\-image=\f[]\f[I]FILE\f[]
@@ -989,7 +1120,7 @@ However, if you use wildcards on the command line, be sure to escape
them or put the whole filename in single quotes, to prevent them from
being interpreted by the shell.
To use the embedded fonts, you will need to add declarations like the
-following to your CSS (see \f[C]\-\-epub\-stylesheet\f[]):
+following to your CSS (see \f[C]\-\-css\f[]):
.RS
.IP
.nf
@@ -1025,7 +1156,7 @@ body\ {\ font\-family:\ "DejaVuSans";\ }
.TP
.B \f[C]\-\-epub\-chapter\-level=\f[]\f[I]NUMBER\f[]
Specify the header level at which to split the EPUB into separate
-\[lq]chapter\[rq] files.
+"chapter" files.
The default is to split into chapters at level 1 headers.
This option only affects the internal composition of the EPUB, not the
way chapters and sections are displayed to users.
@@ -1035,17 +1166,25 @@ chapter level of 2 or 3.
.RS
.RE
.TP
-.B \f[C]\-\-latex\-engine=pdflatex\f[]|\f[C]lualatex\f[]|\f[C]xelatex\f[]
-Use the specified LaTeX engine when producing PDF output.
+.B \f[C]\-\-epub\-subdirectory=\f[]\f[I]DIRNAME\f[]
+Specify the subdirectory in the OCF container that is to hold the
+EPUB\-specific contents.
+The default is \f[C]EPUB\f[].
+To put the EPUB contents in the top level, use an empty string.
+.RS
+.RE
+.TP
+.B \f[C]\-\-pdf\-engine=pdflatex\f[]|\f[C]lualatex\f[]|\f[C]xelatex\f[]|\f[C]wkhtmltopdf\f[]|\f[C]weasyprint\f[]|\f[C]prince\f[]|\f[C]context\f[]|\f[C]pdfroff\f[]
+Use the specified engine when producing PDF output.
The default is \f[C]pdflatex\f[].
If the engine is not in your PATH, the full path of the engine may be
specified here.
.RS
.RE
.TP
-.B \f[C]\-\-latex\-engine\-opt=\f[]\f[I]STRING\f[]
+.B \f[C]\-\-pdf\-engine\-opt=\f[]\f[I]STRING\f[]
Use the given string as a command\-line argument to the
-\f[C]latex\-engine\f[].
+\f[C]pdf\-engine\f[].
If used multiple times, the arguments are provided with spaces between
them.
Note that no check for duplicate options is done.
@@ -1054,7 +1193,7 @@ Note that no check for duplicate options is done.
.SS Citation rendering
.TP
.B \f[C]\-\-bibliography=\f[]\f[I]FILE\f[]
-Set the \f[C]bibliography\f[] field in the document's metadata to
+Set the \f[C]bibliography\f[] field in the document\[aq]s metadata to
\f[I]FILE\f[], overriding any value set in the metadata, and process
citations using \f[C]pandoc\-citeproc\f[].
(This is equivalent to
@@ -1068,15 +1207,15 @@ added to bibliography.
.RE
.TP
.B \f[C]\-\-csl=\f[]\f[I]FILE\f[]
-Set the \f[C]csl\f[] field in the document's metadata to \f[I]FILE\f[],
-overriding any value set in the metadata.
+Set the \f[C]csl\f[] field in the document\[aq]s metadata to
+\f[I]FILE\f[], overriding any value set in the metadata.
(This is equivalent to \f[C]\-\-metadata\ csl=FILE\f[].) This option is
only relevant with \f[C]pandoc\-citeproc\f[].
.RS
.RE
.TP
.B \f[C]\-\-citation\-abbreviations=\f[]\f[I]FILE\f[]
-Set the \f[C]citation\-abbreviations\f[] field in the document's
+Set the \f[C]citation\-abbreviations\f[] field in the document\[aq]s
metadata to \f[I]FILE\f[], overriding any value set in the metadata.
(This is equivalent to
\f[C]\-\-metadata\ citation\-abbreviations=FILE\f[].) This option is
@@ -1102,78 +1241,55 @@ with \f[C]bibtex\f[] or \f[C]biber\f[].
.RS
.RE
.SS Math rendering in HTML
-.TP
-.B \f[C]\-m\f[] [\f[I]URL\f[]], \f[C]\-\-latexmathml\f[][\f[C]=\f[]\f[I]URL\f[]]
-Use the LaTeXMathML script to display embedded TeX math in HTML output.
-To insert a link to a local copy of the \f[C]LaTeXMathML.js\f[] script,
-provide a \f[I]URL\f[].
-If no \f[I]URL\f[] is provided, the contents of the script will be
-inserted directly into the HTML header, preserving portability at the
-price of efficiency.
-If you plan to use math on several pages, it is much better to link to a
-copy of the script, so it can be cached.
-.RS
-.RE
-.TP
-.B \f[C]\-\-mathml\f[][\f[C]=\f[]\f[I]URL\f[]]
-Convert TeX math to MathML (in \f[C]docbook\f[], \f[C]docbook5\f[],
-\f[C]html\f[] and \f[C]html5\f[]).
-In standalone \f[C]html\f[] output, a small JavaScript (or a link to
-such a script if a \f[I]URL\f[] is supplied) will be inserted that
-allows the MathML to be viewed on some browsers.
-.RS
-.RE
-.TP
-.B \f[C]\-\-jsmath\f[][\f[C]=\f[]\f[I]URL\f[]]
-Use jsMath to display embedded TeX math in HTML output.
-The \f[I]URL\f[] should point to the jsMath load script (e.g.
-\f[C]jsMath/easy/load.js\f[]); if provided, it will be linked to in the
-header of standalone HTML documents.
-If a \f[I]URL\f[] is not provided, no link to the jsMath load script
-will be inserted; it is then up to the author to provide such a link in
-the HTML template.
-.RS
-.RE
+.PP
+The default is to render TeX math as far as possible using Unicode
+characters.
+Formulas are put inside a \f[C]span\f[] with \f[C]class="math"\f[], so
+that they may be styled differently from the surrounding text if needed.
+However, this gives acceptable results only for basic math, usually you
+will want to use \f[C]\-\-mathjax\f[] or another of the following
+options.
.TP
.B \f[C]\-\-mathjax\f[][\f[C]=\f[]\f[I]URL\f[]]
Use MathJax to display embedded TeX math in HTML output.
+TeX math will be put between \f[C]\\(...\\)\f[] (for inline math) or
+\f[C]\\[...\\]\f[] (for display math) and wrapped in \f[C]<span>\f[]
+tags with class \f[C]math\f[].
+Then the MathJax JavaScript will render it.
The \f[I]URL\f[] should point to the \f[C]MathJax.js\f[] load script.
-If a \f[I]URL\f[] is not provided, a link to the MathJax CDN will be
+If a \f[I]URL\f[] is not provided, a link to the Cloudflare CDN will be
inserted.
.RS
.RE
.TP
-.B \f[C]\-\-gladtex\f[]
-Enclose TeX math in \f[C]<eq>\f[] tags in HTML output.
-These can then be processed by gladTeX to produce links to images of the
-typeset formulas.
-.RS
-.RE
-.TP
-.B \f[C]\-\-mimetex\f[][\f[C]=\f[]\f[I]URL\f[]]
-Render TeX math using the mimeTeX CGI script.
-If \f[I]URL\f[] is not specified, it is assumed that the script is at
-\f[C]/cgi\-bin/mimetex.cgi\f[].
+.B \f[C]\-\-mathml\f[]
+Convert TeX math to MathML (in \f[C]epub3\f[], \f[C]docbook4\f[],
+\f[C]docbook5\f[], \f[C]jats\f[], \f[C]html4\f[] and \f[C]html5\f[]).
+This is the default in \f[C]odt\f[] output.
+Note that currently only Firefox and Safari (and select e\-book readers)
+natively support MathML.
.RS
.RE
.TP
.B \f[C]\-\-webtex\f[][\f[C]=\f[]\f[I]URL\f[]]
-Render TeX formulas using an external script that converts TeX formulas
-to images.
-The formula will be concatenated with the URL provided.
-If \f[I]URL\f[] is not specified, the CodeCogs will be used.
+Convert TeX formulas to \f[C]<img>\f[] tags that link to an external
+script that converts formulas to images.
+The formula will be URL\-encoded and concatenated with the URL provided.
+For SVG images you can for example use
+\f[C]\-\-webtex\ https://latex.codecogs.com/svg.latex?\f[].
+If no URL is specified, the CodeCogs URL generating PNGs will be used
+(\f[C]https://latex.codecogs.com/png.latex?\f[]).
Note: the \f[C]\-\-webtex\f[] option will affect Markdown output as well
-as HTML, which is useful if you're targeting a version of Markdown
+as HTML, which is useful if you\[aq]re targeting a version of Markdown
without native math support.
.RS
.RE
.TP
.B \f[C]\-\-katex\f[][\f[C]=\f[]\f[I]URL\f[]]
Use KaTeX to display embedded TeX math in HTML output.
-The \f[I]URL\f[] should point to the \f[C]katex.js\f[] load script.
+The \f[I]URL\f[] is the base URL for the KaTeX library.
If a \f[I]URL\f[] is not provided, a link to the KaTeX CDN will be
inserted.
-Note: KaTeX seems to work best with \f[C]html5\f[] output.
.RS
.RE
.TP
@@ -1184,6 +1300,60 @@ inserted.
Note that this option does not imply \f[C]\-\-katex\f[].
.RS
.RE
+.TP
+.B \f[C]\-m\f[] [\f[I]URL\f[]], \f[C]\-\-latexmathml\f[][\f[C]=\f[]\f[I]URL\f[]]
+\f[I]Deprecated.\f[] Use the LaTeXMathML script to display embedded TeX
+math in HTML output.
+TeX math will be displayed between \f[C]$\f[] or \f[C]$$\f[] characters
+and put in \f[C]<span>\f[] tags with class \f[C]LaTeX\f[].
+The LaTeXMathML JavaScript will then change it to MathML.
+Note that currently only Firefox and Safari (and select e\-book readers)
+natively support MathML.
+To insert a link the \f[C]LaTeXMathML.js\f[] script, provide a
+\f[I]URL\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-\-jsmath\f[][\f[C]=\f[]\f[I]URL\f[]]
+\f[I]Deprecated.\f[] Use jsMath (the predecessor of MathJax) to display
+embedded TeX math in HTML output.
+TeX math will be put inside \f[C]<span>\f[] tags (for inline math) or
+\f[C]<div>\f[] tags (for display math) with class \f[C]math\f[] and
+rendered by the jsMath script.
+The \f[I]URL\f[] should point to the script (e.g.
+\f[C]jsMath/easy/load.js\f[]); if provided, it will be linked to in the
+header of standalone HTML documents.
+If a \f[I]URL\f[] is not provided, no link to the jsMath load script
+will be inserted; it is then up to the author to provide such a link in
+the HTML template.
+.RS
+.RE
+.TP
+.B \f[C]\-\-gladtex\f[]
+\f[I]Deprecated.\f[] Enclose TeX math in \f[C]<eq>\f[] tags in HTML
+output.
+The resulting HTML can then be processed by gladTeX to produce images of
+the typeset formulas and an HTML file with links to these images.
+So, the procedure is:
+.RS
+.IP
+.nf
+\f[C]
+pandoc\ \-s\ \-\-gladtex\ input.md\ \-o\ myfile.htex
+gladtex\ \-d\ myfile\-images\ myfile.htex
+#\ produces\ myfile.html\ and\ images\ in\ myfile\-images
+\f[]
+.fi
+.RE
+.TP
+.B \f[C]\-\-mimetex\f[][\f[C]=\f[]\f[I]URL\f[]]
+\f[I]Deprecated.\f[] Render TeX math using the mimeTeX CGI script, which
+generates an image for each TeX formula.
+This should work in all browsers.
+If \f[I]URL\f[] is not specified, it is assumed that the script is at
+\f[C]/cgi\-bin/mimetex.cgi\f[].
+.RS
+.RE
.SS Options for wrapper scripts
.TP
.B \f[C]\-\-dump\-args\f[]
@@ -1247,12 +1417,13 @@ For \f[C]odt\f[] output, customize the \f[C]default.opendocument\f[]
template.
.IP \[bu] 2
For \f[C]pdf\f[] output, customize the \f[C]default.latex\f[] template
-(or the \f[C]default.beamer\f[] template, if you use
-\f[C]\-t\ beamer\f[], or the \f[C]default.context\f[] template, if you
-use \f[C]\-t\ context\f[]).
+(or the \f[C]default.context\f[] template, if you use
+\f[C]\-t\ context\f[], or the \f[C]default.ms\f[] template, if you use
+\f[C]\-t\ ms\f[], or the \f[C]default.html5\f[] template, if you use
+\f[C]\-t\ html5\f[]).
.IP \[bu] 2
\f[C]docx\f[] has no template (however, you can use
-\f[C]\-\-reference\-docx\f[] to customize the output).
+\f[C]\-\-reference\-doc\f[] to customize the output).
.PP
Templates contain \f[I]variables\f[], which allow for the inclusion of
arbitrary information at any point in the file.
@@ -1266,6 +1437,29 @@ Some variables are set automatically by pandoc.
These vary somewhat depending on the output format, but include metadata
fields as well as the following:
.TP
+.B \f[C]sourcefile\f[], \f[C]outputfile\f[]
+source and destination filenames, as given on the command line.
+\f[C]sourcefile\f[] can also be a list if input comes from multiple
+files, or empty if input is from stdin.
+You can use the following snippet in your template to distinguish them:
+.RS
+.IP
+.nf
+\f[C]
+$if(sourcefile)$
+$for(sourcefile)$
+$sourcefile$
+$endfor$
+$else$
+(stdin)
+$endif$
+\f[]
+.fi
+.PP
+Similarly, \f[C]outputfile\f[] can be \f[C]\-\f[] if output goes to the
+terminal.
+.RE
+.TP
.B \f[C]title\f[], \f[C]author\f[], \f[C]date\f[]
allow identification of basic aspects of the document.
Included in PDF metadata through LaTeX and ConTeXt.
@@ -1322,7 +1516,8 @@ specified
.RE
.TP
.B \f[C]toc\-title\f[]
-title of table of contents (works only with EPUB and docx)
+title of table of contents (works only with EPUB, opendocument, odt,
+docx, pptx)
.RS
.RE
.TP
@@ -1344,7 +1539,8 @@ body of document
.RE
.TP
.B \f[C]meta\-json\f[]
-JSON representation of all of the document's metadata
+JSON representation of all of the document\[aq]s metadata.
+Field values are transformed to the selected output format.
.RS
.RE
.SS Language variables
@@ -1358,23 +1554,12 @@ stored in the additional variables \f[C]babel\-lang\f[],
\f[C]polyglossia\-lang\f[] (LaTeX) and \f[C]context\-lang\f[] (ConTeXt).
.RS
.PP
-Native pandoc \f[C]span\f[]s and \f[C]div\f[]s with the lang attribute
-(value in BCP 47) can be used to switch the language in that range.
-.RE
-.TP
-.B \f[C]otherlangs\f[]
-a list of other languages used in the document in the YAML metadata,
-according to BCP 47.
-For example: \f[C]otherlangs:\ [en\-GB,\ fr]\f[].
-This is automatically generated from the \f[C]lang\f[] attributes in all
-\f[C]span\f[]s and \f[C]div\f[]s but can be overridden.
-Currently only used by LaTeX through the generated
-\f[C]babel\-otherlangs\f[] and \f[C]polyglossia\-otherlangs\f[]
-variables.
-The LaTeX writer outputs polyglossia commands in the text but the
-\f[C]babel\-newcommands\f[] variable contains mappings for them to the
-corresponding babel.
-.RS
+Native pandoc Spans and Divs with the lang attribute (value in BCP 47)
+can be used to switch the language in that range.
+In LaTeX output, \f[C]babel\-otherlangs\f[] and
+\f[C]polyglossia\-otherlangs\f[] variables will be generated
+automatically based on the \f[C]lang\f[] attributes of Spans and Divs in
+the document.
.RE
.TP
.B \f[C]dir\f[]
@@ -1386,21 +1571,31 @@ For bidirectional documents, native pandoc \f[C]span\f[]s and
\f[C]div\f[]s with the \f[C]dir\f[] attribute (value \f[C]rtl\f[] or
\f[C]ltr\f[]) can be used to override the base direction in some output
formats.
-This may not always be necessary if the final renderer (e.g.\ the
-browser, when generating HTML) supports the Unicode Bidirectional
+This may not always be necessary if the final renderer (e.g.
+the browser, when generating HTML) supports the Unicode Bidirectional
Algorithm.
.PP
When using LaTeX for bidirectional documents, only the \f[C]xelatex\f[]
-engine is fully supported (use \f[C]\-\-latex\-engine=xelatex\f[]).
+engine is fully supported (use \f[C]\-\-pdf\-engine=xelatex\f[]).
.RE
.SS Variables for slides
.PP
Variables are available for producing slide shows with pandoc, including
all reveal.js configuration options.
.TP
+.B \f[C]titlegraphic\f[]
+title graphic for Beamer documents
+.RS
+.RE
+.TP
+.B \f[C]logo\f[]
+logo for Beamer documents
+.RS
+.RE
+.TP
.B \f[C]slidy\-url\f[]
base URL for Slidy documents (defaults to
-\f[C]http://www.w3.org/Talks/Tools/Slidy2\f[])
+\f[C]https://www.w3.org/Talks/Tools/Slidy2\f[])
.RS
.RE
.TP
@@ -1437,8 +1632,8 @@ controls navigation symbols in \f[C]beamer\f[] documents (default is
.RE
.TP
.B \f[C]section\-titles\f[]
-enables on \[lq]title pages\[rq] for new sections in \f[C]beamer\f[]
-documents (default = true).
+enables on "title pages" for new sections in \f[C]beamer\f[] documents
+(default = true).
.RS
.RE
.TP
@@ -1448,17 +1643,11 @@ an article from beamer slides).
.RS
.RE
.TP
-.B \f[C]colorlinks\f[]
-add color to link text; automatically enabled if any of
-\f[C]linkcolor\f[], \f[C]citecolor\f[], \f[C]urlcolor\f[], or
-\f[C]toccolor\f[] are set (for beamer only).
-.RS
-.RE
-.TP
-.B \f[C]linkcolor\f[], \f[C]citecolor\f[], \f[C]urlcolor\f[], \f[C]toccolor\f[]
-color for internal links, citation links, external links, and links in
-table of contents: uses any of the predefined LaTeX colors (for beamer
-only).
+.B \f[C]aspectratio\f[]
+aspect ratio of slides (for beamer only, \f[C]1610\f[] for 16:10,
+\f[C]169\f[] for 16:9, \f[C]149\f[] for 14:9, \f[C]141\f[] for 1.41:1,
+\f[C]54\f[] for 5:4, \f[C]43\f[] for 4:3 which is the default, and
+\f[C]32\f[] for 3:2).
.RS
.RE
.SS Variables for LaTeX
@@ -1467,7 +1656,7 @@ LaTeX variables are used when creating a PDF.
.TP
.B \f[C]papersize\f[]
paper size, e.g.
-\f[C]letter\f[], \f[C]A4\f[]
+\f[C]letter\f[], \f[C]a4\f[]
.RS
.RE
.TP
@@ -1561,7 +1750,8 @@ add color to link text; automatically enabled if any of
.TP
.B \f[C]linkcolor\f[], \f[C]citecolor\f[], \f[C]urlcolor\f[], \f[C]toccolor\f[]
color for internal links, citation links, external links, and links in
-table of contents: uses any of the predefined LaTeX colors
+table of contents: uses options allowed by \f[C]xcolor\f[], including
+the \f[C]dvipsnames\f[], \f[C]svgnames\f[], and \f[C]x11names\f[] lists
.RS
.RE
.TP
@@ -1630,6 +1820,19 @@ bibliography title, when used with \f[C]\-\-natbib\f[] and
list of options for biblatex.
.RS
.RE
+.TP
+.B \f[C]natbiboptions\f[]
+list of options for natbib.
+.RS
+.RE
+.TP
+.B \f[C]pagestyle\f[]
+An option for LaTeX\[aq]s \f[C]\\pagestyle{}\f[].
+The default article class supports \[aq]plain\[aq] (default),
+\[aq]empty\[aq], and \[aq]headings\[aq]; headings puts section titles in
+the header.
+.RS
+.RE
.SS Variables for ConTeXt
.TP
.B \f[C]papersize\f[]
@@ -1745,6 +1948,31 @@ adjusts text to left (\f[C]l\f[]), right (\f[C]r\f[]), center
if \f[C]true\f[] (the default), hyphenation will be used
.RS
.RE
+.SS Variables for ms
+.TP
+.B \f[C]pointsize\f[]
+point size (e.g.
+\f[C]10p\f[])
+.RS
+.RE
+.TP
+.B \f[C]lineheight\f[]
+line height (e.g.
+\f[C]12p\f[])
+.RS
+.RE
+.TP
+.B \f[C]fontfamily\f[]
+font family (e.g.
+\f[C]T\f[] or \f[C]P\f[])
+.RS
+.RE
+.TP
+.B \f[C]indent\f[]
+paragraph indent (e.g.
+\f[C]2m\f[])
+.RS
+.RE
.SS Using variables in templates
.PP
Variable names are sequences of alphanumerics, \f[C]\-\f[], and
@@ -1818,19 +2046,370 @@ We recommend tracking the changes in the default templates, and
modifying your custom templates accordingly.
An easy way to do this is to fork the pandoc\-templates repository and
merge in changes after each pandoc release.
-.SH PANDOC'S MARKDOWN
+.PP
+Templates may contain comments: anything on a line after \f[C]$\-\-\f[]
+will be treated as a comment and ignored.
+.SH EXTENSIONS
+.PP
+The behavior of some of the readers and writers can be adjusted by
+enabling or disabling various extensions.
+.PP
+An extension can be enabled by adding \f[C]+EXTENSION\f[] to the format
+name and disabled by adding \f[C]\-EXTENSION\f[].
+For example, \f[C]\-\-from\ markdown_strict+footnotes\f[] is strict
+Markdown with footnotes enabled, while
+\f[C]\-\-from\ markdown\-footnotes\-pipe_tables\f[] is pandoc\[aq]s
+Markdown without footnotes or pipe tables.
+.PP
+The markdown reader and writer make by far the most use of extensions.
+Extensions only used by them are therefore covered in the section
+Pandoc\[aq]s Markdown below (See Markdown variants for
+\f[C]commonmark\f[] and \f[C]gfm\f[].) In the following, extensions that
+also work for other formats are covered.
+.SS Typography
+.SS Extension: \f[C]smart\f[]
+.PP
+Interpret straight quotes as curly quotes, \f[C]\-\-\-\f[] as
+em\-dashes, \f[C]\-\-\f[] as en\-dashes, and \f[C]\&...\f[] as ellipses.
+Nonbreaking spaces are inserted after certain abbreviations, such as
+"Mr."
+.PP
+This extension can be enabled/disabled for the following formats:
+.TP
+.B input formats
+\f[C]markdown\f[], \f[C]commonmark\f[], \f[C]latex\f[],
+\f[C]mediawiki\f[], \f[C]org\f[], \f[C]rst\f[], \f[C]twiki\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]markdown\f[], \f[C]latex\f[], \f[C]context\f[], \f[C]rst\f[]
+.RS
+.RE
+.TP
+.B enabled by default in
+\f[C]markdown\f[], \f[C]latex\f[], \f[C]context\f[] (both input and
+output)
+.RS
+.RE
+.PP
+Note: If you are \f[I]writing\f[] Markdown, then the \f[C]smart\f[]
+extension has the reverse effect: what would have been curly quotes
+comes out straight.
+.PP
+In LaTeX, \f[C]smart\f[] means to use the standard TeX ligatures for
+quotation marks (\f[C]``\f[] and \f[C]\[aq]\[aq]\f[] for double quotes,
+\f[C]`\f[] and \f[C]\[aq]\f[] for single quotes) and dashes
+(\f[C]\-\-\f[] for en\-dash and \f[C]\-\-\-\f[] for em\-dash).
+If \f[C]smart\f[] is disabled, then in reading LaTeX pandoc will parse
+these characters literally.
+In writing LaTeX, enabling \f[C]smart\f[] tells pandoc to use the
+ligatures when possible; if \f[C]smart\f[] is disabled pandoc will use
+unicode quotation mark and dash characters.
+.SS Headers and sections
+.SS Extension: \f[C]auto_identifiers\f[]
+.PP
+A header without an explicitly specified identifier will be
+automatically assigned a unique identifier based on the header text.
+.PP
+This extension can be enabled/disabled for the following formats:
+.TP
+.B input formats
+\f[C]markdown\f[], \f[C]latex\f[], \f[C]rst\f[], \f[C]mediawiki\f[],
+\f[C]textile\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]markdown\f[], \f[C]muse\f[]
+.RS
+.RE
+.TP
+.B enabled by default in
+\f[C]markdown\f[], \f[C]muse\f[]
+.RS
+.RE
+.PP
+The algorithm used to derive the identifier from the header text is:
+.IP \[bu] 2
+Remove all formatting, links, etc.
+.IP \[bu] 2
+Remove all footnotes.
+.IP \[bu] 2
+Remove all punctuation, except underscores, hyphens, and periods.
+.IP \[bu] 2
+Replace all spaces and newlines with hyphens.
+.IP \[bu] 2
+Convert all alphabetic characters to lowercase.
+.IP \[bu] 2
+Remove everything up to the first letter (identifiers may not begin with
+a number or punctuation mark).
+.IP \[bu] 2
+If nothing is left after this, use the identifier \f[C]section\f[].
+.PP
+Thus, for example,
+.PP
+.TS
+tab(@);
+l l.
+T{
+Header
+T}@T{
+Identifier
+T}
+_
+T{
+\f[C]Header\ identifiers\ in\ HTML\f[]
+T}@T{
+\f[C]header\-identifiers\-in\-html\f[]
+T}
+T{
+\f[C]*Dogs*?\-\-in\ *my*\ house?\f[]
+T}@T{
+\f[C]dogs\-\-in\-my\-house\f[]
+T}
+T{
+\f[C][HTML],\ [S5],\ or\ [RTF]?\f[]
+T}@T{
+\f[C]html\-s5\-or\-rtf\f[]
+T}
+T{
+\f[C]3.\ Applications\f[]
+T}@T{
+\f[C]applications\f[]
+T}
+T{
+\f[C]33\f[]
+T}@T{
+\f[C]section\f[]
+T}
+.TE
+.PP
+These rules should, in most cases, allow one to determine the identifier
+from the header text.
+The exception is when several headers have the same text; in this case,
+the first will get an identifier as described above; the second will get
+the same identifier with \f[C]\-1\f[] appended; the third with
+\f[C]\-2\f[]; and so on.
+.PP
+These identifiers are used to provide link targets in the table of
+contents generated by the \f[C]\-\-toc|\-\-table\-of\-contents\f[]
+option.
+They also make it easy to provide links from one section of a document
+to another.
+A link to this section, for example, might look like this:
+.IP
+.nf
+\f[C]
+See\ the\ section\ on
+[header\ identifiers](#header\-identifiers\-in\-html\-latex\-and\-context).
+\f[]
+.fi
+.PP
+Note, however, that this method of providing links to sections works
+only in HTML, LaTeX, and ConTeXt formats.
+.PP
+If the \f[C]\-\-section\-divs\f[] option is specified, then each section
+will be wrapped in a \f[C]section\f[] (or a \f[C]div\f[], if
+\f[C]html4\f[] was specified), and the identifier will be attached to
+the enclosing \f[C]<section>\f[] (or \f[C]<div>\f[]) tag rather than the
+header itself.
+This allows entire sections to be manipulated using JavaScript or
+treated differently in CSS.
+.SS Extension: \f[C]ascii_identifiers\f[]
+.PP
+Causes the identifiers produced by \f[C]auto_identifiers\f[] to be pure
+ASCII.
+Accents are stripped off of accented Latin letters, and non\-Latin
+letters are omitted.
+.SS Math Input
+.PP
+The extensions \f[C]tex_math_dollars\f[],
+\f[C]tex_math_single_backslash\f[], and
+\f[C]tex_math_double_backslash\f[] are described in the section about
+Pandoc\[aq]s Markdown.
+.PP
+However, they can also be used with HTML input.
+This is handy for reading web pages formatted using MathJax, for
+example.
+.SS Raw HTML/TeX
+.PP
+The following extensions (especially how they affect Markdown
+input/output) are also described in more detail in their respective
+sections of Pandoc\[aq]s Markdown.
+.SS Extension: \f[C]raw_html\f[]
+.PP
+When converting from HTML, parse elements to raw HTML which are not
+representable in pandoc\[aq]s AST.
+By default, this is disabled for HTML input.
+.SS Extension: \f[C]raw_tex\f[]
+.PP
+Allows raw LaTeX, TeX, and ConTeXt to be included in a document.
+.PP
+This extension can be enabled/disabled for the following formats (in
+addition to \f[C]markdown\f[]):
+.TP
+.B input formats
+\f[C]latex\f[], \f[C]org\f[], \f[C]textile\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]textile\f[]
+.RS
+.RE
+.SS Extension: \f[C]native_divs\f[]
+.PP
+This extension is enabled by default for HTML input.
+This means that \f[C]div\f[]s are parsed to pandoc native elements.
+(Alternatively, you can parse them to raw HTML using
+\f[C]\-f\ html\-native_divs+raw_html\f[].)
+.PP
+When converting HTML to Markdown, for example, you may want to drop all
+\f[C]div\f[]s and \f[C]span\f[]s:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ html\-native_divs\-native_spans\ \-t\ markdown
+\f[]
+.fi
+.SS Extension: \f[C]native_spans\f[]
+.PP
+Analogous to \f[C]native_divs\f[] above.
+.SS Literate Haskell support
+.SS Extension: \f[C]literate_haskell\f[]
+.PP
+Treat the document as literate Haskell source.
+.PP
+This extension can be enabled/disabled for the following formats:
+.TP
+.B input formats
+\f[C]markdown\f[], \f[C]rst\f[], \f[C]latex\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]markdown\f[], \f[C]rst\f[], \f[C]latex\f[], \f[C]html\f[]
+.RS
+.RE
+.PP
+If you append \f[C]+lhs\f[] (or \f[C]+literate_haskell\f[]) to one of
+the formats above, pandoc will treat the document as literate Haskell
+source.
+This means that
+.IP \[bu] 2
+In Markdown input, "bird track" sections will be parsed as Haskell code
+rather than block quotations.
+Text between \f[C]\\begin{code}\f[] and \f[C]\\end{code}\f[] will also
+be treated as Haskell code.
+For ATX\-style headers the character \[aq]=\[aq] will be used instead of
+\[aq]#\[aq].
+.IP \[bu] 2
+In Markdown output, code blocks with classes \f[C]haskell\f[] and
+\f[C]literate\f[] will be rendered using bird tracks, and block
+quotations will be indented one space, so they will not be treated as
+Haskell code.
+In addition, headers will be rendered setext\-style (with underlines)
+rather than ATX\-style (with \[aq]#\[aq] characters).
+(This is because ghc treats \[aq]#\[aq] characters in column 1 as
+introducing line numbers.)
+.IP \[bu] 2
+In restructured text input, "bird track" sections will be parsed as
+Haskell code.
+.IP \[bu] 2
+In restructured text output, code blocks with class \f[C]haskell\f[]
+will be rendered using bird tracks.
+.IP \[bu] 2
+In LaTeX input, text in \f[C]code\f[] environments will be parsed as
+Haskell code.
+.IP \[bu] 2
+In LaTeX output, code blocks with class \f[C]haskell\f[] will be
+rendered inside \f[C]code\f[] environments.
+.IP \[bu] 2
+In HTML output, code blocks with class \f[C]haskell\f[] will be rendered
+with class \f[C]literatehaskell\f[] and bird tracks.
+.PP
+Examples:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ markdown+lhs\ \-t\ html
+\f[]
+.fi
+.PP
+reads literate Haskell source formatted with Markdown conventions and
+writes ordinary HTML (without bird tracks).
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ markdown+lhs\ \-t\ html+lhs
+\f[]
+.fi
+.PP
+writes HTML with the Haskell code in bird tracks, so it can be copied
+and pasted as literate Haskell source.
+.PP
+Note that GHC expects the bird tracks in the first column, so indentend
+literate code blocks (e.g.
+inside an itemized environment) will not be picked up by the Haskell
+compiler.
+.SS Other extensions
+.SS Extension: \f[C]empty_paragraphs\f[]
+.PP
+Allows empty paragraphs.
+By default empty paragraphs are omitted.
+.PP
+This extension can be enabled/disabled for the following formats:
+.TP
+.B input formats
+\f[C]docx\f[], \f[C]html\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]markdown\f[], \f[C]docx\f[], \f[C]odt\f[], \f[C]opendocument\f[],
+\f[C]html\f[]
+.RS
+.RE
+.SS Extension: \f[C]styles\f[]
+.PP
+Read all docx styles as divs (for paragraph styles) and spans (for
+character styles) regardless of whether pandoc understands the meaning
+of these styles.
+This can be used with docx custom styles.
+Disabled by default.
+.TP
+.B input formats
+\f[C]docx\f[]
+.RS
+.RE
+.SS Extension: \f[C]amuse\f[]
+.PP
+In the \f[C]muse\f[] input format, this enables Text::Amuse extensions
+to Emacs Muse markup.
+.SS Extension: \f[C]citations\f[]
+.PP
+Some aspects of Pandoc\[aq]s Markdown citation syntax are also accepted
+in \f[C]org\f[] input.
+.SS Extension: \f[C]ntb\f[]
+.PP
+In the \f[C]context\f[] output format this enables the use of Natural
+Tables (TABLE) instead of the default Extreme Tables (xtables).
+Natural tables allow more fine\-grained global customization but come at
+a performance penalty compared to extreme tables.
+.SH PANDOC\[aq]S MARKDOWN
.PP
Pandoc understands an extended and slightly revised version of John
-Gruber's Markdown syntax.
+Gruber\[aq]s Markdown syntax.
This document explains the syntax, noting differences from standard
Markdown.
Except where noted, these differences can be suppressed by using the
\f[C]markdown_strict\f[] format instead of \f[C]markdown\f[].
-An extensions can be enabled by adding \f[C]+EXTENSION\f[] to the format
-name and disabled by adding \f[C]\-EXTENSION\f[].
-For example, \f[C]markdown_strict+footnotes\f[] is strict Markdown with
-footnotes enabled, while \f[C]markdown\-footnotes\-pipe_tables\f[] is
-pandoc's Markdown without footnotes or pipe tables.
+Extensions can be enabled or disabled to specify the behavior more
+granularly.
+They are described in the following.
+See also Extensions above, for extensions that work also on other
+formats.
.SS Philosophy
.PP
Markdown is designed to be easy to write, and, even more importantly,
@@ -1838,16 +2417,16 @@ easy to read:
.RS
.PP
A Markdown\-formatted document should be publishable as\-is, as plain
-text, without looking like it's been marked up with tags or formatting
-instructions.
-\[en] John Gruber
+text, without looking like it\[aq]s been marked up with tags or
+formatting instructions.
+\-\- John Gruber
.RE
.PP
-This principle has guided pandoc's decisions in finding syntax for
+This principle has guided pandoc\[aq]s decisions in finding syntax for
tables, footnotes, and other extensions.
.PP
-There is, however, one respect in which pandoc's aims are different from
-the original aims of Markdown.
+There is, however, one respect in which pandoc\[aq]s aims are different
+from the original aims of Markdown.
Whereas Markdown was originally designed with HTML generation in mind,
pandoc is designed for multiple output formats.
Thus, while pandoc allows the embedding of raw HTML, it discourages it,
@@ -1871,8 +2450,8 @@ a hard line break, since trailing spaces in the cells are ignored.
There are two kinds of headers: Setext and ATX.
.SS Setext\-style headers
.PP
-A setext\-style header is a line of text \[lq]underlined\[rq] with a row
-of \f[C]=\f[] signs (for a level one header) or \f[C]\-\f[] signs (for a
+A setext\-style header is a line of text "underlined" with a row of
+\f[C]=\f[] signs (for a level one header) or \f[C]\-\f[] signs (for a
level two header):
.IP
.nf
@@ -1925,7 +2504,15 @@ I\ like\ several\ of\ their\ flavors\ of\ ice\ cream:
#22,\ for\ example,\ and\ #5.
\f[]
.fi
+.SS Extension: \f[C]space_in_atx_header\f[]
+.PP
+Many Markdown implementations do not require a space between the opening
+\f[C]#\f[]s of an ATX header and the header text, so that
+\f[C]#5\ bolt\f[] and \f[C]#hashtag\f[] count as headers.
+With this extension, pandoc does require the space.
.SS Header identifiers
+.PP
+See also the \f[C]auto_identifiers\f[] extension above.
.SS Extension: \f[C]header_attributes\f[]
.PP
Headers can be assigned attributes using this syntax at the end of the
@@ -1954,7 +2541,7 @@ My\ other\ header\ \ \ {#foo}
(This syntax is compatible with PHP Markdown Extra.)
.PP
Note that although this syntax allows assignment of classes and
-key/value attributes, writers generally don't use all of this
+key/value attributes, writers generally don\[aq]t use all of this
information.
Identifiers, classes, and key/value attributes are used in HTML and
HTML\-based formats such as EPUB and slidy.
@@ -1980,96 +2567,6 @@ is just the same as
#\ My\ header\ {.unnumbered}
\f[]
.fi
-.SS Extension: \f[C]auto_identifiers\f[]
-.PP
-A header without an explicitly specified identifier will be
-automatically assigned a unique identifier based on the header text.
-To derive the identifier from the header text,
-.IP \[bu] 2
-Remove all formatting, links, etc.
-.IP \[bu] 2
-Remove all footnotes.
-.IP \[bu] 2
-Remove all punctuation, except underscores, hyphens, and periods.
-.IP \[bu] 2
-Replace all spaces and newlines with hyphens.
-.IP \[bu] 2
-Convert all alphabetic characters to lowercase.
-.IP \[bu] 2
-Remove everything up to the first letter (identifiers may not begin with
-a number or punctuation mark).
-.IP \[bu] 2
-If nothing is left after this, use the identifier \f[C]section\f[].
-.PP
-Thus, for example,
-.PP
-.TS
-tab(@);
-l l.
-T{
-Header
-T}@T{
-Identifier
-T}
-_
-T{
-\f[C]Header\ identifiers\ in\ HTML\f[]
-T}@T{
-\f[C]header\-identifiers\-in\-html\f[]
-T}
-T{
-\f[C]*Dogs*?\-\-in\ *my*\ house?\f[]
-T}@T{
-\f[C]dogs\-\-in\-my\-house\f[]
-T}
-T{
-\f[C][HTML],\ [S5],\ or\ [RTF]?\f[]
-T}@T{
-\f[C]html\-s5\-or\-rtf\f[]
-T}
-T{
-\f[C]3.\ Applications\f[]
-T}@T{
-\f[C]applications\f[]
-T}
-T{
-\f[C]33\f[]
-T}@T{
-\f[C]section\f[]
-T}
-.TE
-.PP
-These rules should, in most cases, allow one to determine the identifier
-from the header text.
-The exception is when several headers have the same text; in this case,
-the first will get an identifier as described above; the second will get
-the same identifier with \f[C]\-1\f[] appended; the third with
-\f[C]\-2\f[]; and so on.
-.PP
-These identifiers are used to provide link targets in the table of
-contents generated by the \f[C]\-\-toc|\-\-table\-of\-contents\f[]
-option.
-They also make it easy to provide links from one section of a document
-to another.
-A link to this section, for example, might look like this:
-.IP
-.nf
-\f[C]
-See\ the\ section\ on
-[header\ identifiers](#header\-identifiers\-in\-html\-latex\-and\-context).
-\f[]
-.fi
-.PP
-Note, however, that this method of providing links to sections works
-only in HTML, LaTeX, and ConTeXt formats.
-.PP
-If the \f[C]\-\-section\-divs\f[] option is specified, then each section
-will be wrapped in a \f[C]div\f[] (or a \f[C]section\f[], if
-\f[C]\-\-html5\f[] was specified), and the identifier will be attached
-to the enclosing \f[C]<div>\f[] (or \f[C]<section>\f[]) tag rather than
-the header itself.
-This allows entire sections to be manipulated using JavaScript or
-treated differently in CSS.
.SS Extension: \f[C]implicit_header_references\f[]
.PP
Pandoc behaves as if reference links have been defined for each header.
@@ -2153,8 +2650,8 @@ indented more than three spaces.)
\f[]
.fi
.PP
-A \[lq]lazy\[rq] form, which requires the \f[C]>\f[] character only on
-the first line of each block, is also allowed:
+A "lazy" form, which requires the \f[C]>\f[] character only on the first
+line of each block, is also allowed:
.IP
.nf
\f[C]
@@ -2285,8 +2782,8 @@ Here \f[C]mycode\f[] is an identifier, \f[C]haskell\f[] and
\f[C]numberLines\f[] are classes, and \f[C]startFrom\f[] is an attribute
with value \f[C]100\f[].
Some output formats can use this information to do syntax highlighting.
-Currently, the only output formats that uses this information are HTML
-and LaTeX.
+Currently, the only output formats that uses this information are HTML,
+LaTeX, Docx, Ms, and PowerPoint.
If highlighting is supported for your output format and language, then
the code block above will appear highlighted, with numbered lines.
(To see which languages are supported, type
@@ -2303,6 +2800,12 @@ block above will appear as follows:
\f[]
.fi
.PP
+The \f[C]numberLines\f[] (or \f[C]number\-lines\f[]) class will cause
+the lines of the code block to be numbered, starting with \f[C]1\f[] or
+the value of the \f[C]startFrom\f[] attribute.
+The \f[C]lineAnchors\f[] (or \f[C]line\-anchors\f[]) class will cause
+the lines to be clickable anchors in HTML output.
+.PP
A shortcut form can also be used for specifying the language of the code
block:
.IP
@@ -2382,8 +2885,8 @@ Here is a simple example:
\f[]
.fi
.PP
-This will produce a \[lq]compact\[rq] list.
-If you want a \[lq]loose\[rq] list, in which each item is formatted as a
+This will produce a "compact" list.
+If you want a "loose" list, in which each item is formatted as a
paragraph, put spaces between the items:
.IP
.nf
@@ -2411,7 +2914,7 @@ List items look best if subsequent lines are flush with the first line
\f[]
.fi
.PP
-But Markdown also allows a \[lq]lazy\[rq] format:
+But Markdown also allows a "lazy" format:
.IP
.nf
\f[C]
@@ -2420,14 +2923,13 @@ list\ item.
*\ and\ my\ second.
\f[]
.fi
-.SS The four\-space rule
+.SS Block content in list items
.PP
A list item may contain multiple paragraphs and other block\-level
content.
However, subsequent paragraphs must be preceded by a blank line and
-indented four spaces or a tab.
-The list will look better if the first paragraph is aligned with the
-rest:
+indented to line up with the first non\-space content after the list
+marker.
.IP
.nf
\f[C]
@@ -2442,26 +2944,40 @@ rest:
\f[]
.fi
.PP
+Exception: if the list marker is followed by an indented code block,
+which must begin 5 spaces after the list marker, then subsequent
+paragraphs must begin two columns after the last character of the list
+marker:
+.IP
+.nf
+\f[C]
+*\ \ \ \ \ code
+
+\ \ continuation\ paragraph
+\f[]
+.fi
+.PP
List items may include other lists.
In this case the preceding blank line is optional.
-The nested list must be indented four spaces or one tab:
+The nested list must be indented to line up with the first non\-space
+character after the list marker of the containing list item.
.IP
.nf
\f[C]
*\ fruits
-\ \ \ \ +\ apples
-\ \ \ \ \ \ \ \ \-\ macintosh
-\ \ \ \ \ \ \ \ \-\ red\ delicious
-\ \ \ \ +\ pears
-\ \ \ \ +\ peaches
+\ \ +\ apples
+\ \ \ \ \-\ macintosh
+\ \ \ \ \-\ red\ delicious
+\ \ +\ pears
+\ \ +\ peaches
*\ vegetables
-\ \ \ \ +\ broccoli
-\ \ \ \ +\ chard
+\ \ +\ broccoli
+\ \ +\ chard
\f[]
.fi
.PP
-As noted above, Markdown allows you to write list items
-\[lq]lazily,\[rq] instead of indenting continuation lines.
+As noted above, Markdown allows you to write list items "lazily,"
+instead of indenting continuation lines.
However, if there are multiple paragraphs or other blocks in a list
item, the first line of each must be indented.
.IP
@@ -2477,18 +2993,6 @@ bad\ but\ is\ legal.
list\ item.
\f[]
.fi
-.PP
-\f[B]Note:\f[] Although the four\-space rule for continuation paragraphs
-comes from the official Markdown syntax guide, the reference
-implementation, \f[C]Markdown.pl\f[], does not follow it.
-So pandoc will give different results than \f[C]Markdown.pl\f[] when
-authors have indented continuation paragraphs fewer than four spaces.
-.PP
-The Markdown syntax guide is not explicit whether the four\-space rule
-applies to \f[I]all\f[] block\-level content in a list item; it only
-mentions paragraphs and code blocks.
-But it implies that the rule applies to all block\-level content
-(including nested lists), and pandoc interprets it that way.
.SS Ordered lists
.PP
Ordered lists work just like bulleted lists, except that the items begin
@@ -2527,8 +3031,8 @@ They must be separated from the text that follows by at least one space,
and, if the list marker is a capital letter with a period, by at least
two spaces.
.PP
-The \f[C]fancy_lists\f[] extension also allows `\f[C]#\f[]' to be used
-as an ordered list marker in place of a numeral:
+The \f[C]fancy_lists\f[] extension also allows \[aq]\f[C]#\f[]\[aq] to
+be used as an ordered list marker in place of a numeral:
.IP
.nf
\f[C]
@@ -2610,9 +3114,8 @@ one or more block elements (paragraph, code block, list, etc.), each
indented four spaces or one tab stop.
The body of the definition (including the first line, aside from the
colon or tilde) should be indented four spaces.
-However, as with other Markdown lists, you can \[lq]lazily\[rq] omit
-indentation except at the beginning of a paragraph or other block
-element:
+However, as with other Markdown lists, you can "lazily" omit indentation
+except at the beginning of a paragraph or other block element:
.IP
.nf
\f[C]
@@ -2644,16 +3147,16 @@ Term\ 2
.fi
.PP
Note that space between items in a definition list is required.
-(A variant that loosens this requirement, but disallows \[lq]lazy\[rq]
-hard wrapping, can be activated with \f[C]compact_definition_lists\f[]:
-see Non\-pandoc extensions, below.)
+(A variant that loosens this requirement, but disallows "lazy" hard
+wrapping, can be activated with \f[C]compact_definition_lists\f[]: see
+Non\-pandoc extensions, below.)
.SS Numbered example lists
.SS Extension: \f[C]example_lists\f[]
.PP
The special list marker \f[C]\@\f[] can be used for sequentially
numbered examples.
-The first list item with a \f[C]\@\f[] marker will be numbered `1', the
-next `2', and so on, throughout the document.
+The first list item with a \f[C]\@\f[] marker will be numbered
+\[aq]1\[aq], the next \[aq]2\[aq], and so on, throughout the document.
The numbered examples need not occur in a single list; each new list
using \f[C]\@\f[] will take up where the last stopped.
So, for example:
@@ -2682,10 +3185,17 @@ As\ (\@good)\ illustrates,\ ...
.PP
The label can be any string of alphanumeric characters, underscores, or
hyphens.
+.PP
+Note: continuation paragraphs in example lists must always be indented
+four spaces, regardless of the length of the list marker.
+That is, example lists always behave as if the \f[C]four_space_rule\f[]
+extension is set.
+This is because example labels tend to be long, and indenting content to
+the first non\-space character after the label would be awkward.
.SS Compact and loose lists
.PP
-Pandoc behaves differently from \f[C]Markdown.pl\f[] on some \[lq]edge
-cases\[rq] involving lists.
+Pandoc behaves differently from \f[C]Markdown.pl\f[] on some "edge
+cases" involving lists.
Consider this source:
.IP
.nf
@@ -2700,15 +3210,14 @@ Consider this source:
\f[]
.fi
.PP
-Pandoc transforms this into a \[lq]compact list\[rq] (with no
-\f[C]<p>\f[] tags around \[lq]First\[rq], \[lq]Second\[rq], or
-\[lq]Third\[rq]), while Markdown puts \f[C]<p>\f[] tags around
-\[lq]Second\[rq] and \[lq]Third\[rq] (but not \[lq]First\[rq]), because
-of the blank space around \[lq]Third\[rq].
+Pandoc transforms this into a "compact list" (with no \f[C]<p>\f[] tags
+around "First", "Second", or "Third"), while Markdown puts \f[C]<p>\f[]
+tags around "Second" and "Third" (but not "First"), because of the blank
+space around "Third".
Pandoc follows a simple rule: if the text is followed by a blank line,
it is treated as a paragraph.
-Since \[lq]Second\[rq] is followed by a list, and not a blank line, it
-isn't treated as a paragraph.
+Since "Second" is followed by a list, and not a blank line, it isn\[aq]t
+treated as a paragraph.
The fact that the list is followed by a blank line is irrelevant.
(Note: Pandoc works this way even when the \f[C]markdown_strict\f[]
format is specified.
@@ -2732,9 +3241,9 @@ Trouble! Here pandoc (like other Markdown implementations) will treat
\f[C]{\ my\ code\ block\ }\f[] as the second paragraph of item two, and
not as a code block.
.PP
-To \[lq]cut off\[rq] the list after item two, you can insert some
-non\-indented content, like an HTML comment, which won't produce visible
-output in any format:
+To "cut off" the list after item two, you can insert some non\-indented
+content, like an HTML comment, which won\[aq]t produce visible output in
+any format:
.IP
.nf
\f[C]
@@ -2953,6 +3462,15 @@ For headerless tables, the colons go on the top line instead:
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
\f[]
.fi
+.SS Grid Table Limitations
+.PP
+Pandoc does not support grid tables with row spans or column spans.
+This means that neither variable numbers of columns across rows nor
+variable numbers of rows across columns are supported by Pandoc.
+All grid tables must have the same number of columns in each row, and
+the same number of rows in each column.
+For example, the Docutils sample grid tables will not render as expected
+with Pandoc.
.SS Extension: \f[C]pipe_tables\f[]
.PP
Pipe tables look like this:
@@ -2996,9 +3514,12 @@ If a pipe table contains a row whose printable content is wider than the
column width (see \f[C]\-\-columns\f[]), then the cell contents will
wrap, with the relative cell widths determined by the widths of the
separator lines.
+(In this case, the table will take up the full text width.) If no lines
+are wider than column width, then cell contents will not be wrapped, and
+the cells will be sized to their contents.
.PP
Note: pandoc also recognizes pipe tables of the following form, as can
-be produced by Emacs' orgtbl\-mode:
+be produced by Emacs\[aq] orgtbl\-mode:
.IP
.nf
\f[C]
@@ -3011,8 +3532,8 @@ be produced by Emacs' orgtbl\-mode:
.PP
The difference is that \f[C]+\f[] is used instead of \f[C]|\f[].
Other orgtbl features are not supported.
-In particular, to get non\-default column alignment, you'll need to add
-colons as above.
+In particular, to get non\-default column alignment, you\[aq]ll need to
+add colons as above.
.SS Metadata blocks
.SS Extension: \f[C]pandoc_title_block\f[]
.PP
@@ -3077,13 +3598,13 @@ All three metadata fields may contain standard inline formatting
.PP
Title blocks will always be parsed, but they will affect the output only
when the \f[C]\-\-standalone\f[] (\f[C]\-s\f[]) option is chosen.
-In HTML output, titles will appear twice: once in the document head
-\[en] this is the title that will appear at the top of the window in a
-browser \[en] and once at the beginning of the document body.
+In HTML output, titles will appear twice: once in the document head \-\-
+this is the title that will appear at the top of the window in a browser
+\-\- and once at the beginning of the document body.
The title in the document head can have an optional prefix attached
(\f[C]\-\-title\-prefix\f[] or \f[C]\-T\f[] option).
-The title in the body appears as an H1 element with class
-\[lq]title\[rq], so it can be suppressed or reformatted with CSS.
+The title in the body appears as an H1 element with class "title", so it
+can be suppressed or reformatted with CSS.
If a title prefix is specified with \f[C]\-T\f[] and no title block
appears in the document, the title prefix will be used by itself as the
HTML title.
@@ -3112,7 +3633,7 @@ will yield a man page with the title \f[C]PANDOC\f[] and section 1.
\f[]
.fi
.PP
-will also have \[lq]Pandoc User Manuals\[rq] in the footer.
+will also have "Pandoc User Manuals" in the footer.
.IP
.nf
\f[C]
@@ -3120,7 +3641,7 @@ will also have \[lq]Pandoc User Manuals\[rq] in the footer.
\f[]
.fi
.PP
-will also have \[lq]Version 4.0\[rq] in the header.
+will also have "Version 4.0" in the header.
.SS Extension: \f[C]yaml_metadata_block\f[]
.PP
A YAML metadata block is a valid YAML object, delimited by a line of
@@ -3164,7 +3685,8 @@ Note that YAML escaping rules must be followed.
Thus, for example, if a title contains a colon, it must be quoted.
The pipe character (\f[C]|\f[]) can be used to begin an indented block
that will be interpreted literally, without need for escaping.
-This form is necessary when the field contains blank lines:
+This form is necessary when the field contains blank lines or
+block\-level formatting:
.IP
.nf
\f[C]
@@ -3229,6 +3751,23 @@ $endif$
$endfor$
\f[]
.fi
+.PP
+Raw content to include in the document\[aq]s header may be specified
+using \f[C]header\-includes\f[]; however, it is important to mark up
+this content as raw code for a particular output format, using the
+\f[C]raw_attribute\f[] extension), or it will be interpreted as
+markdown.
+For example:
+.IP
+.nf
+\f[C]
+header\-includes:
+\-\ ```{=latex}
+\ \ \\let\\oldsection\\section
+\ \ \\renewcommand{\\section}[1]{\\clearpage\\oldsection{#1}}
+\ \ ```
+\f[]
+.fi
.SS Backslash escapes
.SS Extension: \f[C]all_symbols_escapable\f[]
.PP
@@ -3259,7 +3798,7 @@ instead of
\f[]
.fi
.PP
-This rule is easier to remember than standard Markdown's rule, which
+This rule is easier to remember than standard Markdown\[aq]s rule, which
allows only the following characters to be backslash\-escaped:
.IP
.nf
@@ -3275,27 +3814,15 @@ A backslash\-escaped space is parsed as a nonbreaking space.
It will appear in TeX output as \f[C]~\f[] and in HTML and XML as
\f[C]\\&#160;\f[] or \f[C]\\&nbsp;\f[].
.PP
-A backslash\-escaped newline (i.e.\ a backslash occurring at the end of
-a line) is parsed as a hard line break.
+A backslash\-escaped newline (i.e.
+a backslash occurring at the end of a line) is parsed as a hard line
+break.
It will appear in TeX output as \f[C]\\\\\f[] and in HTML as
\f[C]<br\ />\f[].
-This is a nice alternative to Markdown's \[lq]invisible\[rq] way of
+This is a nice alternative to Markdown\[aq]s "invisible" way of
indicating hard line breaks using two trailing spaces on a line.
.PP
Backslash escapes do not work in verbatim contexts.
-.SS Smart punctuation
-.SS Extension
-.PP
-If the \f[C]\-\-smart\f[] option is specified, pandoc will produce
-typographically correct output, converting straight quotes to curly
-quotes, \f[C]\-\-\-\f[] to em\-dashes, \f[C]\-\-\f[] to en\-dashes, and
-\f[C]\&...\f[] to ellipses.
-Nonbreaking spaces are inserted after certain abbreviations, such as
-\[lq]Mr.\[rq]
-.PP
-Note: if your LaTeX template or any included header file call for the
-\f[C]csquotes\f[] package, pandoc will detect this automatically and use
-\f[C]\\enquote{...}\f[] for quoted text.
.SS Inline formatting
.SS Emphasis
.PP
@@ -3367,8 +3894,8 @@ If the superscripted or subscripted text contains spaces, these spaces
must be escaped with backslashes.
(This is to prevent accidental superscripting and subscripting through
the ordinary use of \f[C]~\f[] and \f[C]^\f[].) Thus, if you want the
-letter P with `a cat' in subscripts, use \f[C]P~a\\\ cat~\f[], not
-\f[C]P~a\ cat~\f[].
+letter P with \[aq]a cat\[aq] in subscripts, use \f[C]P~a\\\ cat~\f[],
+not \f[C]P~a\ cat~\f[].
.SS Verbatim
.PP
To make a short span of text verbatim, put it inside backticks:
@@ -3414,24 +3941,31 @@ blocks:
.fi
.SS Small caps
.PP
-To write small caps, you can use an HTML span tag:
+To write small caps, use the \f[C]smallcaps\f[] class:
.IP
.nf
\f[C]
-<span\ style="font\-variant:small\-caps;">Small\ caps</span>
+[Small\ caps]{.smallcaps}
\f[]
.fi
.PP
-(The semicolon is optional and there may be space after the colon.) This
-will work in all output formats that support small caps.
+Or, without the \f[C]bracketed_spans\f[] extension:
+.IP
+.nf
+\f[C]
+<span\ class="smallcaps">Small\ caps</span>
+\f[]
+.fi
.PP
-Alternatively, you can also use the new \f[C]bracketed_spans\f[] syntax:
+For compatibility with other Markdown flavors, CSS is also supported:
.IP
.nf
\f[C]
-[Small\ caps]{style="font\-variant:small\-caps;"}
+<span\ style="font\-variant:small\-caps;">Small\ caps</span>
\f[]
.fi
+.PP
+This will work in all output formats that support small caps.
.SS Math
.SS Extension: \f[C]tex_math_dollars\f[]
.PP
@@ -3440,9 +3974,9 @@ The opening \f[C]$\f[] must have a non\-space character immediately to
its right, while the closing \f[C]$\f[] must have a non\-space character
immediately to its left, and must not be followed immediately by a
digit.
-Thus, \f[C]$20,000\ and\ $30,000\f[] won't parse as math.
+Thus, \f[C]$20,000\ and\ $30,000\f[] won\[aq]t parse as math.
If for some reason you need to enclose text in literal \f[C]$\f[]
-characters, backslash\-escape them and they won't be treated as math
+characters, backslash\-escape them and they won\[aq]t be treated as math
delimiters.
.PP
TeX math will be printed in all output formats.
@@ -3469,7 +4003,7 @@ It will be rendered inside a \f[C]\@math\f[] command.
.RE
.TP
.B groff man
-It will be rendered verbatim without \f[C]$\f[]'s.
+It will be rendered verbatim without \f[C]$\f[]\[aq]s.
.RS
.RE
.TP
@@ -3483,12 +4017,17 @@ It will be rendered inside \f[C]<span\ class="math">\f[] tags.
.RS
.RE
.TP
-.B RTF, OpenDocument, ODT
+.B RTF, OpenDocument
It will be rendered, if possible, using Unicode characters, and will
otherwise appear verbatim.
.RS
.RE
.TP
+.B ODT
+It will be rendered, if possible, using MathML.
+.RS
+.RE
+.TP
.B DocBook
If the \f[C]\-\-mathml\f[] flag is used, it will be rendered using
MathML in an \f[C]inlineequation\f[] or \f[C]informalequation\f[] tag.
@@ -3511,62 +4050,9 @@ Otherwise, they will appear verbatim.
.TP
.B HTML, Slidy, DZSlides, S5, EPUB
The way math is rendered in HTML will depend on the command\-line
-options selected:
+options selected.
+Therefore see Math rendering in HTML above.
.RS
-.IP "1." 3
-The default is to render TeX math as far as possible using Unicode
-characters, as with RTF, DocBook, and OpenDocument output.
-Formulas are put inside a \f[C]span\f[] with \f[C]class="math"\f[], so
-that they may be styled differently from the surrounding text if needed.
-.IP "2." 3
-If the \f[C]\-\-latexmathml\f[] option is used, TeX math will be
-displayed between \f[C]$\f[] or \f[C]$$\f[] characters and put in
-\f[C]<span>\f[] tags with class \f[C]LaTeX\f[].
-The LaTeXMathML script will be used to render it as formulas.
-(This trick does not work in all browsers, but it works in Firefox.
-In browsers that do not support LaTeXMathML, TeX math will appear
-verbatim between \f[C]$\f[] characters.)
-.IP "3." 3
-If the \f[C]\-\-jsmath\f[] option is used, TeX math will be put inside
-\f[C]<span>\f[] tags (for inline math) or \f[C]<div>\f[] tags (for
-display math) with class \f[C]math\f[].
-The jsMath script will be used to render it.
-.IP "4." 3
-If the \f[C]\-\-mimetex\f[] option is used, the mimeTeX CGI script will
-be called to generate images for each TeX formula.
-This should work in all browsers.
-The \f[C]\-\-mimetex\f[] option takes an optional URL as argument.
-If no URL is specified, it will be assumed that the mimeTeX CGI script
-is at \f[C]/cgi\-bin/mimetex.cgi\f[].
-.IP "5." 3
-If the \f[C]\-\-gladtex\f[] option is used, TeX formulas will be
-enclosed in \f[C]<eq>\f[] tags in the HTML output.
-The resulting \f[C]htex\f[] file may then be processed by gladTeX, which
-will produce image files for each formula and an HTML file with links to
-these images.
-So, the procedure is:
-.RS 4
-.IP
-.nf
-\f[C]
-pandoc\ \-s\ \-\-gladtex\ myfile.txt\ \-o\ myfile.htex
-gladtex\ \-d\ myfile\-images\ myfile.htex
-#\ produces\ myfile.html\ and\ images\ in\ myfile\-images
-\f[]
-.fi
-.RE
-.IP "6." 3
-If the \f[C]\-\-webtex\f[] option is used, TeX formulas will be
-converted to \f[C]<img>\f[] tags that link to an external script that
-converts formulas to images.
-The formula will be URL\-encoded and concatenated with the URL provided.
-If no URL is specified, the CodeCogs will be used
-(\f[C]https://latex.codecogs.com/png.latex?\f[]).
-.IP "7." 3
-If the \f[C]\-\-mathjax\f[] option is used, TeX math will be displayed
-between \f[C]\\(...\\)\f[] (for inline math) or \f[C]\\[...\\]\f[] (for
-display math) and put in \f[C]<span>\f[] tags with class \f[C]math\f[].
-The MathJax script will be used to render it as formulas.
.RE
.SS Raw HTML
.SS Extension: \f[C]raw_html\f[]
@@ -3583,9 +4069,9 @@ DZSlides, EPUB, Markdown, Emacs Org mode, and Textile output, and
suppressed in other formats.
.SS Extension: \f[C]markdown_in_html_blocks\f[]
.PP
-Standard Markdown allows you to include HTML \[lq]blocks\[rq]: blocks of
-HTML between balanced tags that are separated from the surrounding text
-with blank lines, and start and end at the left margin.
+Standard Markdown allows you to include HTML "blocks": blocks of HTML
+between balanced tags that are separated from the surrounding text with
+blank lines, and start and end at the left margin.
Within these blocks, everything is interpreted as HTML, not Markdown; so
(for example), \f[C]*\f[] does not signify emphasis.
.PP
@@ -3642,7 +4128,6 @@ Use native pandoc \f[C]Span\f[] blocks for content inside
For the most part this should give the same output as \f[C]raw_html\f[],
but it makes it easier to write pandoc filters to manipulate groups of
inlines.
-.SS Raw TeX
.SS Extension: \f[C]raw_tex\f[]
.PP
In addition to raw HTML, pandoc allows raw LaTeX, TeX, and ConTeXt to be
@@ -3675,12 +4160,46 @@ LaTeX, not as Markdown.
.PP
Inline LaTeX is ignored in output formats other than Markdown, LaTeX,
Emacs Org mode, and ConTeXt.
+.SS Generic raw attribute
+.SS Extension: \f[C]raw_attribute\f[]
+.PP
+Inline spans and fenced code blocks with a special kind of attribute
+will be parsed as raw content with the designated format.
+For example, the following produces a raw groff \f[C]ms\f[] block:
+.IP
+.nf
+\f[C]
+```{=ms}
+\&.MYMACRO
+blah\ blah
+```
+\f[]
+.fi
+.PP
+And the following produces a raw \f[C]html\f[] inline element:
+.IP
+.nf
+\f[C]
+This\ is\ `<a>html</a>`{=html}
+\f[]
+.fi
+.PP
+The format name should match the target format name (see
+\f[C]\-t/\-\-to\f[], above, for a list, or use
+\f[C]pandoc\ \-\-list\-output\-formats\f[]).
+.PP
+This extension presupposes that the relevant kind of inline code or
+fenced code block is enabled.
+Thus, for example, to use a raw attribute with a backtick code block,
+\f[C]backtick_code_blocks\f[] must be enabled.
+.PP
+The raw attribute cannot be combined with regular attributes.
.SS LaTeX macros
.SS Extension: \f[C]latex_macros\f[]
.PP
-For output formats other than LaTeX, pandoc will parse LaTeX
-\f[C]\\newcommand\f[] and \f[C]\\renewcommand\f[] definitions and apply
-the resulting macros to all LaTeX math.
+For output formats other than LaTeX, pandoc will parse LaTeX macro
+definitions and apply the resulting macros to all LaTeX math and raw
+LaTeX.
So, for example, the following will work in all output formats, not just
LaTeX:
.IP
@@ -3692,8 +4211,15 @@ $\\tuple{a,\ b,\ c}$
\f[]
.fi
.PP
-In LaTeX output, the \f[C]\\newcommand\f[] definition will simply be
-passed unchanged to the output.
+Note that LaTeX macros will not be applied if they occur inside inside a
+raw span or block marked with the \f[C]raw_attribute\f[] extension.
+.PP
+When \f[C]latex_macros\f[] is disabled, the raw LaTeX and math will not
+have macros applied.
+This is usually a better approach when you are targeting LaTeX or PDF.
+.PP
+Whether or not \f[C]latex_macros\f[] is enabled, the macro definitions
+will still be passed through as raw LaTeX.
.SS Links
.PP
Markdown allows links to be specified in several ways.
@@ -3742,10 +4268,11 @@ before or after the link).
.PP
The link consists of link text in square brackets, followed by a label
in square brackets.
-(There can be space between the two.) The link definition consists of
-the bracketed label, followed by a colon and a space, followed by the
-URL, and optionally (after a space) a link title either in quotes or in
-parentheses.
+(There cannot be space between the two unless the
+\f[C]spaced_reference_links\f[] extension is enabled.) The link
+definition consists of the bracketed label, followed by a colon and a
+space, followed by the URL, and optionally (after a space) a link title
+either in quotes or in parentheses.
The label must not be parseable as a citation (assuming the
\f[C]citations\f[] extension is enabled): citations take precedence over
link labels.
@@ -3853,7 +4380,7 @@ slide shows and EPUB), LaTeX, and ConTeXt.
.SS Images
.PP
A link immediately preceded by a \f[C]!\f[] will be treated as an image.
-The link text will be used as the image's alt text:
+The link text will be used as the image\[aq]s alt text:
.IP
.nf
\f[C]
@@ -3866,11 +4393,9 @@ The link text will be used as the image's alt text:
.fi
.SS Extension: \f[C]implicit_figures\f[]
.PP
-An image occurring by itself in a paragraph will be rendered as a figure
-with a caption. (In LaTeX, a figure environment will be used; in HTML,
-the image will be placed in a \f[C]div\f[] with class \f[C]figure\f[],
-together with a caption in a \f[C]p\f[] with class \f[C]caption\f[].)
-The image's alt text will be used as the caption.
+An image with nonempty alt text, occurring by itself in a paragraph,
+will be rendered as a figure with a caption.
+The image\[aq]s alt text will be used as the caption.
.IP
.nf
\f[C]
@@ -3878,15 +4403,25 @@ The image's alt text will be used as the caption.
\f[]
.fi
.PP
+How this is rendered depends on the output format.
+Some output formats (e.g.
+RTF) do not yet support figures.
+In those formats, you\[aq]ll just get an image in a paragraph by itself,
+with no caption.
+.PP
If you just want a regular inline image, just make sure it is not the
only thing in the paragraph.
One way to do this is to insert a nonbreaking space after the image:
.IP
.nf
\f[C]
-![This\ image\ won\[aq]t\ be\ a\ figure](/url/of/image.png)\\\
+![This\ image\ won\[aq]t\ be\ a\ figure](/url/of/image.png)\\
\f[]
.fi
+.PP
+Note that in reveal.js slide shows, an image in a paragraph by itself
+that has the \f[C]stretch\f[] class will fill the screen, and the
+caption and figure tags will be omitted.
.SS Extension: \f[C]link_attributes\f[]
.PP
Attributes can be set on links and images:
@@ -3942,12 +4477,67 @@ identifier (LaTeX \f[C]\\caption\f[]), or both (HTML).
When no \f[C]width\f[] or \f[C]height\f[] attributes are specified, the
fallback is to look at the image resolution and the dpi metadata
embedded in the image file.
-.SS Spans
+.SS Divs and Spans
+.PP
+Using the \f[C]native_divs\f[] and \f[C]native_spans\f[] extensions (see
+above), HTML syntax can be used as part of markdown to create native
+\f[C]Div\f[] and \f[C]Span\f[] elements in the pandoc AST (as opposed to
+raw HTML).
+However, there is also nicer syntax available:
+.SS Extension: \f[C]fenced_divs\f[]
+.PP
+Allow special fenced syntax for native \f[C]Div\f[] blocks.
+A Div starts with a fence containing at least three consecutive colons
+plus some attributes.
+The attributes may optionally be followed by another string of
+consecutive colons.
+The attribute syntax is exactly as in fenced code blocks (see Extension:
+\f[C]fenced_code_attributes\f[]).
+As with fenced code blocks, one can use either attributes in curly
+braces or a single unbraced word, which will be treated as a class name.
+The Div ends with another line containing a string of at least three
+consecutive colons.
+The fenced Div should be separated by blank lines from preceding and
+following blocks.
+.PP
+Example:
+.IP
+.nf
+\f[C]
+:::::\ {#special\ .sidebar}
+Here\ is\ a\ paragraph.
+
+And\ another.
+:::::
+\f[]
+.fi
+.PP
+Fenced divs can be nested.
+Opening fences are distinguished because they \f[I]must\f[] have
+attributes:
+.IP
+.nf
+\f[C]
+:::\ Warning\ ::::::
+This\ is\ a\ warning.
+
+:::\ Danger
+This\ is\ a\ warning\ within\ a\ warning.
+:::
+::::::::::::::::::
+\f[]
+.fi
+.PP
+Fences without attributes are always closing fences.
+Unlike with fenced code blocks, the number of colons in the closing
+fence need not match the number in the opening fence.
+However, it can be helpful for visual clarity to use fences of different
+lengths to distinguish nested divs from their parents.
.SS Extension: \f[C]bracketed_spans\f[]
.PP
A bracketed sequence of inlines, as one would use to begin a link, will
-be treated as a span with attributes if it is followed immediately by
-attributes:
+be treated as a \f[C]Span\f[] with attributes if it is followed
+immediately by attributes:
.IP
.nf
\f[C]
@@ -3957,7 +4547,7 @@ attributes:
.SS Footnotes
.SS Extension: \f[C]footnotes\f[]
.PP
-Pandoc's Markdown allows footnotes, using the following syntax:
+Pandoc\[aq]s Markdown allows footnotes, using the following syntax:
.IP
.nf
\f[C]
@@ -4141,7 +4731,7 @@ JSON and CSL YAML formats as far as possible.
As an alternative to specifying a bibliography file using
\f[C]\-\-bibliography\f[] or the YAML metadata field
\f[C]bibliography\f[], you can include the citation data directly in the
-\f[C]references\f[] field of the document's YAML metadata.
+\f[C]references\f[] field of the document\[aq]s YAML metadata.
The field should contain an array of YAML\-encoded references, for
example:
.IP
@@ -4191,7 +4781,7 @@ To make your citations hyperlinks to the corresponding bibliography
entries, add \f[C]link\-citations:\ true\f[] to your YAML metadata.
.PP
Citations go inside square brackets and are separated by semicolons.
-Each citation must have a key, composed of `\@' + the citation
+Each citation must have a key, composed of \[aq]\@\[aq] + the citation
identifier from the database, and may optionally have a prefix, a
locator, and a suffix.
The citation key must begin with a letter, digit, or \f[C]_\f[], and may
@@ -4226,7 +4816,7 @@ singular or plural forms, as \f[C]book\f[], \f[C]bk.\f[]/\f[C]bks.\f[];
\f[C]s.v.\f[]/\f[C]s.vv.\f[]; \f[C]verse\f[], \f[C]v.\f[]/\f[C]vv.\f[];
\f[C]volume\f[], \f[C]vol.\f[]/\f[C]vols.\f[]; \f[C]¶\f[]/\f[C]¶¶\f[];
\f[C]§\f[]/\f[C]§§\f[].
-If no locator term is used, \[lq]page\[rq] is assumed.
+If no locator term is used, "page" is assumed.
.PP
A minus sign (\f[C]\-\f[]) before the \f[C]\@\f[] will suppress mention
of the author in the citation.
@@ -4311,15 +4901,36 @@ pandoc, but may be enabled by adding \f[C]+EXTENSION\f[] to the format
name, where \f[C]EXTENSION\f[] is the name of the extension.
Thus, for example, \f[C]markdown+hard_line_breaks\f[] is Markdown with
hard line breaks.
+.SS Extension: \f[C]old_dashes\f[]
+.PP
+Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes:
+\f[C]\-\f[] before a numeral is an en\-dash, and \f[C]\-\-\f[] is an
+em\-dash.
+This option only has an effect if \f[C]smart\f[] is enabled.
+It is selected automatically for \f[C]textile\f[] input.
.SS Extension: \f[C]angle_brackets_escapable\f[]
.PP
Allow \f[C]<\f[] and \f[C]>\f[] to be backslash\-escaped, as they can be
in GitHub flavored Markdown but not original Markdown.
-This is implied by pandoc's default \f[C]all_symbols_escapable\f[].
+This is implied by pandoc\[aq]s default \f[C]all_symbols_escapable\f[].
.SS Extension: \f[C]lists_without_preceding_blankline\f[]
.PP
Allow a list to occur right after a paragraph, with no intervening blank
space.
+.SS Extension: \f[C]four_space_rule\f[]
+.PP
+Selects the pandoc <= 2.0 behavior for parsing lists, so that four
+spaces indent are needed for list item continuation paragraphs.
+.SS Extension: \f[C]spaced_reference_links\f[]
+.PP
+Allow whitespace between the two components of a reference link, for
+example,
+.IP
+.nf
+\f[C]
+[foo]\ [bar].
+\f[]
+.fi
.SS Extension: \f[C]hard_line_breaks\f[]
.PP
Causes all newlines within a paragraph to be interpreted as hard line
@@ -4395,12 +5006,6 @@ opposed to being parsed as paragraphs).
.PP
Makes all absolute URIs into links, even when not surrounded by pointy
braces \f[C]<...>\f[].
-.SS Extension: \f[C]ascii_identifiers\f[]
-.PP
-Causes the identifiers produced by \f[C]auto_identifiers\f[] to be pure
-ASCII.
-Accents are stripped off of accented Latin letters, and non\-Latin
-letters are omitted.
.SS Extension: \f[C]mmd_link_attributes\f[]
.PP
Parses multimarkdown style key\-value attributes on link and image
@@ -4429,15 +5034,15 @@ in several respects:
No blank line is required between consecutive items of the definition
list.
.IP \[bu] 2
-To get a \[lq]tight\[rq] or \[lq]compact\[rq] list, omit space between
-consecutive items; the space between a term and its definition does not
-affect anything.
+To get a "tight" or "compact" list, omit space between consecutive
+items; the space between a term and its definition does not affect
+anything.
.IP \[bu] 2
Lazy wrapping of paragraphs is not allowed: the entire definition must
be indented four spaces.
.SS Markdown variants
.PP
-In addition to pandoc's extended Markdown, the following Markdown
+In addition to pandoc\[aq]s extended Markdown, the following Markdown
variants are supported:
.TP
.B \f[C]markdown_phpextra\f[] (PHP Markdown Extra)
@@ -4445,17 +5050,19 @@ variants are supported:
\f[C]markdown_attribute\f[], \f[C]fenced_code_blocks\f[],
\f[C]definition_lists\f[], \f[C]intraword_underscores\f[],
\f[C]header_attributes\f[], \f[C]link_attributes\f[],
-\f[C]abbreviations\f[], \f[C]shortcut_reference_links\f[].
+\f[C]abbreviations\f[], \f[C]shortcut_reference_links\f[],
+\f[C]spaced_reference_links\f[].
.RS
.RE
.TP
-.B \f[C]markdown_github\f[] (GitHub\-Flavored Markdown)
+.B \f[C]markdown_github\f[] (deprecated GitHub\-Flavored Markdown)
\f[C]pipe_tables\f[], \f[C]raw_html\f[], \f[C]fenced_code_blocks\f[],
-\f[C]auto_identifiers\f[], \f[C]ascii_identifiers\f[],
+\f[C]gfm_auto_identifiers\f[], \f[C]ascii_identifiers\f[],
\f[C]backtick_code_blocks\f[], \f[C]autolink_bare_uris\f[],
-\f[C]intraword_underscores\f[], \f[C]strikeout\f[],
-\f[C]hard_line_breaks\f[], \f[C]emoji\f[],
-\f[C]shortcut_reference_links\f[], \f[C]angle_brackets_escapable\f[].
+\f[C]space_in_atx_header\f[], \f[C]intraword_underscores\f[],
+\f[C]strikeout\f[], \f[C]emoji\f[], \f[C]shortcut_reference_links\f[],
+\f[C]angle_brackets_escapable\f[],
+\f[C]lists_without_preceding_blankline\f[].
.RS
.RE
.TP
@@ -4466,35 +5073,49 @@ variants are supported:
\f[C]footnotes\f[], \f[C]definition_lists\f[],
\f[C]all_symbols_escapable\f[], \f[C]implicit_header_references\f[],
\f[C]auto_identifiers\f[], \f[C]mmd_header_identifiers\f[],
-\f[C]shortcut_reference_links\f[].
+\f[C]shortcut_reference_links\f[], \f[C]implicit_figures\f[],
+\f[C]superscript\f[], \f[C]subscript\f[], \f[C]backtick_code_blocks\f[],
+\f[C]spaced_reference_links\f[], \f[C]raw_attribute\f[].
.RS
.RE
.TP
.B \f[C]markdown_strict\f[] (Markdown.pl)
-\f[C]raw_html\f[]
+\f[C]raw_html\f[], \f[C]shortcut_reference_links\f[],
+\f[C]spaced_reference_links\f[].
.RS
.RE
-.SS Extensions with formats other than Markdown
.PP
-Some of the extensions discussed above can be used with formats other
-than Markdown:
-.IP \[bu] 2
-\f[C]auto_identifiers\f[] can be used with \f[C]latex\f[], \f[C]rst\f[],
-\f[C]mediawiki\f[], and \f[C]textile\f[] input (and is used by default).
-.IP \[bu] 2
-\f[C]tex_math_dollars\f[], \f[C]tex_math_single_backslash\f[], and
-\f[C]tex_math_double_backslash\f[] can be used with \f[C]html\f[] input.
-(This is handy for reading web pages formatted using MathJax, for
-example.)
+We also support \f[C]commonmark\f[] and \f[C]gfm\f[] (GitHub\-Flavored
+Markdown, which is implemented as a set of extensions on
+\f[C]commonmark\f[]).
+.PP
+Note, however, that \f[C]commonmark\f[] and \f[C]gfm\f[] have limited
+support for extensions.
+Only those listed below (and \f[C]smart\f[] and \f[C]raw_tex\f[]) will
+work.
+The extensions can, however, all be individually disabled.
+Also, \f[C]raw_tex\f[] only affects \f[C]gfm\f[] output, not input.
+.TP
+.B \f[C]gfm\f[] (GitHub\-Flavored Markdown)
+\f[C]pipe_tables\f[], \f[C]raw_html\f[], \f[C]fenced_code_blocks\f[],
+\f[C]auto_identifiers\f[], \f[C]ascii_identifiers\f[],
+\f[C]backtick_code_blocks\f[], \f[C]autolink_bare_uris\f[],
+\f[C]intraword_underscores\f[], \f[C]strikeout\f[],
+\f[C]hard_line_breaks\f[], \f[C]emoji\f[],
+\f[C]shortcut_reference_links\f[], \f[C]angle_brackets_escapable\f[].
+.RS
+.RE
.SH PRODUCING SLIDE SHOWS WITH PANDOC
.PP
You can use pandoc to produce an HTML + JavaScript slide presentation
that can be viewed via a web browser.
There are five ways to do this, using S5, DZSlides, Slidy, Slideous, or
reveal.js.
-You can also produce a PDF slide show using LaTeX \f[C]beamer\f[].
+You can also produce a PDF slide show using LaTeX \f[C]beamer\f[], or
+slides shows in Microsoft PowerPoint format.
.PP
-Here's the Markdown source for a simple slide show, \f[C]habits.txt\f[]:
+Here\[aq]s the Markdown source for a simple slide show,
+\f[C]habits.txt\f[]:
.IP
.nf
\f[C]
@@ -4570,6 +5191,14 @@ pandoc\ \-t\ beamer\ habits.txt\ \-o\ habits.pdf
.PP
Note that a reveal.js slide show can also be converted to a PDF by
printing it to a file from the browser.
+.PP
+To produce a Powerpoint slide show, type
+.IP
+.nf
+\f[C]
+pandoc\ habits.txt\ \-o\ habits.pptx
+\f[]
+.fi
.SS Structuring the slide show
.PP
By default, the \f[I]slide level\f[] is the highest header level in the
@@ -4589,17 +5218,20 @@ A header at the slide level always starts a new slide.
Headers \f[I]below\f[] the slide level in the hierarchy create headers
\f[I]within\f[] a slide.
.IP \[bu] 2
-Headers \f[I]above\f[] the slide level in the hierarchy create
-\[lq]title slides,\[rq] which just contain the section title and help to
-break the slide show into sections.
+Headers \f[I]above\f[] the slide level in the hierarchy create "title
+slides," which just contain the section title and help to break the
+slide show into sections.
+.IP \[bu] 2
+Content \f[I]above\f[] the slide level will not appear in the slide
+show.
.IP \[bu] 2
-A title page is constructed automatically from the document's title
+A title page is constructed automatically from the document\[aq]s title
block, if present.
(In the case of beamer, this can be disabled by commenting out some
lines in the default template.)
.PP
These rules are designed to support many different styles of slide show.
-If you don't care about structuring your slides into sections and
+If you don\[aq]t care about structuring your slides into sections and
subsections, you can just use level 1 headers for all each slide.
(In that case, level 1 will be the slide level.) But you can also
structure the slide show into sections, as in the example above.
@@ -4611,12 +5243,45 @@ It is not recommended that you use deeper nesting of section levels with
reveal.js.
.SS Incremental lists
.PP
-By default, these writers produce lists that display \[lq]all at
-once.\[rq] If you want your lists to display incrementally (one item at
-a time), use the \f[C]\-i\f[] option.
-If you want a particular list to depart from the default (that is, to
+By default, these writers produce lists that display "all at once." If
+you want your lists to display incrementally (one item at a time), use
+the \f[C]\-i\f[] option.
+If you want a particular list to depart from the default, put it in a
+\f[C]div\f[] block with class \f[C]incremental\f[] or
+\f[C]nonincremental\f[].
+So, for example, using the \f[C]fenced\ div\f[] syntax, the following
+would be incremental regardless of the document default:
+.IP
+.nf
+\f[C]
+:::\ incremental
+
+\-\ Eat\ spaghetti
+\-\ Drink\ wine
+
+:::
+\f[]
+.fi
+.PP
+or
+.IP
+.nf
+\f[C]
+:::\ nonincremental
+
+\-\ Eat\ spaghetti
+\-\ Drink\ wine
+
+:::
+\f[]
+.fi
+.PP
+While using \f[C]incremental\f[] and \f[C]nonincremental\f[] divs are
+the recommended method of setting incremental lists on a per\-case
+basis, an older method is also supported: putting lists inside a
+blockquote will depart from the document default (that is, it will
display incrementally without the \f[C]\-i\f[] option and all at once
-with the \f[C]\-i\f[] option), put it in a block quote:
+with the \f[C]\-i\f[] option):
.IP
.nf
\f[C]
@@ -4625,12 +5290,12 @@ with the \f[C]\-i\f[] option), put it in a block quote:
\f[]
.fi
.PP
-In this way incremental and nonincremental lists can be mixed in a
+Both methods allow incremental and nonincremental lists to be mixed in a
single document.
.SS Inserting pauses
.PP
-You can add \[lq]pauses\[rq] within a slide by including a paragraph
-containing three dots, separated by spaces:
+You can add "pauses" within a slide by including a paragraph containing
+three dots, separated by spaces:
.IP
.nf
\f[C]
@@ -4650,8 +5315,8 @@ in \f[C]$DATADIR/s5/default\f[] (for S5), \f[C]$DATADIR/slidy\f[] (for
Slidy), or \f[C]$DATADIR/slideous\f[] (for Slideous), where
\f[C]$DATADIR\f[] is the user data directory (see
\f[C]\-\-data\-dir\f[], above).
-The originals may be found in pandoc's system data directory (generally
-\f[C]$CABALDIR/pandoc\-VERSION/s5/default\f[]).
+The originals may be found in pandoc\[aq]s system data directory
+(generally \f[C]$CABALDIR/pandoc\-VERSION/s5/default\f[]).
Pandoc will look there for any files it does not find in the user data
directory.
.PP
@@ -4696,25 +5361,47 @@ This is recommended especially for bibliographies:
.fi
.SS Speaker notes
.PP
-reveal.js has good support for speaker notes.
+Speaker notes are supported in reveal.js and PowerPoint (pptx) output.
You can add notes to your Markdown document thus:
.IP
.nf
\f[C]
-<div\ class="notes">
+:::\ notes
+
This\ is\ my\ note.
\-\ It\ can\ contain\ Markdown
\-\ like\ this\ list
-</div>
+:::
\f[]
.fi
.PP
-To show the notes window, press \f[C]s\f[] while viewing the
-presentation.
+To show the notes window in reveal.js, press \f[C]s\f[] while viewing
+the presentation.
+Speaker notes in PowerPoint will be available, as usual, in handouts and
+presenter view.
+.PP
Notes are not yet supported for other slide formats, but the notes will
not appear on the slides themselves.
+.SS Columns
+.PP
+To put material in side by side columns, you can use a native div
+container with class \f[C]columns\f[], containing two or more div
+containers with class \f[C]column\f[] and a \f[C]width\f[] attribute:
+.IP
+.nf
+\f[C]
+::::::::::::::\ {.columns}
+:::\ {.column\ width="40%"}
+contents...
+:::
+:::\ {.column\ width="60%"}
+contents...
+:::
+::::::::::::::
+\f[]
+.fi
.SS Frame attributes in beamer
.PP
Sometimes it is necessary to add the LaTeX \f[C][fragile]\f[] option to
@@ -4730,7 +5417,7 @@ introducing the slide:
.fi
.PP
All of the other frame attributes described in Section 8.1 of the Beamer
-User's Guide may also be used: \f[C]allowdisplaybreaks\f[],
+User\[aq]s Guide may also be used: \f[C]allowdisplaybreaks\f[],
\f[C]allowframebreaks\f[], \f[C]b\f[], \f[C]c\f[], \f[C]t\f[],
\f[C]environment\f[], \f[C]label\f[], \f[C]plain\f[], \f[C]shrink\f[].
.SH CREATING EPUBS WITH PANDOC
@@ -4759,6 +5446,8 @@ identifier:
\ \ text:\ doi:10.234234.234/33
publisher:\ \ My\ Press
rights:\ ©\ 2007\ John\ Smith,\ CC\ BY\-NC
+ibooks:
+\ \ version:\ 1.3.4
\&...
\f[]
.fi
@@ -4789,8 +5478,8 @@ Valid values for \f[C]type\f[] are \f[C]main\f[], \f[C]subtitle\f[],
Either a string value, or an object with fields \f[C]role\f[],
\f[C]file\-as\f[], and \f[C]text\f[], or a list of such objects.
Valid values for \f[C]role\f[] are MARC relators, but pandoc will
-attempt to translate the human\-readable versions (like \[lq]author\[rq]
-and \[lq]editor\[rq]) to the appropriate marc relators.
+attempt to translate the human\-readable versions (like "author" and
+"editor") to the appropriate marc relators.
.RS
.RE
.TP
@@ -4863,6 +5552,27 @@ Specifies the \f[C]page\-progression\-direction\f[] attribute for the
\f[C]spine\f[] element.
.RS
.RE
+.TP
+.B \f[C]ibooks\f[]
+iBooks\-specific metadata, with the following fields:
+.RS
+.IP \[bu] 2
+\f[C]version\f[]: (string)
+.IP \[bu] 2
+\f[C]specified\-fonts\f[]: \f[C]true\f[]|\f[C]false\f[] (default
+\f[C]false\f[])
+.IP \[bu] 2
+\f[C]ipad\-orientation\-lock\f[]:
+\f[C]portrait\-only\f[]|\f[C]landscape\-only\f[]
+.IP \[bu] 2
+\f[C]iphone\-orientation\-lock\f[]:
+\f[C]portrait\-only\f[]|\f[C]landscape\-only\f[]
+.IP \[bu] 2
+\f[C]binding\f[]: \f[C]true\f[]|\f[C]false\f[] (default \f[C]true\f[])
+.IP \[bu] 2
+\f[C]scroll\-axis\f[]:
+\f[C]vertical\f[]|\f[C]horizontal\f[]|\f[C]default\f[]
+.RE
.SS Linked media
.PP
By default, pandoc will download linked media (including audio and
@@ -4882,70 +5592,12 @@ For example:
</audio>
\f[]
.fi
-.SH LITERATE HASKELL SUPPORT
-.PP
-If you append \f[C]+lhs\f[] (or \f[C]+literate_haskell\f[]) to an
-appropriate input or output format (\f[C]markdown\f[],
-\f[C]markdown_strict\f[], \f[C]rst\f[], or \f[C]latex\f[] for input or
-output; \f[C]beamer\f[], \f[C]html\f[] or \f[C]html5\f[] for output
-only), pandoc will treat the document as literate Haskell source.
-This means that
-.IP \[bu] 2
-In Markdown input, \[lq]bird track\[rq] sections will be parsed as
-Haskell code rather than block quotations.
-Text between \f[C]\\begin{code}\f[] and \f[C]\\end{code}\f[] will also
-be treated as Haskell code.
-For ATX\-style headers the character `=' will be used instead of `#'.
-.IP \[bu] 2
-In Markdown output, code blocks with classes \f[C]haskell\f[] and
-\f[C]literate\f[] will be rendered using bird tracks, and block
-quotations will be indented one space, so they will not be treated as
-Haskell code.
-In addition, headers will be rendered setext\-style (with underlines)
-rather than ATX\-style (with `#' characters).
-(This is because ghc treats `#' characters in column 1 as introducing
-line numbers.)
-.IP \[bu] 2
-In restructured text input, \[lq]bird track\[rq] sections will be parsed
-as Haskell code.
-.IP \[bu] 2
-In restructured text output, code blocks with class \f[C]haskell\f[]
-will be rendered using bird tracks.
-.IP \[bu] 2
-In LaTeX input, text in \f[C]code\f[] environments will be parsed as
-Haskell code.
-.IP \[bu] 2
-In LaTeX output, code blocks with class \f[C]haskell\f[] will be
-rendered inside \f[C]code\f[] environments.
-.IP \[bu] 2
-In HTML output, code blocks with class \f[C]haskell\f[] will be rendered
-with class \f[C]literatehaskell\f[] and bird tracks.
-.PP
-Examples:
-.IP
-.nf
-\f[C]
-pandoc\ \-f\ markdown+lhs\ \-t\ html
-\f[]
-.fi
-.PP
-reads literate Haskell source formatted with Markdown conventions and
-writes ordinary HTML (without bird tracks).
-.IP
-.nf
-\f[C]
-pandoc\ \-f\ markdown+lhs\ \-t\ html+lhs
-\f[]
-.fi
-.PP
-writes HTML with the Haskell code in bird tracks, so it can be copied
-and pasted as literate Haskell source.
.SH SYNTAX HIGHLIGHTING
.PP
Pandoc will automatically highlight syntax in fenced code blocks that
are marked with a language name.
-The Haskell library highlighting\-kate is used for highlighting, which
-works in HTML, Docx, and LaTeX/PDF output.
+The Haskell library skylighting is used for highlighting, which works in
+HTML, Docx, Ms, and LaTeX/PDF output.
To see a list of language names that pandoc will recognize, type
\f[C]pandoc\ \-\-list\-highlight\-languages\f[].
.PP
@@ -4958,10 +5610,65 @@ To see a list of highlight styles, type
\f[C]pandoc\ \-\-list\-highlight\-styles\f[].
.PP
To disable highlighting, use the \f[C]\-\-no\-highlight\f[] option.
-.SH CUSTOM STYLES IN DOCX OUTPUT
+.SH CUSTOM STYLES IN DOCX
+.SS Input
+.PP
+The docx reader, by default, only reads those styles that it can convert
+into pandoc elements, either by direct conversion or interpreting the
+derivation of the input document\[aq]s styles.
+.PP
+By enabling the \f[C]styles\f[] extension in the docx reader
+(\f[C]\-f\ docx+styles\f[]), you can produce output that maintains the
+styles of the input document, using the \f[C]custom\-style\f[] class.
+Paragraph styles are interpreted as divs, while character styles are
+interpreted as spans.
+.PP
+For example, using the \f[C]custom\-style\-reference.docx\f[] file in
+the test directory, we have the following different outputs:
+.PP
+Without the \f[C]+styles\f[] extension:
+.IP
+.nf
+\f[C]
+$\ pandoc\ test/docx/custom\-style\-reference.docx\ \-f\ docx\ \-t\ markdown
+This\ is\ some\ text.
+
+This\ is\ text\ with\ an\ *emphasized*\ text\ style.\ And\ this\ is\ text\ with\ a
+**strengthened**\ text\ style.
+
+>\ Here\ is\ a\ styled\ paragraph\ that\ inherits\ from\ Block\ Text.
+\f[]
+.fi
+.PP
+And with the extension:
+.IP
+.nf
+\f[C]
+$\ pandoc\ test/docx/custom\-style\-reference.docx\ \-f\ docx+styles\ \-t\ markdown
+
+:::\ {custom\-style="FirstParagraph"}
+This\ is\ some\ text.
+:::
+
+:::\ {custom\-style="BodyText"}
+This\ is\ text\ with\ an\ [emphasized]{custom\-style="Emphatic"}\ text\ style.
+And\ this\ is\ text\ with\ a\ [strengthened]{custom\-style="Strengthened"}
+text\ style.
+:::
+
+:::\ {custom\-style="MyBlockStyle"}
+>\ Here\ is\ a\ styled\ paragraph\ that\ inherits\ from\ Block\ Text.
+:::
+\f[]
+.fi
+.PP
+With these custom styles, you can use your input document as a
+reference\-doc while creating docx output (see below), and maintain the
+same styles in your input and output files.
+.SS Output
.PP
-By default, pandoc's docx output applies a predefined set of styles for
-blocks such as paragraphs and block quotes, and uses largely default
+By default, pandoc\[aq]s docx output applies a predefined set of styles
+for blocks such as paragraphs and block quotes, and uses largely default
formatting (italics, bold) for inlines.
This will work for most purposes, especially alongside a
\f[C]reference.docx\f[] file.
@@ -4972,26 +5679,26 @@ blocks and text using \f[C]div\f[]s and \f[C]span\f[]s, respectively.
If you define a \f[C]div\f[] or \f[C]span\f[] with the attribute
\f[C]custom\-style\f[], pandoc will apply your specified style to the
contained elements.
-So, for example,
+So, for example using the \f[C]bracketed_spans\f[] syntax,
.IP
.nf
\f[C]
-<span\ custom\-style="Emphatically">Get\ out,</span>\ he\ said.
+[Get\ out]{custom\-style="Emphatically"},\ he\ said.
\f[]
.fi
.PP
-would produce a docx file with \[lq]Get out,\[rq] styled with character
-style \f[C]Emphatically\f[].
-Similarly,
+would produce a docx file with "Get out" styled with character style
+\f[C]Emphatically\f[].
+Similarly, using the \f[C]fenced_divs\f[] syntax,
.IP
.nf
\f[C]
Dickinson\ starts\ the\ poem\ simply:
-<div\ custom\-style="Poetry">
+:::\ {custom\-style="Poetry"}
|\ A\ Bird\ came\ down\ the\ Walk\-\-\-
|\ He\ did\ not\ know\ I\ saw\-\-\-
-</div>
+:::
\f[]
.fi
.PP
@@ -5038,55 +5745,11 @@ pandoc\ \-\-print\-default\-data\-file\ sample.lua
.fi
.SH AUTHORS
.PP
-© 2006\-2016 John MacFarlane (jgm\@berkeley.edu).
+Copyright 2006\-2017 John MacFarlane (jgm\@berkeley.edu).
Released under the GPL, version 2 or greater.
This software carries no warranty of any kind.
-(See COPYRIGHT for full copyright and warranty notices.)
-.PP
-Contributors include Arata Mizuki, Aaron Wolen, Albert Krewinkel, Alex
-Ivkin, Alex Vong, Alexander Kondratskiy, Alexander Sulfrian, Alexander V
-Vershilov, Alfred Wechselberger, Andreas Lööw, Andrew Dunning, Antoine
-Latter, Arata Mizuki, Arlo O'Keeffe, Artyom Kazak, B.
-Scott Michel, Ben Gamari, Beni Cherniavsky\-Paskin, Benoit Schweblin,
-Bjorn Buckwalter, Bradley Kuhn, Brent Yorgey, Bryan O'Sullivan, Caleb
-McDaniel, Calvin Beck, Carlos Sosa, Chris Black, Christian Conkle,
-Christoffer Ackelman, Christoffer Sawicki, Clare Macrae, Clint Adams,
-Conal Elliott, Craig S.
-Bosma, Daniel Bergey, Daniel T.
-Staal, Daniele D'Orazio, David Lazar, David Röthlisberger, Denis
-Laxalde, Douglas Calvert, Emanuel Evans, Emily Eisenberg, Eric Kow, Eric
-Seidel, Felix Yan, Florian Eitel, François Gannaz, Freiric Barral,
-Freirich Raabe, Frerich Raabe, Fyodor Sheremetyev, Gabor Pali, Gavin
-Beatty, Gottfried Haider, Greg Maslov, Greg Rundlett, Grégory Bataille,
-Gwern Branwen, Hans\-Peter Deifel, Henrik Tramberend, Henry de Valence,
-Hubert Plociniczak, Ilya V.
-Portnov, Ivo Clarysse, J.
-Lewis Muir, Jaime Marquínez Ferrándiz, Jakob Voß, James Aspnes, Jamie F.
-Olson, Jan Larres, Jan Schulz, Jason Ronallo, Jeff Arnold, Jeff
-Runningen, Jens Petersen, Jesse Rosenthal, Joe Hillenbrand, John
-MacFarlane, John Muccigrosso, Jonas Smedegaard, Jonathan Daugherty, Jose
-Luis Duran, Josef Svenningsson, Julien Cretel, Juliusz Gonera, Justin
-Bogner, Jérémy Bobbio, Kelsey Hightower, Kolen Cheung, Konstantin Zudov,
-Kristof Bastiaensen, Lars\-Dominik Braun, Luke Plant, Mark Szepieniec,
-Mark Wright, Martin Linn, Masayoshi Takahashi, Matej Kollar, Mathias
-Schenner, Mathieu Duponchelle, Matthew Eddey, Matthew Pickering,
-Matthias C.
-M.
-Troffaes, Mauro Bieg, Max Bolingbroke, Max Rydahl Andersen, Merijn
-Verstraaten, Michael Beaumont, Michael Chladek, Michael Snoyman, Michael
-Thompson, MinRK, Morton Fox, Nathan Gass, Neil Mayhew, Nick Bart,
-Nicolas Kaiser, Nikolay Yakimov, Oliver Matthews, Ophir Lifshitz, Pablo
-Rodríguez, Paul Rivier, Paulo Tanimoto, Peter Wang, Philippe Ombredanne,
-Phillip Alday, Prayag Verma, Puneeth Chaganti, Ralf Stephan, Raniere
-Silva, Recai Oktaş, RyanGlScott, Scott Morrison, Sergei Trofimovich,
-Sergey Astanin, Shahbaz Youssefi, Shaun Attfield, Sidarth Kapur,
-Sidharth Kapur, Simon Hengel, Sumit Sahrawat, Thomas Hodgson, Thomas
-Weißschuh, Tim Lin, Timothy Humphries, Tiziano Müller, Todd Sifleet, Tom
-Leese, Uli Köhler, Václav Zeman, Viktor Kronvall, Vincent, Václav
-Haisman, Václav Zeman, Wandmalfarbe, Waldir Pimenta, Wikiwide, Xavier
-Olive, bumper314, csforste, infinity0x, nkalvi, qerub, robabla,
-roblabla, rodja.trappe, rski, shreevatsa.public, takahashim, tgkokk,
-thsutton.
+(See COPYRIGHT for full copyright and warranty notices.) For a full list
+of contributors, see the file AUTHORS.md in the pandoc source code.
.PP
The Pandoc source code and all documentation may be downloaded
from <http://pandoc.org>.
diff --git a/man/removeLinks.hs b/man/removeLinks.hs
deleted file mode 100644
index 52414ebd0..000000000
--- a/man/removeLinks.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-import Text.Pandoc.JSON
-
-main :: IO ()
-main = toJSONFilter removeLinks
-
-removeLinks :: Inline -> [Inline]
-removeLinks (Link _ l _) = l
-removeLinks x = [x]
-
diff --git a/man/removeNotes.hs b/man/removeNotes.hs
deleted file mode 100644
index e61cb932a..000000000
--- a/man/removeNotes.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-import Text.Pandoc.JSON
-
-main :: IO ()
-main = toJSONFilter removeNotes
-
-removeNotes :: Inline -> Inline
-removeNotes (Note _) = Str ""
-removeNotes x = x
-
diff --git a/pandoc.cabal b/pandoc.cabal
index e2b19dfe5..a11a1bb63 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,31 +1,33 @@
-Name: pandoc
-Version: 1.19.2.4
-Cabal-Version: >= 1.10
-Build-Type: Custom
-License: GPL
-License-File: COPYING.md
-Copyright: (c) 2006-2017 John MacFarlane
-Author: John MacFarlane <jgm@berkeley.edu>
-Maintainer: John MacFarlane <jgm@berkeley.edu>
-Bug-Reports: https://github.com/jgm/pandoc/issues
-Stability: alpha
-Homepage: http://pandoc.org
-Category: Text
-Tested-With: GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1
-Synopsis: Conversion between markup formats
-Description: Pandoc is a Haskell library for converting from one markup
+name: pandoc
+version: 2.1.2
+cabal-version: >= 1.10
+build-type: Custom
+license: GPL
+license-file: COPYING.md
+copyright: (c) 2006-2018 John MacFarlane
+author: John MacFarlane <jgm@berkeley.edu>
+maintainer: John MacFarlane <jgm@berkeley.edu>
+bug-reports: https://github.com/jgm/pandoc/issues
+stability: alpha
+homepage: http://pandoc.org
+category: Text
+tested-with: GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2
+synopsis: Conversion between markup formats
+description: Pandoc is a Haskell library for converting from one markup
format to another, and a command-line tool that uses
this library. It can read several dialects of Markdown and
- (subsets of) HTML, reStructuredText, LaTeX, DocBook,
- MediaWiki markup, TWiki markup, Haddock markup, OPML,
- Emacs Org-Mode, txt2tags, Word Docx, ODT, and Textile, and
- it can write Markdown, reStructuredText, XHTML, HTML 5,
- LaTeX, ConTeXt, DocBook, OPML, TEI, OpenDocument, ODT,
- Word docx, RTF, MediaWiki, DokuWiki, ZimWiki, Textile,
- groff man pages, plain text, Emacs Org-Mode, AsciiDoc,
- Haddock markup, EPUB (v2 and v3), FictionBook2, InDesign ICML,
- and several kinds of HTML/javascript slide shows (S5, Slidy,
- Slideous, DZSlides, reveal.js).
+ (subsets of) HTML, reStructuredText, LaTeX, DocBook, JATS,
+ MediaWiki markup, TWiki markup, TikiWiki markup, Creole 1.0,
+ Haddock markup, OPML, Emacs Org-Mode, Emacs Muse, txt2tags,
+ Vimwiki, Word Docx, ODT, and Textile, and it can write
+ Markdown, reStructuredText, XHTML, HTML 5, LaTeX, ConTeXt,
+ DocBook, JATS, OPML, TEI, OpenDocument, ODT, Word docx,
+ RTF, MediaWiki, DokuWiki, ZimWiki, Textile, groff man,
+ groff ms, plain text, Emacs Org-Mode, AsciiDoc,
+ Haddock markup, EPUB (v2 and v3), FictionBook2, InDesign
+ ICML, Muse, LaTeX beamer slides, PowerPoint, and several
+ kinds of HTML/JavaScript slide shows (S5, Slidy, Slideous,
+ DZSlides, reveal.js).
.
In contrast to most existing tools for converting Markdown
to HTML, pandoc has a modular design: it consists of a set of
@@ -34,14 +36,14 @@ Description: Pandoc is a Haskell library for converting from one markup
which convert this native representation into a target
format. Thus, adding an input or output format requires
only adding a reader or writer.
-Data-Files:
+data-files:
-- templates
- data/templates/default.html
+ data/templates/default.html4
data/templates/default.html5
- data/templates/default.docbook
+ data/templates/default.docbook4
data/templates/default.docbook5
+ data/templates/default.jats
data/templates/default.tei
- data/templates/default.beamer
data/templates/default.opendocument
data/templates/default.icml
data/templates/default.opml
@@ -49,7 +51,9 @@ Data-Files:
data/templates/default.context
data/templates/default.texinfo
data/templates/default.man
+ data/templates/default.ms
data/templates/default.markdown
+ data/templates/default.muse
data/templates/default.commonmark
data/templates/default.rst
data/templates/default.plain
@@ -66,8 +70,10 @@ Data-Files:
data/templates/default.haddock
data/templates/default.textile
data/templates/default.org
- data/templates/default.epub
+ data/templates/default.epub2
data/templates/default.epub3
+ -- translations
+ data/translations/*.yaml
-- source files for reference.docx
data/docx/[Content_Types].xml
data/docx/_rels/.rels
@@ -75,6 +81,7 @@ Data-Files:
data/docx/docProps/core.xml
data/docx/word/document.xml
data/docx/word/fontTable.xml
+ data/docx/word/comments.xml
data/docx/word/footnotes.xml
data/docx/word/numbering.xml
data/docx/word/settings.xml
@@ -93,269 +100,367 @@ Data-Files:
data/odt/Configurations2/accelerator/current.xml
data/odt/Thumbnails/thumbnail.png
data/odt/META-INF/manifest.xml
+ -- source files for reference.pptx
+ data/pptx/_rels/.rels
+ data/pptx/docProps/thumbnail.jpeg
+ data/pptx/docProps/app.xml
+ data/pptx/docProps/core.xml
+ data/pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels
+ data/pptx/ppt/slideLayouts/slideLayout1.xml
+ data/pptx/ppt/slideLayouts/slideLayout2.xml
+ data/pptx/ppt/slideLayouts/slideLayout3.xml
+ data/pptx/ppt/slideLayouts/slideLayout4.xml
+ data/pptx/ppt/slideLayouts/slideLayout5.xml
+ data/pptx/ppt/slideLayouts/slideLayout6.xml
+ data/pptx/ppt/slideLayouts/slideLayout7.xml
+ data/pptx/ppt/slideLayouts/slideLayout8.xml
+ data/pptx/ppt/slideLayouts/slideLayout9.xml
+ data/pptx/ppt/slideLayouts/slideLayout10.xml
+ data/pptx/ppt/slideLayouts/slideLayout11.xml
+ data/pptx/ppt/_rels/presentation.xml.rels
+ data/pptx/ppt/theme/theme1.xml
+ data/pptx/ppt/presProps.xml
+ data/pptx/ppt/slides/_rels/slide1.xml.rels
+ data/pptx/ppt/slides/_rels/slide2.xml.rels
+ data/pptx/ppt/slides/slide2.xml
+ data/pptx/ppt/slides/slide1.xml
+ data/pptx/ppt/viewProps.xml
+ data/pptx/ppt/tableStyles.xml
+ data/pptx/ppt/slideMasters/_rels/slideMaster1.xml.rels
+ data/pptx/ppt/slideMasters/slideMaster1.xml
+ data/pptx/ppt/presentation.xml
+ data/pptx/ppt/notesMasters/_rels/notesMaster1.xml.rels
+ data/pptx/ppt/notesMasters/notesMaster1.xml
+ data/pptx/ppt/notesSlides/_rels/notesSlide1.xml.rels
+ data/pptx/ppt/notesSlides/notesSlide1.xml
+ data/pptx/ppt/notesSlides/_rels/notesSlide2.xml.rels
+ data/pptx/ppt/notesSlides/notesSlide2.xml
+ data/pptx/ppt/theme/theme2.xml
+ data/pptx/[Content_Types].xml
-- stylesheet for EPUB writer
data/epub.css
-- data for LaTeXMathML writer
data/LaTeXMathML.js
-- data for dzslides writer
data/dzslides/template.html
+ -- default abbreviations file
+ data/abbreviations
-- sample lua custom writer
data/sample.lua
+ -- lua init script
+ data/init.lua
+ -- pandoc lua module
+ data/pandoc.lua
+ -- lua List module
+ data/pandoc.List.lua
-- bash completion template
data/bash_completion.tpl
+ -- jats csl
+ data/jats.csl
-- documentation
MANUAL.txt, COPYRIGHT
-Extra-Source-Files:
+extra-source-files:
-- documentation
- INSTALL.md, BUGS, README.md, CONTRIBUTING.md, changelog
+ INSTALL.md, AUTHORS.md, README.md,
+ CONTRIBUTING.md, BUGS, changelog,
man/pandoc.1
-- stack build plan
stack.yaml
-- files needed to build man page
- man/capitalizeHeaders.hs
- man/removeNotes.hs
- man/removeLinks.hs
+ man/manfilter.lua
man/pandoc.1.template
-- trypandoc
trypandoc/Makefile
trypandoc/index.html
-- tests
- tests/bodybg.gif
- tests/*.native
- tests/docbook-reader.docbook
- tests/docbook-xref.docbook
- tests/html-reader.html
- tests/opml-reader.opml
- tests/haddock-reader.haddock
- tests/insert
- tests/lalune.jpg
- tests/movie.jpg
- tests/media/rId25.jpg
- tests/media/rId26.jpg
- tests/media/rId27.jpg
- tests/latex-reader.latex
- tests/textile-reader.textile
- tests/markdown-reader-more.txt
- tests/markdown-citations.txt
- tests/textile-reader.textile
- tests/mediawiki-reader.wiki
- tests/rst-reader.rst
- tests/s5-basic.html
- tests/s5-fancy.html
- tests/s5-fragment.html
- tests/s5-inserts.html
- tests/tables.context
- tests/tables.docbook
- tests/tables.docbook5
- tests/tables.dokuwiki
- tests/tables.zimwiki
- tests/tables.icml
- tests/tables.html
- tests/tables.latex
- tests/tables.man
- tests/tables.plain
- tests/tables.markdown
- tests/tables.mediawiki
- tests/tables.tei
- tests/tables.textile
- tests/tables.opendocument
- tests/tables.org
- tests/tables.asciidoc
- tests/tables.haddock
- tests/tables.texinfo
- tests/tables.rst
- tests/tables.rtf
- tests/tables.txt
- tests/tables.fb2
- tests/testsuite.txt
- tests/writer.latex
- tests/writer.context
- tests/writer.docbook
- tests/writer.docbook5
- tests/writer.html
- tests/writer.man
- tests/writer.markdown
- tests/writer.plain
- tests/writer.mediawiki
- tests/writer.textile
- tests/writer.opendocument
- tests/writer.org
- tests/writer.asciidoc
- tests/writer.haddock
- tests/writer.rst
- tests/writer.icml
- tests/writer.rtf
- tests/writer.tei
- tests/writer.texinfo
- tests/writer.fb2
- tests/writer.opml
- tests/writer.dokuwiki
- tests/writer.zimwiki
- tests/writers-lang-and-dir.latex
- tests/writers-lang-and-dir.context
- tests/dokuwiki_inline_formatting.dokuwiki
- tests/lhs-test.markdown
- tests/lhs-test.markdown+lhs
- tests/lhs-test.rst
- tests/lhs-test.rst+lhs
- tests/lhs-test.latex
- tests/lhs-test.latex+lhs
- tests/lhs-test.html
- tests/lhs-test.html+lhs
- tests/lhs-test.fragment.html+lhs
- tests/pipe-tables.txt
- tests/dokuwiki_external_images.dokuwiki
- tests/dokuwiki_external_images.native
- tests/dokuwiki_multiblock_table.dokuwiki
- tests/dokuwiki_multiblock_table.native
- tests/fb2/*.markdown
- tests/fb2/*.fb2
- tests/fb2/images-embedded.html
- tests/fb2/images-embedded.fb2
- tests/fb2/test-small.png
- tests/fb2/test.jpg
- tests/docx/*.docx
- tests/docx/*.native
- tests/epub/*.epub
- tests/epub/*.native
- tests/txt2tags.t2t
- tests/twiki-reader.twiki
- tests/odt/odt/*.odt
- tests/odt/markdown/*.md
- tests/odt/native/*.native
-Source-repository head
+ test/bodybg.gif
+ test/*.native
+ test/command/*.md
+ test/command/3533-rst-csv-tables.csv
+ test/command/3880.txt
+ test/command/abbrevs
+ test/command/SVG_logo-without-xml-declaration.svg
+ test/command/SVG_logo.svg
+ test/command/corrupt.svg
+ test/command/inkscape-cube.svg
+ test/command/sub-file-chapter-1.tex
+ test/command/sub-file-chapter-2.tex
+ test/command/3510-subdoc.org
+ test/command/3510-export.latex
+ test/command/3510-src.hs
+ test/command/3971b.tex
+ test/docbook-reader.docbook
+ test/docbook-xref.docbook
+ test/html-reader.html
+ test/opml-reader.opml
+ test/haddock-reader.haddock
+ test/insert
+ test/lalune.jpg
+ test/movie.jpg
+ test/media/rId25.jpg
+ test/media/rId26.jpg
+ test/media/rId27.jpg
+ test/latex-reader.latex
+ test/textile-reader.textile
+ test/markdown-reader-more.txt
+ test/markdown-citations.txt
+ test/textile-reader.textile
+ test/mediawiki-reader.wiki
+ test/vimwiki-reader.wiki
+ test/creole-reader.txt
+ test/creole-reader.native
+ test/rst-reader.rst
+ test/jats-reader.xml
+ test/s5-basic.html
+ test/s5-fancy.html
+ test/s5-fragment.html
+ test/s5-inserts.html
+ test/tables.context
+ test/tables.docbook4
+ test/tables.docbook5
+ test/tables.jats
+ test/tables.dokuwiki
+ test/tables.zimwiki
+ test/tables.icml
+ test/tables.html4
+ test/tables.html5
+ test/tables.latex
+ test/tables.man
+ test/tables.ms
+ test/tables.plain
+ test/tables.markdown
+ test/tables.mediawiki
+ test/tables.tei
+ test/tables.textile
+ test/tables.opendocument
+ test/tables.org
+ test/tables.asciidoc
+ test/tables.haddock
+ test/tables.texinfo
+ test/tables.rst
+ test/tables.rtf
+ test/tables.txt
+ test/tables.fb2
+ test/tables.muse
+ test/tables.custom
+ test/testsuite.txt
+ test/writer.latex
+ test/writer.context
+ test/writer.docbook4
+ test/writer.docbook5
+ test/writer.jats
+ test/writer.html4
+ test/writer.html5
+ test/writer.man
+ test/writer.ms
+ test/writer.markdown
+ test/writer.plain
+ test/writer.mediawiki
+ test/writer.textile
+ test/writer.opendocument
+ test/writer.org
+ test/writer.asciidoc
+ test/writer.haddock
+ test/writer.rst
+ test/writer.icml
+ test/writer.rtf
+ test/writer.tei
+ test/writer.texinfo
+ test/writer.fb2
+ test/writer.opml
+ test/writer.dokuwiki
+ test/writer.zimwiki
+ test/writer.muse
+ test/writer.custom
+ test/writers-lang-and-dir.latex
+ test/writers-lang-and-dir.context
+ test/dokuwiki_inline_formatting.dokuwiki
+ test/lhs-test.markdown
+ test/lhs-test.markdown+lhs
+ test/lhs-test.rst
+ test/lhs-test.rst+lhs
+ test/lhs-test.latex
+ test/lhs-test.latex+lhs
+ test/lhs-test.html
+ test/lhs-test.html+lhs
+ test/lhs-test.fragment.html+lhs
+ test/pipe-tables.txt
+ test/dokuwiki_external_images.dokuwiki
+ test/dokuwiki_external_images.native
+ test/dokuwiki_multiblock_table.dokuwiki
+ test/dokuwiki_multiblock_table.native
+ test/fb2/*.markdown
+ test/fb2/*.fb2
+ test/fb2/images-embedded.html
+ test/fb2/images-embedded.fb2
+ test/fb2/test-small.png
+ test/fb2/test.jpg
+ test/docx/*.docx
+ test/docx/golden/*.docx
+ test/docx/*.native
+ test/epub/*.epub
+ test/epub/*.native
+ test/pptx/*.pptx
+ test/pptx/*.native
+ test/txt2tags.t2t
+ test/twiki-reader.twiki
+ test/tikiwiki-reader.tikiwiki
+ test/odt/odt/*.odt
+ test/odt/markdown/*.md
+ test/odt/native/*.native
+ test/lua/*.lua
+source-repository head
type: git
location: git://github.com/jgm/pandoc.git
-Flag embed_data_files
+flag static
+ Description: Use static linking for pandoc executable.
+ Default: False
+
+flag embed_data_files
Description: Embed data files in binary for relocatable executable.
Default: False
-Flag trypandoc
+flag trypandoc
Description: Build trypandoc cgi executable.
Default: False
-Flag weigh-pandoc
+flag weigh-pandoc
Description: Build weigh-pandoc to measure memory usage.
Default: False
-Flag https
- Description: Enable support for downloading of resources over https.
- Default: True
-
-Flag network-uri
+flag network-uri
Description: Get Network.URI from the network-uri package
Default: True
-Flag old-locale
+flag old-locale
Description: Use old-locale and time < 1.5
Default: False
custom-setup
- setup-depends: base,
- Cabal
+ setup-depends: base, Cabal
-Library
- Build-Depends: base >= 4.7 && <5,
+library
+ build-depends: base >= 4.7 && < 5,
syb >= 0.1 && < 0.8,
- containers >= 0.1 && < 0.6,
+ containers >= 0.4.2.1 && < 0.6,
unordered-containers >= 0.2 && < 0.3,
- array >= 0.3 && < 0.6,
parsec >= 3.1 && < 3.2,
mtl >= 2.2 && < 2.3,
+ exceptions >= 0.8 && < 0.10,
filepath >= 1.1 && < 1.5,
- process >= 1 && < 1.7,
+ process >= 1.2.3 && < 1.7,
directory >= 1 && < 1.4,
bytestring >= 0.9 && < 0.11,
text >= 0.11 && < 1.3,
+ safe >= 0.3 && < 0.4,
zip-archive >= 0.2.3.4 && < 0.4,
HTTP >= 4000.0.5 && < 4000.4,
- texmath >= 0.9 && < 0.10,
+ texmath >= 0.10 && < 0.11,
xml >= 1.3.12 && < 1.4,
+ split >= 0.2 && < 0.3,
random >= 1 && < 1.2,
- extensible-exceptions >= 0.1 && < 0.2,
- pandoc-types >= 1.17 && < 1.17.1,
+ pandoc-types >= 1.17.3 && < 1.18,
aeson >= 0.7 && < 1.3,
- tagsoup >= 0.13.7 && < 0.15,
+ aeson-pretty >= 0.8.5 && < 0.9,
+ tagsoup >= 0.14.6 && < 0.15,
base64-bytestring >= 0.1 && < 1.1,
zlib >= 0.5 && < 0.7,
- skylighting >= 0.1.1.4 && < 0.2,
+ skylighting >= 0.5.1 && < 0.7,
data-default >= 0.4 && < 0.8,
temporary >= 1.1 && < 1.3,
- blaze-html >= 0.5 && < 0.10,
- blaze-markup >= 0.5.1 && < 0.9,
+ blaze-html >= 0.9 && < 0.10,
+ blaze-markup >= 0.8 && < 0.9,
yaml >= 0.8.8.2 && < 0.9,
scientific >= 0.2 && < 0.4,
vector >= 0.10 && < 0.13,
- hslua >= 0.3 && < 0.5,
+ hslua >= 0.9.5 && < 0.9.6,
+ hslua-module-text >= 0.1.2 && < 0.2,
binary >= 0.5 && < 0.10,
SHA >= 1.6 && < 1.7,
haddock-library >= 1.1 && < 1.5,
- old-time,
deepseq >= 1.3 && < 1.5,
JuicyPixels >= 3.1.6.1 && < 3.3,
- filemanip >= 0.3 && < 0.4,
- cmark >= 0.5 && < 0.6,
- doctemplates >= 0.1 && < 0.2,
- ghc-prim >= 0.2
+ Glob >= 0.7 && < 0.10,
+ cmark-gfm >= 0.1.1 && < 0.2,
+ doctemplates >= 0.2.1 && < 0.3,
+ http-client >= 0.4.30 && < 0.6,
+ http-client-tls >= 0.2.4 && < 0.4,
+ http-types >= 0.8 && < 0.12,
+ case-insensitive >= 1.2 && < 1.3
+ if os(windows)
+ cpp-options: -D_WINDOWS
+ else
+ build-depends: unix >= 2.4 && < 2.8
if flag(old-locale)
- Build-Depends: old-locale >= 1 && < 1.1,
+ build-depends: old-locale >= 1 && < 1.1,
time >= 1.2 && < 1.5
else
- Build-Depends: time >= 1.5 && < 1.9
+ build-depends: time >= 1.5 && < 1.9
if flag(network-uri)
- Build-Depends: network-uri >= 2.6 && < 2.7, network >= 2.6
+ build-depends: network-uri >= 2.6 && < 2.7, network >= 2.6
else
- Build-Depends: network >= 2 && < 2.6
- if flag(https)
- Build-Depends: http-client >= 0.4.30 && < 0.6,
- http-client-tls >= 0.2.4 && < 0.4,
- http-types >= 0.8 && < 0.10
- cpp-options: -DHTTP_CLIENT
+ build-depends: network >= 2 && < 2.6
if flag(embed_data_files)
cpp-options: -DEMBED_DATA_FILES
- Build-Tools: hsb2hs >= 0.3.1
+ build-depends: file-embed >= 0.0 && < 0.1
other-modules: Text.Pandoc.Data
if os(windows)
- Cpp-options: -D_WINDOWS
- Ghc-Options: -Wall -fno-warn-unused-do-bind
- Ghc-Prof-Options: -fprof-auto-exported
- Default-Language: Haskell98
- Other-Extensions: PatternGuards, OverloadedStrings,
+ cpp-options: -D_WINDOWS
+ ghc-options: -Wall -fno-warn-unused-do-bind
+ default-language: Haskell98
+ other-extensions: PatternGuards, OverloadedStrings,
ScopedTypeVariables, GeneralizedNewtypeDeriving,
RelaxedPolyRec, DeriveDataTypeable, TypeSynonymInstances,
FlexibleInstances
- Hs-Source-Dirs: src
- if impl(ghc < 7.10)
- Hs-Source-Dirs: prelude
- Other-Modules: Prelude
+ hs-source-dirs: src
- Exposed-Modules: Text.Pandoc,
+ exposed-modules: Text.Pandoc,
+ Text.Pandoc.App,
Text.Pandoc.Options,
+ Text.Pandoc.Extensions,
Text.Pandoc.Pretty,
Text.Pandoc.Shared,
Text.Pandoc.MediaBag,
Text.Pandoc.Error,
+ Text.Pandoc.Readers,
Text.Pandoc.Readers.HTML,
Text.Pandoc.Readers.LaTeX,
+ Text.Pandoc.Readers.LaTeX.Types,
Text.Pandoc.Readers.Markdown,
Text.Pandoc.Readers.CommonMark,
+ Text.Pandoc.Readers.Creole,
Text.Pandoc.Readers.MediaWiki,
+ Text.Pandoc.Readers.Vimwiki,
Text.Pandoc.Readers.RST,
Text.Pandoc.Readers.Org,
Text.Pandoc.Readers.DocBook,
+ Text.Pandoc.Readers.JATS,
Text.Pandoc.Readers.OPML,
- Text.Pandoc.Readers.TeXMath,
Text.Pandoc.Readers.Textile,
Text.Pandoc.Readers.Native,
Text.Pandoc.Readers.Haddock,
Text.Pandoc.Readers.TWiki,
+ Text.Pandoc.Readers.TikiWiki,
Text.Pandoc.Readers.Txt2Tags,
Text.Pandoc.Readers.Docx,
Text.Pandoc.Readers.Odt,
Text.Pandoc.Readers.EPUB,
+ Text.Pandoc.Readers.Muse,
+ Text.Pandoc.Writers,
Text.Pandoc.Writers.Native,
Text.Pandoc.Writers.Docbook,
+ Text.Pandoc.Writers.JATS,
Text.Pandoc.Writers.OPML,
Text.Pandoc.Writers.HTML,
Text.Pandoc.Writers.ICML,
@@ -364,6 +469,7 @@ Library
Text.Pandoc.Writers.OpenDocument,
Text.Pandoc.Writers.Texinfo,
Text.Pandoc.Writers.Man,
+ Text.Pandoc.Writers.Ms,
Text.Pandoc.Writers.Markdown,
Text.Pandoc.Writers.CommonMark,
Text.Pandoc.Writers.Haddock,
@@ -378,21 +484,40 @@ Library
Text.Pandoc.Writers.RTF,
Text.Pandoc.Writers.ODT,
Text.Pandoc.Writers.Docx,
+ Text.Pandoc.Writers.Powerpoint,
Text.Pandoc.Writers.EPUB,
Text.Pandoc.Writers.FB2,
Text.Pandoc.Writers.TEI,
+ Text.Pandoc.Writers.Muse,
+ Text.Pandoc.Writers.Math,
+ Text.Pandoc.Writers.Shared,
+ Text.Pandoc.Writers.OOXML,
+ Text.Pandoc.Lua,
Text.Pandoc.PDF,
Text.Pandoc.UTF8,
Text.Pandoc.Templates,
Text.Pandoc.XML,
Text.Pandoc.SelfContained,
+ Text.Pandoc.Highlighting,
+ Text.Pandoc.Logging,
Text.Pandoc.Process,
- Text.Pandoc.CSS
- Other-Modules: Text.Pandoc.Readers.Docx.Lists,
+ Text.Pandoc.MIME,
+ Text.Pandoc.Parsing,
+ Text.Pandoc.Asciify,
+ Text.Pandoc.Emoji,
+ Text.Pandoc.ImageSize,
+ Text.Pandoc.BCP47,
+ Text.Pandoc.Class
+ other-modules: Text.Pandoc.Filter,
+ Text.Pandoc.Filter.JSON,
+ Text.Pandoc.Filter.Lua,
+ Text.Pandoc.Filter.Path,
+ Text.Pandoc.Readers.Docx.Lists,
Text.Pandoc.Readers.Docx.Combine,
Text.Pandoc.Readers.Docx.Parse,
Text.Pandoc.Readers.Docx.Util,
Text.Pandoc.Readers.Docx.StyleMap,
+ Text.Pandoc.Readers.Docx.Fields,
Text.Pandoc.Readers.Odt.Base,
Text.Pandoc.Readers.Odt.Namespaces,
Text.Pandoc.Readers.Odt.StyleReader,
@@ -406,160 +531,164 @@ Library
Text.Pandoc.Readers.Odt.Arrows.Utils,
Text.Pandoc.Readers.Org.BlockStarts,
Text.Pandoc.Readers.Org.Blocks,
+ Text.Pandoc.Readers.Org.DocumentTree,
Text.Pandoc.Readers.Org.ExportSettings,
Text.Pandoc.Readers.Org.Inlines,
Text.Pandoc.Readers.Org.Meta,
Text.Pandoc.Readers.Org.ParserState,
Text.Pandoc.Readers.Org.Parsing,
Text.Pandoc.Readers.Org.Shared,
- Text.Pandoc.Writers.Shared,
- Text.Pandoc.Asciify,
- Text.Pandoc.MIME,
- Text.Pandoc.Emoji,
- Text.Pandoc.Parsing,
+ Text.Pandoc.Writers.Powerpoint.Presentation,
+ Text.Pandoc.Writers.Powerpoint.Output,
+ Text.Pandoc.Lua.Filter,
+ Text.Pandoc.Lua.Init,
+ Text.Pandoc.Lua.Module.MediaBag,
+ Text.Pandoc.Lua.Module.Pandoc,
+ Text.Pandoc.Lua.Module.Utils,
+ Text.Pandoc.Lua.Packages,
+ Text.Pandoc.Lua.StackInstances,
+ Text.Pandoc.Lua.Util,
+ Text.Pandoc.CSS,
+ Text.Pandoc.CSV,
Text.Pandoc.UUID,
- Text.Pandoc.ImageSize,
+ Text.Pandoc.Translations,
Text.Pandoc.Slides,
- Text.Pandoc.Highlighting,
Text.Pandoc.Compat.Time,
Paths_pandoc
- Buildable: True
-
-Executable pandoc
- Build-Depends: pandoc,
- pandoc-types >= 1.17 && < 1.18,
- base >= 4.2 && <5,
- directory >= 1.2 && < 1.4,
- filepath >= 1.1 && < 1.5,
- text >= 0.11 && < 1.3,
- bytestring >= 0.9 && < 0.11,
- extensible-exceptions >= 0.1 && < 0.2,
- skylighting >= 0.1.1.5 && < 0.2,
- aeson >= 0.7.0.5 && < 1.2,
- yaml >= 0.8.8.2 && < 0.9,
- containers >= 0.1 && < 0.6,
- skylighting >= 0.1.1.4 && < 0.2,
- texmath >= 0.9 && < 0.10,
- HTTP >= 4000.0.5 && < 4000.4
- if flag(network-uri)
- Build-Depends: network-uri >= 2.6 && < 2.7, network >= 2.6
- else
- Build-Depends: network >= 2 && < 2.6
- Ghc-Options: -rtsopts -with-rtsopts=-K16m -Wall -fno-warn-unused-do-bind
- Ghc-Prof-Options: -fprof-auto-exported -rtsopts -with-rtsopts=-K16m
- if os(windows)
- Cpp-options: -D_WINDOWS
- else
- Build-Depends: unix >= 2.4 && < 2.8
+ buildable: True
- Default-Language: Haskell98
- Other-Extensions: PatternGuards, OverloadedStrings,
+executable pandoc
+ build-depends: pandoc, base >= 4.7 && < 5
+ ghc-options: -rtsopts -with-rtsopts=-K16m -Wall -fno-warn-unused-do-bind -threaded
+ if flag(static)
+ ld-options: -static
+ default-language: Haskell98
+ other-extensions: PatternGuards, OverloadedStrings,
ScopedTypeVariables, GeneralizedNewtypeDeriving,
RelaxedPolyRec, DeriveDataTypeable, TypeSynonymInstances,
FlexibleInstances
- Hs-Source-Dirs: .
- if impl(ghc < 7.10)
- Hs-Source-Dirs: prelude
- Other-Modules: Prelude
- Main-Is: pandoc.hs
- Buildable: True
- Other-Modules: Paths_pandoc
+ hs-source-dirs: .
+ main-is: pandoc.hs
+ buildable: True
+ other-modules: Paths_pandoc
-Executable trypandoc
- Main-Is: trypandoc.hs
- Hs-Source-Dirs: trypandoc
- if impl(ghc < 7.10)
- Hs-Source-Dirs: prelude
- Other-Modules: Prelude
+executable trypandoc
+ main-is: trypandoc.hs
+ hs-source-dirs: trypandoc
default-language: Haskell2010
if flag(trypandoc)
- Build-Depends: base, aeson, pandoc,
+ build-depends: base, aeson, pandoc,
text, wai-extra, wai >= 0.3, http-types
- Buildable: True
+ buildable: True
else
- Buildable: False
+ buildable: False
-Executable weigh-pandoc
- Main-Is: weigh-pandoc.hs
- Hs-Source-Dirs: benchmark
- if impl(ghc < 7.10)
- Hs-Source-Dirs: prelude
- Other-Modules: Prelude
+executable weigh-pandoc
+ main-is: weigh-pandoc.hs
+ hs-source-dirs: benchmark
if flag(weigh-pandoc)
- Build-Depends: pandoc,
+ build-depends: pandoc,
base >= 4.2 && < 5,
- weigh >= 0.0 && < 0.1
- Buildable: True
+ text,
+ weigh >= 0.0 && < 0.1,
+ mtl >= 2.2 && < 2.3
+ buildable: True
else
- Buildable: False
- Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
- Default-Language: Haskell98
+ buildable: False
+ ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind
+ default-language: Haskell98
-Test-Suite test-pandoc
- Type: exitcode-stdio-1.0
- Main-Is: test-pandoc.hs
- Hs-Source-Dirs: tests
- if impl(ghc < 7.10)
- Hs-Source-Dirs: prelude
- Other-Modules: Prelude
- Build-Depends: base >= 4.2 && < 5,
- syb >= 0.1 && < 0.8,
+test-suite test-pandoc
+ type: exitcode-stdio-1.0
+ main-is: test-pandoc.hs
+ hs-source-dirs: test
+ build-depends: base >= 4.2 && < 5,
pandoc,
- pandoc-types >= 1.17 && < 1.18,
+ pandoc-types >= 1.17.3 && < 1.18,
bytestring >= 0.9 && < 0.11,
+ base64-bytestring >= 0.1 && < 1.1,
text >= 0.11 && < 1.3,
+ time >= 1.5 && < 1.9,
directory >= 1 && < 1.4,
filepath >= 1.1 && < 1.5,
- process >= 1 && < 1.7,
- skylighting >= 0.1.1.3 && < 0.2,
+ hslua >= 0.9.5 && < 0.9.6,
+ process >= 1.2.3 && < 1.7,
+ temporary >= 1.1 && < 1.3,
Diff >= 0.2 && < 0.4,
- test-framework >= 0.3 && < 0.9,
- test-framework-hunit >= 0.2 && < 0.4,
- test-framework-quickcheck2 >= 0.2.9 && < 0.4,
- QuickCheck >= 2.4 && < 2.11,
- HUnit >= 1.2 && < 1.7,
- containers >= 0.1 && < 0.6,
- ansi-terminal >= 0.5 && < 0.8,
- executable-path >= 0.0 && < 0.4,
- zip-archive >= 0.2.3.4 && < 0.4
- Other-Modules: Tests.Old
+ tasty >= 0.11 && < 1.1,
+ tasty-hunit >= 0.9 && < 0.11,
+ tasty-quickcheck >= 0.8 && < 0.10,
+ tasty-golden >= 2.3 && < 2.4,
+ QuickCheck >= 2.4 && < 2.12,
+ containers >= 0.4.2.1 && < 0.6,
+ executable-path >= 0.0 && < 0.1,
+ zip-archive >= 0.2.3.4 && < 0.4,
+ xml >= 1.3.12 && < 1.4,
+ Glob >= 0.7 && < 0.10
+ if flag(old-locale)
+ build-depends: old-locale >= 1 && < 1.1,
+ time >= 1.2 && < 1.5
+ else
+ build-depends: time >= 1.5 && < 1.9
+ other-modules: Tests.Old
+ Tests.Command
Tests.Helpers
+ Tests.Lua
Tests.Shared
- Tests.Walk
Tests.Readers.LaTeX
Tests.Readers.HTML
+ Tests.Readers.JATS
Tests.Readers.Markdown
Tests.Readers.Org
+ Tests.Readers.Org.Block
+ Tests.Readers.Org.Block.CodeBlock
+ Tests.Readers.Org.Block.Figure
+ Tests.Readers.Org.Block.Header
+ Tests.Readers.Org.Block.List
+ Tests.Readers.Org.Block.Table
+ Tests.Readers.Org.Directive
+ Tests.Readers.Org.Inline
+ Tests.Readers.Org.Inline.Citation
+ Tests.Readers.Org.Inline.Note
+ Tests.Readers.Org.Inline.Smart
+ Tests.Readers.Org.Meta
+ Tests.Readers.Org.Shared
Tests.Readers.RST
Tests.Readers.Docx
Tests.Readers.Odt
Tests.Readers.Txt2Tags
Tests.Readers.EPUB
+ Tests.Readers.Muse
+ Tests.Readers.Creole
Tests.Writers.Native
Tests.Writers.ConTeXt
Tests.Writers.Docbook
Tests.Writers.HTML
+ Tests.Writers.JATS
Tests.Writers.Markdown
+ Tests.Writers.Org
Tests.Writers.Plain
Tests.Writers.AsciiDoc
Tests.Writers.LaTeX
Tests.Writers.Docx
Tests.Writers.RST
Tests.Writers.TEI
- Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
- Default-Language: Haskell98
+ Tests.Writers.Muse
+ Tests.Writers.FB2
+ Tests.Writers.Powerpoint
+ Tests.Writers.OOXML
+ ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
+ default-language: Haskell98
benchmark benchmark-pandoc
- Type: exitcode-stdio-1.0
- Main-Is: benchmark-pandoc.hs
- Hs-Source-Dirs: benchmark
- if impl(ghc < 7.10)
- Hs-Source-Dirs: prelude
- Other-Modules: Prelude
- Build-Depends: pandoc,
+ type: exitcode-stdio-1.0
+ main-is: benchmark-pandoc.hs
+ hs-source-dirs: benchmark
+ build-depends: pandoc,
+ time, bytestring, containers,
base >= 4.2 && < 5,
- syb >= 0.1 && < 0.8,
- criterion >= 1.0 && < 1.3
- Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
- Default-Language: Haskell98
+ text >= 0.11 && < 1.3,
+ criterion >= 1.0 && < 1.4
+ ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind
+ default-language: Haskell98
diff --git a/pandoc.hs b/pandoc.hs
index a032922be..780e41ce1 100644
--- a/pandoc.hs
+++ b/pandoc.hs
@@ -1,6 +1,5 @@
-{-# LANGUAGE CPP, TupleSections, ScopedTypeVariables, PatternGuards #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Main
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley@edu>
@@ -30,1487 +29,10 @@ Parses command-line options and calls the appropriate readers and
writers.
-}
module Main where
-import Text.Pandoc
-import Text.Pandoc.Builder (setMeta)
-import Text.Pandoc.PDF (makePDF)
-import Text.Pandoc.Walk (walk)
-import Text.Pandoc.Readers.LaTeX (handleIncludes)
-import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile,
- safeRead, headerShift, normalize, err, warn,
- openURL )
-import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag, MediaBag )
-import Text.Pandoc.XML ( toEntities )
-import Text.Pandoc.SelfContained ( makeSelfContained )
-import Text.Pandoc.Process (pipeProcess)
-import Skylighting ( defaultSyntaxMap, Syntax(..), Style, tango, pygments,
- espresso, zenburn, kate, haddock, breezeDark, monochrome )
-import System.Environment ( getArgs, getProgName, getEnvironment )
-import System.Exit ( ExitCode (..), exitSuccess )
-import System.FilePath
-import System.Console.GetOpt
-import qualified Data.Set as Set
-import Data.Char ( toLower, toUpper )
-import Data.List ( intercalate, isPrefixOf, isSuffixOf, sort )
-import System.Directory ( getAppUserDataDirectory, findExecutable,
- doesFileExist, Permissions(..), getPermissions )
-import System.IO ( stdout, stderr )
-import System.IO.Error ( isDoesNotExistError )
import qualified Control.Exception as E
-import Control.Exception.Extensible ( throwIO )
-import qualified Text.Pandoc.UTF8 as UTF8
-import Control.Monad (when, unless, (>=>))
-import Data.Maybe (fromMaybe, isNothing, isJust)
-import Data.Foldable (foldrM)
-import Network.URI (parseURI, isURI, URI(..))
-import qualified Data.ByteString.Lazy as B
-import qualified Data.ByteString as BS
-import Data.Aeson (eitherDecode', encode)
-import qualified Data.Map as M
-import Data.Yaml (decode)
-import qualified Data.Yaml as Yaml
-import qualified Data.Text as T
-import Control.Applicative ((<|>))
-import Text.Pandoc.Readers.Txt2Tags (getT2TMeta)
-import Paths_pandoc (getDataDir)
-import Text.Printf (printf)
-#ifndef _WINDOWS
-import System.Posix.Terminal (queryTerminal)
-import System.Posix.IO (stdOutput)
-#endif
-
-type Transform = Pandoc -> Pandoc
-
-copyrightMessage :: String
-copyrightMessage = intercalate "\n" [
- "",
- "Copyright (C) 2006-2016 John MacFarlane",
- "Web: http://pandoc.org",
- "This is free software; see the source for copying conditions.",
- "There is no warranty, not even for merchantability or fitness",
- "for a particular purpose." ]
-
-compileInfo :: String
-compileInfo =
- "\nCompiled with pandoc-types " ++ VERSION_pandoc_types ++ ", texmath " ++
- VERSION_texmath ++ ", skylighting " ++ VERSION_skylighting
-
--- | Converts a list of strings into a single string with the items printed as
--- comma separated words in lines with a maximum line length.
-wrapWords :: Int -> Int -> [String] -> String
-wrapWords indent c = wrap' (c - indent) (c - indent)
- where
- wrap' _ _ [] = ""
- wrap' cols remaining (x:xs)
- | remaining == cols =
- x ++ wrap' cols (remaining - length x) xs
- | (length x + 1) > remaining =
- ",\n" ++ replicate indent ' ' ++ x ++
- wrap' cols (cols - length x) xs
- | otherwise =
- ", " ++ x ++
- wrap' cols (remaining - length x - 2) xs
-
-isTextFormat :: String -> Bool
-isTextFormat s = s `notElem` ["odt","docx","epub","epub3"]
-
-externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc
-externalFilter f args' d = do
- exists <- doesFileExist f
- isExecutable <- if exists
- then executable <$> getPermissions f
- else return True
- let (f', args'') = if exists
- then case map toLower (takeExtension f) of
- _ | isExecutable -> ("." </> f, args')
- ".py" -> ("python", f:args')
- ".hs" -> ("runhaskell", f:args')
- ".pl" -> ("perl", f:args')
- ".rb" -> ("ruby", f:args')
- ".php" -> ("php", f:args')
- ".js" -> ("node", f:args')
- _ -> (f, args')
- else (f, args')
- unless (exists && isExecutable) $ do
- mbExe <- findExecutable f'
- when (isNothing mbExe) $
- err 83 $ "Error running filter " ++ f ++ ":\n" ++
- "Could not find executable '" ++ f' ++ "'."
- env <- getEnvironment
- let env' = Just $ ("PANDOC_VERSION", pandocVersion) : env
- (exitcode, outbs, errbs) <- E.handle filterException $
- pipeProcess env' f' args'' $ encode d
- unless (B.null errbs) $ B.hPutStr stderr errbs
- case exitcode of
- ExitSuccess -> return $ either error id $ eitherDecode' outbs
- ExitFailure ec -> err 83 $ "Error running filter " ++ f ++ "\n" ++
- "Filter returned error status " ++ show ec
- where filterException :: E.SomeException -> IO a
- filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++
- show e
-
-highlightingStyles :: [(String, Style)]
-highlightingStyles =
- [("pygments", pygments),
- ("tango", tango),
- ("espresso", espresso),
- ("zenburn", zenburn),
- ("kate", kate),
- ("monochrome", monochrome),
- ("breezedark", breezeDark),
- ("haddock", haddock)]
-
--- | Data structure for command line options.
-data Opt = Opt
- { optTabStop :: Int -- ^ Number of spaces per tab
- , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
- , optStandalone :: Bool -- ^ Include header, footer
- , optReader :: String -- ^ Reader format
- , optWriter :: String -- ^ Writer format
- , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
- , optTableOfContents :: Bool -- ^ Include table of contents
- , optTransforms :: [Transform] -- ^ Doc transforms to apply
- , optTemplate :: Maybe FilePath -- ^ Custom template
- , optVariables :: [(String,String)] -- ^ Template variables to set
- , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set
- , optOutputFile :: String -- ^ Name of output file
- , optNumberSections :: Bool -- ^ Number sections in LaTeX
- , optNumberOffset :: [Int] -- ^ Starting number for sections
- , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML
- , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
- , optSelfContained :: Bool -- ^ Make HTML accessible offline
- , optSmart :: Bool -- ^ Use smart typography
- , optOldDashes :: Bool -- ^ Parse dashes like pandoc <=1.8.2.1
- , optHtml5 :: Bool -- ^ Produce HTML5 in HTML
- , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
- , optHighlight :: Bool -- ^ Highlight source code
- , optHighlightStyle :: Style -- ^ Style to use for highlighted code
- , optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions
- , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
- , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt
- , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx
- , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet
- , optEpubMetadata :: String -- ^ EPUB metadata
- , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed
- , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters
- , optTOCDepth :: Int -- ^ Number of levels to include in TOC
- , optDumpArgs :: Bool -- ^ Output command-line arguments
- , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
- , optVerbose :: Bool -- ^ Verbose diagnostic output
- , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
- , optReferenceLocation :: ReferenceLocation -- ^ location for footnotes and link references in markdown output
- , optDpi :: Int -- ^ Dpi
- , optWrapText :: WrapOption -- ^ Options for wrapping text
- , optColumns :: Int -- ^ Line length in characters
- , optFilters :: [FilePath] -- ^ Filters to apply
- , optEmailObfuscation :: ObfuscationMethod
- , optIdentifierPrefix :: String
- , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
- , optDataDir :: Maybe FilePath
- , optCiteMethod :: CiteMethod -- ^ Method to output cites
- , optListings :: Bool -- ^ Use listings package for code blocks
- , optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
- , optLaTeXEngineArgs :: [String] -- ^ Flags to pass to the latex-engine
- , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
- , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
- , optAscii :: Bool -- ^ Use ascii characters only in html
- , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes
- , optDefaultImageExtension :: String -- ^ Default image extension
- , optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media
- , optTrace :: Bool -- ^ Print debug information
- , optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes.
- , optFileScope :: Bool -- ^ Parse input files before combining
- , optKaTeXStylesheet :: Maybe String -- ^ Path to stylesheet for KaTeX
- , optKaTeXJS :: Maybe String -- ^ Path to js file for KaTeX
- }
-
--- | Defaults for command-line options.
-defaultOpts :: Opt
-defaultOpts = Opt
- { optTabStop = 4
- , optPreserveTabs = False
- , optStandalone = False
- , optReader = "" -- null for default reader
- , optWriter = "" -- null for default writer
- , optParseRaw = False
- , optTableOfContents = False
- , optTransforms = []
- , optTemplate = Nothing
- , optVariables = []
- , optMetadata = M.empty
- , optOutputFile = "-" -- "-" means stdout
- , optNumberSections = False
- , optNumberOffset = [0,0,0,0,0,0]
- , optSectionDivs = False
- , optIncremental = False
- , optSelfContained = False
- , optSmart = False
- , optOldDashes = False
- , optHtml5 = False
- , optHtmlQTags = False
- , optHighlight = True
- , optHighlightStyle = pygments
- , optTopLevelDivision = TopLevelDefault
- , optHTMLMathMethod = PlainMath
- , optReferenceODT = Nothing
- , optReferenceDocx = Nothing
- , optEpubStylesheet = Nothing
- , optEpubMetadata = ""
- , optEpubFonts = []
- , optEpubChapterLevel = 1
- , optTOCDepth = 3
- , optDumpArgs = False
- , optIgnoreArgs = False
- , optVerbose = False
- , optReferenceLinks = False
- , optReferenceLocation = EndOfDocument
- , optDpi = 96
- , optWrapText = WrapAuto
- , optColumns = 72
- , optFilters = []
- , optEmailObfuscation = NoObfuscation
- , optIdentifierPrefix = ""
- , optIndentedCodeClasses = []
- , optDataDir = Nothing
- , optCiteMethod = Citeproc
- , optListings = False
- , optLaTeXEngine = "pdflatex"
- , optLaTeXEngineArgs = []
- , optSlideLevel = Nothing
- , optSetextHeaders = True
- , optAscii = False
- , optTeXLigatures = True
- , optDefaultImageExtension = ""
- , optExtractMedia = Nothing
- , optTrace = False
- , optTrackChanges = AcceptChanges
- , optFileScope = False
- , optKaTeXStylesheet = Nothing
- , optKaTeXJS = Nothing
- }
-
--- | A list of functions, each transforming the options data structure
--- in response to a command-line option.
-options :: [OptDescr (Opt -> IO Opt)]
-options =
- [ Option "fr" ["from","read"]
- (ReqArg
- (\arg opt -> return opt { optReader = arg })
- "FORMAT")
- ""
-
- , Option "tw" ["to","write"]
- (ReqArg
- (\arg opt -> return opt { optWriter = arg })
- "FORMAT")
- ""
-
- , Option "o" ["output"]
- (ReqArg
- (\arg opt -> return opt { optOutputFile = arg })
- "FILENAME")
- "" -- "Name of output file"
-
- , Option "" ["data-dir"]
- (ReqArg
- (\arg opt -> return opt { optDataDir = Just arg })
- "DIRECTORY") -- "Directory containing pandoc data files."
- ""
-
- , Option "R" ["parse-raw"]
- (NoArg
- (\opt -> return opt { optParseRaw = True }))
- "" -- "Parse untranslatable HTML codes and LaTeX environments as raw"
-
- , Option "S" ["smart"]
- (NoArg
- (\opt -> return opt { optSmart = True }))
- "" -- "Use smart quotes, dashes, and ellipses"
-
- , Option "" ["old-dashes"]
- (NoArg
- (\opt -> return opt { optSmart = True
- , optOldDashes = True }))
- "" -- "Use smart quotes, dashes, and ellipses"
-
- , Option "" ["base-header-level"]
- (ReqArg
- (\arg opt ->
- case safeRead arg of
- Just t | t > 0 -> do
- let oldTransforms = optTransforms opt
- let shift = t - 1
- return opt{ optTransforms =
- headerShift shift : oldTransforms }
- _ -> err 19
- "base-header-level must be a number > 0")
- "NUMBER")
- "" -- "Headers base level"
-
- , Option "" ["indented-code-classes"]
- (ReqArg
- (\arg opt -> return opt { optIndentedCodeClasses = words $
- map (\c -> if c == ',' then ' ' else c) arg })
- "STRING")
- "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
-
- , Option "F" ["filter"]
- (ReqArg
- (\arg opt -> return opt { optFilters = arg : optFilters opt })
- "PROGRAM")
- "" -- "External JSON filter"
-
- , Option "" ["normalize"]
- (NoArg
- (\opt -> return opt { optTransforms =
- normalize : optTransforms opt } ))
- "" -- "Normalize the Pandoc AST"
-
- , Option "p" ["preserve-tabs"]
- (NoArg
- (\opt -> return opt { optPreserveTabs = True }))
- "" -- "Preserve tabs instead of converting to spaces"
-
- , Option "" ["tab-stop"]
- (ReqArg
- (\arg opt ->
- case safeRead arg of
- Just t | t > 0 -> return opt { optTabStop = t }
- _ -> err 31
- "tab-stop must be a number greater than 0")
- "NUMBER")
- "" -- "Tab stop (default 4)"
-
- , Option "" ["track-changes"]
- (ReqArg
- (\arg opt -> do
- action <- case arg of
- "accept" -> return AcceptChanges
- "reject" -> return RejectChanges
- "all" -> return AllChanges
- _ -> err 6
- ("Unknown option for track-changes: " ++ arg)
- return opt { optTrackChanges = action })
- "accept|reject|all")
- "" -- "Accepting or reject MS Word track-changes.""
-
- , Option "" ["file-scope"]
- (NoArg
- (\opt -> return opt { optFileScope = True }))
- "" -- "Parse input files before combining"
-
- , Option "" ["extract-media"]
- (ReqArg
- (\arg opt ->
- return opt { optExtractMedia = Just arg })
- "PATH")
- "" -- "Directory to which to extract embedded media"
-
- , Option "s" ["standalone"]
- (NoArg
- (\opt -> return opt { optStandalone = True }))
- "" -- "Include needed header and footer on output"
-
- , Option "" ["template"]
- (ReqArg
- (\arg opt ->
- return opt{ optTemplate = Just arg,
- optStandalone = True })
- "FILENAME")
- "" -- "Use custom template"
-
- , Option "M" ["metadata"]
- (ReqArg
- (\arg opt -> do
- let (key,val) = case break (`elem` ":=") arg of
- (k,_:v) -> (k, readMetaValue v)
- (k,_) -> (k, MetaBool True)
- return opt{ optMetadata = addMetadata key val
- $ optMetadata opt })
- "KEY[:VALUE]")
- ""
-
- , Option "V" ["variable"]
- (ReqArg
- (\arg opt -> do
- let (key,val) = case break (`elem` ":=") arg of
- (k,_:v) -> (k,v)
- (k,_) -> (k,"true")
- return opt{ optVariables = (key,val) : optVariables opt })
- "KEY[:VALUE]")
- ""
-
- , Option "D" ["print-default-template"]
- (ReqArg
- (\arg _ -> do
- templ <- getDefaultTemplate Nothing arg
- case templ of
- Right t -> UTF8.hPutStr stdout t
- Left e -> error $ show e
- exitSuccess)
- "FORMAT")
- "" -- "Print default template for FORMAT"
-
- , Option "" ["print-default-data-file"]
- (ReqArg
- (\arg _ -> do
- readDataFile Nothing arg >>= BS.hPutStr stdout
- exitSuccess)
- "FILE")
- "" -- "Print default data file"
-
- , Option "" ["dpi"]
- (ReqArg
- (\arg opt ->
- case safeRead arg of
- Just t | t > 0 -> return opt { optDpi = t }
- _ -> err 31
- "dpi must be a number greater than 0")
- "NUMBER")
- "" -- "Dpi (default 96)"
-
- , Option "" ["no-wrap"]
- (NoArg
- (\opt -> do warn $ "--no-wrap is deprecated. " ++
- "Use --wrap=none or --wrap=preserve instead."
- return opt { optWrapText = WrapNone }))
- ""
-
- , Option "" ["wrap"]
- (ReqArg
- (\arg opt ->
- case safeRead ("Wrap" ++ uppercaseFirstLetter arg) of
- Just o -> return opt { optWrapText = o }
- Nothing -> err 77 "--wrap must be auto, none, or preserve")
- "auto|none|preserve")
- "" -- "Option for wrapping text in output"
-
- , Option "" ["columns"]
- (ReqArg
- (\arg opt ->
- case safeRead arg of
- Just t | t > 0 -> return opt { optColumns = t }
- _ -> err 33
- "columns must be a number greater than 0")
- "NUMBER")
- "" -- "Length of line in characters"
-
- , Option "" ["toc", "table-of-contents"]
- (NoArg
- (\opt -> return opt { optTableOfContents = True }))
- "" -- "Include table of contents"
-
- , Option "" ["toc-depth"]
- (ReqArg
- (\arg opt ->
- case safeRead arg of
- Just t | t >= 1 && t <= 6 ->
- return opt { optTOCDepth = t }
- _ -> err 57
- "TOC level must be a number between 1 and 6")
- "NUMBER")
- "" -- "Number of levels to include in TOC"
-
- , Option "" ["no-highlight"]
- (NoArg
- (\opt -> return opt { optHighlight = False }))
- "" -- "Don't highlight source code"
-
- , Option "" ["highlight-style"]
- (ReqArg
- (\arg opt -> do
- case lookup (map toLower arg) highlightingStyles of
- Just s -> return opt{ optHighlightStyle = s }
- Nothing -> err 39 $ "Unknown style: " ++ arg)
- "STYLE")
- "" -- "Style for highlighted code"
-
- , Option "H" ["include-in-header"]
- (ReqArg
- (\arg opt -> do
- text <- UTF8.readFile arg
- -- add new ones to end, so they're included in order specified
- let newvars = optVariables opt ++ [("header-includes",text)]
- return opt { optVariables = newvars,
- optStandalone = True })
- "FILENAME")
- "" -- "File to include at end of header (implies -s)"
-
- , Option "B" ["include-before-body"]
- (ReqArg
- (\arg opt -> do
- text <- UTF8.readFile arg
- -- add new ones to end, so they're included in order specified
- let newvars = optVariables opt ++ [("include-before",text)]
- return opt { optVariables = newvars,
- optStandalone = True })
- "FILENAME")
- "" -- "File to include before document body"
-
- , Option "A" ["include-after-body"]
- (ReqArg
- (\arg opt -> do
- text <- UTF8.readFile arg
- -- add new ones to end, so they're included in order specified
- let newvars = optVariables opt ++ [("include-after",text)]
- return opt { optVariables = newvars,
- optStandalone = True })
- "FILENAME")
- "" -- "File to include after document body"
-
- , Option "" ["self-contained"]
- (NoArg
- (\opt -> return opt { optSelfContained = True,
- optStandalone = True }))
- "" -- "Make slide shows include all the needed js and css"
-
- , Option "" ["html-q-tags"]
- (NoArg
- (\opt ->
- return opt { optHtmlQTags = True }))
- "" -- "Use <q> tags for quotes in HTML"
-
- , Option "" ["ascii"]
- (NoArg
- (\opt -> return opt { optAscii = True }))
- "" -- "Use ascii characters only in HTML output"
-
- , Option "" ["reference-links"]
- (NoArg
- (\opt -> return opt { optReferenceLinks = True } ))
- "" -- "Use reference links in parsing HTML"
-
- , Option "" ["reference-location"]
- (ReqArg
- (\arg opt -> do
- action <- case arg of
- "block" -> return EndOfBlock
- "section" -> return EndOfSection
- "document" -> return EndOfDocument
- _ -> err 6
- ("Unknown option for reference-location: " ++ arg)
- return opt { optReferenceLocation = action })
- "block|section|document")
- "" -- "Accepting or reject MS Word track-changes.""
-
- , Option "" ["atx-headers"]
- (NoArg
- (\opt -> return opt { optSetextHeaders = False } ))
- "" -- "Use atx-style headers for markdown"
-
- , Option "" ["chapters"]
- (NoArg
- (\opt -> do warn $ "--chapters is deprecated. " ++
- "Use --top-level-division=chapter instead."
- return opt { optTopLevelDivision = TopLevelChapter }))
- "" -- "Use chapter for top-level sections in LaTeX, DocBook"
-
- , Option "" ["top-level-division"]
- (ReqArg
- (\arg opt -> do
- let tldName = "TopLevel" ++ uppercaseFirstLetter arg
- case safeRead tldName of
- Just tlDiv -> return opt { optTopLevelDivision = tlDiv }
- _ -> err 76 ("Top-level division must be " ++
- "section, chapter, part, or default"))
- "section|chapter|part")
- "" -- "Use top-level division type in LaTeX, ConTeXt, DocBook"
-
- , Option "N" ["number-sections"]
- (NoArg
- (\opt -> return opt { optNumberSections = True }))
- "" -- "Number sections in LaTeX"
-
- , Option "" ["number-offset"]
- (ReqArg
- (\arg opt ->
- case safeRead ('[':arg ++ "]") of
- Just ns -> return opt { optNumberOffset = ns,
- optNumberSections = True }
- _ -> err 57 "could not parse number-offset")
- "NUMBERS")
- "" -- "Starting number for sections, subsections, etc."
-
- , Option "" ["no-tex-ligatures"]
- (NoArg
- (\opt -> return opt { optTeXLigatures = False }))
- "" -- "Don't use tex ligatures for quotes, dashes"
-
- , Option "" ["listings"]
- (NoArg
- (\opt -> return opt { optListings = True }))
- "" -- "Use listings package for LaTeX code blocks"
-
- , Option "i" ["incremental"]
- (NoArg
- (\opt -> return opt { optIncremental = True }))
- "" -- "Make list items display incrementally in Slidy/Slideous/S5"
-
- , Option "" ["slide-level"]
- (ReqArg
- (\arg opt ->
- case safeRead arg of
- Just t | t >= 1 && t <= 6 ->
- return opt { optSlideLevel = Just t }
- _ -> err 39
- "slide level must be a number between 1 and 6")
- "NUMBER")
- "" -- "Force header level for slides"
-
- , Option "" ["section-divs"]
- (NoArg
- (\opt -> return opt { optSectionDivs = True }))
- "" -- "Put sections in div tags in HTML"
-
- , Option "" ["default-image-extension"]
- (ReqArg
- (\arg opt -> return opt { optDefaultImageExtension = arg })
- "extension")
- "" -- "Default extension for extensionless images"
-
- , Option "" ["email-obfuscation"]
- (ReqArg
- (\arg opt -> do
- method <- case arg of
- "references" -> return ReferenceObfuscation
- "javascript" -> return JavascriptObfuscation
- "none" -> return NoObfuscation
- _ -> err 6
- ("Unknown obfuscation method: " ++ arg)
- return opt { optEmailObfuscation = method })
- "none|javascript|references")
- "" -- "Method for obfuscating email in HTML"
-
- , Option "" ["id-prefix"]
- (ReqArg
- (\arg opt -> return opt { optIdentifierPrefix = arg })
- "STRING")
- "" -- "Prefix to add to automatically generated HTML identifiers"
-
- , Option "T" ["title-prefix"]
- (ReqArg
- (\arg opt -> do
- let newvars = ("title-prefix", arg) : optVariables opt
- return opt { optVariables = newvars,
- optStandalone = True })
- "STRING")
- "" -- "String to prefix to HTML window title"
-
- , Option "c" ["css"]
- (ReqArg
- (\arg opt -> do
- -- add new link to end, so it is included in proper order
- let newvars = optVariables opt ++ [("css",arg)]
- return opt { optVariables = newvars,
- optStandalone = True })
- "URL")
- "" -- "Link to CSS style sheet"
-
- , Option "" ["reference-odt"]
- (ReqArg
- (\arg opt ->
- return opt { optReferenceODT = Just arg })
- "FILENAME")
- "" -- "Path of custom reference.odt"
-
- , Option "" ["reference-docx"]
- (ReqArg
- (\arg opt ->
- return opt { optReferenceDocx = Just arg })
- "FILENAME")
- "" -- "Path of custom reference.docx"
-
- , Option "" ["epub-stylesheet"]
- (ReqArg
- (\arg opt -> do
- text <- UTF8.readFile arg
- return opt { optEpubStylesheet = Just text })
- "FILENAME")
- "" -- "Path of epub.css"
-
- , Option "" ["epub-cover-image"]
- (ReqArg
- (\arg opt ->
- return opt { optVariables =
- ("epub-cover-image", arg) : optVariables opt })
- "FILENAME")
- "" -- "Path of epub cover image"
-
- , Option "" ["epub-metadata"]
- (ReqArg
- (\arg opt -> do
- text <- UTF8.readFile arg
- return opt { optEpubMetadata = text })
- "FILENAME")
- "" -- "Path of epub metadata file"
-
- , Option "" ["epub-embed-font"]
- (ReqArg
- (\arg opt ->
- return opt{ optEpubFonts = arg : optEpubFonts opt })
- "FILE")
- "" -- "Directory of fonts to embed"
-
- , Option "" ["epub-chapter-level"]
- (ReqArg
- (\arg opt ->
- case safeRead arg of
- Just t | t >= 1 && t <= 6 ->
- return opt { optEpubChapterLevel = t }
- _ -> err 59
- "chapter level must be a number between 1 and 6")
- "NUMBER")
- "" -- "Header level at which to split chapters in EPUB"
-
- , Option "" ["latex-engine"]
- (ReqArg
- (\arg opt -> do
- let b = takeBaseName arg
- if b `elem` ["pdflatex", "lualatex", "xelatex"]
- then return opt { optLaTeXEngine = arg }
- else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.")
- "PROGRAM")
- "" -- "Name of latex program to use in generating PDF"
-
- , Option "" ["latex-engine-opt"]
- (ReqArg
- (\arg opt -> do
- let oldArgs = optLaTeXEngineArgs opt
- return opt { optLaTeXEngineArgs = arg : oldArgs })
- "STRING")
- "" -- "Flags to pass to the LaTeX engine, all instances of this option are accumulated and used"
-
- , Option "" ["bibliography"]
- (ReqArg
- (\arg opt -> return opt{ optMetadata = addMetadata
- "bibliography" (readMetaValue arg)
- $ optMetadata opt
- })
- "FILE")
- ""
-
- , Option "" ["csl"]
- (ReqArg
- (\arg opt ->
- return opt{ optMetadata = addMetadata "csl"
- (readMetaValue arg)
- $ optMetadata opt })
- "FILE")
- ""
-
- , Option "" ["citation-abbreviations"]
- (ReqArg
- (\arg opt ->
- return opt{ optMetadata = addMetadata
- "citation-abbreviations"
- (readMetaValue arg)
- $ optMetadata opt })
- "FILE")
- ""
-
- , Option "" ["natbib"]
- (NoArg
- (\opt -> return opt { optCiteMethod = Natbib }))
- "" -- "Use natbib cite commands in LaTeX output"
-
- , Option "" ["biblatex"]
- (NoArg
- (\opt -> return opt { optCiteMethod = Biblatex }))
- "" -- "Use biblatex cite commands in LaTeX output"
-
- , Option "m" ["latexmathml", "asciimathml"]
- (OptArg
- (\arg opt ->
- return opt { optHTMLMathMethod = LaTeXMathML arg })
- "URL")
- "" -- "Use LaTeXMathML script in html output"
-
- , Option "" ["mathml"]
- (OptArg
- (\arg opt ->
- return opt { optHTMLMathMethod = MathML arg })
- "URL")
- "" -- "Use mathml for HTML math"
-
- , Option "" ["mimetex"]
- (OptArg
- (\arg opt -> do
- let url' = case arg of
- Just u -> u ++ "?"
- Nothing -> "/cgi-bin/mimetex.cgi?"
- return opt { optHTMLMathMethod = WebTeX url' })
- "URL")
- "" -- "Use mimetex for HTML math"
-
- , Option "" ["webtex"]
- (OptArg
- (\arg opt -> do
- let url' = fromMaybe "https://latex.codecogs.com/png.latex?" arg
- return opt { optHTMLMathMethod = WebTeX url' })
- "URL")
- "" -- "Use web service for HTML math"
-
- , Option "" ["jsmath"]
- (OptArg
- (\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
- "URL")
- "" -- "Use jsMath for HTML math"
-
- , Option "" ["mathjax"]
- (OptArg
- (\arg opt -> do
- let url' = fromMaybe "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML-full" arg
- return opt { optHTMLMathMethod = MathJax url'})
- "URL")
- "" -- "Use MathJax for HTML math"
- , Option "" ["katex"]
- (OptArg
- (\arg opt ->
- return opt
- { optKaTeXJS =
- arg <|> Just "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js"})
- "URL")
- "" -- Use KaTeX for HTML Math
-
- , Option "" ["katex-stylesheet"]
- (ReqArg
- (\arg opt ->
- return opt { optKaTeXStylesheet = Just arg })
- "URL")
- "" -- Set the KaTeX Stylesheet location
-
- , Option "" ["gladtex"]
- (NoArg
- (\opt -> return opt { optHTMLMathMethod = GladTeX }))
- "" -- "Use gladtex for HTML math"
-
- , Option "" ["trace"]
- (NoArg
- (\opt -> return opt { optTrace = True }))
- "" -- "Turn on diagnostic tracing in readers."
-
- , Option "" ["dump-args"]
- (NoArg
- (\opt -> return opt { optDumpArgs = True }))
- "" -- "Print output filename and arguments to stdout."
-
- , Option "" ["ignore-args"]
- (NoArg
- (\opt -> return opt { optIgnoreArgs = True }))
- "" -- "Ignore command-line arguments."
-
- , Option "" ["verbose"]
- (NoArg
- (\opt -> return opt { optVerbose = True }))
- "" -- "Verbose diagnostic output."
-
- , Option "" ["bash-completion"]
- (NoArg
- (\_ -> do
- ddir <- getDataDir
- tpl <- readDataFileUTF8 Nothing "bash_completion.tpl"
- let optnames (Option shorts longs _ _) =
- map (\c -> ['-',c]) shorts ++
- map ("--" ++) longs
- let allopts = unwords (concatMap optnames options)
- UTF8.hPutStrLn stdout $ printf tpl allopts
- (unwords (map fst readers))
- (unwords (map fst writers))
- (unwords $ map fst highlightingStyles)
- ddir
- exitSuccess ))
- "" -- "Print bash completion script"
-
- , Option "" ["list-input-formats"]
- (NoArg
- (\_ -> do
- let readers'names = sort (map fst readers)
- mapM_ (UTF8.hPutStrLn stdout) readers'names
- exitSuccess ))
- ""
-
- , Option "" ["list-output-formats"]
- (NoArg
- (\_ -> do
- let writers'names = sort (map fst writers)
- mapM_ (UTF8.hPutStrLn stdout) writers'names
- exitSuccess ))
- ""
-
- , Option "" ["list-extensions"]
- (NoArg
- (\_ -> do
- let showExt x = drop 4 (show x) ++
- if x `Set.member` pandocExtensions
- then " +"
- else " -"
- mapM_ (UTF8.hPutStrLn stdout . showExt)
- ([minBound..maxBound] :: [Extension])
- exitSuccess ))
- ""
-
- , Option "" ["list-highlight-languages"]
- (NoArg
- (\_ -> do
- let langs = [ T.unpack (T.toLower (sShortname s))
- | s <- M.elems defaultSyntaxMap
- , sShortname s `notElem`
- [T.pack "Alert", T.pack "Alert_indent"]
- ]
- mapM_ (UTF8.hPutStrLn stdout) langs
- exitSuccess ))
- ""
-
- , Option "" ["list-highlight-styles"]
- (NoArg
- (\_ -> do
- mapM_ (UTF8.hPutStrLn stdout) $
- map fst highlightingStyles
- exitSuccess ))
- ""
-
- , Option "v" ["version"]
- (NoArg
- (\_ -> do
- prg <- getProgName
- defaultDatadir <- E.catch
- (getAppUserDataDirectory "pandoc")
- (\e -> let _ = (e :: E.SomeException)
- in return "")
- UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
- compileInfo ++ "\nDefault user data directory: " ++
- defaultDatadir ++ copyrightMessage)
- exitSuccess ))
- "" -- "Print version"
-
- , Option "h" ["help"]
- (NoArg
- (\_ -> do
- prg <- getProgName
- UTF8.hPutStr stdout (usageMessage prg options)
- exitSuccess ))
- "" -- "Show help"
-
- ]
-
-
-addMetadata :: String -> MetaValue -> M.Map String MetaValue
- -> M.Map String MetaValue
-addMetadata k v m = case M.lookup k m of
- Nothing -> M.insert k v m
- Just (MetaList xs) -> M.insert k
- (MetaList (xs ++ [v])) m
- Just x -> M.insert k (MetaList [v, x]) m
-
-readMetaValue :: String -> MetaValue
-readMetaValue s = case decode (UTF8.fromString s) of
- Just (Yaml.String t) -> MetaString $ T.unpack t
- Just (Yaml.Bool b) -> MetaBool b
- _ -> MetaString s
-
--- Returns usage message
-usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
-usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]")
-
--- Determine default reader based on source file extensions
-defaultReaderName :: String -> [FilePath] -> String
-defaultReaderName fallback [] = fallback
-defaultReaderName fallback (x:xs) =
- case takeExtension (map toLower x) of
- ".xhtml" -> "html"
- ".html" -> "html"
- ".htm" -> "html"
- ".md" -> "markdown"
- ".markdown" -> "markdown"
- ".tex" -> "latex"
- ".latex" -> "latex"
- ".ltx" -> "latex"
- ".rst" -> "rst"
- ".org" -> "org"
- ".lhs" -> "markdown+lhs"
- ".db" -> "docbook"
- ".opml" -> "opml"
- ".wiki" -> "mediawiki"
- ".dokuwiki" -> "dokuwiki"
- ".textile" -> "textile"
- ".native" -> "native"
- ".json" -> "json"
- ".docx" -> "docx"
- ".t2t" -> "t2t"
- ".epub" -> "epub"
- ".odt" -> "odt"
- ".pdf" -> "pdf" -- so we get an "unknown reader" error
- ".doc" -> "doc" -- so we get an "unknown reader" error
- _ -> defaultReaderName fallback xs
-
--- Returns True if extension of first source is .lhs
-lhsExtension :: [FilePath] -> Bool
-lhsExtension (x:_) = takeExtension x == ".lhs"
-lhsExtension _ = False
-
--- Determine default writer based on output file extension
-defaultWriterName :: FilePath -> String
-defaultWriterName "-" = "html" -- no output file
-defaultWriterName x =
- case takeExtension (map toLower x) of
- "" -> "markdown" -- empty extension
- ".tex" -> "latex"
- ".latex" -> "latex"
- ".ltx" -> "latex"
- ".context" -> "context"
- ".ctx" -> "context"
- ".rtf" -> "rtf"
- ".rst" -> "rst"
- ".s5" -> "s5"
- ".native" -> "native"
- ".json" -> "json"
- ".txt" -> "markdown"
- ".text" -> "markdown"
- ".md" -> "markdown"
- ".markdown" -> "markdown"
- ".textile" -> "textile"
- ".lhs" -> "markdown+lhs"
- ".texi" -> "texinfo"
- ".texinfo" -> "texinfo"
- ".db" -> "docbook"
- ".odt" -> "odt"
- ".docx" -> "docx"
- ".epub" -> "epub"
- ".org" -> "org"
- ".asciidoc" -> "asciidoc"
- ".adoc" -> "asciidoc"
- ".pdf" -> "latex"
- ".fb2" -> "fb2"
- ".opml" -> "opml"
- ".icml" -> "icml"
- ".tei.xml" -> "tei"
- ".tei" -> "tei"
- ['.',y] | y `elem` ['1'..'9'] -> "man"
- _ -> "html"
-
--- Transformations of a Pandoc document post-parsing:
-
-extractMedia :: MediaBag -> FilePath -> Pandoc -> IO Pandoc
-extractMedia media dir d =
- case [fp | (fp, _, _) <- mediaDirectory media] of
- [] -> return d
- fps -> do
- extractMediaBag True dir media
- return $ walk (adjustImagePath dir fps) d
-
-adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
-adjustImagePath dir paths (Image attr lab (src, tit))
- | src `elem` paths = Image attr lab (dir ++ "/" ++ src, tit)
-adjustImagePath _ _ x = x
-
-adjustMetadata :: M.Map String MetaValue -> Pandoc -> IO Pandoc
-adjustMetadata metadata d = return $ M.foldWithKey setMeta d metadata
-
-applyTransforms :: [Transform] -> Pandoc -> IO Pandoc
-applyTransforms transforms d = return $ foldr ($) d transforms
-
- -- First we check to see if a filter is found. If not, and if it's
- -- not an absolute path, we check to see whether it's in `userdir/filters`.
- -- If not, we leave it unchanged.
-expandFilterPath :: Maybe FilePath -> FilePath -> IO FilePath
-expandFilterPath mbDatadir fp = do
- fpExists <- doesFileExist fp
- if fpExists
- then return fp
- else case mbDatadir of
- Just datadir | isRelative fp -> do
- let filterPath = (datadir </> "filters" </> fp)
- filterPathExists <- doesFileExist filterPath
- if filterPathExists
- then return filterPath
- else return fp
- _ -> return fp
-
-applyFilters :: Maybe FilePath -> [FilePath] -> [String] -> Pandoc -> IO Pandoc
-applyFilters mbDatadir filters args d = do
- expandedFilters <- mapM (expandFilterPath mbDatadir) filters
- foldrM ($) d $ map (flip externalFilter args) expandedFilters
-
-uppercaseFirstLetter :: String -> String
-uppercaseFirstLetter (c:cs) = toUpper c : cs
-uppercaseFirstLetter [] = []
+import Text.Pandoc.App (convertWithOpts, defaultOpts, options, parseOptions)
+import Text.Pandoc.Error (handleError)
main :: IO ()
-main = do
-
- rawArgs <- map UTF8.decodeArg <$> getArgs
- prg <- getProgName
-
- let (actions, args, errors) = getOpt Permute options rawArgs
-
- unless (null errors) $
- err 2 $ concat $ errors ++
- ["Try " ++ prg ++ " --help for more information."]
-
- -- thread option data structure through all supplied option actions
- opts <- foldl (>>=) (return defaultOpts) actions
- convertWithOpts opts args
-
-convertWithOpts :: Opt -> [FilePath] -> IO ()
-convertWithOpts opts args = do
- let Opt { optTabStop = tabStop
- , optPreserveTabs = preserveTabs
- , optStandalone = standalone
- , optReader = readerName
- , optWriter = writerName
- , optParseRaw = parseRaw
- , optVariables = variables
- , optMetadata = metadata
- , optTableOfContents = toc
- , optTransforms = transforms
- , optTemplate = templatePath
- , optOutputFile = outputFile
- , optNumberSections = numberSections
- , optNumberOffset = numberFrom
- , optSectionDivs = sectionDivs
- , optIncremental = incremental
- , optSelfContained = selfContained
- , optSmart = smart
- , optOldDashes = oldDashes
- , optHtml5 = html5
- , optHtmlQTags = htmlQTags
- , optHighlight = highlight
- , optHighlightStyle = highlightStyle
- , optTopLevelDivision = topLevelDivision
- , optHTMLMathMethod = mathMethod'
- , optReferenceODT = referenceODT
- , optReferenceDocx = referenceDocx
- , optEpubStylesheet = epubStylesheet
- , optEpubMetadata = epubMetadata
- , optEpubFonts = epubFonts
- , optEpubChapterLevel = epubChapterLevel
- , optTOCDepth = epubTOCDepth
- , optDumpArgs = dumpArgs
- , optIgnoreArgs = ignoreArgs
- , optVerbose = verbose
- , optReferenceLinks = referenceLinks
- , optReferenceLocation = referenceLocation
- , optDpi = dpi
- , optWrapText = wrap
- , optColumns = columns
- , optFilters = filters
- , optEmailObfuscation = obfuscationMethod
- , optIdentifierPrefix = idPrefix
- , optIndentedCodeClasses = codeBlockClasses
- , optDataDir = mbDataDir
- , optCiteMethod = citeMethod
- , optListings = listings
- , optLaTeXEngine = latexEngine
- , optLaTeXEngineArgs = latexEngineArgs
- , optSlideLevel = slideLevel
- , optSetextHeaders = setextHeaders
- , optAscii = ascii
- , optTeXLigatures = texLigatures
- , optDefaultImageExtension = defaultImageExtension
- , optExtractMedia = mbExtractMedia
- , optTrace = trace
- , optTrackChanges = trackChanges
- , optFileScope = fileScope
- , optKaTeXStylesheet = katexStylesheet
- , optKaTeXJS = katexJS
- } = opts
-
- when dumpArgs $
- do UTF8.hPutStrLn stdout outputFile
- mapM_ (UTF8.hPutStrLn stdout) args
- exitSuccess
-
- let csscdn = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css"
- let mathMethod =
- case (katexJS, katexStylesheet) of
- (Nothing, _) -> mathMethod'
- (Just js, ss) -> KaTeX js (fromMaybe csscdn ss)
-
-
- -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
- let needsCiteproc = isJust (M.lookup "bibliography" (optMetadata opts)) &&
- optCiteMethod opts `notElem` [Natbib, Biblatex] &&
- "pandoc-citeproc" `notElem` map takeBaseName filters
- let filters' = if needsCiteproc then "pandoc-citeproc" : filters
- else filters
-
- let sources = if ignoreArgs then [] else args
-
- datadir <- case mbDataDir of
- Nothing -> E.catch
- (Just <$> getAppUserDataDirectory "pandoc")
- (\e -> let _ = (e :: E.SomeException)
- in return Nothing)
- Just _ -> return mbDataDir
-
- -- assign reader and writer based on options and filenames
- let readerName' = case map toLower readerName of
- [] -> defaultReaderName
- (if any isURI sources
- then "html"
- else "markdown") sources
- "html4" -> "html"
- x -> x
-
- let writerName' = case map toLower writerName of
- [] -> defaultWriterName outputFile
- "epub2" -> "epub"
- "html4" -> "html"
- x -> x
- let format = takeWhile (`notElem` ['+','-'])
- $ takeFileName writerName' -- in case path to lua script
-
- let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
-
- let laTeXOutput = format `elem` ["latex", "beamer"]
- let conTeXtOutput = format == "context"
- let html5Output = format == "html5"
-
- let laTeXInput = "latex" `isPrefixOf` readerName' ||
- "beamer" `isPrefixOf` readerName'
-
- writer <- if ".lua" `isSuffixOf` format
- -- note: use non-lowercased version writerName
- then return $ IOStringWriter $ writeCustom writerName
- else case getWriter writerName' of
- Left e -> err 9 $
- if format == "pdf"
- then e ++
- "\nTo create a pdf with pandoc, use " ++
- "the latex or beamer writer and specify\n" ++
- "an output file with .pdf extension " ++
- "(pandoc -t latex -o filename.pdf)."
- else e
- Right w -> return w
-
- reader <- if "t2t" == readerName'
- then (mkStringReader .
- readTxt2Tags) <$>
- getT2TMeta sources outputFile
- else case getReader readerName' of
- Right r -> return r
- Left e -> err 7 e'
- where e' = case readerName' of
- "pdf" -> e ++
- "\nPandoc can convert to PDF, but not from PDF."
- "doc" -> e ++
- "\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc."
- _ -> e
-
- let standalone' = standalone || not (isTextFormat format) || pdfOutput
-
- templ <- case templatePath of
- _ | not standalone' -> return Nothing
- Nothing -> do
- deftemp <- getDefaultTemplate datadir format
- case deftemp of
- Left e -> throwIO e
- Right t -> return (Just t)
- Just tp -> do
- -- strip off extensions
- let tp' = case takeExtension tp of
- "" -> tp <.> format
- _ -> tp
- Just <$> E.catch (UTF8.readFile tp')
- (\e -> if isDoesNotExistError e
- then E.catch
- (readDataFileUTF8 datadir
- ("templates" </> tp'))
- (\e' -> let _ = (e' :: E.SomeException)
- in throwIO e')
- else throwIO e)
-
- variables' <- case mathMethod of
- LaTeXMathML Nothing -> do
- s <- readDataFileUTF8 datadir "LaTeXMathML.js"
- return $ ("mathml-script", s) : variables
- _ -> return variables
-
- variables'' <- if format == "dzslides"
- then do
- dztempl <- readDataFileUTF8 datadir
- ("dzslides" </> "template.html")
- let dzline = "<!-- {{{{ dzslides core"
- let dzcore = unlines
- $ dropWhile (not . (dzline `isPrefixOf`))
- $ lines dztempl
- return $ ("dzslides-core", dzcore) : variables'
- else return variables'
-
- let sourceURL = case sources of
- [] -> Nothing
- (x:_) -> case parseURI x of
- Just u
- | uriScheme u `elem` ["http:","https:"] ->
- Just $ show u{ uriQuery = "",
- uriFragment = "" }
- _ -> Nothing
-
- let readerOpts = def{ readerSmart = if laTeXInput
- then texLigatures
- else smart || (texLigatures &&
- (laTeXOutput || conTeXtOutput))
- , readerStandalone = standalone'
- , readerParseRaw = parseRaw
- , readerColumns = columns
- , readerTabStop = tabStop
- , readerOldDashes = oldDashes
- , readerIndentedCodeClasses = codeBlockClasses
- , readerApplyMacros = not laTeXOutput
- , readerDefaultImageExtension = defaultImageExtension
- , readerTrace = trace
- , readerTrackChanges = trackChanges
- , readerFileScope = fileScope
- }
-
-#ifdef _WINDOWS
- let istty = True
-#else
- istty <- queryTerminal stdOutput
-#endif
- when (istty && not (isTextFormat format) && outputFile == "-") $
- err 5 $ "Cannot write " ++ format ++ " output to stdout.\n" ++
- "Specify an output file using the -o option."
-
- let readSources [] = mapM readSource ["-"]
- readSources srcs = mapM readSource srcs
- readSource "-" = UTF8.getContents
- readSource src = case parseURI src of
- Just u | uriScheme u `elem` ["http:","https:"] ->
- readURI src
- | uriScheme u == "file:" ->
- UTF8.readFile (uriPath u)
- _ -> UTF8.readFile src
- readURI src = do
- res <- openURL src
- case res of
- Left e -> throwIO e
- Right (bs,_) -> return $ UTF8.toString bs
-
- let readFiles [] = error "Cannot read archive from stdin"
- readFiles [x] = B.readFile x
- readFiles (x:xs) = mapM_ (warn . ("Ignoring: " ++)) xs >> B.readFile x
-
- let convertTabs = tabFilter (if preserveTabs || readerName' == "t2t"
- then 0
- else tabStop)
-
- let handleIncludes' :: String -> IO (Either PandocError String)
- handleIncludes' = if readerName' `elem` ["latex", "latex+lhs"]
- then handleIncludes
- else return . Right
-
- let sourceToDoc :: [FilePath] -> IO (Pandoc, MediaBag)
- sourceToDoc sources' = fmap handleError $
- case reader of
- StringReader r-> do
- srcs <- convertTabs . intercalate "\n" <$> readSources sources'
- doc <- handleIncludes' srcs
- either (return . Left) (\s -> fmap (,mempty) <$> r readerOpts s) doc
- ByteStringReader r -> readFiles sources' >>= r readerOpts
-
- -- We parse first if (1) fileScope is set, (2), it's a binary
- -- reader, or (3) we're reading JSON. This is easier to do of an AND
- -- of negatives as opposed to an OR of positives, so we do default
- -- parsing if it's a StringReader AND (fileScope is set AND it's not
- -- a JSON reader).
- (doc, media) <- case reader of
- (StringReader _) | not fileScope && readerName' /= "json" ->
- sourceToDoc sources
- _ | null sources -> sourceToDoc sources
- _ -> do pairs <- mapM (\s -> sourceToDoc [s]) sources
- return (mconcat $ map fst pairs, mconcat $ map snd pairs)
-
- let writerOptions = def { writerTemplate = templ,
- writerVariables = variables'',
- writerTabStop = tabStop,
- writerTableOfContents = toc,
- writerHTMLMathMethod = mathMethod,
- writerIncremental = incremental,
- writerCiteMethod = citeMethod,
- writerIgnoreNotes = False,
- writerNumberSections = numberSections,
- writerNumberOffset = numberFrom,
- writerSectionDivs = sectionDivs,
- writerReferenceLinks = referenceLinks,
- writerReferenceLocation = referenceLocation,
- writerDpi = dpi,
- writerWrapText = wrap,
- writerColumns = columns,
- writerEmailObfuscation = obfuscationMethod,
- writerIdentifierPrefix = idPrefix,
- writerSourceURL = sourceURL,
- writerUserDataDir = datadir,
- writerHtml5 = html5,
- writerHtmlQTags = htmlQTags,
- writerTopLevelDivision = topLevelDivision,
- writerListings = listings,
- writerBeamer = False,
- writerSlideLevel = slideLevel,
- writerHighlight = highlight,
- writerHighlightStyle = highlightStyle,
- writerSetextHeaders = setextHeaders,
- writerTeXLigatures = texLigatures,
- writerEpubMetadata = epubMetadata,
- writerEpubStylesheet = epubStylesheet,
- writerEpubFonts = epubFonts,
- writerEpubChapterLevel = epubChapterLevel,
- writerTOCDepth = epubTOCDepth,
- writerReferenceODT = referenceODT,
- writerReferenceDocx = referenceDocx,
- writerMediaBag = media,
- writerVerbose = verbose,
- writerLaTeXArgs = latexEngineArgs
- }
-
-
- doc' <- (maybe return (extractMedia media) mbExtractMedia >=>
- adjustMetadata metadata >=>
- applyTransforms transforms >=>
- applyFilters datadir filters' [format]) doc
-
- let writeFnBinary :: FilePath -> B.ByteString -> IO ()
- writeFnBinary "-" = B.putStr
- writeFnBinary f = B.writeFile (UTF8.encodePath f)
-
- let writerFn :: FilePath -> String -> IO ()
- writerFn "-" = UTF8.putStr
- writerFn f = UTF8.writeFile f
-
- case writer of
- IOStringWriter f -> f writerOptions doc' >>= writerFn outputFile
- IOByteStringWriter f -> f writerOptions doc' >>= writeFnBinary outputFile
- PureStringWriter f
- | pdfOutput -> do
- -- make sure writer is latex or beamer or context or html5
- unless (laTeXOutput || conTeXtOutput || html5Output) $
- err 47 $ "cannot produce pdf output with " ++ format ++
- " writer"
-
- let pdfprog = case () of
- _ | conTeXtOutput -> "context"
- _ | html5Output -> "wkhtmltopdf"
- _ -> latexEngine
- -- check for pdf creating program
- mbPdfProg <- findExecutable pdfprog
- when (isNothing mbPdfProg) $
- err 41 $ pdfprog ++ " not found. " ++
- pdfprog ++ " is needed for pdf output."
-
- res <- makePDF pdfprog f writerOptions doc'
- case res of
- Right pdf -> writeFnBinary outputFile pdf
- Left err' -> do
- B.hPutStr stderr err'
- B.hPut stderr $ B.pack [10]
- err 43 "Error producing PDF"
- | otherwise -> selfcontain (f writerOptions doc' ++
- ['\n' | not standalone'])
- >>= writerFn outputFile . handleEntities
- where htmlFormat = format `elem`
- ["html","html5","s5","slidy","slideous","dzslides","revealjs"]
- selfcontain = if selfContained && htmlFormat
- then makeSelfContained writerOptions
- else return
- handleEntities = if htmlFormat && ascii
- then toEntities
- else id
+main = E.catch (parseOptions options defaultOpts >>= convertWithOpts)
+ (handleError . Left)
diff --git a/prelude/Prelude.hs b/prelude/Prelude.hs
deleted file mode 100644
index 34f133d83..000000000
--- a/prelude/Prelude.hs
+++ /dev/null
@@ -1,26 +0,0 @@
-{-# LANGUAGE PackageImports #-}
-{-# LANGUAGE CPP #-}
-
--- This custom Prelude emulates the API of the prelude
--- with base 4.8.
-
-module Prelude
-(
- module P
-#if MIN_VERSION_base(4,8,0)
-#else
-, Monoid(..)
-, Applicative(..)
-, (<$>)
-, (<$)
-#endif
-)
-where
-
-#if MIN_VERSION_base(4,8,0)
-import "base" Prelude as P
-#else
-import "base" Prelude as P
-import Control.Applicative
-import Data.Monoid
-#endif
diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs
index d83fa85e7..dd2856674 100644
--- a/src/Text/Pandoc.hs
+++ b/src/Text/Pandoc.hs
@@ -1,6 +1,8 @@
-{-# LANGUAGE ScopedTypeVariables, FlexibleInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -37,17 +39,18 @@ inline links:
> module Main where
> import Text.Pandoc
+> import Data.Text (Text)
+> import qualified Data.Text.IO as T
>
-> markdownToRST :: String -> String
-> markdownToRST =
-> writeRST def {writerReferenceLinks = True} .
-> handleError . readMarkdown def
->
-> main = getContents >>= putStrLn . markdownToRST
+> mdToRST :: Text -> IO Text
+> mdToRST txt = runIOorExplode $
+> readMarkdown def txt
+> >>= writeRST def{ writerReferenceLinks = True }
-Note: all of the readers assume that the input text has @'\n'@
-line endings. So if you get your input text from a web form,
-you should remove @'\r'@ characters using @filter (/='\r')@.
+>
+> main :: IO ()
+> main = do
+> T.getContents >>= mdToRST >>= T.putStrLn
-}
@@ -59,332 +62,29 @@ module Text.Pandoc
, module Text.Pandoc.Generic
-- * Options
, module Text.Pandoc.Options
+ -- * Logging
+ , module Text.Pandoc.Logging
+ -- * Typeclass
+ , module Text.Pandoc.Class
-- * Error handling
, module Text.Pandoc.Error
- -- * Lists of readers and writers
- , readers
- , writers
-- * Readers: converting /to/ Pandoc format
- , Reader (..)
- , mkStringReader
- , readDocx
- , readOdt
- , readMarkdown
- , readCommonMark
- , readMediaWiki
- , readRST
- , readOrg
- , readLaTeX
- , readHtml
- , readTextile
- , readDocBook
- , readOPML
- , readHaddock
- , readNative
- , readJSON
- , readTWiki
- , readTxt2Tags
- , readTxt2TagsNoMacros
- , readEPUB
+ , module Text.Pandoc.Readers
-- * Writers: converting /from/ Pandoc format
- , Writer (..)
- , writeNative
- , writeJSON
- , writeMarkdown
- , writePlain
- , writeRST
- , writeLaTeX
- , writeConTeXt
- , writeTexinfo
- , writeHtml
- , writeHtmlString
- , writeICML
- , writeDocbook
- , writeOPML
- , writeOpenDocument
- , writeMan
- , writeMediaWiki
- , writeDokuWiki
- , writeZimWiki
- , writeTextile
- , writeRTF
- , writeODT
- , writeDocx
- , writeEPUB
- , writeFB2
- , writeOrg
- , writeAsciiDoc
- , writeHaddock
- , writeCommonMark
- , writeCustom
- , writeTEI
+ , module Text.Pandoc.Writers
-- * Rendering templates and default templates
, module Text.Pandoc.Templates
-- * Miscellaneous
- , getReader
- , getWriter
- , getDefaultExtensions
- , ToJsonFilter(..)
, pandocVersion
) where
+import Text.Pandoc.Class
import Text.Pandoc.Definition
+import Text.Pandoc.Error
import Text.Pandoc.Generic
-import Text.Pandoc.JSON
-import Text.Pandoc.Readers.Markdown
-import Text.Pandoc.Readers.CommonMark
-import Text.Pandoc.Readers.MediaWiki
-import Text.Pandoc.Readers.RST
-import Text.Pandoc.Readers.Org
-import Text.Pandoc.Readers.DocBook
-import Text.Pandoc.Readers.OPML
-import Text.Pandoc.Readers.LaTeX
-import Text.Pandoc.Readers.HTML
-import Text.Pandoc.Readers.Textile
-import Text.Pandoc.Readers.Native
-import Text.Pandoc.Readers.Haddock
-import Text.Pandoc.Readers.TWiki
-import Text.Pandoc.Readers.Docx
-import Text.Pandoc.Readers.Odt
-import Text.Pandoc.Readers.Txt2Tags
-import Text.Pandoc.Readers.EPUB
-import Text.Pandoc.Writers.Native
-import Text.Pandoc.Writers.Markdown
-import Text.Pandoc.Writers.RST
-import Text.Pandoc.Writers.LaTeX
-import Text.Pandoc.Writers.ConTeXt
-import Text.Pandoc.Writers.Texinfo
-import Text.Pandoc.Writers.HTML
-import Text.Pandoc.Writers.ODT
-import Text.Pandoc.Writers.Docx
-import Text.Pandoc.Writers.EPUB
-import Text.Pandoc.Writers.FB2
-import Text.Pandoc.Writers.ICML
-import Text.Pandoc.Writers.Docbook
-import Text.Pandoc.Writers.OPML
-import Text.Pandoc.Writers.OpenDocument
-import Text.Pandoc.Writers.Man
-import Text.Pandoc.Writers.RTF
-import Text.Pandoc.Writers.MediaWiki
-import Text.Pandoc.Writers.DokuWiki
-import Text.Pandoc.Writers.ZimWiki
-import Text.Pandoc.Writers.Textile
-import Text.Pandoc.Writers.Org
-import Text.Pandoc.Writers.AsciiDoc
-import Text.Pandoc.Writers.Haddock
-import Text.Pandoc.Writers.CommonMark
-import Text.Pandoc.Writers.Custom
-import Text.Pandoc.Writers.TEI
-import Text.Pandoc.Templates
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Shared (safeRead, warn, mapLeft, pandocVersion)
-import Text.Pandoc.MediaBag (MediaBag)
-import Text.Pandoc.Error
-import Data.Aeson
-import qualified Data.ByteString.Lazy as BL
-import Data.List (intercalate)
-import Data.Set (Set)
-import qualified Data.Set as Set
-import Text.Parsec
-import Text.Parsec.Error
-import qualified Text.Pandoc.UTF8 as UTF8
-
-parseFormatSpec :: String
- -> Either ParseError (String, Set Extension -> Set Extension)
-parseFormatSpec = parse formatSpec ""
- where formatSpec = do
- name <- formatName
- extMods <- many extMod
- return (name, \x -> foldl (flip ($)) x extMods)
- formatName = many1 $ noneOf "-+"
- extMod = do
- polarity <- oneOf "-+"
- name <- many $ noneOf "-+"
- ext <- case safeRead ("Ext_" ++ name) of
- Just n -> return n
- Nothing
- | name == "lhs" -> return Ext_literate_haskell
- | otherwise -> fail $ "Unknown extension: " ++ name
- return $ case polarity of
- '-' -> Set.delete ext
- _ -> Set.insert ext
-
-
-data Reader = StringReader (ReaderOptions -> String -> IO (Either PandocError Pandoc))
- | ByteStringReader (ReaderOptions -> BL.ByteString -> IO (Either PandocError (Pandoc,MediaBag)))
-
-mkStringReader :: (ReaderOptions -> String -> Either PandocError Pandoc) -> Reader
-mkStringReader r = StringReader (\o s -> return $ r o s)
-
-mkStringReaderWithWarnings :: (ReaderOptions -> String -> Either PandocError (Pandoc, [String])) -> Reader
-mkStringReaderWithWarnings r = StringReader $ \o s ->
- case r o s of
- Left err -> return $ Left err
- Right (doc, warnings) -> do
- mapM_ warn warnings
- return (Right doc)
-
-mkBSReader :: (ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag)) -> Reader
-mkBSReader r = ByteStringReader (\o s -> return $ r o s)
-
-mkBSReaderWithWarnings :: (ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag, [String])) -> Reader
-mkBSReaderWithWarnings r = ByteStringReader $ \o s ->
- case r o s of
- Left err -> return $ Left err
- Right (doc, mediaBag, warnings) -> do
- mapM_ warn warnings
- return $ Right (doc, mediaBag)
-
--- | Association list of formats and readers.
-readers :: [(String, Reader)]
-readers = [ ("native" , StringReader $ \_ s -> return $ readNative s)
- ,("json" , mkStringReader readJSON )
- ,("markdown" , mkStringReaderWithWarnings readMarkdownWithWarnings)
- ,("markdown_strict" , mkStringReaderWithWarnings readMarkdownWithWarnings)
- ,("markdown_phpextra" , mkStringReaderWithWarnings readMarkdownWithWarnings)
- ,("markdown_github" , mkStringReaderWithWarnings readMarkdownWithWarnings)
- ,("markdown_mmd", mkStringReaderWithWarnings readMarkdownWithWarnings)
- ,("commonmark" , mkStringReader readCommonMark)
- ,("rst" , mkStringReaderWithWarnings readRSTWithWarnings )
- ,("mediawiki" , mkStringReader readMediaWiki)
- ,("docbook" , mkStringReader readDocBook)
- ,("opml" , mkStringReader readOPML)
- ,("org" , mkStringReader readOrg)
- ,("textile" , mkStringReader readTextile) -- TODO : textile+lhs
- ,("html" , mkStringReader readHtml)
- ,("latex" , mkStringReader readLaTeX)
- ,("haddock" , mkStringReader readHaddock)
- ,("twiki" , mkStringReader readTWiki)
- ,("docx" , mkBSReaderWithWarnings readDocxWithWarnings)
- ,("odt" , mkBSReader readOdt)
- ,("t2t" , mkStringReader readTxt2TagsNoMacros)
- ,("epub" , mkBSReader readEPUB)
- ]
-
-data Writer = PureStringWriter (WriterOptions -> Pandoc -> String)
- | IOStringWriter (WriterOptions -> Pandoc -> IO String)
- | IOByteStringWriter (WriterOptions -> Pandoc -> IO BL.ByteString)
-
--- | Association list of formats and writers.
-writers :: [ ( String, Writer ) ]
-writers = [
- ("native" , PureStringWriter writeNative)
- ,("json" , PureStringWriter writeJSON)
- ,("docx" , IOByteStringWriter writeDocx)
- ,("odt" , IOByteStringWriter writeODT)
- ,("epub" , IOByteStringWriter $ \o ->
- writeEPUB o{ writerEpubVersion = Just EPUB2 })
- ,("epub3" , IOByteStringWriter $ \o ->
- writeEPUB o{ writerEpubVersion = Just EPUB3 })
- ,("fb2" , IOStringWriter writeFB2)
- ,("html" , PureStringWriter writeHtmlString)
- ,("html5" , PureStringWriter $ \o ->
- writeHtmlString o{ writerHtml5 = True })
- ,("icml" , IOStringWriter writeICML)
- ,("s5" , PureStringWriter $ \o ->
- writeHtmlString o{ writerSlideVariant = S5Slides
- , writerTableOfContents = False })
- ,("slidy" , PureStringWriter $ \o ->
- writeHtmlString o{ writerSlideVariant = SlidySlides })
- ,("slideous" , PureStringWriter $ \o ->
- writeHtmlString o{ writerSlideVariant = SlideousSlides })
- ,("dzslides" , PureStringWriter $ \o ->
- writeHtmlString o{ writerSlideVariant = DZSlides
- , writerHtml5 = True })
- ,("revealjs" , PureStringWriter $ \o ->
- writeHtmlString o{ writerSlideVariant = RevealJsSlides
- , writerHtml5 = True })
- ,("docbook" , PureStringWriter writeDocbook)
- ,("docbook5" , PureStringWriter $ \o ->
- writeDocbook o{ writerDocbook5 = True })
- ,("opml" , PureStringWriter writeOPML)
- ,("opendocument" , PureStringWriter writeOpenDocument)
- ,("latex" , PureStringWriter writeLaTeX)
- ,("beamer" , PureStringWriter $ \o ->
- writeLaTeX o{ writerBeamer = True })
- ,("context" , PureStringWriter writeConTeXt)
- ,("texinfo" , PureStringWriter writeTexinfo)
- ,("man" , PureStringWriter writeMan)
- ,("markdown" , PureStringWriter writeMarkdown)
- ,("markdown_strict" , PureStringWriter writeMarkdown)
- ,("markdown_phpextra" , PureStringWriter writeMarkdown)
- ,("markdown_github" , PureStringWriter writeMarkdown)
- ,("markdown_mmd" , PureStringWriter writeMarkdown)
- ,("plain" , PureStringWriter writePlain)
- ,("rst" , PureStringWriter writeRST)
- ,("mediawiki" , PureStringWriter writeMediaWiki)
- ,("dokuwiki" , PureStringWriter writeDokuWiki)
- ,("zimwiki" , PureStringWriter writeZimWiki)
- ,("textile" , PureStringWriter writeTextile)
- ,("rtf" , IOStringWriter writeRTFWithEmbeddedImages)
- ,("org" , PureStringWriter writeOrg)
- ,("asciidoc" , PureStringWriter writeAsciiDoc)
- ,("haddock" , PureStringWriter writeHaddock)
- ,("commonmark" , PureStringWriter writeCommonMark)
- ,("tei" , PureStringWriter writeTEI)
- ]
-
-getDefaultExtensions :: String -> Set Extension
-getDefaultExtensions "markdown_strict" = strictExtensions
-getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
-getDefaultExtensions "markdown_mmd" = multimarkdownExtensions
-getDefaultExtensions "markdown_github" = githubMarkdownExtensions
-getDefaultExtensions "markdown" = pandocExtensions
-getDefaultExtensions "plain" = plainExtensions
-getDefaultExtensions "org" = Set.fromList [Ext_citations,
- Ext_auto_identifiers]
-getDefaultExtensions "textile" = Set.fromList [Ext_auto_identifiers]
-getDefaultExtensions "html" = Set.fromList [Ext_auto_identifiers,
- Ext_native_divs,
- Ext_native_spans]
-getDefaultExtensions "html5" = getDefaultExtensions "html"
-getDefaultExtensions "epub" = Set.fromList [Ext_raw_html,
- Ext_native_divs,
- Ext_native_spans,
- Ext_epub_html_exts]
-getDefaultExtensions _ = Set.fromList [Ext_auto_identifiers]
-
--- | Retrieve reader based on formatSpec (format+extensions).
-getReader :: String -> Either String Reader
-getReader s =
- case parseFormatSpec s of
- Left e -> Left $ intercalate "\n" [m | Message m <- errorMessages e]
- Right (readerName, setExts) ->
- case lookup readerName readers of
- Nothing -> Left $ "Unknown reader: " ++ readerName
- Just (StringReader r) -> Right $ StringReader $ \o ->
- r o{ readerExtensions = setExts $
- getDefaultExtensions readerName }
- Just (ByteStringReader r) -> Right $ ByteStringReader $ \o ->
- r o{ readerExtensions = setExts $
- getDefaultExtensions readerName }
-
--- | Retrieve writer based on formatSpec (format+extensions).
-getWriter :: String -> Either String Writer
-getWriter s
- = case parseFormatSpec s of
- Left e -> Left $ intercalate "\n" [m | Message m <- errorMessages e]
- Right (writerName, setExts) ->
- case lookup writerName writers of
- Nothing -> Left $ "Unknown writer: " ++ writerName
- Just (PureStringWriter r) -> Right $ PureStringWriter $
- \o -> r o{ writerExtensions = setExts $
- getDefaultExtensions writerName }
- Just (IOStringWriter r) -> Right $ IOStringWriter $
- \o -> r o{ writerExtensions = setExts $
- getDefaultExtensions writerName }
- Just (IOByteStringWriter r) -> Right $ IOByteStringWriter $
- \o -> r o{ writerExtensions = setExts $
- getDefaultExtensions writerName }
-
-{-# DEPRECATED toJsonFilter "Use 'toJSONFilter' from 'Text.Pandoc.JSON' instead" #-}
--- | Deprecated. Use @toJSONFilter@ from @Text.Pandoc.JSON@ instead.
-class ToJSONFilter a => ToJsonFilter a
- where toJsonFilter :: a -> IO ()
- toJsonFilter = toJSONFilter
-
-readJSON :: ReaderOptions -> String -> Either PandocError Pandoc
-readJSON _ = mapLeft ParseFailure . eitherDecode' . UTF8.fromStringLazy
-
-writeJSON :: WriterOptions -> Pandoc -> String
-writeJSON _ = UTF8.toStringLazy . encode
+import Text.Pandoc.Readers
+import Text.Pandoc.Shared (pandocVersion)
+import Text.Pandoc.Templates
+import Text.Pandoc.Writers
diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs
new file mode 100644
index 000000000..26c754cd6
--- /dev/null
+++ b/src/Text/Pandoc/App.hs
@@ -0,0 +1,1636 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TupleSections #-}
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.App
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley@edu>
+ Stability : alpha
+ Portability : portable
+
+Does a pandoc conversion based on command-line options.
+-}
+module Text.Pandoc.App (
+ convertWithOpts
+ , Opt(..)
+ , LineEnding(..)
+ , Filter(..)
+ , defaultOpts
+ , parseOptions
+ , options
+ , applyFilters
+ ) where
+import qualified Control.Exception as E
+import Control.Monad
+import Control.Monad.Except (catchError, throwError)
+import Control.Monad.Trans
+import Data.Aeson (defaultOptions)
+import Data.Aeson.TH (deriveJSON)
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as B
+import Data.Char (toLower, toUpper)
+import Data.List (find, intercalate, isPrefixOf, isSuffixOf, sort)
+import qualified Data.Map as M
+import Data.Maybe (fromMaybe, isJust, isNothing)
+import Data.Monoid
+import qualified Data.Set as Set
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as TE
+import qualified Data.Text.Encoding.Error as TE
+import Data.Yaml (decode)
+import qualified Data.Yaml as Yaml
+import GHC.Generics
+import Network.URI (URI (..), parseURI)
+import Paths_pandoc (getDataDir)
+import Data.Aeson.Encode.Pretty (encodePretty', Config(..), keyOrder,
+ defConfig, Indent(..), NumberFormat(..))
+import Skylighting (Style, Syntax (..), defaultSyntaxMap, parseTheme,
+ pygments)
+import Skylighting.Parser (addSyntaxDefinition, parseSyntaxDefinition)
+import System.Console.GetOpt
+import System.Directory (getAppUserDataDirectory)
+import System.Environment (getArgs, getProgName)
+import System.Exit (exitSuccess)
+import System.FilePath
+import System.IO (nativeNewline, stdout)
+import qualified System.IO as IO (Newline (..))
+import System.IO.Error (isDoesNotExistError)
+import Text.Pandoc
+import Text.Pandoc.BCP47 (Lang (..), parseBCP47)
+import Text.Pandoc.Builder (setMeta, deleteMeta)
+import Text.Pandoc.Filter (Filter (JSONFilter, LuaFilter), applyFilters)
+import Text.Pandoc.Highlighting (highlightingStyles)
+import Text.Pandoc.PDF (makePDF)
+import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained)
+import Text.Pandoc.Shared (eastAsianLineBreakFilter, stripEmptyParagraphs,
+ headerShift, isURI, ordNub, safeRead, tabFilter)
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.Pandoc.Writers.Math (defaultKaTeXURL, defaultMathJaxURL)
+import Text.Pandoc.XML (toEntities)
+import Text.Printf
+#ifndef _WINDOWS
+import System.Posix.IO (stdOutput)
+import System.Posix.Terminal (queryTerminal)
+#endif
+
+data LineEnding = LF | CRLF | Native deriving (Show, Generic)
+
+parseOptions :: [OptDescr (Opt -> IO Opt)] -> Opt -> IO Opt
+parseOptions options' defaults = do
+ rawArgs <- map UTF8.decodeArg <$> getArgs
+ prg <- getProgName
+
+ let (actions, args, unrecognizedOpts, errors) =
+ getOpt' Permute options' rawArgs
+
+ let unknownOptionErrors =
+ foldr (handleUnrecognizedOption . takeWhile (/= '=')) []
+ unrecognizedOpts
+
+ unless (null errors && null unknownOptionErrors) $
+ E.throwIO $ PandocOptionError $
+ concat errors ++ unlines unknownOptionErrors ++
+ ("Try " ++ prg ++ " --help for more information.")
+
+ -- thread option data structure through all supplied option actions
+ opts <- foldl (>>=) (return defaults) actions
+ return (opts{ optInputFiles = args })
+
+latexEngines :: [String]
+latexEngines = ["pdflatex", "lualatex", "xelatex"]
+
+htmlEngines :: [String]
+htmlEngines = ["wkhtmltopdf", "weasyprint", "prince"]
+
+engines :: [(String, String)]
+engines = map ("html",) htmlEngines ++
+ map ("html5",) htmlEngines ++
+ map ("latex",) latexEngines ++
+ map ("beamer",) latexEngines ++
+ [ ("ms", "pdfroff")
+ , ("context", "context")
+ ]
+
+pdfEngines :: [String]
+pdfEngines = ordNub $ map snd engines
+
+pdfWriterAndProg :: Maybe String -- ^ user-specified writer name
+ -> Maybe String -- ^ user-specified pdf-engine
+ -> IO (String, Maybe String) -- ^ IO (writerName, maybePdfEngineProg)
+pdfWriterAndProg mWriter mEngine = do
+ let panErr msg = liftIO $ E.throwIO $ PandocAppError msg
+ case go mWriter mEngine of
+ Right (writ, prog) -> return (writ, Just prog)
+ Left err -> panErr err
+ where
+ go Nothing Nothing = Right ("latex", "pdflatex")
+ go (Just writer) Nothing = (writer,) <$> engineForWriter writer
+ go Nothing (Just engine) = (,engine) <$> writerForEngine engine
+ go (Just writer) (Just engine) =
+ case find (== (baseWriterName writer, engine)) engines of
+ Just _ -> Right (writer, engine)
+ Nothing -> Left $ "pdf-engine " ++ engine ++
+ " is not compatible with output format " ++ writer
+
+ writerForEngine eng = case [f | (f,e) <- engines, e == eng] of
+ fmt : _ -> Right fmt
+ [] -> Left $
+ "pdf-engine " ++ eng ++ " not known"
+
+ engineForWriter w = case [e | (f,e) <- engines, f == baseWriterName w] of
+ eng : _ -> Right eng
+ [] -> Left $
+ "cannot produce pdf output from " ++ w
+
+convertWithOpts :: Opt -> IO ()
+convertWithOpts opts = do
+ let outputFile = fromMaybe "-" (optOutputFile opts)
+ let filters = optFilters opts
+ let verbosity = optVerbosity opts
+
+ when (optDumpArgs opts) $
+ do UTF8.hPutStrLn stdout outputFile
+ mapM_ (UTF8.hPutStrLn stdout) (optInputFiles opts)
+ exitSuccess
+
+ epubMetadata <- case optEpubMetadata opts of
+ Nothing -> return Nothing
+ Just fp -> Just <$> UTF8.readFile fp
+
+ let isPandocCiteproc (JSONFilter f) = takeBaseName f == "pandoc-citeproc"
+ isPandocCiteproc _ = False
+ -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
+ let needsCiteproc = isJust (lookup "bibliography" (optMetadata opts)) &&
+ optCiteMethod opts `notElem` [Natbib, Biblatex] &&
+ all (not . isPandocCiteproc) filters
+ let filters' = if needsCiteproc then JSONFilter "pandoc-citeproc" : filters
+ else filters
+
+ let sources = case optInputFiles opts of
+ [] -> ["-"]
+ xs | optIgnoreArgs opts -> ["-"]
+ | otherwise -> xs
+
+ datadir <- case optDataDir opts of
+ Nothing -> E.catch
+ (Just <$> getAppUserDataDirectory "pandoc")
+ (\e -> let _ = (e :: E.SomeException)
+ in return Nothing)
+ Just _ -> return $ optDataDir opts
+
+ -- assign reader and writer based on options and filenames
+ let readerName = fromMaybe ( defaultReaderName
+ (if any isURI sources
+ then "html"
+ else "markdown") sources) (optReader opts)
+
+ let nonPdfWriterName Nothing = defaultWriterName outputFile
+ nonPdfWriterName (Just x) = x
+
+ let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
+ (writerName, maybePdfProg) <-
+ if pdfOutput
+ then pdfWriterAndProg (optWriter opts) (optPdfEngine opts)
+ else return (nonPdfWriterName $ optWriter opts, Nothing)
+
+ let format = baseWriterName
+ $ takeFileName writerName -- in case path to lua script
+
+ -- disabling the custom writer for now
+ (writer, writerExts) <-
+ if ".lua" `isSuffixOf` format
+ -- note: use non-lowercased version writerName
+ then return (TextWriter
+ (\o d -> writeCustom writerName o d)
+ :: Writer PandocIO, mempty)
+ else case getWriter writerName of
+ Left e -> E.throwIO $ PandocAppError $
+ if format == "pdf"
+ then e ++
+ "\nTo create a pdf using pandoc, use " ++
+ "-t latex|beamer|context|ms|html5" ++
+ "\nand specify an output file with " ++
+ ".pdf extension (-o filename.pdf)."
+ else e
+ Right (w, es) -> return (w :: Writer PandocIO, es)
+
+ -- TODO: we have to get the input and the output into the state for
+ -- the sake of the text2tags reader.
+ (reader, readerExts) <-
+ case getReader readerName of
+ Right (r, es) -> return (r :: Reader PandocIO, es)
+ Left e -> E.throwIO $ PandocAppError e'
+ where e' = case readerName of
+ "pdf" -> e ++
+ "\nPandoc can convert to PDF, but not from PDF."
+ "doc" -> e ++
+ "\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc."
+ _ -> e
+
+ let standalone = optStandalone opts || not (isTextFormat format) || pdfOutput
+ let addStringAsVariable varname s vars = return $ (varname, s) : vars
+
+ highlightStyle <- lookupHighlightStyle $ optHighlightStyle opts
+ let addSyntaxMap existingmap f = do
+ res <- parseSyntaxDefinition f
+ case res of
+ Left errstr -> E.throwIO $ PandocSyntaxMapError errstr
+ Right syn -> return $ addSyntaxDefinition syn existingmap
+
+ syntaxMap <- foldM addSyntaxMap defaultSyntaxMap
+ (optSyntaxDefinitions opts)
+
+ -- We don't want to send output to the terminal if the user
+ -- does 'pandoc -t docx input.txt'; though we allow them to
+ -- force this with '-o -'. On posix systems, we detect
+ -- when stdout is being piped and allow output to stdout
+ -- in that case, but on Windows we can't.
+#ifdef _WINDOWS
+ let istty = True
+#else
+ istty <- queryTerminal stdOutput
+#endif
+ when (not (isTextFormat format) && istty && isNothing ( optOutputFile opts)) $
+ E.throwIO $ PandocAppError $
+ "Cannot write " ++ format ++ " output to terminal.\n" ++
+ "Specify an output file using the -o option, or " ++
+ "use '-o -' to force output to stdout."
+
+ let convertTabs = tabFilter (if optPreserveTabs opts || readerName == "t2t"
+ then 0
+ else optTabStop opts)
+
+ readSources :: [FilePath] -> PandocIO Text
+ readSources srcs = convertTabs . T.intercalate (T.pack "\n") <$>
+ mapM readSource srcs
+
+ let runIO' :: PandocIO a -> IO a
+ runIO' f = do
+ (res, reports) <- runIOorExplode $ do
+ setTrace (optTrace opts)
+ setVerbosity verbosity
+ x <- f
+ rs <- getLog
+ return (x, rs)
+ case optLogFile opts of
+ Nothing -> return ()
+ Just logfile -> B.writeFile logfile (encodeLogMessages reports)
+ let isWarning msg = messageVerbosity msg == WARNING
+ when (optFailIfWarnings opts && any isWarning reports) $
+ E.throwIO PandocFailOnWarningError
+ return res
+
+ let eol = case optEol opts of
+ CRLF -> IO.CRLF
+ LF -> IO.LF
+ Native -> nativeNewline
+
+ -- note: this reverses the list constructed in option parsing,
+ -- which in turn was reversed from the command-line order,
+ -- so we end up with the correct order in the variable list:
+ let withList _ [] vars = return vars
+ withList f (x:xs) vars = f x vars >>= withList f xs
+
+ let addContentsAsVariable varname fp vars = do
+ s <- UTF8.toString <$> readFileStrict fp
+ return $ (varname, s) : vars
+
+ runIO' $ do
+ setUserDataDir datadir
+ setInputFiles (optInputFiles opts)
+ setOutputFile (optOutputFile opts)
+
+ variables <-
+ withList (addStringAsVariable "sourcefile")
+ (reverse $ optInputFiles opts)
+ (("outputfile", fromMaybe "-" (optOutputFile opts))
+ : optVariables opts)
+ -- we reverse this list because, unlike
+ -- the other option lists here, it is
+ -- not reversed when parsed from CLI arguments.
+ -- See withList, above.
+ >>=
+ withList (addContentsAsVariable "include-before")
+ (optIncludeBeforeBody opts)
+ >>=
+ withList (addContentsAsVariable "include-after")
+ (optIncludeAfterBody opts)
+ >>=
+ withList (addContentsAsVariable "header-includes")
+ (optIncludeInHeader opts)
+ >>=
+ withList (addStringAsVariable "css") (optCss opts)
+ >>=
+ maybe return (addStringAsVariable "title-prefix")
+ (optTitlePrefix opts)
+ >>=
+ maybe return (addStringAsVariable "epub-cover-image")
+ (optEpubCoverImage opts)
+ >>=
+ (\vars -> case optHTMLMathMethod opts of
+ LaTeXMathML Nothing -> do
+ s <- UTF8.toString <$> readDataFile "LaTeXMathML.js"
+ return $ ("mathml-script", s) : vars
+ _ -> return vars)
+ >>=
+ (\vars -> if format == "dzslides"
+ then do
+ dztempl <- UTF8.toString <$> readDataFile
+ ("dzslides" </> "template.html")
+ let dzline = "<!-- {{{{ dzslides core"
+ let dzcore = unlines
+ $ dropWhile (not . (dzline `isPrefixOf`))
+ $ lines dztempl
+ return $ ("dzslides-core", dzcore) : vars
+ else return vars)
+
+ abbrevs <- (Set.fromList . filter (not . null) . lines) <$>
+ case optAbbreviations opts of
+ Nothing -> UTF8.toString <$> readDataFile "abbreviations"
+ Just f -> UTF8.toString <$> readFileStrict f
+
+ templ <- case optTemplate opts of
+ _ | not standalone -> return Nothing
+ Nothing -> Just <$> getDefaultTemplate format
+ Just tp -> do
+ -- strip off extensions
+ let tp' = case takeExtension tp of
+ "" -> tp <.> format
+ _ -> tp
+ Just . UTF8.toString <$>
+ (readFileStrict tp' `catchError`
+ (\e ->
+ case e of
+ PandocIOError _ e' |
+ isDoesNotExistError e' ->
+ readDataFile ("templates" </> tp')
+ _ -> throwError e))
+
+ metadata <- if format == "jats" &&
+ isNothing (lookup "csl" (optMetadata opts)) &&
+ isNothing (lookup "citation-style" (optMetadata opts))
+ then do
+ jatsCSL <- readDataFile "jats.csl"
+ let jatsEncoded = makeDataURI
+ ("application/xml", jatsCSL)
+ return $ ("csl", jatsEncoded) : optMetadata opts
+ else return $ optMetadata opts
+
+ case lookup "lang" (optMetadata opts) of
+ Just l -> case parseBCP47 l of
+ Left _ -> return ()
+ Right l' -> setTranslations l'
+ Nothing -> setTranslations $ Lang "en" "" "US" []
+
+ let writerOptions = def {
+ writerTemplate = templ
+ , writerVariables = variables
+ , writerTabStop = optTabStop opts
+ , writerTableOfContents = optTableOfContents opts
+ , writerHTMLMathMethod = optHTMLMathMethod opts
+ , writerIncremental = optIncremental opts
+ , writerCiteMethod = optCiteMethod opts
+ , writerNumberSections = optNumberSections opts
+ , writerNumberOffset = optNumberOffset opts
+ , writerSectionDivs = optSectionDivs opts
+ , writerExtensions = writerExts
+ , writerReferenceLinks = optReferenceLinks opts
+ , writerReferenceLocation = optReferenceLocation opts
+ , writerDpi = optDpi opts
+ , writerWrapText = optWrapText opts
+ , writerColumns = optColumns opts
+ , writerEmailObfuscation = optEmailObfuscation opts
+ , writerIdentifierPrefix = optIdentifierPrefix opts
+ , writerHtmlQTags = optHtmlQTags opts
+ , writerTopLevelDivision = optTopLevelDivision opts
+ , writerListings = optListings opts
+ , writerSlideLevel = optSlideLevel opts
+ , writerHighlightStyle = highlightStyle
+ , writerSetextHeaders = optSetextHeaders opts
+ , writerEpubSubdirectory = optEpubSubdirectory opts
+ , writerEpubMetadata = epubMetadata
+ , writerEpubFonts = optEpubFonts opts
+ , writerEpubChapterLevel = optEpubChapterLevel opts
+ , writerTOCDepth = optTOCDepth opts
+ , writerReferenceDoc = optReferenceDoc opts
+ , writerSyntaxMap = syntaxMap
+ }
+
+ let readerOpts = def{
+ readerStandalone = standalone
+ , readerColumns = optColumns opts
+ , readerTabStop = optTabStop opts
+ , readerIndentedCodeClasses = optIndentedCodeClasses opts
+ , readerDefaultImageExtension =
+ optDefaultImageExtension opts
+ , readerTrackChanges = optTrackChanges opts
+ , readerAbbreviations = abbrevs
+ , readerExtensions = readerExts
+ , readerStripComments = optStripComments opts
+ }
+
+ let transforms = (case optBaseHeaderLevel opts of
+ x | x > 1 -> (headerShift (x - 1) :)
+ | otherwise -> id) .
+ (if optStripEmptyParagraphs opts
+ then (stripEmptyParagraphs :)
+ else id) .
+ (if extensionEnabled Ext_east_asian_line_breaks
+ readerExts &&
+ not (extensionEnabled Ext_east_asian_line_breaks
+ writerExts &&
+ writerWrapText writerOptions == WrapPreserve)
+ then (eastAsianLineBreakFilter :)
+ else id) $
+ []
+
+ let sourceToDoc :: [FilePath] -> PandocIO Pandoc
+ sourceToDoc sources' =
+ case reader of
+ TextReader r
+ | optFileScope opts || readerName == "json" ->
+ mconcat <$> mapM (readSource >=> r readerOpts) sources
+ | otherwise ->
+ readSources sources' >>= r readerOpts
+ ByteStringReader r ->
+ mconcat <$> mapM (readFile' >=> r readerOpts) sources
+
+
+ when (readerName == "markdown_github" ||
+ writerName == "markdown_github") $
+ report $ Deprecated "markdown_github" "Use gfm instead."
+
+ setResourcePath (optResourcePath opts)
+ mapM_ (uncurry setRequestHeader) (optRequestHeaders opts)
+
+ doc <- sourceToDoc sources >>=
+ ( (if isJust (optExtractMedia opts)
+ then fillMediaBag
+ else return)
+ >=> return . addMetadata metadata
+ >=> applyTransforms transforms
+ >=> applyFilters readerOpts filters' [format]
+ >=> maybe return extractMedia (optExtractMedia opts)
+ )
+
+ case writer of
+ ByteStringWriter f -> f writerOptions doc >>= writeFnBinary outputFile
+ TextWriter f -> case maybePdfProg of
+ Just pdfProg -> do
+ res <- makePDF pdfProg (optPdfEngineArgs opts) f
+ writerOptions doc
+ case res of
+ Right pdf -> writeFnBinary outputFile pdf
+ Left err' -> liftIO $
+ E.throwIO $ PandocPDFError $
+ TL.unpack (TE.decodeUtf8With TE.lenientDecode err')
+
+ Nothing -> do
+ let htmlFormat = format `elem`
+ ["html","html4","html5","s5","slidy",
+ "slideous","dzslides","revealjs"]
+ handleEntities = if (htmlFormat ||
+ format == "docbook4" ||
+ format == "docbook5" ||
+ format == "docbook") && optAscii opts
+ then toEntities
+ else id
+ addNl = if standalone
+ then id
+ else (<> T.singleton '\n')
+ output <- (addNl . handleEntities) <$> f writerOptions doc
+ writerFn eol outputFile =<<
+ if optSelfContained opts && htmlFormat
+ -- TODO not maximally efficient; change type
+ -- of makeSelfContained so it works w/ Text
+ then T.pack <$> makeSelfContained (T.unpack output)
+ else return output
+
+type Transform = Pandoc -> Pandoc
+
+isTextFormat :: String -> Bool
+isTextFormat s = s `notElem` ["odt","docx","epub2","epub3","epub","pptx"]
+
+-- | Data structure for command line options.
+data Opt = Opt
+ { optTabStop :: Int -- ^ Number of spaces per tab
+ , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
+ , optStandalone :: Bool -- ^ Include header, footer
+ , optReader :: Maybe String -- ^ Reader format
+ , optWriter :: Maybe String -- ^ Writer format
+ , optTableOfContents :: Bool -- ^ Include table of contents
+ , optBaseHeaderLevel :: Int -- ^ Base header level
+ , optTemplate :: Maybe FilePath -- ^ Custom template
+ , optVariables :: [(String,String)] -- ^ Template variables to set
+ , optMetadata :: [(String, String)] -- ^ Metadata fields to set
+ , optOutputFile :: Maybe FilePath -- ^ Name of output file
+ , optInputFiles :: [FilePath] -- ^ Names of input files
+ , optNumberSections :: Bool -- ^ Number sections in LaTeX
+ , optNumberOffset :: [Int] -- ^ Starting number for sections
+ , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML
+ , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
+ , optSelfContained :: Bool -- ^ Make HTML accessible offline
+ , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
+ , optHighlightStyle :: Maybe String -- ^ Style to use for highlighted code
+ , optSyntaxDefinitions :: [FilePath] -- ^ xml syntax defs to load
+ , optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions
+ , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
+ , optAbbreviations :: Maybe FilePath -- ^ Path to abbrevs file
+ , optReferenceDoc :: Maybe FilePath -- ^ Path of reference doc
+ , optEpubSubdirectory :: String -- ^ EPUB subdir in OCF container
+ , optEpubMetadata :: Maybe FilePath -- ^ EPUB metadata
+ , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed
+ , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters
+ , optEpubCoverImage :: Maybe FilePath -- ^ Cover image for epub
+ , optTOCDepth :: Int -- ^ Number of levels to include in TOC
+ , optDumpArgs :: Bool -- ^ Output command-line arguments
+ , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
+ , optVerbosity :: Verbosity -- ^ Verbosity of diagnostic output
+ , optTrace :: Bool -- ^ Enable tracing
+ , optLogFile :: Maybe FilePath -- ^ File to write JSON log output
+ , optFailIfWarnings :: Bool -- ^ Fail on warnings
+ , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
+ , optReferenceLocation :: ReferenceLocation -- ^ location for footnotes and link references in markdown output
+ , optDpi :: Int -- ^ Dpi
+ , optWrapText :: WrapOption -- ^ Options for wrapping text
+ , optColumns :: Int -- ^ Line length in characters
+ , optFilters :: [Filter] -- ^ Filters to apply
+ , optEmailObfuscation :: ObfuscationMethod
+ , optIdentifierPrefix :: String
+ , optStripEmptyParagraphs :: Bool -- ^ Strip empty paragraphs
+ , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
+ , optDataDir :: Maybe FilePath
+ , optCiteMethod :: CiteMethod -- ^ Method to output cites
+ , optListings :: Bool -- ^ Use listings package for code blocks
+ , optPdfEngine :: Maybe String -- ^ Program to use for latex/html -> pdf
+ , optPdfEngineArgs :: [String] -- ^ Flags to pass to the engine
+ , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
+ , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
+ , optAscii :: Bool -- ^ Use ascii characters only in html
+ , optDefaultImageExtension :: String -- ^ Default image extension
+ , optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media
+ , optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes.
+ , optFileScope :: Bool -- ^ Parse input files before combining
+ , optTitlePrefix :: Maybe String -- ^ Prefix for title
+ , optCss :: [FilePath] -- ^ CSS files to link to
+ , optIncludeBeforeBody :: [FilePath] -- ^ Files to include before
+ , optIncludeAfterBody :: [FilePath] -- ^ Files to include after body
+ , optIncludeInHeader :: [FilePath] -- ^ Files to include in header
+ , optResourcePath :: [FilePath] -- ^ Path to search for images etc
+ , optRequestHeaders :: [(String, String)] -- ^ Headers for HTTP requests
+ , optEol :: LineEnding -- ^ Style of line-endings to use
+ , optStripComments :: Bool -- ^ Skip HTML comments
+ } deriving (Generic, Show)
+
+-- | Defaults for command-line options.
+defaultOpts :: Opt
+defaultOpts = Opt
+ { optTabStop = 4
+ , optPreserveTabs = False
+ , optStandalone = False
+ , optReader = Nothing
+ , optWriter = Nothing
+ , optTableOfContents = False
+ , optBaseHeaderLevel = 1
+ , optTemplate = Nothing
+ , optVariables = []
+ , optMetadata = []
+ , optOutputFile = Nothing
+ , optInputFiles = []
+ , optNumberSections = False
+ , optNumberOffset = [0,0,0,0,0,0]
+ , optSectionDivs = False
+ , optIncremental = False
+ , optSelfContained = False
+ , optHtmlQTags = False
+ , optHighlightStyle = Just "pygments"
+ , optSyntaxDefinitions = []
+ , optTopLevelDivision = TopLevelDefault
+ , optHTMLMathMethod = PlainMath
+ , optAbbreviations = Nothing
+ , optReferenceDoc = Nothing
+ , optEpubSubdirectory = "EPUB"
+ , optEpubMetadata = Nothing
+ , optEpubFonts = []
+ , optEpubChapterLevel = 1
+ , optEpubCoverImage = Nothing
+ , optTOCDepth = 3
+ , optDumpArgs = False
+ , optIgnoreArgs = False
+ , optVerbosity = WARNING
+ , optTrace = False
+ , optLogFile = Nothing
+ , optFailIfWarnings = False
+ , optReferenceLinks = False
+ , optReferenceLocation = EndOfDocument
+ , optDpi = 96
+ , optWrapText = WrapAuto
+ , optColumns = 72
+ , optFilters = []
+ , optEmailObfuscation = NoObfuscation
+ , optIdentifierPrefix = ""
+ , optStripEmptyParagraphs = False
+ , optIndentedCodeClasses = []
+ , optDataDir = Nothing
+ , optCiteMethod = Citeproc
+ , optListings = False
+ , optPdfEngine = Nothing
+ , optPdfEngineArgs = []
+ , optSlideLevel = Nothing
+ , optSetextHeaders = True
+ , optAscii = False
+ , optDefaultImageExtension = ""
+ , optExtractMedia = Nothing
+ , optTrackChanges = AcceptChanges
+ , optFileScope = False
+ , optTitlePrefix = Nothing
+ , optCss = []
+ , optIncludeBeforeBody = []
+ , optIncludeAfterBody = []
+ , optIncludeInHeader = []
+ , optResourcePath = ["."]
+ , optRequestHeaders = []
+ , optEol = Native
+ , optStripComments = False
+ }
+
+addMetadata :: [(String, String)] -> Pandoc -> Pandoc
+addMetadata kvs pdc = foldr addMeta (removeMetaKeys kvs pdc) kvs
+
+addMeta :: (String, String) -> Pandoc -> Pandoc
+addMeta (k, v) (Pandoc meta bs) = Pandoc meta' bs
+ where meta' = case lookupMeta k meta of
+ Nothing -> setMeta k v' meta
+ Just (MetaList xs) ->
+ setMeta k (MetaList (xs ++ [v'])) meta
+ Just x -> setMeta k (MetaList [x, v']) meta
+ v' = readMetaValue v
+
+removeMetaKeys :: [(String,String)] -> Pandoc -> Pandoc
+removeMetaKeys kvs pdc = foldr (deleteMeta . fst) pdc kvs
+
+readMetaValue :: String -> MetaValue
+readMetaValue s = case decode (UTF8.fromString s) of
+ Just (Yaml.String t) -> MetaString $ T.unpack t
+ Just (Yaml.Bool b) -> MetaBool b
+ _ -> MetaString s
+
+-- Determine default reader based on source file extensions
+defaultReaderName :: String -> [FilePath] -> String
+defaultReaderName fallback [] = fallback
+defaultReaderName fallback (x:xs) =
+ case takeExtension (map toLower x) of
+ ".xhtml" -> "html"
+ ".html" -> "html"
+ ".htm" -> "html"
+ ".md" -> "markdown"
+ ".markdown" -> "markdown"
+ ".muse" -> "muse"
+ ".tex" -> "latex"
+ ".latex" -> "latex"
+ ".ltx" -> "latex"
+ ".rst" -> "rst"
+ ".org" -> "org"
+ ".lhs" -> "markdown+lhs"
+ ".db" -> "docbook"
+ ".opml" -> "opml"
+ ".wiki" -> "mediawiki"
+ ".dokuwiki" -> "dokuwiki"
+ ".textile" -> "textile"
+ ".native" -> "native"
+ ".json" -> "json"
+ ".docx" -> "docx"
+ ".t2t" -> "t2t"
+ ".epub" -> "epub"
+ ".odt" -> "odt"
+ ".pdf" -> "pdf" -- so we get an "unknown reader" error
+ ".doc" -> "doc" -- so we get an "unknown reader" error
+ _ -> defaultReaderName fallback xs
+
+-- Determine default writer based on output file extension
+defaultWriterName :: FilePath -> String
+defaultWriterName "-" = "html" -- no output file
+defaultWriterName x =
+ case takeExtension (map toLower x) of
+ "" -> "markdown" -- empty extension
+ ".tex" -> "latex"
+ ".latex" -> "latex"
+ ".ltx" -> "latex"
+ ".context" -> "context"
+ ".ctx" -> "context"
+ ".rtf" -> "rtf"
+ ".rst" -> "rst"
+ ".s5" -> "s5"
+ ".native" -> "native"
+ ".json" -> "json"
+ ".txt" -> "markdown"
+ ".text" -> "markdown"
+ ".md" -> "markdown"
+ ".muse" -> "muse"
+ ".markdown" -> "markdown"
+ ".textile" -> "textile"
+ ".lhs" -> "markdown+lhs"
+ ".texi" -> "texinfo"
+ ".texinfo" -> "texinfo"
+ ".db" -> "docbook"
+ ".odt" -> "odt"
+ ".docx" -> "docx"
+ ".epub" -> "epub"
+ ".org" -> "org"
+ ".asciidoc" -> "asciidoc"
+ ".adoc" -> "asciidoc"
+ ".fb2" -> "fb2"
+ ".opml" -> "opml"
+ ".icml" -> "icml"
+ ".tei.xml" -> "tei"
+ ".tei" -> "tei"
+ ".ms" -> "ms"
+ ".roff" -> "ms"
+ ".pptx" -> "pptx"
+ ['.',y] | y `elem` ['1'..'9'] -> "man"
+ _ -> "html"
+
+-- Transformations of a Pandoc document post-parsing:
+
+applyTransforms :: Monad m => [Transform] -> Pandoc -> m Pandoc
+applyTransforms transforms d = return $ foldr ($) d transforms
+
+readSource :: FilePath -> PandocIO Text
+readSource "-" = liftIO (UTF8.toText <$> BS.getContents)
+readSource src = case parseURI src of
+ Just u | uriScheme u `elem` ["http:","https:"] ->
+ readURI src
+ | uriScheme u == "file:" ->
+ liftIO $ UTF8.toText <$>
+ BS.readFile (uriPath u)
+ _ -> liftIO $ UTF8.toText <$>
+ BS.readFile src
+
+readURI :: FilePath -> PandocIO Text
+readURI src = UTF8.toText . fst <$> openURL src
+
+readFile' :: MonadIO m => FilePath -> m B.ByteString
+readFile' "-" = liftIO B.getContents
+readFile' f = liftIO $ B.readFile f
+
+writeFnBinary :: MonadIO m => FilePath -> B.ByteString -> m ()
+writeFnBinary "-" = liftIO . B.putStr
+writeFnBinary f = liftIO . B.writeFile (UTF8.encodePath f)
+
+writerFn :: MonadIO m => IO.Newline -> FilePath -> Text -> m ()
+-- TODO this implementation isn't maximally efficient:
+writerFn eol "-" = liftIO . UTF8.putStrWith eol . T.unpack
+writerFn eol f = liftIO . UTF8.writeFileWith eol f . T.unpack
+
+lookupHighlightStyle :: Maybe String -> IO (Maybe Style)
+lookupHighlightStyle Nothing = return Nothing
+lookupHighlightStyle (Just s)
+ | takeExtension s == ".theme" = -- attempt to load KDE theme
+ do contents <- B.readFile s
+ case parseTheme contents of
+ Left _ -> E.throwIO $ PandocOptionError $
+ "Could not read highlighting theme " ++ s
+ Right sty -> return (Just sty)
+ | otherwise =
+ case lookup (map toLower s) highlightingStyles of
+ Just sty -> return (Just sty)
+ Nothing -> E.throwIO $ PandocOptionError $
+ "Unknown highlight-style " ++ s
+
+-- | A list of functions, each transforming the options data structure
+-- in response to a command-line option.
+options :: [OptDescr (Opt -> IO Opt)]
+options =
+ [ Option "fr" ["from","read"]
+ (ReqArg
+ (\arg opt -> return opt { optReader =
+ Just (map toLower arg) })
+ "FORMAT")
+ ""
+
+ , Option "tw" ["to","write"]
+ (ReqArg
+ (\arg opt -> return opt { optWriter =
+ Just (map toLower arg) })
+ "FORMAT")
+ ""
+
+ , Option "o" ["output"]
+ (ReqArg
+ (\arg opt -> return opt { optOutputFile = Just arg })
+ "FILE")
+ "" -- "Name of output file"
+
+ , Option "" ["data-dir"]
+ (ReqArg
+ (\arg opt -> return opt { optDataDir = Just arg })
+ "DIRECTORY") -- "Directory containing pandoc data files."
+ ""
+
+ , Option "" ["base-header-level"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead arg of
+ Just t | t > 0 && t < 6 ->
+ return opt{ optBaseHeaderLevel = t }
+ _ -> E.throwIO $ PandocOptionError
+ "base-header-level must be 1-5")
+ "NUMBER")
+ "" -- "Headers base level"
+
+ , Option "" ["strip-empty-paragraphs"]
+ (NoArg
+ (\opt -> do
+ deprecatedOption "--stripEmptyParagraphs"
+ "Use +empty_paragraphs extension."
+ return opt{ optStripEmptyParagraphs = True }))
+ "" -- "Strip empty paragraphs"
+
+ , Option "" ["indented-code-classes"]
+ (ReqArg
+ (\arg opt -> return opt { optIndentedCodeClasses = words $
+ map (\c -> if c == ',' then ' ' else c) arg })
+ "STRING")
+ "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
+
+ , Option "F" ["filter"]
+ (ReqArg
+ (\arg opt -> return opt { optFilters =
+ JSONFilter arg : optFilters opt })
+ "PROGRAM")
+ "" -- "External JSON filter"
+
+ , Option "" ["lua-filter"]
+ (ReqArg
+ (\arg opt -> return opt { optFilters =
+ LuaFilter arg : optFilters opt })
+ "SCRIPTPATH")
+ "" -- "Lua filter"
+
+ , Option "p" ["preserve-tabs"]
+ (NoArg
+ (\opt -> return opt { optPreserveTabs = True }))
+ "" -- "Preserve tabs instead of converting to spaces"
+
+ , Option "" ["tab-stop"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead arg of
+ Just t | t > 0 -> return opt { optTabStop = t }
+ _ -> E.throwIO $ PandocOptionError
+ "tab-stop must be a number greater than 0")
+ "NUMBER")
+ "" -- "Tab stop (default 4)"
+
+ , Option "" ["track-changes"]
+ (ReqArg
+ (\arg opt -> do
+ action <- case arg of
+ "accept" -> return AcceptChanges
+ "reject" -> return RejectChanges
+ "all" -> return AllChanges
+ _ -> E.throwIO $ PandocOptionError
+ ("Unknown option for track-changes: " ++ arg)
+ return opt { optTrackChanges = action })
+ "accept|reject|all")
+ "" -- "Accepting or reject MS Word track-changes.""
+
+ , Option "" ["file-scope"]
+ (NoArg
+ (\opt -> return opt { optFileScope = True }))
+ "" -- "Parse input files before combining"
+
+ , Option "" ["extract-media"]
+ (ReqArg
+ (\arg opt ->
+ return opt { optExtractMedia = Just arg })
+ "PATH")
+ "" -- "Directory to which to extract embedded media"
+
+ , Option "s" ["standalone"]
+ (NoArg
+ (\opt -> return opt { optStandalone = True }))
+ "" -- "Include needed header and footer on output"
+
+ , Option "" ["template"]
+ (ReqArg
+ (\arg opt ->
+ return opt{ optTemplate = Just arg,
+ optStandalone = True })
+ "FILE")
+ "" -- "Use custom template"
+
+ , Option "M" ["metadata"]
+ (ReqArg
+ (\arg opt -> do
+ let (key, val) = splitField arg
+ return opt{ optMetadata = (key, val) : optMetadata opt })
+ "KEY[:VALUE]")
+ ""
+
+ , Option "V" ["variable"]
+ (ReqArg
+ (\arg opt -> do
+ let (key, val) = splitField arg
+ return opt{ optVariables = (key, val) : optVariables opt })
+ "KEY[:VALUE]")
+ ""
+
+ , Option "D" ["print-default-template"]
+ (ReqArg
+ (\arg _ -> do
+ templ <- runIO $ do
+ setUserDataDir Nothing
+ getDefaultTemplate arg
+ case templ of
+ Right t -> UTF8.hPutStr stdout t
+ Left e -> E.throwIO e
+ exitSuccess)
+ "FORMAT")
+ "" -- "Print default template for FORMAT"
+
+ , Option "" ["print-default-data-file"]
+ (ReqArg
+ (\arg _ -> do
+ runIOorExplode $
+ readDefaultDataFile arg >>= liftIO . BS.hPutStr stdout
+ exitSuccess)
+ "FILE")
+ "" -- "Print default data file"
+
+ , Option "" ["print-highlight-style"]
+ (ReqArg
+ (\arg _ -> do
+ sty <- fromMaybe pygments <$>
+ lookupHighlightStyle (Just arg)
+ B.putStr $ encodePretty'
+ defConfig{confIndent = Spaces 4
+ ,confCompare = keyOrder
+ (map T.pack
+ ["text-color"
+ ,"background-color"
+ ,"line-number-color"
+ ,"line-number-background-color"
+ ,"bold"
+ ,"italic"
+ ,"underline"
+ ,"text-styles"])
+ ,confNumFormat = Generic
+ ,confTrailingNewline = True} sty
+ exitSuccess)
+ "STYLE|FILE")
+ "" -- "Print default template for FORMAT"
+
+ , Option "" ["dpi"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead arg of
+ Just t | t > 0 -> return opt { optDpi = t }
+ _ -> E.throwIO $ PandocOptionError
+ "dpi must be a number greater than 0")
+ "NUMBER")
+ "" -- "Dpi (default 96)"
+
+ , Option "" ["eol"]
+ (ReqArg
+ (\arg opt ->
+ case toLower <$> arg of
+ "crlf" -> return opt { optEol = CRLF }
+ "lf" -> return opt { optEol = LF }
+ "native" -> return opt { optEol = Native }
+ -- mac-syntax (cr) is not supported in ghc-base.
+ _ -> E.throwIO $ PandocOptionError
+ "--eol must be crlf, lf, or native")
+ "crlf|lf|native")
+ "" -- "EOL (default OS-dependent)"
+
+ , Option "" ["wrap"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead ("Wrap" ++ uppercaseFirstLetter arg) of
+ Just o -> return opt { optWrapText = o }
+ Nothing -> E.throwIO $ PandocOptionError
+ "--wrap must be auto, none, or preserve")
+ "auto|none|preserve")
+ "" -- "Option for wrapping text in output"
+
+ , Option "" ["columns"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead arg of
+ Just t | t > 0 -> return opt { optColumns = t }
+ _ -> E.throwIO $ PandocOptionError
+ "columns must be a number greater than 0")
+ "NUMBER")
+ "" -- "Length of line in characters"
+
+ , Option "" ["strip-comments"]
+ (NoArg
+ (\opt -> return opt { optStripComments = True }))
+ "" -- "Strip HTML comments"
+
+ , Option "" ["toc", "table-of-contents"]
+ (NoArg
+ (\opt -> return opt { optTableOfContents = True }))
+ "" -- "Include table of contents"
+
+ , Option "" ["toc-depth"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead arg of
+ Just t | t >= 1 && t <= 6 ->
+ return opt { optTOCDepth = t }
+ _ -> E.throwIO $ PandocOptionError
+ "TOC level must be a number between 1 and 6")
+ "NUMBER")
+ "" -- "Number of levels to include in TOC"
+
+ , Option "" ["no-highlight"]
+ (NoArg
+ (\opt -> return opt { optHighlightStyle = Nothing }))
+ "" -- "Don't highlight source code"
+
+ , Option "" ["highlight-style"]
+ (ReqArg
+ (\arg opt -> return opt{ optHighlightStyle = Just arg })
+ "STYLE|FILE")
+ "" -- "Style for highlighted code"
+
+ , Option "" ["syntax-definition"]
+ (ReqArg
+ (\arg opt -> return opt{ optSyntaxDefinitions = arg :
+ optSyntaxDefinitions opt })
+ "FILE")
+ "" -- "Syntax definition (xml) file"
+
+ , Option "H" ["include-in-header"]
+ (ReqArg
+ (\arg opt -> return opt{ optIncludeInHeader =
+ arg : optIncludeInHeader opt,
+ optStandalone = True })
+ "FILE")
+ "" -- "File to include at end of header (implies -s)"
+
+ , Option "B" ["include-before-body"]
+ (ReqArg
+ (\arg opt -> return opt{ optIncludeBeforeBody =
+ arg : optIncludeBeforeBody opt,
+ optStandalone = True })
+ "FILE")
+ "" -- "File to include before document body"
+
+ , Option "A" ["include-after-body"]
+ (ReqArg
+ (\arg opt -> return opt{ optIncludeAfterBody =
+ arg : optIncludeAfterBody opt,
+ optStandalone = True })
+ "FILE")
+ "" -- "File to include after document body"
+
+ , Option "" ["resource-path"]
+ (ReqArg
+ (\arg opt -> return opt { optResourcePath =
+ splitSearchPath arg })
+ "SEARCHPATH")
+ "" -- "Paths to search for images and other resources"
+
+ , Option "" ["request-header"]
+ (ReqArg
+ (\arg opt -> do
+ let (key, val) = splitField arg
+ return opt{ optRequestHeaders =
+ (key, val) : optRequestHeaders opt })
+ "NAME:VALUE")
+ ""
+
+ , Option "" ["self-contained"]
+ (NoArg
+ (\opt -> return opt { optSelfContained = True,
+ optStandalone = True }))
+ "" -- "Make slide shows include all the needed js and css"
+
+ , Option "" ["html-q-tags"]
+ (NoArg
+ (\opt ->
+ return opt { optHtmlQTags = True }))
+ "" -- "Use <q> tags for quotes in HTML"
+
+ , Option "" ["ascii"]
+ (NoArg
+ (\opt -> return opt { optAscii = True }))
+ "" -- "Use ascii characters only in HTML output"
+
+ , Option "" ["reference-links"]
+ (NoArg
+ (\opt -> return opt { optReferenceLinks = True } ))
+ "" -- "Use reference links in parsing HTML"
+
+ , Option "" ["reference-location"]
+ (ReqArg
+ (\arg opt -> do
+ action <- case arg of
+ "block" -> return EndOfBlock
+ "section" -> return EndOfSection
+ "document" -> return EndOfDocument
+ _ -> E.throwIO $ PandocOptionError
+ ("Unknown option for reference-location: " ++ arg)
+ return opt { optReferenceLocation = action })
+ "block|section|document")
+ "" -- "Accepting or reject MS Word track-changes.""
+
+ , Option "" ["atx-headers"]
+ (NoArg
+ (\opt -> return opt { optSetextHeaders = False } ))
+ "" -- "Use atx-style headers for markdown"
+
+ , Option "" ["top-level-division"]
+ (ReqArg
+ (\arg opt -> do
+ let tldName = "TopLevel" ++ uppercaseFirstLetter arg
+ case safeRead tldName of
+ Just tlDiv -> return opt { optTopLevelDivision = tlDiv }
+ _ -> E.throwIO $ PandocOptionError
+ ("Top-level division must be " ++
+ "section, chapter, part, or default"))
+ "section|chapter|part")
+ "" -- "Use top-level division type in LaTeX, ConTeXt, DocBook"
+
+ , Option "N" ["number-sections"]
+ (NoArg
+ (\opt -> return opt { optNumberSections = True }))
+ "" -- "Number sections in LaTeX"
+
+ , Option "" ["number-offset"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead ('[':arg ++ "]") of
+ Just ns -> return opt { optNumberOffset = ns,
+ optNumberSections = True }
+ _ -> E.throwIO $ PandocOptionError
+ "could not parse number-offset")
+ "NUMBERS")
+ "" -- "Starting number for sections, subsections, etc."
+
+ , Option "" ["listings"]
+ (NoArg
+ (\opt -> return opt { optListings = True }))
+ "" -- "Use listings package for LaTeX code blocks"
+
+ , Option "i" ["incremental"]
+ (NoArg
+ (\opt -> return opt { optIncremental = True }))
+ "" -- "Make list items display incrementally in Slidy/Slideous/S5"
+
+ , Option "" ["slide-level"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead arg of
+ Just t | t >= 1 && t <= 6 ->
+ return opt { optSlideLevel = Just t }
+ _ -> E.throwIO $ PandocOptionError
+ "slide level must be a number between 1 and 6")
+ "NUMBER")
+ "" -- "Force header level for slides"
+
+ , Option "" ["section-divs"]
+ (NoArg
+ (\opt -> return opt { optSectionDivs = True }))
+ "" -- "Put sections in div tags in HTML"
+
+ , Option "" ["default-image-extension"]
+ (ReqArg
+ (\arg opt -> return opt { optDefaultImageExtension = arg })
+ "extension")
+ "" -- "Default extension for extensionless images"
+
+ , Option "" ["email-obfuscation"]
+ (ReqArg
+ (\arg opt -> do
+ method <- case arg of
+ "references" -> return ReferenceObfuscation
+ "javascript" -> return JavascriptObfuscation
+ "none" -> return NoObfuscation
+ _ -> E.throwIO $ PandocOptionError
+ ("Unknown obfuscation method: " ++ arg)
+ return opt { optEmailObfuscation = method })
+ "none|javascript|references")
+ "" -- "Method for obfuscating email in HTML"
+
+ , Option "" ["id-prefix"]
+ (ReqArg
+ (\arg opt -> return opt { optIdentifierPrefix = arg })
+ "STRING")
+ "" -- "Prefix to add to automatically generated HTML identifiers"
+
+ , Option "T" ["title-prefix"]
+ (ReqArg
+ (\arg opt -> do
+ let newvars = ("title-prefix", arg) : optVariables opt
+ return opt { optVariables = newvars,
+ optStandalone = True })
+ "STRING")
+ "" -- "String to prefix to HTML window title"
+
+ , Option "c" ["css"]
+ (ReqArg
+ (\arg opt -> return opt{ optCss = arg : optCss opt })
+ -- add new link to end, so it is included in proper order
+ "URL")
+ "" -- "Link to CSS style sheet"
+
+ , Option "" ["reference-doc"]
+ (ReqArg
+ (\arg opt ->
+ return opt { optReferenceDoc = Just arg })
+ "FILE")
+ "" -- "Path of custom reference doc"
+
+ , Option "" ["epub-subdirectory"]
+ (ReqArg
+ (\arg opt ->
+ return opt { optEpubSubdirectory = arg })
+ "DIRNAME")
+ "" -- "Name of subdirectory for epub content in OCF container"
+
+ , Option "" ["epub-cover-image"]
+ (ReqArg
+ (\arg opt ->
+ return opt { optVariables =
+ ("epub-cover-image", arg) : optVariables opt })
+ "FILE")
+ "" -- "Path of epub cover image"
+
+ , Option "" ["epub-metadata"]
+ (ReqArg
+ (\arg opt -> return opt { optEpubMetadata = Just arg })
+ "FILE")
+ "" -- "Path of epub metadata file"
+
+ , Option "" ["epub-embed-font"]
+ (ReqArg
+ (\arg opt ->
+ return opt{ optEpubFonts = arg : optEpubFonts opt })
+ "FILE")
+ "" -- "Directory of fonts to embed"
+
+ , Option "" ["epub-chapter-level"]
+ (ReqArg
+ (\arg opt ->
+ case safeRead arg of
+ Just t | t >= 1 && t <= 6 ->
+ return opt { optEpubChapterLevel = t }
+ _ -> E.throwIO $ PandocOptionError
+ "chapter level must be a number between 1 and 6")
+ "NUMBER")
+ "" -- "Header level at which to split chapters in EPUB"
+
+ , Option "" ["pdf-engine"]
+ (ReqArg
+ (\arg opt -> do
+ let b = takeBaseName arg
+ if b `elem` pdfEngines
+ then return opt { optPdfEngine = Just arg }
+ else E.throwIO $ PandocOptionError $ "pdf-engine must be one of "
+ ++ intercalate ", " pdfEngines)
+ "PROGRAM")
+ "" -- "Name of program to use in generating PDF"
+
+ , Option "" ["pdf-engine-opt"]
+ (ReqArg
+ (\arg opt -> do
+ let oldArgs = optPdfEngineArgs opt
+ return opt { optPdfEngineArgs = oldArgs ++ [arg]})
+ "STRING")
+ "" -- "Flags to pass to the PDF-engine, all instances of this option are accumulated and used"
+
+ , Option "" ["bibliography"]
+ (ReqArg
+ (\arg opt -> return opt{ optMetadata =
+ ("bibliography", arg) : optMetadata opt })
+ "FILE")
+ ""
+
+ , Option "" ["csl"]
+ (ReqArg
+ (\arg opt ->
+ return opt{ optMetadata =
+ ("csl", arg) : optMetadata opt })
+ "FILE")
+ ""
+
+ , Option "" ["citation-abbreviations"]
+ (ReqArg
+ (\arg opt ->
+ return opt{ optMetadata =
+ ("citation-abbreviations", arg): optMetadata opt })
+ "FILE")
+ ""
+
+ , Option "" ["natbib"]
+ (NoArg
+ (\opt -> return opt { optCiteMethod = Natbib }))
+ "" -- "Use natbib cite commands in LaTeX output"
+
+ , Option "" ["biblatex"]
+ (NoArg
+ (\opt -> return opt { optCiteMethod = Biblatex }))
+ "" -- "Use biblatex cite commands in LaTeX output"
+
+ , Option "" ["mathml"]
+ (NoArg
+ (\opt ->
+ return opt { optHTMLMathMethod = MathML }))
+ "" -- "Use mathml for HTML math"
+
+ , Option "" ["webtex"]
+ (OptArg
+ (\arg opt -> do
+ let url' = fromMaybe "https://latex.codecogs.com/png.latex?" arg
+ return opt { optHTMLMathMethod = WebTeX url' })
+ "URL")
+ "" -- "Use web service for HTML math"
+
+ , Option "" ["mathjax"]
+ (OptArg
+ (\arg opt -> do
+ let url' = fromMaybe (defaultMathJaxURL ++
+ "MathJax.js?config=TeX-AMS_CHTML-full") arg
+ return opt { optHTMLMathMethod = MathJax url'})
+ "URL")
+ "" -- "Use MathJax for HTML math"
+
+ , Option "" ["katex"]
+ (OptArg
+ (\arg opt ->
+ return opt
+ { optHTMLMathMethod = KaTeX $
+ fromMaybe defaultKaTeXURL arg })
+ "URL")
+ "" -- Use KaTeX for HTML Math
+
+ , Option "m" ["latexmathml", "asciimathml"]
+ (OptArg
+ (\arg opt -> do
+ deprecatedOption "--latexmathml, --asciimathml, -m" ""
+ return opt { optHTMLMathMethod = LaTeXMathML arg })
+ "URL")
+ "" -- "Use LaTeXMathML script in html output"
+
+ , Option "" ["mimetex"]
+ (OptArg
+ (\arg opt -> do
+ deprecatedOption "--mimetex" ""
+ let url' = case arg of
+ Just u -> u ++ "?"
+ Nothing -> "/cgi-bin/mimetex.cgi?"
+ return opt { optHTMLMathMethod = WebTeX url' })
+ "URL")
+ "" -- "Use mimetex for HTML math"
+
+ , Option "" ["jsmath"]
+ (OptArg
+ (\arg opt -> do
+ deprecatedOption "--jsmath" ""
+ return opt { optHTMLMathMethod = JsMath arg})
+ "URL")
+ "" -- "Use jsMath for HTML math"
+
+ , Option "" ["gladtex"]
+ (NoArg
+ (\opt -> do
+ deprecatedOption "--gladtex" ""
+ return opt { optHTMLMathMethod = GladTeX }))
+ "" -- "Use gladtex for HTML math"
+
+ , Option "" ["abbreviations"]
+ (ReqArg
+ (\arg opt -> return opt { optAbbreviations = Just arg })
+ "FILE")
+ "" -- "Specify file for custom abbreviations"
+
+ , Option "" ["trace"]
+ (NoArg
+ (\opt -> return opt { optTrace = True }))
+ "" -- "Turn on diagnostic tracing in readers."
+
+ , Option "" ["dump-args"]
+ (NoArg
+ (\opt -> return opt { optDumpArgs = True }))
+ "" -- "Print output filename and arguments to stdout."
+
+ , Option "" ["ignore-args"]
+ (NoArg
+ (\opt -> return opt { optIgnoreArgs = True }))
+ "" -- "Ignore command-line arguments."
+
+ , Option "" ["verbose"]
+ (NoArg
+ (\opt -> return opt { optVerbosity = INFO }))
+ "" -- "Verbose diagnostic output."
+
+ , Option "" ["quiet"]
+ (NoArg
+ (\opt -> return opt { optVerbosity = ERROR }))
+ "" -- "Suppress warnings."
+
+ , Option "" ["fail-if-warnings"]
+ (NoArg
+ (\opt -> return opt { optFailIfWarnings = True }))
+ "" -- "Exit with error status if there were warnings."
+
+ , Option "" ["log"]
+ (ReqArg
+ (\arg opt -> return opt{ optLogFile = Just arg })
+ "FILE")
+ "" -- "Log messages in JSON format to this file."
+
+ , Option "" ["bash-completion"]
+ (NoArg
+ (\_ -> do
+ ddir <- getDataDir
+ tpl <- runIOorExplode $
+ UTF8.toString <$>
+ readDefaultDataFile "bash_completion.tpl"
+ let optnames (Option shorts longs _ _) =
+ map (\c -> ['-',c]) shorts ++
+ map ("--" ++) longs
+ let allopts = unwords (concatMap optnames options)
+ UTF8.hPutStrLn stdout $ printf tpl allopts
+ (unwords readersNames)
+ (unwords writersNames)
+ (unwords $ map fst highlightingStyles)
+ ddir
+ exitSuccess ))
+ "" -- "Print bash completion script"
+
+ , Option "" ["list-input-formats"]
+ (NoArg
+ (\_ -> do
+ mapM_ (UTF8.hPutStrLn stdout) readersNames
+ exitSuccess ))
+ ""
+
+ , Option "" ["list-output-formats"]
+ (NoArg
+ (\_ -> do
+ mapM_ (UTF8.hPutStrLn stdout) writersNames
+ exitSuccess ))
+ ""
+
+ , Option "" ["list-extensions"]
+ (OptArg
+ (\arg _ -> do
+ let exts = getDefaultExtensions (fromMaybe "markdown" arg)
+ let showExt x = (if extensionEnabled x exts
+ then '+'
+ else '-') : drop 4 (show x)
+ mapM_ (UTF8.hPutStrLn stdout . showExt)
+ ([minBound..maxBound] :: [Extension])
+ exitSuccess )
+ "FORMAT")
+ ""
+
+ , Option "" ["list-highlight-languages"]
+ (NoArg
+ (\_ -> do
+ let langs = [ T.unpack (T.toLower (sShortname s))
+ | s <- M.elems defaultSyntaxMap
+ , sShortname s `notElem`
+ [T.pack "Alert", T.pack "Alert_indent"]
+ ]
+ mapM_ (UTF8.hPutStrLn stdout) langs
+ exitSuccess ))
+ ""
+
+ , Option "" ["list-highlight-styles"]
+ (NoArg
+ (\_ -> do
+ mapM_ (UTF8.hPutStrLn stdout . fst) highlightingStyles
+ exitSuccess ))
+ ""
+
+ , Option "v" ["version"]
+ (NoArg
+ (\_ -> do
+ prg <- getProgName
+ defaultDatadir <- E.catch
+ (getAppUserDataDirectory "pandoc")
+ (\e -> let _ = (e :: E.SomeException)
+ in return "")
+ UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
+ compileInfo ++ "\nDefault user data directory: " ++
+ defaultDatadir ++ copyrightMessage)
+ exitSuccess ))
+ "" -- "Print version"
+
+ , Option "h" ["help"]
+ (NoArg
+ (\_ -> do
+ prg <- getProgName
+ UTF8.hPutStr stdout (usageMessage prg options)
+ exitSuccess ))
+ "" -- "Show help"
+
+ ]
+
+-- Returns usage message
+usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
+usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]")
+
+copyrightMessage :: String
+copyrightMessage = intercalate "\n" [
+ "",
+ "Copyright (C) 2006-2018 John MacFarlane",
+ "Web: http://pandoc.org",
+ "This is free software; see the source for copying conditions.",
+ "There is no warranty, not even for merchantability or fitness",
+ "for a particular purpose." ]
+
+compileInfo :: String
+compileInfo =
+ "\nCompiled with pandoc-types " ++ VERSION_pandoc_types ++ ", texmath " ++
+ VERSION_texmath ++ ", skylighting " ++ VERSION_skylighting
+
+handleUnrecognizedOption :: String -> [String] -> [String]
+handleUnrecognizedOption "--smart" =
+ (("--smart/-S has been removed. Use +smart or -smart extension instead.\n" ++
+ "For example: pandoc -f markdown+smart -t markdown-smart.") :)
+handleUnrecognizedOption "--normalize" =
+ ("--normalize has been removed. Normalization is now automatic." :)
+handleUnrecognizedOption "-S" = handleUnrecognizedOption "--smart"
+handleUnrecognizedOption "--old-dashes" =
+ ("--old-dashes has been removed. Use +old_dashes extension instead." :)
+handleUnrecognizedOption "--no-wrap" =
+ ("--no-wrap has been removed. Use --wrap=none instead." :)
+handleUnrecognizedOption "--latex-engine" =
+ ("--latex-engine has been removed. Use --pdf-engine instead." :)
+handleUnrecognizedOption "--latex-engine-opt" =
+ ("--latex-engine-opt has been removed. Use --pdf-engine-opt instead." :)
+handleUnrecognizedOption "--chapters" =
+ ("--chapters has been removed. Use --top-level-division=chapter instead." :)
+handleUnrecognizedOption "--reference-docx" =
+ ("--reference-docx has been removed. Use --reference-doc instead." :)
+handleUnrecognizedOption "--reference-odt" =
+ ("--reference-odt has been removed. Use --reference-doc instead." :)
+handleUnrecognizedOption "--parse-raw" =
+ ("--parse-raw/-R has been removed. Use +raw_html or +raw_tex extension.\n" :)
+handleUnrecognizedOption "--epub-stylesheet" =
+ ("--epub-stylesheet has been removed. Use --css instead.\n" :)
+handleUnrecognizedOption "-R" = handleUnrecognizedOption "--parse-raw"
+handleUnrecognizedOption x =
+ (("Unknown option " ++ x ++ ".") :)
+
+uppercaseFirstLetter :: String -> String
+uppercaseFirstLetter (c:cs) = toUpper c : cs
+uppercaseFirstLetter [] = []
+
+readersNames :: [String]
+readersNames = sort (map fst (readers :: [(String, Reader PandocIO)]))
+
+writersNames :: [String]
+writersNames = sort (map fst (writers :: [(String, Writer PandocIO)]))
+
+splitField :: String -> (String, String)
+splitField s =
+ case break (`elem` ":=") s of
+ (k,_:v) -> (k,v)
+ (k,[]) -> (k,"true")
+
+baseWriterName :: String -> String
+baseWriterName = takeWhile (\c -> c /= '+' && c /= '-')
+
+deprecatedOption :: String -> String -> IO ()
+deprecatedOption o msg =
+ runIO (report $ Deprecated o msg) >>=
+ \r -> case r of
+ Right () -> return ()
+ Left e -> E.throwIO e
+
+-- see https://github.com/jgm/pandoc/pull/4083
+-- using generic deriving caused long compilation times
+$(deriveJSON defaultOptions ''LineEnding)
+$(deriveJSON defaultOptions ''Opt)
diff --git a/src/Text/Pandoc/Asciify.hs b/src/Text/Pandoc/Asciify.hs
index 8eb1ba663..11d3eddac 100644
--- a/src/Text/Pandoc/Asciify.hs
+++ b/src/Text/Pandoc/Asciify.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2013-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Asciify
- Copyright : Copyright (C) 2013-2016 John MacFarlane
+ Copyright : Copyright (C) 2013-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,8 +30,8 @@ ascii equivalents (used in constructing HTML identifiers).
-}
module Text.Pandoc.Asciify (toAsciiChar)
where
-import qualified Data.Map as M
import Data.Char (isAscii)
+import qualified Data.Map as M
toAsciiChar :: Char -> Maybe Char
toAsciiChar c | isAscii c = Just c
diff --git a/src/Text/Pandoc/BCP47.hs b/src/Text/Pandoc/BCP47.hs
new file mode 100644
index 000000000..2dd825142
--- /dev/null
+++ b/src/Text/Pandoc/BCP47.hs
@@ -0,0 +1,125 @@
+{-
+Copyright (C) 2017–2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.BCP47
+ Copyright : Copyright (C) 2017–2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Functions for parsing and rendering BCP47 language identifiers.
+-}
+module Text.Pandoc.BCP47 (
+ getLang
+ , parseBCP47
+ , Lang(..)
+ , renderLang
+ )
+where
+import Control.Monad (guard)
+import Data.Char (isAlphaNum, isAscii, isLetter, isLower, isUpper, toLower,
+ toUpper)
+import Data.List (intercalate)
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import qualified Text.Parsec as P
+
+-- | Represents BCP 47 language/country code.
+data Lang = Lang{ langLanguage :: String
+ , langScript :: String
+ , langRegion :: String
+ , langVariants :: [String] }
+ deriving (Eq, Ord, Show)
+
+-- | Render a Lang as BCP 47.
+renderLang :: Lang -> String
+renderLang lang = intercalate "-" (langLanguage lang : filter (not . null)
+ ([langScript lang, langRegion lang] ++ langVariants lang))
+
+-- | Get the contents of the `lang` metadata field or variable.
+getLang :: WriterOptions -> Meta -> Maybe String
+getLang opts meta =
+ case lookup "lang" (writerVariables opts) of
+ Just s -> Just s
+ _ ->
+ case lookupMeta "lang" meta of
+ Just (MetaInlines [Str s]) -> Just s
+ Just (MetaString s) -> Just s
+ _ -> Nothing
+
+-- | Parse a BCP 47 string as a Lang. Currently we parse
+-- extensions and private-use fields as "variants," even
+-- though officially they aren't.
+parseBCP47 :: String -> Either String Lang
+parseBCP47 lang =
+ case P.parse bcp47 "lang" lang of
+ Right r -> Right r
+ Left e -> Left $ show e
+ where bcp47 = do
+ language <- pLanguage
+ script <- P.option "" pScript
+ region <- P.option "" pRegion
+ variants <- P.many (pVariant P.<|> pExtension P.<|> pPrivateUse)
+ P.eof
+ return Lang{ langLanguage = language
+ , langScript = script
+ , langRegion = region
+ , langVariants = variants }
+ asciiLetter = P.satisfy (\c -> isAscii c && isLetter c)
+ pLanguage = do
+ cs <- P.many1 asciiLetter
+ let lcs = length cs
+ guard $ lcs == 2 || lcs == 3
+ return $ map toLower cs
+ pScript = P.try $ do
+ P.char '-'
+ x <- P.satisfy (\c -> isAscii c && isLetter c && isUpper c)
+ xs <- P.count 3
+ (P.satisfy (\c -> isAscii c && isLetter c && isLower c))
+ return $ map toLower (x:xs)
+ pRegion = P.try $ do
+ P.char '-'
+ cs <- P.many1 asciiLetter
+ let lcs = length cs
+ guard $ lcs == 2 || lcs == 3
+ return $ map toUpper cs
+ pVariant = P.try $ do
+ P.char '-'
+ ds <- P.option "" (P.count 1 P.digit)
+ cs <- P.many1 asciiLetter
+ let var = ds ++ cs
+ guard $ if null ds
+ then length var >= 5 && length var <= 8
+ else length var == 4
+ return $ map toLower var
+ pExtension = P.try $ do
+ P.char '-'
+ cs <- P.many1 $ P.satisfy (\c -> isAscii c && isAlphaNum c)
+ guard $ length cs >= 2 && length cs <= 8
+ return $ map toLower cs
+ pPrivateUse = P.try $ do
+ P.char '-'
+ P.char 'x'
+ P.char '-'
+ cs <- P.many1 $ P.satisfy (\c -> isAscii c && isAlphaNum c)
+ guard $ not (null cs) && length cs <= 8
+ let var = "x-" ++ cs
+ return $ map toLower var
diff --git a/src/Text/Pandoc/CSS.hs b/src/Text/Pandoc/CSS.hs
index f479ed9d0..d44b5e1e2 100644
--- a/src/Text/Pandoc/CSS.hs
+++ b/src/Text/Pandoc/CSS.hs
@@ -11,7 +11,7 @@ import Text.Parsec.String
ruleParser :: Parser (String, String)
ruleParser = do
p <- many1 (noneOf ":") <* char ':'
- v <- many1 (noneOf ":;") <* (optional $ char ';') <* spaces
+ v <- many1 (noneOf ":;") <* optional (char ';') <* spaces
return (trim p, trim v)
styleAttrParser :: Parser [(String, String)]
@@ -25,14 +25,14 @@ foldOrElse v xs = foldr (orElse v) v xs
eitherToMaybe :: Either a b -> Maybe b
eitherToMaybe (Right x) = Just x
-eitherToMaybe _ = Nothing
+eitherToMaybe _ = Nothing
-- | takes a list of keys/properties and a CSS string and
-- returns the corresponding key-value-pairs.
pickStylesToKVs :: [String] -> String -> [(String, String)]
pickStylesToKVs props styleAttr =
case parse styleAttrParser "" styleAttr of
- Left _ -> []
+ Left _ -> []
Right styles -> filter (\s -> fst s `elem` props) styles
-- | takes a list of key/property synonyms and a CSS string and maybe
@@ -40,4 +40,4 @@ pickStylesToKVs props styleAttr =
pickStyleAttrProps :: [String] -> String -> Maybe String
pickStyleAttrProps lookupProps styleAttr = do
styles <- eitherToMaybe $ parse styleAttrParser "" styleAttr
- foldOrElse Nothing $ map (flip lookup styles) lookupProps
+ foldOrElse Nothing $ map (`lookup` styles) lookupProps
diff --git a/src/Text/Pandoc/CSV.hs b/src/Text/Pandoc/CSV.hs
new file mode 100644
index 000000000..3415ae88f
--- /dev/null
+++ b/src/Text/Pandoc/CSV.hs
@@ -0,0 +1,102 @@
+{-
+Copyright (C) 2017–2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.CSV
+ Copyright : Copyright (C) 2017–2018 John MacFarlane <jgm@berkeley.edu>
+ License : GNU GPL, version 2 or above
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Simple CSV parser.
+-}
+
+module Text.Pandoc.CSV (
+ CSVOptions(..),
+ defaultCSVOptions,
+ parseCSV,
+ ParseError
+) where
+
+import Control.Monad (void)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.Parsec
+import Text.Parsec.Text (Parser)
+
+data CSVOptions = CSVOptions{
+ csvDelim :: Char
+ , csvQuote :: Char
+ , csvKeepSpace :: Bool -- treat whitespace following delim as significant
+ , csvEscape :: Maybe Char -- default is to double up quote
+} deriving (Read, Show)
+
+defaultCSVOptions :: CSVOptions
+defaultCSVOptions = CSVOptions{
+ csvDelim = ','
+ , csvQuote = '"'
+ , csvKeepSpace = False
+ , csvEscape = Nothing }
+
+parseCSV :: CSVOptions -> Text -> Either ParseError [[Text]]
+parseCSV opts t = parse (pCSV opts) "csv" t
+
+pCSV :: CSVOptions -> Parser [[Text]]
+pCSV opts =
+ (pCSVRow opts `sepEndBy` endline) <* (spaces *> eof)
+
+pCSVRow :: CSVOptions -> Parser [Text]
+pCSVRow opts = notFollowedBy blank >> pCSVCell opts `sepBy` pCSVDelim opts
+
+blank :: Parser ()
+blank = try $ spaces >> (() <$ endline <|> eof)
+
+pCSVCell :: CSVOptions -> Parser Text
+pCSVCell opts = pCSVQuotedCell opts <|> pCSVUnquotedCell opts
+
+pCSVQuotedCell :: CSVOptions -> Parser Text
+pCSVQuotedCell opts = do
+ char (csvQuote opts)
+ res <- many (satisfy (\c -> c /= csvQuote opts &&
+ Just c /= csvEscape opts) <|> escaped opts)
+ char (csvQuote opts)
+ return $ T.pack res
+
+escaped :: CSVOptions -> Parser Char
+escaped opts =
+ case csvEscape opts of
+ Nothing -> try $ char (csvQuote opts) >> char (csvQuote opts)
+ Just c -> try $ char c >> noneOf "\r\n"
+
+pCSVUnquotedCell :: CSVOptions -> Parser Text
+pCSVUnquotedCell opts = T.pack <$>
+ many (satisfy (\c -> c /= csvDelim opts && c /= '\r' && c /= '\n'
+ && c /= csvQuote opts))
+
+pCSVDelim :: CSVOptions -> Parser ()
+pCSVDelim opts = do
+ char (csvDelim opts)
+ if csvKeepSpace opts
+ then return ()
+ else skipMany (oneOf " \t")
+
+endline :: Parser ()
+endline = do
+ optional (void $ char '\r')
+ void $ char '\n'
diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs
new file mode 100644
index 000000000..aa0379942
--- /dev/null
+++ b/src/Text/Pandoc/Class.hs
@@ -0,0 +1,1082 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+#if MIN_VERSION_base(4,8,0)
+#else
+{-# LANGUAGE OverlappingInstances #-}
+#endif
+
+{-
+Copyright (C) 2016-17 Jesse Rosenthal <jrosenthal@jhu.edu>
+and John MacFarlane.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Class
+ Copyright : Copyright (C) 2016-17 Jesse Rosenthal, John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
+ Stability : alpha
+ Portability : portable
+
+This module defines a type class, 'PandocMonad', for pandoc readers
+and writers. A pure instance 'PandocPure' and an impure instance
+'PandocIO' are provided. This allows users of the library to choose
+whether they want conversions to perform IO operations (such as
+reading include files or images).
+-}
+
+module Text.Pandoc.Class ( PandocMonad(..)
+ , CommonState(..)
+ , PureState(..)
+ , getPureState
+ , getsPureState
+ , putPureState
+ , modifyPureState
+ , getPOSIXTime
+ , getZonedTime
+ , readFileFromDirs
+ , report
+ , setTrace
+ , setRequestHeader
+ , getLog
+ , setVerbosity
+ , getVerbosity
+ , getMediaBag
+ , setMediaBag
+ , insertMedia
+ , setUserDataDir
+ , getUserDataDir
+ , fetchItem
+ , getInputFiles
+ , setInputFiles
+ , getOutputFile
+ , setOutputFile
+ , setResourcePath
+ , getResourcePath
+ , PandocIO(..)
+ , PandocPure(..)
+ , FileTree
+ , FileInfo(..)
+ , addToFileTree
+ , insertInFileTree
+ , runIO
+ , runIOorExplode
+ , runPure
+ , readDefaultDataFile
+ , readDataFile
+ , fetchMediaResource
+ , fillMediaBag
+ , extractMedia
+ , toLang
+ , setTranslations
+ , translateTerm
+ , Translations
+ ) where
+
+import Prelude hiding (readFile)
+import System.Random (StdGen, next, mkStdGen)
+import qualified System.Random as IO (newStdGen)
+import Codec.Archive.Zip
+import qualified Data.CaseInsensitive as CI
+import Data.Unique (hashUnique)
+import Data.List (stripPrefix)
+import qualified Data.Unique as IO (newUnique)
+import qualified Text.Pandoc.UTF8 as UTF8
+import qualified System.Directory as Directory
+import Text.Pandoc.Compat.Time (UTCTime)
+import Text.Pandoc.Logging
+import Text.Parsec (ParsecT, getPosition, sourceLine, sourceName)
+import qualified Text.Pandoc.Compat.Time as IO (getCurrentTime)
+import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType)
+import Text.Pandoc.Definition
+import Data.Digest.Pure.SHA (sha1, showDigest)
+import Data.Maybe (fromMaybe)
+import Data.Time.Clock.POSIX ( utcTimeToPOSIXSeconds
+ , posixSecondsToUTCTime
+ , POSIXTime )
+import Data.Time.LocalTime (TimeZone, ZonedTime, utcToZonedTime, utc)
+import Data.ByteString.Base64 (decodeLenient)
+import Network.URI ( escapeURIString, nonStrictRelativeTo,
+ unEscapeString, parseURIReference, isAllowedInURI,
+ parseURI, URI(..) )
+import Network.HTTP.Client
+ (httpLbs, responseBody, responseHeaders,
+ Request(port, host, requestHeaders), parseRequest, newManager)
+import Network.HTTP.Client.Internal (addProxy)
+import Network.HTTP.Client.TLS (tlsManagerSettings)
+import System.Environment (getEnv)
+import Network.HTTP.Types.Header ( hContentType )
+import Network (withSocketsDo)
+import Data.ByteString.Lazy (toChunks)
+import qualified Control.Exception as E
+import qualified Data.Time.LocalTime as IO (getCurrentTimeZone)
+import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
+import Text.Pandoc.Walk (walkM, walk)
+import qualified Text.Pandoc.MediaBag as MB
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as BL
+import qualified System.Environment as IO (lookupEnv)
+import System.FilePath.Glob (match, compile)
+import System.Directory (createDirectoryIfMissing, getDirectoryContents,
+ doesDirectoryExist)
+import System.FilePath
+ ((</>), (<.>), takeDirectory, takeExtension, dropExtension,
+ isRelative, normalise, splitDirectories)
+import qualified System.FilePath.Glob as IO (glob)
+import qualified System.FilePath.Posix as Posix
+import qualified System.Directory as IO (getModificationTime)
+import Control.Monad as M (fail)
+import Control.Monad.State.Strict
+import Control.Monad.Except
+import Data.Word (Word8)
+import Data.Default
+import System.IO.Error
+import System.IO (stderr)
+import qualified Data.Map as M
+import Text.Pandoc.Error
+import Text.Pandoc.BCP47 (Lang(..), parseBCP47, renderLang)
+import Text.Pandoc.Translations (Term(..), Translations, lookupTerm,
+ readTranslations)
+import qualified Debug.Trace
+#ifdef EMBED_DATA_FILES
+import Text.Pandoc.Data (dataFiles)
+#else
+import qualified Paths_pandoc as Paths
+#endif
+
+-- | The PandocMonad typeclass contains all the potentially
+-- IO-related functions used in pandoc's readers and writers.
+-- Instances of this typeclass may implement these functions
+-- in IO (as in 'PandocIO') or using an internal state that
+-- represents a file system, time, and so on (as in 'PandocPure').
+class (Functor m, Applicative m, Monad m, MonadError PandocError m)
+ => PandocMonad m where
+ -- | Lookup an environment variable.
+ lookupEnv :: String -> m (Maybe String)
+ -- | Get the current (UTC) time.
+ getCurrentTime :: m UTCTime
+ -- | Get the locale's time zone.
+ getCurrentTimeZone :: m TimeZone
+ -- | Return a new generator for random numbers.
+ newStdGen :: m StdGen
+ -- | Return a new unique integer.
+ newUniqueHash :: m Int
+ -- | Retrieve contents and mime type from a URL, raising
+ -- an error on failure.
+ openURL :: String -> m (B.ByteString, Maybe MimeType)
+ -- | Read the lazy ByteString contents from a file path,
+ -- raising an error on failure.
+ readFileLazy :: FilePath -> m BL.ByteString
+ -- | Read the strict ByteString contents from a file path,
+ -- raising an error on failure.
+ readFileStrict :: FilePath -> m B.ByteString
+ -- | Return a list of paths that match a glob, relative to
+ -- the working directory. See 'System.FilePath.Glob' for
+ -- the glob syntax.
+ glob :: String -> m [FilePath]
+ -- | Returns True if file exists.
+ fileExists :: FilePath -> m Bool
+ -- | Returns the path of data file.
+ getDataFileName :: FilePath -> m FilePath
+ -- | Return the modification time of a file.
+ getModificationTime :: FilePath -> m UTCTime
+ -- | Get the value of the 'CommonState' used by all instances
+ -- of 'PandocMonad'.
+ getCommonState :: m CommonState
+ -- | Set the value of the 'CommonState' used by all instances
+ -- of 'PandocMonad'.
+ -- | Get the value of a specific field of 'CommonState'.
+ putCommonState :: CommonState -> m ()
+ -- | Get the value of a specific field of 'CommonState'.
+ getsCommonState :: (CommonState -> a) -> m a
+ getsCommonState f = f <$> getCommonState
+ -- | Modify the 'CommonState'.
+ modifyCommonState :: (CommonState -> CommonState) -> m ()
+ modifyCommonState f = getCommonState >>= putCommonState . f
+ -- Output a log message.
+ logOutput :: LogMessage -> m ()
+ -- Output a debug message to sterr, using 'Debug.Trace.trace',
+ -- if tracing is enabled. Note: this writes to stderr even in
+ -- pure instances.
+ trace :: String -> m ()
+ trace msg = do
+ tracing <- getsCommonState stTrace
+ when tracing $ Debug.Trace.trace ("[trace] " ++ msg) (return ())
+
+-- * Functions defined for all PandocMonad instances
+
+-- | Set the verbosity level.
+setVerbosity :: PandocMonad m => Verbosity -> m ()
+setVerbosity verbosity =
+ modifyCommonState $ \st -> st{ stVerbosity = verbosity }
+
+-- | Get the verbosity level.
+getVerbosity :: PandocMonad m => m Verbosity
+getVerbosity = getsCommonState stVerbosity
+
+-- Get the accomulated log messages (in temporal order).
+getLog :: PandocMonad m => m [LogMessage]
+getLog = reverse <$> getsCommonState stLog
+
+-- | Log a message using 'logOutput'. Note that 'logOutput' is
+-- called only if the verbosity level exceeds the level of the
+-- message, but the message is added to the list of log messages
+-- that will be retrieved by 'getLog' regardless of its verbosity level.
+report :: PandocMonad m => LogMessage -> m ()
+report msg = do
+ verbosity <- getsCommonState stVerbosity
+ let level = messageVerbosity msg
+ when (level <= verbosity) $ logOutput msg
+ modifyCommonState $ \st -> st{ stLog = msg : stLog st }
+
+-- | Determine whether tracing is enabled. This affects
+-- the behavior of 'trace'. If tracing is not enabled,
+-- 'trace' does nothing.
+setTrace :: PandocMonad m => Bool -> m ()
+setTrace useTracing = modifyCommonState $ \st -> st{stTrace = useTracing}
+
+-- | Set request header to use in HTTP requests.
+setRequestHeader :: PandocMonad m
+ => String -- ^ Header name
+ -> String -- ^ Value
+ -> m ()
+setRequestHeader name val = modifyCommonState $ \st ->
+ st{ stRequestHeaders =
+ (name, val) : filter (\(n,_) -> n /= name) (stRequestHeaders st) }
+
+-- | Initialize the media bag.
+setMediaBag :: PandocMonad m => MediaBag -> m ()
+setMediaBag mb = modifyCommonState $ \st -> st{stMediaBag = mb}
+
+-- Retrieve the media bag.
+getMediaBag :: PandocMonad m => m MediaBag
+getMediaBag = getsCommonState stMediaBag
+
+-- Insert an item into the media bag.
+insertMedia :: PandocMonad m => FilePath -> Maybe MimeType -> BL.ByteString -> m ()
+insertMedia fp mime bs = do
+ mb <- getMediaBag
+ let mb' = MB.insertMedia fp mime bs mb
+ setMediaBag mb'
+
+-- Retrieve the input filenames.
+getInputFiles :: PandocMonad m => m [FilePath]
+getInputFiles = getsCommonState stInputFiles
+
+-- Set the input filenames.
+setInputFiles :: PandocMonad m => [FilePath] -> m ()
+setInputFiles fs = do
+ let sourceURL = case fs of
+ [] -> Nothing
+ (x:_) -> case parseURI x of
+ Just u
+ | uriScheme u `elem` ["http:","https:"] ->
+ Just $ show u{ uriQuery = "",
+ uriFragment = "" }
+ _ -> Nothing
+
+ modifyCommonState $ \st -> st{ stInputFiles = fs
+ , stSourceURL = sourceURL }
+
+-- Retrieve the output filename.
+getOutputFile :: PandocMonad m => m (Maybe FilePath)
+getOutputFile = getsCommonState stOutputFile
+
+-- Set the output filename.
+setOutputFile :: PandocMonad m => Maybe FilePath -> m ()
+setOutputFile mbf = modifyCommonState $ \st -> st{ stOutputFile = mbf }
+
+-- Retrieve the resource path searched by 'fetchItem'.
+getResourcePath :: PandocMonad m => m [FilePath]
+getResourcePath = getsCommonState stResourcePath
+
+-- Set the resource path searched by 'fetchItem'.
+setResourcePath :: PandocMonad m => [FilePath] -> m ()
+setResourcePath ps = modifyCommonState $ \st -> st{stResourcePath = ps}
+
+-- Get the POSIX time.
+getPOSIXTime :: PandocMonad m => m POSIXTime
+getPOSIXTime = utcTimeToPOSIXSeconds <$> getCurrentTime
+
+-- Get the zoned time.
+getZonedTime :: PandocMonad m => m ZonedTime
+getZonedTime = do
+ t <- getCurrentTime
+ tz <- getCurrentTimeZone
+ return $ utcToZonedTime tz t
+
+-- | Read file, checking in any number of directories.
+readFileFromDirs :: PandocMonad m => [FilePath] -> FilePath -> m (Maybe String)
+readFileFromDirs [] _ = return Nothing
+readFileFromDirs (d:ds) f = catchError
+ ((Just . UTF8.toStringLazy) <$> readFileLazy (d </> f))
+ (\_ -> readFileFromDirs ds f)
+
+--
+
+-- | 'CommonState' represents state that is used by all
+-- instances of 'PandocMonad'. Normally users should not
+-- need to interact with it directly; instead, auxiliary
+-- functions like 'setVerbosity' and 'withMediaBag' should be used.
+data CommonState = CommonState { stLog :: [LogMessage]
+ -- ^ A list of log messages in reverse order
+ , stUserDataDir :: Maybe FilePath
+ -- ^ Directory to search for data files
+ , stSourceURL :: Maybe String
+ -- ^ Absolute URL + dir of 1st source file
+ , stRequestHeaders :: [(String, String)]
+ -- ^ Headers to add for HTTP requests
+ , stMediaBag :: MediaBag
+ -- ^ Media parsed from binary containers
+ , stTranslations :: Maybe
+ (Lang, Maybe Translations)
+ -- ^ Translations for localization
+ , stInputFiles :: [FilePath]
+ -- ^ List of input files from command line
+ , stOutputFile :: Maybe FilePath
+ -- ^ Output file from command line
+ , stResourcePath :: [FilePath]
+ -- ^ Path to search for resources like
+ -- included images
+ , stVerbosity :: Verbosity
+ -- ^ Verbosity level
+ , stTrace :: Bool
+ -- ^ Controls whether tracing messages are
+ -- issued.
+ }
+
+instance Default CommonState where
+ def = CommonState { stLog = []
+ , stUserDataDir = Nothing
+ , stSourceURL = Nothing
+ , stRequestHeaders = []
+ , stMediaBag = mempty
+ , stTranslations = Nothing
+ , stInputFiles = []
+ , stOutputFile = Nothing
+ , stResourcePath = ["."]
+ , stVerbosity = WARNING
+ , stTrace = False
+ }
+
+-- | Convert BCP47 string to a Lang, issuing warning
+-- if there are problems.
+toLang :: PandocMonad m => Maybe String -> m (Maybe Lang)
+toLang Nothing = return Nothing
+toLang (Just s) =
+ case parseBCP47 s of
+ Left _ -> do
+ report $ InvalidLang s
+ return Nothing
+ Right l -> return (Just l)
+
+-- | Select the language to use with 'translateTerm'.
+-- Note that this does not read a translation file;
+-- that is only done the first time 'translateTerm' is
+-- used.
+setTranslations :: PandocMonad m => Lang -> m ()
+setTranslations lang =
+ modifyCommonState $ \st -> st{ stTranslations = Just (lang, Nothing) }
+
+-- | Load term map.
+getTranslations :: PandocMonad m => m Translations
+getTranslations = do
+ mbtrans <- getsCommonState stTranslations
+ case mbtrans of
+ Nothing -> return mempty -- no language defined
+ Just (_, Just t) -> return t
+ Just (lang, Nothing) -> do -- read from file
+ let translationFile = "translations/" ++ renderLang lang ++ ".yaml"
+ let fallbackFile = "translations/" ++ langLanguage lang ++ ".yaml"
+ let getTrans fp = do
+ bs <- readDataFile fp
+ case readTranslations (UTF8.toString bs) of
+ Left e -> do
+ report $ CouldNotLoadTranslations (renderLang lang)
+ (fp ++ ": " ++ e)
+ -- make sure we don't try again...
+ modifyCommonState $ \st ->
+ st{ stTranslations = Nothing }
+ return mempty
+ Right t -> do
+ modifyCommonState $ \st ->
+ st{ stTranslations = Just (lang, Just t) }
+ return t
+ catchError (getTrans translationFile)
+ (\_ ->
+ catchError (getTrans fallbackFile)
+ (\e -> do
+ report $ CouldNotLoadTranslations (renderLang lang)
+ $ case e of
+ PandocCouldNotFindDataFileError _ ->
+ "data file " ++ fallbackFile ++ " not found"
+ _ -> ""
+ -- make sure we don't try again...
+ modifyCommonState $ \st -> st{ stTranslations = Nothing }
+ return mempty))
+
+-- | Get a translation from the current term map.
+-- Issue a warning if the term is not defined.
+translateTerm :: PandocMonad m => Term -> m String
+translateTerm term = do
+ translations <- getTranslations
+ case lookupTerm term translations of
+ Just s -> return s
+ Nothing -> do
+ report $ NoTranslation (show term)
+ return ""
+
+-- | Evaluate a 'PandocIO' operation.
+runIO :: PandocIO a -> IO (Either PandocError a)
+runIO ma = flip evalStateT def $ runExceptT $ unPandocIO ma
+
+-- | Evaluate a 'PandocIO' operation, handling any errors
+-- by exiting with an appropriate message and error status.
+runIOorExplode :: PandocIO a -> IO a
+runIOorExplode ma = runIO ma >>= handleError
+
+newtype PandocIO a = PandocIO {
+ unPandocIO :: ExceptT PandocError (StateT CommonState IO) a
+ } deriving ( MonadIO
+ , Functor
+ , Applicative
+ , Monad
+ , MonadError PandocError
+ )
+
+-- | Utility function to lift IO errors into 'PandocError's.
+liftIOError :: (String -> IO a) -> String -> PandocIO a
+liftIOError f u = do
+ res <- liftIO $ tryIOError $ f u
+ case res of
+ Left e -> throwError $ PandocIOError u e
+ Right r -> return r
+
+instance PandocMonad PandocIO where
+ lookupEnv = liftIO . IO.lookupEnv
+ getCurrentTime = liftIO IO.getCurrentTime
+ getCurrentTimeZone = liftIO IO.getCurrentTimeZone
+ newStdGen = liftIO IO.newStdGen
+ newUniqueHash = hashUnique <$> liftIO IO.newUnique
+
+ openURL u
+ | Just u'' <- stripPrefix "data:" u = do
+ let mime = takeWhile (/=',') u''
+ let contents = UTF8.fromString $
+ unEscapeString $ drop 1 $ dropWhile (/=',') u''
+ return (decodeLenient contents, Just mime)
+ | otherwise = do
+ let toReqHeader (n, v) = (CI.mk (UTF8.fromString n), UTF8.fromString v)
+ customHeaders <- map toReqHeader <$> getsCommonState stRequestHeaders
+ report $ Fetching u
+ res <- liftIO $ E.try $ withSocketsDo $ do
+ let parseReq = parseRequest
+ proxy <- tryIOError (getEnv "http_proxy")
+ let addProxy' x = case proxy of
+ Left _ -> return x
+ Right pr -> parseReq pr >>= \r ->
+ return (addProxy (host r) (port r) x)
+ req <- parseReq u >>= addProxy'
+ let req' = req{requestHeaders = customHeaders ++ requestHeaders req}
+ resp <- newManager tlsManagerSettings >>= httpLbs req'
+ return (B.concat $ toChunks $ responseBody resp,
+ UTF8.toString `fmap` lookup hContentType (responseHeaders resp))
+
+ case res of
+ Right r -> return r
+ Left e -> throwError $ PandocHttpError u e
+
+ readFileLazy s = liftIOError BL.readFile s
+ readFileStrict s = liftIOError B.readFile s
+
+ glob = liftIOError IO.glob
+ fileExists = liftIOError Directory.doesFileExist
+#ifdef EMBED_DATA_FILES
+ getDataFileName = return
+#else
+ getDataFileName = liftIOError Paths.getDataFileName
+#endif
+ getModificationTime = liftIOError IO.getModificationTime
+ getCommonState = PandocIO $ lift get
+ putCommonState x = PandocIO $ lift $ put x
+ logOutput msg = liftIO $ do
+ UTF8.hPutStr stderr $
+ "[" ++ show (messageVerbosity msg) ++ "] "
+ alertIndent $ lines $ showLogMessage msg
+
+alertIndent :: [String] -> IO ()
+alertIndent [] = return ()
+alertIndent (l:ls) = do
+ UTF8.hPutStrLn stderr l
+ mapM_ go ls
+ where go l' = do UTF8.hPutStr stderr " "
+ UTF8.hPutStrLn stderr l'
+
+-- | Specialized version of parseURIReference that disallows
+-- single-letter schemes. Reason: these are usually windows absolute
+-- paths.
+parseURIReference' :: String -> Maybe URI
+parseURIReference' s =
+ case parseURIReference s of
+ Just u
+ | length (uriScheme u) > 2 -> Just u
+ | null (uriScheme u) -> Just u -- protocol-relative
+ _ -> Nothing
+
+-- | Set the user data directory in common state.
+setUserDataDir :: PandocMonad m
+ => Maybe FilePath
+ -> m ()
+setUserDataDir mbfp = modifyCommonState $ \st -> st{ stUserDataDir = mbfp }
+
+-- | Get the user data directory from common state.
+getUserDataDir :: PandocMonad m
+ => m (Maybe FilePath)
+getUserDataDir = getsCommonState stUserDataDir
+
+-- | Fetch an image or other item from the local filesystem or the net.
+-- Returns raw content and maybe mime type.
+fetchItem :: PandocMonad m
+ => String
+ -> m (B.ByteString, Maybe MimeType)
+fetchItem s = do
+ mediabag <- getMediaBag
+ case lookupMedia s mediabag of
+ Just (mime, bs) -> return (BL.toStrict bs, Just mime)
+ Nothing -> downloadOrRead s
+
+downloadOrRead :: PandocMonad m
+ => String
+ -> m (B.ByteString, Maybe MimeType)
+downloadOrRead s = do
+ sourceURL <- getsCommonState stSourceURL
+ case (sourceURL >>= parseURIReference' .
+ ensureEscaped, ensureEscaped s) of
+ (Just u, s') -> -- try fetching from relative path at source
+ case parseURIReference' s' of
+ Just u' -> openURL $ show $ u' `nonStrictRelativeTo` u
+ Nothing -> openURL s' -- will throw error
+ (Nothing, s'@('/':'/':_)) -> -- protocol-relative URI
+ case parseURIReference' s' of
+ Just u' -> openURL $ show $ u' `nonStrictRelativeTo` httpcolon
+ Nothing -> openURL s' -- will throw error
+ (Nothing, s') ->
+ case parseURI s' of -- requires absolute URI
+ -- We don't want to treat C:/ as a scheme:
+ Just u' | length (uriScheme u') > 2 -> openURL (show u')
+ Just u' | uriScheme u' == "file:" ->
+ readLocalFile $ dropWhile (=='/') (uriPath u')
+ _ -> readLocalFile fp -- get from local file system
+ where readLocalFile f = do
+ resourcePath <- getResourcePath
+ cont <- if isRelative f
+ then withPaths resourcePath readFileStrict f
+ else readFileStrict f
+ return (cont, mime)
+ httpcolon = URI{ uriScheme = "http:",
+ uriAuthority = Nothing,
+ uriPath = "",
+ uriQuery = "",
+ uriFragment = "" }
+ dropFragmentAndQuery = takeWhile (\c -> c /= '?' && c /= '#')
+ fp = unEscapeString $ dropFragmentAndQuery s
+ mime = case takeExtension fp of
+ ".gz" -> getMimeType $ dropExtension fp
+ ".svgz" -> getMimeType $ dropExtension fp ++ ".svg"
+ x -> getMimeType x
+ ensureEscaped = escapeURIString isAllowedInURI . map convertSlash
+ convertSlash '\\' = '/'
+ convertSlash x = x
+
+-- Retrieve default reference.docx.
+getDefaultReferenceDocx :: PandocMonad m => m Archive
+getDefaultReferenceDocx = do
+ let paths = ["[Content_Types].xml",
+ "_rels/.rels",
+ "docProps/app.xml",
+ "docProps/core.xml",
+ "word/document.xml",
+ "word/fontTable.xml",
+ "word/footnotes.xml",
+ "word/comments.xml",
+ "word/numbering.xml",
+ "word/settings.xml",
+ "word/webSettings.xml",
+ "word/styles.xml",
+ "word/_rels/document.xml.rels",
+ "word/_rels/footnotes.xml.rels",
+ "word/theme/theme1.xml"]
+ let toLazy = BL.fromChunks . (:[])
+ let pathToEntry path = do
+ epochtime <- (floor . utcTimeToPOSIXSeconds) <$> getCurrentTime
+ contents <- toLazy <$> readDataFile ("docx/" ++ path)
+ return $ toEntry path epochtime contents
+ datadir <- getUserDataDir
+ mbArchive <- case datadir of
+ Nothing -> return Nothing
+ Just d -> do
+ exists <- fileExists (d </> "reference.docx")
+ if exists
+ then return (Just (d </> "reference.docx"))
+ else return Nothing
+ case mbArchive of
+ Just arch -> toArchive <$> readFileLazy arch
+ Nothing -> foldr addEntryToArchive emptyArchive <$>
+ mapM pathToEntry paths
+
+-- Retrieve default reference.odt.
+getDefaultReferenceODT :: PandocMonad m => m Archive
+getDefaultReferenceODT = do
+ let paths = ["mimetype",
+ "manifest.rdf",
+ "styles.xml",
+ "content.xml",
+ "meta.xml",
+ "settings.xml",
+ "Configurations2/accelerator/current.xml",
+ "Thumbnails/thumbnail.png",
+ "META-INF/manifest.xml"]
+ let pathToEntry path = do epochtime <- floor `fmap` getPOSIXTime
+ contents <- (BL.fromChunks . (:[])) `fmap`
+ readDataFile ("odt/" ++ path)
+ return $ toEntry path epochtime contents
+ datadir <- getUserDataDir
+ mbArchive <- case datadir of
+ Nothing -> return Nothing
+ Just d -> do
+ exists <- fileExists (d </> "reference.odt")
+ if exists
+ then return (Just (d </> "reference.odt"))
+ else return Nothing
+ case mbArchive of
+ Just arch -> toArchive <$> readFileLazy arch
+ Nothing -> foldr addEntryToArchive emptyArchive <$>
+ mapM pathToEntry paths
+
+getDefaultReferencePptx :: PandocMonad m => m Archive
+getDefaultReferencePptx = do
+ -- We're going to narrow this down substantially once we get it
+ -- working.
+ let paths = [ "[Content_Types].xml"
+ , "_rels/.rels"
+ , "docProps/app.xml"
+ , "docProps/core.xml"
+ , "ppt/_rels/presentation.xml.rels"
+ , "ppt/presProps.xml"
+ , "ppt/presentation.xml"
+ , "ppt/slideLayouts/_rels/slideLayout1.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout2.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout3.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout4.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout5.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout6.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout7.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout8.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout9.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout10.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout11.xml.rels"
+ , "ppt/slideLayouts/slideLayout1.xml"
+ , "ppt/slideLayouts/slideLayout10.xml"
+ , "ppt/slideLayouts/slideLayout11.xml"
+ , "ppt/slideLayouts/slideLayout2.xml"
+ , "ppt/slideLayouts/slideLayout3.xml"
+ , "ppt/slideLayouts/slideLayout4.xml"
+ , "ppt/slideLayouts/slideLayout5.xml"
+ , "ppt/slideLayouts/slideLayout6.xml"
+ , "ppt/slideLayouts/slideLayout7.xml"
+ , "ppt/slideLayouts/slideLayout8.xml"
+ , "ppt/slideLayouts/slideLayout9.xml"
+ , "ppt/slideMasters/_rels/slideMaster1.xml.rels"
+ , "ppt/slideMasters/slideMaster1.xml"
+ , "ppt/slides/_rels/slide1.xml.rels"
+ , "ppt/slides/slide1.xml"
+ , "ppt/slides/_rels/slide2.xml.rels"
+ , "ppt/slides/slide2.xml"
+ , "ppt/tableStyles.xml"
+ , "ppt/theme/theme1.xml"
+ , "ppt/viewProps.xml"
+ -- These relate to notes slides.
+ , "ppt/notesMasters/notesMaster1.xml"
+ , "ppt/notesMasters/_rels/notesMaster1.xml.rels"
+ , "ppt/notesSlides/notesSlide1.xml"
+ , "ppt/notesSlides/_rels/notesSlide1.xml.rels"
+ , "ppt/notesSlides/notesSlide2.xml"
+ , "ppt/notesSlides/_rels/notesSlide2.xml.rels"
+ , "ppt/theme/theme2.xml"
+ ]
+ let toLazy = BL.fromChunks . (:[])
+ let pathToEntry path = do
+ epochtime <- (floor . utcTimeToPOSIXSeconds) <$> getCurrentTime
+ contents <- toLazy <$> readDataFile ("pptx/" ++ path)
+ return $ toEntry path epochtime contents
+ datadir <- getUserDataDir
+ mbArchive <- case datadir of
+ Nothing -> return Nothing
+ Just d -> do
+ exists <- fileExists (d </> "reference.pptx")
+ if exists
+ then return (Just (d </> "reference.pptx"))
+ else return Nothing
+ case mbArchive of
+ Just arch -> toArchive <$> readFileLazy arch
+ Nothing -> foldr addEntryToArchive emptyArchive <$>
+ mapM pathToEntry paths
+
+
+-- | Read file from user data directory or,
+-- if not found there, from Cabal data directory.
+readDataFile :: PandocMonad m => FilePath -> m B.ByteString
+readDataFile fname = do
+ datadir <- getUserDataDir
+ case datadir of
+ Nothing -> readDefaultDataFile fname
+ Just userDir -> do
+ exists <- fileExists (userDir </> fname)
+ if exists
+ then readFileStrict (userDir </> fname)
+ else readDefaultDataFile fname
+
+-- | Read file from from Cabal data directory.
+readDefaultDataFile :: PandocMonad m => FilePath -> m B.ByteString
+readDefaultDataFile "reference.docx" =
+ (B.concat . BL.toChunks . fromArchive) <$> getDefaultReferenceDocx
+readDefaultDataFile "reference.pptx" =
+ (B.concat . BL.toChunks . fromArchive) <$> getDefaultReferencePptx
+readDefaultDataFile "reference.odt" =
+ (B.concat . BL.toChunks . fromArchive) <$> getDefaultReferenceODT
+readDefaultDataFile fname =
+#ifdef EMBED_DATA_FILES
+ case lookup (makeCanonical fname) dataFiles of
+ Nothing -> throwError $ PandocCouldNotFindDataFileError fname
+ Just contents -> return contents
+#else
+ getDataFileName fname' >>= checkExistence >>= readFileStrict
+ where fname' = if fname == "MANUAL.txt" then fname else "data" </> fname
+
+checkExistence :: PandocMonad m => FilePath -> m FilePath
+checkExistence fn = do
+ exists <- fileExists fn
+ if exists
+ then return fn
+ else throwError $ PandocCouldNotFindDataFileError fn
+#endif
+
+makeCanonical :: FilePath -> FilePath
+makeCanonical = Posix.joinPath . transformPathParts . splitDirectories
+ where transformPathParts = reverse . foldl go []
+ go as "." = as
+ go (_:as) ".." = as
+ go as x = x : as
+
+withPaths :: PandocMonad m => [FilePath] -> (FilePath -> m a) -> FilePath -> m a
+withPaths [] _ fp = throwError $ PandocResourceNotFound fp
+withPaths (p:ps) action fp =
+ catchError (action (p </> fp))
+ (\_ -> withPaths ps action fp)
+
+-- | Fetch local or remote resource (like an image) and provide data suitable
+-- for adding it to the MediaBag.
+fetchMediaResource :: PandocMonad m
+ => String -> m (FilePath, Maybe MimeType, BL.ByteString)
+fetchMediaResource src = do
+ (bs, mt) <- downloadOrRead src
+ let ext = fromMaybe (takeExtension src)
+ (mt >>= extensionFromMimeType)
+ let bs' = BL.fromChunks [bs]
+ let basename = showDigest $ sha1 bs'
+ let fname = basename <.> ext
+ return (fname, mt, bs')
+
+-- | Traverse tree, filling media bag for any images that
+-- aren't already in the media bag.
+fillMediaBag :: PandocMonad m => Pandoc -> m Pandoc
+fillMediaBag d = walkM handleImage d
+ where handleImage :: PandocMonad m => Inline -> m Inline
+ handleImage (Image attr lab (src, tit)) = catchError
+ (do mediabag <- getMediaBag
+ case lookupMedia src mediabag of
+ Just (_, _) -> return $ Image attr lab (src, tit)
+ Nothing -> do
+ (fname, mt, bs) <- fetchMediaResource src
+ insertMedia fname mt bs
+ return $ Image attr lab (fname, tit))
+ (\e ->
+ case e of
+ PandocResourceNotFound _ -> do
+ report $ CouldNotFetchResource src
+ "replacing image with description"
+ -- emit alt text
+ return $ Span ("",["image"],[]) lab
+ PandocHttpError u er -> do
+ report $ CouldNotFetchResource u
+ (show er ++ "\rReplacing image with description.")
+ -- emit alt text
+ return $ Span ("",["image"],[]) lab
+ _ -> throwError e)
+ handleImage x = return x
+
+-- | Extract media from the mediabag into a directory.
+extractMedia :: FilePath -> Pandoc -> PandocIO Pandoc
+extractMedia dir d = do
+ media <- getMediaBag
+ case [fp | (fp, _, _) <- mediaDirectory media] of
+ [] -> return d
+ fps -> do
+ mapM_ (writeMedia dir media) fps
+ return $ walk (adjustImagePath dir fps) d
+
+-- Write the contents of a media bag to a path.
+writeMedia :: FilePath -> MediaBag -> FilePath -> PandocIO ()
+writeMedia dir mediabag subpath = do
+ -- we join and split to convert a/b/c to a\b\c on Windows;
+ -- in zip containers all paths use /
+ let fullpath = dir </> normalise subpath
+ let mbcontents = lookupMedia subpath mediabag
+ case mbcontents of
+ Nothing -> throwError $ PandocResourceNotFound subpath
+ Just (_, bs) -> do
+ report $ Extracting fullpath
+ liftIOError (createDirectoryIfMissing True) (takeDirectory fullpath)
+ liftIOError (\p -> BL.writeFile p bs) fullpath
+
+adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
+adjustImagePath dir paths (Image attr lab (src, tit))
+ | src `elem` paths = Image attr lab (dir ++ "/" ++ src, tit)
+adjustImagePath _ _ x = x
+
+-- | The 'PureState' contains ersatz representations
+-- of things that would normally be obtained through IO.
+data PureState = PureState { stStdGen :: StdGen
+ , stWord8Store :: [Word8] -- should be
+ -- inifinite,
+ -- i.e. [1..]
+ , stUniqStore :: [Int] -- should be
+ -- inifinite and
+ -- contain every
+ -- element at most
+ -- once, e.g. [1..]
+ , stEnv :: [(String, String)]
+ , stTime :: UTCTime
+ , stTimeZone :: TimeZone
+ , stReferenceDocx :: Archive
+ , stReferencePptx :: Archive
+ , stReferenceODT :: Archive
+ , stFiles :: FileTree
+ , stUserDataFiles :: FileTree
+ , stCabalDataFiles :: FileTree
+ }
+
+instance Default PureState where
+ def = PureState { stStdGen = mkStdGen 1848
+ , stWord8Store = [1..]
+ , stUniqStore = [1..]
+ , stEnv = [("USER", "pandoc-user")]
+ , stTime = posixSecondsToUTCTime 0
+ , stTimeZone = utc
+ , stReferenceDocx = emptyArchive
+ , stReferencePptx = emptyArchive
+ , stReferenceODT = emptyArchive
+ , stFiles = mempty
+ , stUserDataFiles = mempty
+ , stCabalDataFiles = mempty
+ }
+
+
+getPureState :: PandocPure PureState
+getPureState = PandocPure $ lift $ lift get
+
+getsPureState :: (PureState -> a) -> PandocPure a
+getsPureState f = f <$> getPureState
+
+putPureState :: PureState -> PandocPure ()
+putPureState ps= PandocPure $ lift $ lift $ put ps
+
+modifyPureState :: (PureState -> PureState) -> PandocPure ()
+modifyPureState f = PandocPure $ lift $ lift $ modify f
+
+
+data FileInfo = FileInfo { infoFileMTime :: UTCTime
+ , infoFileContents :: B.ByteString
+ }
+
+newtype FileTree = FileTree {unFileTree :: M.Map FilePath FileInfo}
+ deriving (Monoid)
+
+getFileInfo :: FilePath -> FileTree -> Maybe FileInfo
+getFileInfo fp tree =
+ M.lookup (makeCanonical fp) (unFileTree tree)
+
+-- | Add the specified file to the FileTree. If file
+-- is a directory, add its contents recursively.
+addToFileTree :: FileTree -> FilePath -> IO FileTree
+addToFileTree tree fp = do
+ isdir <- doesDirectoryExist fp
+ if isdir
+ then do -- recursively add contents of directories
+ let isSpecial ".." = True
+ isSpecial "." = True
+ isSpecial _ = False
+ fs <- (map (fp </>) . filter (not . isSpecial)) <$> getDirectoryContents fp
+ foldM addToFileTree tree fs
+ else do
+ contents <- B.readFile fp
+ mtime <- IO.getModificationTime fp
+ return $ insertInFileTree fp FileInfo{ infoFileMTime = mtime
+ , infoFileContents = contents } tree
+
+-- | Insert an ersatz file into the 'FileTree'.
+insertInFileTree :: FilePath -> FileInfo -> FileTree -> FileTree
+insertInFileTree fp info (FileTree treemap) =
+ FileTree $ M.insert (makeCanonical fp) info treemap
+
+newtype PandocPure a = PandocPure {
+ unPandocPure :: ExceptT PandocError
+ (StateT CommonState (State PureState)) a
+ } deriving ( Functor
+ , Applicative
+ , Monad
+ , MonadError PandocError
+ )
+
+-- Run a 'PandocPure' operation.
+runPure :: PandocPure a -> Either PandocError a
+runPure x = flip evalState def $
+ flip evalStateT def $
+ runExceptT $
+ unPandocPure x
+
+instance PandocMonad PandocPure where
+ lookupEnv s = do
+ env <- getsPureState stEnv
+ return (lookup s env)
+
+ getCurrentTime = getsPureState stTime
+
+ getCurrentTimeZone = getsPureState stTimeZone
+
+ newStdGen = do
+ g <- getsPureState stStdGen
+ let (_, nxtGen) = next g
+ modifyPureState $ \st -> st { stStdGen = nxtGen }
+ return g
+
+ newUniqueHash = do
+ uniqs <- getsPureState stUniqStore
+ case uniqs of
+ u : us -> do
+ modifyPureState $ \st -> st { stUniqStore = us }
+ return u
+ _ -> M.fail "uniq store ran out of elements"
+ openURL u = throwError $ PandocResourceNotFound u
+ readFileLazy fp = do
+ fps <- getsPureState stFiles
+ case infoFileContents <$> getFileInfo fp fps of
+ Just bs -> return (BL.fromStrict bs)
+ Nothing -> throwError $ PandocResourceNotFound fp
+ readFileStrict fp = do
+ fps <- getsPureState stFiles
+ case infoFileContents <$> getFileInfo fp fps of
+ Just bs -> return bs
+ Nothing -> throwError $ PandocResourceNotFound fp
+
+ glob s = do
+ FileTree ftmap <- getsPureState stFiles
+ return $ filter (match (compile s)) $ M.keys ftmap
+
+ fileExists fp = do
+ fps <- getsPureState stFiles
+ case getFileInfo fp fps of
+ Nothing -> return False
+ Just _ -> return True
+
+ getDataFileName fp = return $ "data/" ++ fp
+
+ getModificationTime fp = do
+ fps <- getsPureState stFiles
+ case infoFileMTime <$> getFileInfo fp fps of
+ Just tm -> return tm
+ Nothing -> throwError $ PandocIOError fp
+ (userError "Can't get modification time")
+
+ getCommonState = PandocPure $ lift get
+ putCommonState x = PandocPure $ lift $ put x
+
+ logOutput _msg = return ()
+
+-- This requires UndecidableInstances. We could avoid that
+-- by repeating the definitions below for every monad transformer
+-- we use: ReaderT, WriterT, StateT, RWST. But this seems to
+-- be harmless.
+instance (MonadTrans t, PandocMonad m, Functor (t m),
+ MonadError PandocError (t m), Monad (t m),
+ Applicative (t m)) => PandocMonad (t m) where
+ lookupEnv = lift . lookupEnv
+ getCurrentTime = lift getCurrentTime
+ getCurrentTimeZone = lift getCurrentTimeZone
+ newStdGen = lift newStdGen
+ newUniqueHash = lift newUniqueHash
+ openURL = lift . openURL
+ readFileLazy = lift . readFileLazy
+ readFileStrict = lift . readFileStrict
+ glob = lift . glob
+ fileExists = lift . fileExists
+ getDataFileName = lift . getDataFileName
+ getModificationTime = lift . getModificationTime
+ getCommonState = lift getCommonState
+ putCommonState = lift . putCommonState
+ logOutput = lift . logOutput
+
+#if MIN_VERSION_base(4,8,0)
+instance {-# OVERLAPS #-} PandocMonad m => PandocMonad (ParsecT s st m) where
+#else
+instance PandocMonad m => PandocMonad (ParsecT s st m) where
+#endif
+ lookupEnv = lift . lookupEnv
+ getCurrentTime = lift getCurrentTime
+ getCurrentTimeZone = lift getCurrentTimeZone
+ newStdGen = lift newStdGen
+ newUniqueHash = lift newUniqueHash
+ openURL = lift . openURL
+ readFileLazy = lift . readFileLazy
+ readFileStrict = lift . readFileStrict
+ glob = lift . glob
+ fileExists = lift . fileExists
+ getDataFileName = lift . getDataFileName
+ getModificationTime = lift . getModificationTime
+ getCommonState = lift getCommonState
+ putCommonState = lift . putCommonState
+ trace msg = do
+ tracing <- getsCommonState stTrace
+ when tracing $ do
+ pos <- getPosition
+ Debug.Trace.trace
+ ("[trace] Parsed " ++ msg ++ " at line " ++
+ show (sourceLine pos) ++
+ if sourceName pos == "chunk"
+ then " of chunk"
+ else "")
+ (return ())
+ logOutput = lift . logOutput
diff --git a/src/Text/Pandoc/Data.hs b/src/Text/Pandoc/Data.hs
new file mode 100644
index 000000000..af0e4504f
--- /dev/null
+++ b/src/Text/Pandoc/Data.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+module Text.Pandoc.Data (dataFiles) where
+
+import qualified Data.ByteString as B
+import Data.FileEmbed
+import System.FilePath (splitDirectories)
+import qualified System.FilePath.Posix as Posix
+
+-- We ensure that the data files are stored using Posix
+-- path separators (/), even on Windows.
+dataFiles :: [(FilePath, B.ByteString)]
+dataFiles = map (\(fp, contents) ->
+ (Posix.joinPath (splitDirectories fp), contents)) dataFiles'
+
+dataFiles' :: [(FilePath, B.ByteString)]
+dataFiles' = ("MANUAL.txt", $(embedFile "MANUAL.txt")) :
+ -- handle the hidden file separately, since embedDir doesn't
+ -- include it:
+ ("docx/_rels/.rels", $(embedFile "data/docx/_rels/.rels")) :
+ ("pptx/_rels/.rels", $(embedFile "data/pptx/_rels/.rels")) :
+ $(embedDir "data")
diff --git a/src/Text/Pandoc/Data.hsb b/src/Text/Pandoc/Data.hsb
deleted file mode 100644
index 8786647c5..000000000
--- a/src/Text/Pandoc/Data.hsb
+++ /dev/null
@@ -1,15 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
--- to be processed using hsb2hs
-module Text.Pandoc.Data (dataFiles) where
-import qualified Data.ByteString as B
-import System.FilePath (splitDirectories)
-import qualified System.FilePath.Posix as Posix
-
--- We ensure that the data files are stored using Posix
--- path separators (/), even on Windows.
-dataFiles :: [(FilePath, B.ByteString)]
-dataFiles = map (\(fp, contents) ->
- (Posix.joinPath (splitDirectories fp), contents)) dataFiles'
-
-dataFiles' :: [(FilePath, B.ByteString)]
-dataFiles' = ("MANUAL.txt", %blob "MANUAL.txt") : %blobs "data"
diff --git a/src/Text/Pandoc/Emoji.hs b/src/Text/Pandoc/Emoji.hs
index c9f368abc..3766960ea 100644
--- a/src/Text/Pandoc/Emoji.hs
+++ b/src/Text/Pandoc/Emoji.hs
@@ -903,4 +903,3 @@ emojis = M.fromList
,("zero","0\65039\8419")
,("zzz","\128164")
]
-
diff --git a/src/Text/Pandoc/Error.hs b/src/Text/Pandoc/Error.hs
index 5e26771fe..f78a31481 100644
--- a/src/Text/Pandoc/Error.hs
+++ b/src/Text/Pandoc/Error.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE DeriveDataTypeable, DeriveGeneric #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
Module : Text.Pandoc.Error
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,40 +30,94 @@ This module provides a standard way to deal with possible errors encounted
during parsing.
-}
-module Text.Pandoc.Error (PandocError(..), handleError) where
+module Text.Pandoc.Error (
+ PandocError(..),
+ handleError) where
+import Control.Exception (Exception)
+import Data.Typeable (Typeable)
+import GHC.Generics (Generic)
+import Network.HTTP.Client (HttpException)
+import System.Exit (ExitCode (..), exitWith)
+import System.IO (stderr)
+import qualified Text.Pandoc.UTF8 as UTF8
import Text.Parsec.Error
import Text.Parsec.Pos hiding (Line)
-import GHC.Generics (Generic)
-import Data.Generics (Typeable)
-import Control.Exception (Exception)
type Input = String
-data PandocError = -- | Generic parse failure
- ParseFailure String
- -- | Error thrown by a Parsec parser
- | ParsecError Input ParseError
+data PandocError = PandocIOError String IOError
+ | PandocHttpError String HttpException
+ | PandocShouldNeverHappenError String
+ | PandocSomeError String
+ | PandocParseError String
+ | PandocParsecError Input ParseError
+ | PandocMakePDFError String
+ | PandocOptionError String
+ | PandocSyntaxMapError String
+ | PandocFailOnWarningError
+ | PandocPDFProgramNotFoundError String
+ | PandocPDFError String
+ | PandocFilterError String String
+ | PandocCouldNotFindDataFileError String
+ | PandocResourceNotFound String
+ | PandocTemplateError String
+ | PandocAppError String
+ | PandocEpubSubdirectoryError String
+ | PandocMacroLoop String
deriving (Show, Typeable, Generic)
instance Exception PandocError
--- | An unsafe method to handle `PandocError`s.
-handleError :: Either PandocError a -> a
-handleError (Right r) = r
-handleError (Left err) =
- case err of
- ParseFailure string -> error string
- ParsecError input err' ->
+-- | Handle PandocError by exiting with an error message.
+handleError :: Either PandocError a -> IO a
+handleError (Right r) = return r
+handleError (Left e) =
+ case e of
+ PandocIOError _ err' -> ioError err'
+ PandocHttpError u err' -> err 61 $
+ "Could not fetch " ++ u ++ "\n" ++ show err'
+ PandocShouldNeverHappenError s -> err 62 s
+ PandocSomeError s -> err 63 s
+ PandocParseError s -> err 64 s
+ PandocParsecError input err' ->
let errPos = errorPos err'
errLine = sourceLine errPos
errColumn = sourceColumn errPos
ls = lines input ++ [""]
errorInFile = if length ls > errLine - 1
- then concat ["\n", (ls !! (errLine - 1))
+ then concat ["\n", ls !! (errLine - 1)
,"\n", replicate (errColumn - 1) ' '
,"^"]
else ""
- in error $ "\nError at " ++ show err'
- ++ errorInFile
+ in err 65 $ "\nError at " ++ show err' ++
+ -- if error comes from a chunk or included file,
+ -- then we won't get the right text this way:
+ if sourceName errPos == "source"
+ then errorInFile
+ else ""
+ PandocMakePDFError s -> err 65 s
+ PandocOptionError s -> err 2 s
+ PandocSyntaxMapError s -> err 67 s
+ PandocFailOnWarningError -> err 3 "Failing because there were warnings."
+ PandocPDFProgramNotFoundError pdfprog -> err 47 $
+ pdfprog ++ " not found. Please select a different --pdf-engine or install " ++ pdfprog
+ PandocPDFError logmsg -> err 43 $ "Error producing PDF.\n" ++ logmsg
+ PandocFilterError filtername msg -> err 83 $ "Error running filter " ++
+ filtername ++ ":\n" ++ msg
+ PandocCouldNotFindDataFileError fn -> err 97 $
+ "Could not find data file " ++ fn
+ PandocResourceNotFound fn -> err 99 $
+ "File " ++ fn ++ " not found in resource path"
+ PandocTemplateError s -> err 5 s
+ PandocAppError s -> err 1 s
+ PandocEpubSubdirectoryError s -> err 31 $
+ "EPUB subdirectory name '" ++ s ++ "' contains illegal characters"
+ PandocMacroLoop s -> err 91 $
+ "Loop encountered in expanding macro " ++ s
+err :: Int -> String -> IO a
+err exitCode msg = do
+ UTF8.hPutStrLn stderr msg
+ exitWith $ ExitFailure exitCode
+ return undefined
diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs
new file mode 100644
index 000000000..968476930
--- /dev/null
+++ b/src/Text/Pandoc/Extensions.hs
@@ -0,0 +1,378 @@
+{-
+Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+{- |
+ Module : Text.Pandoc.Extensions
+ Copyright : Copyright (C) 2012-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Data structures and functions for representing markup extensions.
+-}
+module Text.Pandoc.Extensions ( Extension(..)
+ , Extensions
+ , emptyExtensions
+ , extensionsFromList
+ , parseFormatSpec
+ , extensionEnabled
+ , enableExtension
+ , disableExtension
+ , getDefaultExtensions
+ , pandocExtensions
+ , plainExtensions
+ , strictExtensions
+ , phpMarkdownExtraExtensions
+ , githubMarkdownExtensions
+ , multimarkdownExtensions )
+where
+import Data.Aeson (FromJSON (..), ToJSON (..), defaultOptions)
+import Data.Aeson.TH (deriveJSON)
+import Data.Bits (clearBit, setBit, testBit, (.|.))
+import Data.Data (Data)
+import Data.Typeable (Typeable)
+import GHC.Generics (Generic)
+import Text.Pandoc.Shared (safeRead)
+import Text.Parsec
+
+newtype Extensions = Extensions Integer
+ deriving (Show, Read, Eq, Ord, Data, Typeable, Generic, ToJSON, FromJSON)
+
+instance Monoid Extensions where
+ mempty = Extensions 0
+ mappend (Extensions a) (Extensions b) = Extensions (a .|. b)
+
+extensionsFromList :: [Extension] -> Extensions
+extensionsFromList = foldr enableExtension emptyExtensions
+
+emptyExtensions :: Extensions
+emptyExtensions = Extensions 0
+
+extensionEnabled :: Extension -> Extensions -> Bool
+extensionEnabled x (Extensions exts) = testBit exts (fromEnum x)
+
+enableExtension :: Extension -> Extensions -> Extensions
+enableExtension x (Extensions exts) = Extensions (setBit exts (fromEnum x))
+
+disableExtension :: Extension -> Extensions -> Extensions
+disableExtension x (Extensions exts) = Extensions (clearBit exts (fromEnum x))
+
+-- | Individually selectable syntax extensions.
+data Extension =
+ Ext_abbreviations -- ^ PHP markdown extra abbreviation definitions
+ | Ext_all_symbols_escapable -- ^ Make all non-alphanumerics escapable
+ | Ext_amuse -- ^ Enable Text::Amuse extensions to Emacs Muse markup
+ | Ext_angle_brackets_escapable -- ^ Make < and > escapable
+ | Ext_ascii_identifiers -- ^ ascii-only identifiers for headers
+ | Ext_auto_identifiers -- ^ Automatic identifiers for headers
+ | Ext_autolink_bare_uris -- ^ Make all absolute URIs into links
+ | Ext_backtick_code_blocks -- ^ GitHub style ``` code blocks
+ | Ext_blank_before_blockquote -- ^ Require blank line before a blockquote
+ | Ext_blank_before_header -- ^ Require blank line before a header
+ | Ext_bracketed_spans -- ^ Bracketed spans with attributes
+ | Ext_citations -- ^ Pandoc/citeproc citations
+ | Ext_compact_definition_lists -- ^ Definition lists without space between items,
+ -- and disallow laziness
+ | Ext_definition_lists -- ^ Definition lists as in pandoc, mmd, php
+ | Ext_east_asian_line_breaks -- ^ Newlines in paragraphs are ignored between
+ -- East Asian wide characters
+ | Ext_emoji -- ^ Support emoji like :smile:
+ | Ext_empty_paragraphs -- ^ Allow empty paragraphs
+ | Ext_epub_html_exts -- ^ Recognise the EPUB extended version of HTML
+ | Ext_escaped_line_breaks -- ^ Treat a backslash at EOL as linebreak
+ | Ext_example_lists -- ^ Markdown-style numbered examples
+ | Ext_fancy_lists -- ^ Enable fancy list numbers and delimiters
+ | Ext_fenced_code_attributes -- ^ Allow attributes on fenced code blocks
+ | Ext_fenced_code_blocks -- ^ Parse fenced code blocks
+ | Ext_fenced_divs -- ^ Allow fenced div syntax :::
+ | Ext_footnotes -- ^ Pandoc/PHP/MMD style footnotes
+ | Ext_four_space_rule -- ^ Require 4-space indent for list contents
+ | Ext_gfm_auto_identifiers -- ^ Automatic identifiers for headers, using
+ -- GitHub's method for generating identifiers
+ | Ext_grid_tables -- ^ Grid tables (pandoc, reST)
+ | Ext_hard_line_breaks -- ^ All newlines become hard line breaks
+ | Ext_header_attributes -- ^ Explicit header attributes {#id .class k=v}
+ | Ext_ignore_line_breaks -- ^ Newlines in paragraphs are ignored
+ | Ext_implicit_figures -- ^ A paragraph with just an image is a figure
+ | Ext_implicit_header_references -- ^ Implicit reference links for headers
+ | Ext_inline_code_attributes -- ^ Allow attributes on inline code
+ | Ext_inline_notes -- ^ Pandoc-style inline notes
+ | Ext_intraword_underscores -- ^ Treat underscore inside word as literal
+ | Ext_latex_macros -- ^ Parse LaTeX macro definitions (for math only)
+ | Ext_line_blocks -- ^ RST style line blocks
+ | Ext_link_attributes -- ^ link and image attributes
+ | Ext_lists_without_preceding_blankline -- ^ Allow lists without preceding blank
+ | Ext_literate_haskell -- ^ Enable literate Haskell conventions
+ | Ext_markdown_attribute -- ^ Interpret text inside HTML as markdown iff
+ -- container has attribute 'markdown'
+ | Ext_markdown_in_html_blocks -- ^ Interpret as markdown inside HTML blocks
+ | Ext_mmd_header_identifiers -- ^ Multimarkdown style header identifiers [myid]
+ | Ext_mmd_link_attributes -- ^ MMD style reference link attributes
+ | Ext_mmd_title_block -- ^ Multimarkdown metadata block
+ | Ext_multiline_tables -- ^ Pandoc-style multiline tables
+ | Ext_native_divs -- ^ Use Div blocks for contents of <div> tags
+ | Ext_native_spans -- ^ Use Span inlines for contents of <span>
+ | Ext_ntb -- ^ ConTeXt Natural Tables
+ | Ext_old_dashes -- ^ -- = em, - before number = en
+ | Ext_pandoc_title_block -- ^ Pandoc title block
+ | Ext_pipe_tables -- ^ Pipe tables (as in PHP markdown extra)
+ | Ext_raw_attribute -- ^ Allow explicit raw blocks/inlines
+ | Ext_raw_html -- ^ Allow raw HTML
+ | Ext_raw_tex -- ^ Allow raw TeX (other than math)
+ | Ext_shortcut_reference_links -- ^ Shortcut reference links
+ | Ext_simple_tables -- ^ Pandoc-style simple tables
+ | Ext_smart -- ^ "Smart" quotes, apostrophes, ellipses, dashes
+ | Ext_space_in_atx_header -- ^ Require space between # and header text
+ | Ext_spaced_reference_links -- ^ Allow space between two parts of ref link
+ | Ext_startnum -- ^ Make start number of ordered list significant
+ | Ext_strikeout -- ^ Strikeout using ~~this~~ syntax
+ | Ext_subscript -- ^ Subscript using ~this~ syntax
+ | Ext_superscript -- ^ Superscript using ^this^ syntax
+ | Ext_styles -- ^ Read styles that pandoc doesn't know
+ | Ext_table_captions -- ^ Pandoc-style table captions
+ | Ext_tex_math_dollars -- ^ TeX math between $..$ or $$..$$
+ | Ext_tex_math_double_backslash -- ^ TeX math btw \\(..\\) \\[..\\]
+ | Ext_tex_math_single_backslash -- ^ TeX math btw \(..\) \[..\]
+ | Ext_yaml_metadata_block -- ^ YAML metadata block
+ deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic)
+
+-- | Extensions to be used with pandoc-flavored markdown.
+pandocExtensions :: Extensions
+pandocExtensions = extensionsFromList
+ [ Ext_footnotes
+ , Ext_inline_notes
+ , Ext_pandoc_title_block
+ , Ext_yaml_metadata_block
+ , Ext_table_captions
+ , Ext_implicit_figures
+ , Ext_simple_tables
+ , Ext_multiline_tables
+ , Ext_grid_tables
+ , Ext_pipe_tables
+ , Ext_citations
+ , Ext_raw_tex
+ , Ext_raw_html
+ , Ext_tex_math_dollars
+ , Ext_latex_macros
+ , Ext_fenced_code_blocks
+ , Ext_fenced_code_attributes
+ , Ext_backtick_code_blocks
+ , Ext_inline_code_attributes
+ , Ext_raw_attribute
+ , Ext_markdown_in_html_blocks
+ , Ext_native_divs
+ , Ext_fenced_divs
+ , Ext_native_spans
+ , Ext_bracketed_spans
+ , Ext_escaped_line_breaks
+ , Ext_fancy_lists
+ , Ext_startnum
+ , Ext_definition_lists
+ , Ext_example_lists
+ , Ext_all_symbols_escapable
+ , Ext_intraword_underscores
+ , Ext_blank_before_blockquote
+ , Ext_blank_before_header
+ , Ext_space_in_atx_header
+ , Ext_strikeout
+ , Ext_superscript
+ , Ext_subscript
+ , Ext_auto_identifiers
+ , Ext_header_attributes
+ , Ext_link_attributes
+ , Ext_implicit_header_references
+ , Ext_line_blocks
+ , Ext_shortcut_reference_links
+ , Ext_smart
+ ]
+
+-- | Extensions to be used with plain text output.
+plainExtensions :: Extensions
+plainExtensions = extensionsFromList
+ [ Ext_table_captions
+ , Ext_implicit_figures
+ , Ext_simple_tables
+ , Ext_multiline_tables
+ , Ext_grid_tables
+ , Ext_latex_macros
+ , Ext_fancy_lists
+ , Ext_startnum
+ , Ext_definition_lists
+ , Ext_example_lists
+ , Ext_intraword_underscores
+ , Ext_blank_before_blockquote
+ , Ext_blank_before_header
+ , Ext_strikeout
+ ]
+
+-- | Extensions to be used with github-flavored markdown.
+phpMarkdownExtraExtensions :: Extensions
+phpMarkdownExtraExtensions = extensionsFromList
+ [ Ext_footnotes
+ , Ext_pipe_tables
+ , Ext_raw_html
+ , Ext_markdown_attribute
+ , Ext_fenced_code_blocks
+ , Ext_definition_lists
+ , Ext_intraword_underscores
+ , Ext_header_attributes
+ , Ext_link_attributes
+ , Ext_abbreviations
+ , Ext_shortcut_reference_links
+ , Ext_spaced_reference_links
+ ]
+
+-- | Extensions to be used with github-flavored markdown.
+githubMarkdownExtensions :: Extensions
+githubMarkdownExtensions = extensionsFromList
+ [ Ext_angle_brackets_escapable
+ , Ext_pipe_tables
+ , Ext_raw_html
+ , Ext_fenced_code_blocks
+ , Ext_gfm_auto_identifiers
+ , Ext_ascii_identifiers
+ , Ext_backtick_code_blocks
+ , Ext_autolink_bare_uris
+ , Ext_space_in_atx_header
+ , Ext_intraword_underscores
+ , Ext_strikeout
+ , Ext_emoji
+ , Ext_lists_without_preceding_blankline
+ , Ext_shortcut_reference_links
+ ]
+
+-- | Extensions to be used with multimarkdown.
+multimarkdownExtensions :: Extensions
+multimarkdownExtensions = extensionsFromList
+ [ Ext_pipe_tables
+ , Ext_raw_html
+ , Ext_markdown_attribute
+ , Ext_mmd_link_attributes
+ -- , Ext_raw_tex
+ -- Note: MMD's raw TeX syntax requires raw TeX to be
+ -- enclosed in HTML comment
+ , Ext_tex_math_double_backslash
+ , Ext_intraword_underscores
+ , Ext_mmd_title_block
+ , Ext_footnotes
+ , Ext_definition_lists
+ , Ext_all_symbols_escapable
+ , Ext_implicit_header_references
+ , Ext_shortcut_reference_links
+ , Ext_auto_identifiers
+ , Ext_mmd_header_identifiers
+ , Ext_implicit_figures
+ -- Note: MMD's syntax for superscripts and subscripts
+ -- is a bit more permissive than pandoc's, allowing
+ -- e^2 and a~1 instead of e^2^ and a~1~, so even with
+ -- these options we don't have full support for MMD
+ -- superscripts and subscripts, but there's no reason
+ -- not to include these:
+ , Ext_superscript
+ , Ext_subscript
+ , Ext_backtick_code_blocks
+ , Ext_spaced_reference_links
+ -- So far only in dev version of mmd:
+ , Ext_raw_attribute
+ ]
+
+-- | Language extensions to be used with strict markdown.
+strictExtensions :: Extensions
+strictExtensions = extensionsFromList
+ [ Ext_raw_html
+ , Ext_shortcut_reference_links
+ , Ext_spaced_reference_links
+ ]
+
+-- | Default extensions from format-describing string.
+getDefaultExtensions :: String -> Extensions
+getDefaultExtensions "markdown_strict" = strictExtensions
+getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
+getDefaultExtensions "markdown_mmd" = multimarkdownExtensions
+getDefaultExtensions "markdown_github" = githubMarkdownExtensions
+getDefaultExtensions "markdown" = pandocExtensions
+getDefaultExtensions "muse" = extensionsFromList
+ [Ext_amuse,
+ Ext_auto_identifiers]
+getDefaultExtensions "plain" = plainExtensions
+getDefaultExtensions "gfm" = githubMarkdownExtensions
+getDefaultExtensions "commonmark" = extensionsFromList
+ [Ext_raw_html]
+getDefaultExtensions "org" = extensionsFromList
+ [Ext_citations,
+ Ext_auto_identifiers]
+getDefaultExtensions "html" = extensionsFromList
+ [Ext_auto_identifiers,
+ Ext_native_divs,
+ Ext_line_blocks,
+ Ext_native_spans]
+getDefaultExtensions "html4" = getDefaultExtensions "html"
+getDefaultExtensions "html5" = getDefaultExtensions "html"
+getDefaultExtensions "epub" = extensionsFromList
+ [Ext_raw_html,
+ Ext_native_divs,
+ Ext_native_spans,
+ Ext_epub_html_exts]
+getDefaultExtensions "epub2" = getDefaultExtensions "epub"
+getDefaultExtensions "epub3" = getDefaultExtensions "epub"
+getDefaultExtensions "latex" = extensionsFromList
+ [Ext_smart,
+ Ext_latex_macros,
+ Ext_auto_identifiers]
+getDefaultExtensions "context" = extensionsFromList
+ [Ext_smart,
+ Ext_auto_identifiers]
+getDefaultExtensions "textile" = extensionsFromList
+ [Ext_old_dashes,
+ Ext_smart,
+ Ext_raw_html,
+ Ext_auto_identifiers]
+getDefaultExtensions "opml" = pandocExtensions -- affects notes
+getDefaultExtensions _ = extensionsFromList
+ [Ext_auto_identifiers]
+
+-- | Parse a format-specifying string into a markup format and a function that
+-- takes Extensions and enables and disables extensions as defined in the format
+-- spec.
+parseFormatSpec :: String
+ -> Either ParseError (String, Extensions -> Extensions)
+parseFormatSpec = parse formatSpec ""
+ where formatSpec = do
+ name <- formatName
+ extMods <- many extMod
+ return (name, \x -> foldl (flip ($)) x extMods)
+ formatName = many1 $ noneOf "-+"
+ extMod = do
+ polarity <- oneOf "-+"
+ name <- many $ noneOf "-+"
+ ext <- case safeRead ("Ext_" ++ name) of
+ Just n -> return n
+ Nothing
+ | name == "lhs" -> return Ext_literate_haskell
+ | otherwise -> fail $ "Unknown extension: " ++ name
+ return $ case polarity of
+ '-' -> disableExtension ext
+ _ -> enableExtension ext
+
+$(deriveJSON defaultOptions ''Extension)
diff --git a/src/Text/Pandoc/Filter.hs b/src/Text/Pandoc/Filter.hs
new file mode 100644
index 000000000..e2a3c3e16
--- /dev/null
+++ b/src/Text/Pandoc/Filter.hs
@@ -0,0 +1,60 @@
+{-
+Copyright (C) 2006-2017 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{-# LANGUAGE TemplateHaskell #-}
+
+{- |
+ Module : Text.Pandoc.Filter
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley@edu>
+ Stability : alpha
+ Portability : portable
+
+Programmatically modifications of pandoc documents.
+-}
+module Text.Pandoc.Filter
+ ( Filter (..)
+ , applyFilters
+ ) where
+
+import Data.Aeson (defaultOptions)
+import Data.Aeson.TH (deriveJSON)
+import Data.Foldable (foldrM)
+import Text.Pandoc.Class (PandocIO)
+import Text.Pandoc.Definition (Pandoc)
+import Text.Pandoc.Options (ReaderOptions)
+import qualified Text.Pandoc.Filter.JSON as JSONFilter
+import qualified Text.Pandoc.Filter.Lua as LuaFilter
+
+data Filter = LuaFilter FilePath
+ | JSONFilter FilePath
+ deriving (Show)
+
+applyFilters :: ReaderOptions
+ -> [Filter]
+ -> [String]
+ -> Pandoc
+ -> PandocIO Pandoc
+applyFilters ropts filters args d =
+ foldrM ($) d $ map applyFilter filters
+ where
+ applyFilter (JSONFilter f) = JSONFilter.apply ropts args f
+ applyFilter (LuaFilter f) = LuaFilter.apply ropts args f
+
+$(deriveJSON defaultOptions ''Filter)
diff --git a/src/Text/Pandoc/Filter/JSON.hs b/src/Text/Pandoc/Filter/JSON.hs
new file mode 100644
index 000000000..5772c2c41
--- /dev/null
+++ b/src/Text/Pandoc/Filter/JSON.hs
@@ -0,0 +1,97 @@
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Filter
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley@edu>
+ Stability : alpha
+ Portability : portable
+
+Programmatically modifications of pandoc documents via JSON filters.
+-}
+module Text.Pandoc.Filter.JSON (apply) where
+
+import Control.Monad (unless, when)
+import Control.Monad.Trans (MonadIO (liftIO))
+import Data.Aeson (eitherDecode', encode)
+import Data.Char (toLower)
+import Data.Maybe (isNothing)
+import System.Directory (executable, doesFileExist, findExecutable,
+ getPermissions)
+import System.Environment (getEnvironment)
+import System.Exit (ExitCode (..))
+import System.FilePath ((</>), takeExtension)
+import Text.Pandoc.Class (PandocIO)
+import Text.Pandoc.Error (PandocError (PandocFilterError))
+import Text.Pandoc.Definition (Pandoc)
+import Text.Pandoc.Filter.Path (expandFilterPath)
+import Text.Pandoc.Options (ReaderOptions)
+import Text.Pandoc.Process (pipeProcess)
+import Text.Pandoc.Shared (pandocVersion)
+import qualified Control.Exception as E
+import qualified Text.Pandoc.UTF8 as UTF8
+
+apply :: ReaderOptions
+ -> [String]
+ -> FilePath
+ -> Pandoc
+ -> PandocIO Pandoc
+apply ropts args f d = do
+ f' <- expandFilterPath f
+ liftIO $ externalFilter ropts f' args d
+
+externalFilter :: MonadIO m
+ => ReaderOptions -> FilePath -> [String] -> Pandoc -> m Pandoc
+externalFilter ropts f args' d = liftIO $ do
+ exists <- doesFileExist f
+ isExecutable <- if exists
+ then executable <$> getPermissions f
+ else return True
+ let (f', args'') = if exists
+ then case map toLower (takeExtension f) of
+ _ | isExecutable -> ("." </> f, args')
+ ".py" -> ("python", f:args')
+ ".hs" -> ("runhaskell", f:args')
+ ".pl" -> ("perl", f:args')
+ ".rb" -> ("ruby", f:args')
+ ".php" -> ("php", f:args')
+ ".js" -> ("node", f:args')
+ ".r" -> ("Rscript", f:args')
+ _ -> (f, args')
+ else (f, args')
+ unless (exists && isExecutable) $ do
+ mbExe <- findExecutable f'
+ when (isNothing mbExe) $
+ E.throwIO $ PandocFilterError f ("Could not find executable " ++ f')
+ env <- getEnvironment
+ let env' = Just
+ ( ("PANDOC_VERSION", pandocVersion)
+ : ("PANDOC_READER_OPTIONS", UTF8.toStringLazy (encode ropts))
+ : env )
+ (exitcode, outbs) <- E.handle filterException $
+ pipeProcess env' f' args'' $ encode d
+ case exitcode of
+ ExitSuccess -> either (E.throwIO . PandocFilterError f)
+ return $ eitherDecode' outbs
+ ExitFailure ec -> E.throwIO $ PandocFilterError f
+ ("Filter returned error status " ++ show ec)
+ where filterException :: E.SomeException -> IO a
+ filterException e = E.throwIO $ PandocFilterError f (show e)
diff --git a/src/Text/Pandoc/Filter/Lua.hs b/src/Text/Pandoc/Filter/Lua.hs
new file mode 100644
index 000000000..597a31cbc
--- /dev/null
+++ b/src/Text/Pandoc/Filter/Lua.hs
@@ -0,0 +1,53 @@
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Filter.Lua
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley@edu>
+ Stability : alpha
+ Portability : portable
+
+Apply Lua filters to modify a pandoc documents programmatically.
+-}
+module Text.Pandoc.Filter.Lua (apply) where
+
+import Control.Exception (throw)
+import Text.Pandoc.Class (PandocIO)
+import Text.Pandoc.Definition (Pandoc)
+import Text.Pandoc.Error (PandocError (PandocFilterError))
+import Text.Pandoc.Filter.Path (expandFilterPath)
+import Text.Pandoc.Lua (LuaException (..), runLuaFilter)
+import Text.Pandoc.Options (ReaderOptions)
+
+apply :: ReaderOptions
+ -> [String]
+ -> FilePath
+ -> Pandoc
+ -> PandocIO Pandoc
+apply ropts args f d = do
+ f' <- expandFilterPath f
+ let format = case args of
+ (x:_) -> x
+ _ -> error "Format not supplied for lua filter"
+ res <- runLuaFilter ropts f' format d
+ case res of
+ Right x -> return x
+ Left (LuaException s) -> throw (PandocFilterError f s)
diff --git a/src/Text/Pandoc/Filter/Path.hs b/src/Text/Pandoc/Filter/Path.hs
new file mode 100644
index 000000000..8074bcbb7
--- /dev/null
+++ b/src/Text/Pandoc/Filter/Path.hs
@@ -0,0 +1,53 @@
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Filter.Path
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley@edu>
+ Stability : alpha
+ Portability : portable
+
+Expand paths of filters, searching the data directory.
+-}
+module Text.Pandoc.Filter.Path
+ ( expandFilterPath
+ ) where
+
+import Text.Pandoc.Class (PandocMonad, fileExists, getUserDataDir)
+import System.FilePath ((</>), isRelative)
+
+ -- First we check to see if a filter is found. If not, and if it's
+ -- not an absolute path, we check to see whether it's in `userdir/filters`.
+ -- If not, we leave it unchanged.
+expandFilterPath :: PandocMonad m => FilePath -> m FilePath
+expandFilterPath fp = do
+ mbDatadir <- getUserDataDir
+ fpExists <- fileExists fp
+ if fpExists
+ then return fp
+ else case mbDatadir of
+ Just datadir | isRelative fp -> do
+ let filterPath = datadir </> "filters" </> fp
+ filterPathExists <- fileExists filterPath
+ if filterPathExists
+ then return filterPath
+ else return fp
+ _ -> return fp
diff --git a/src/Text/Pandoc/Highlighting.hs b/src/Text/Pandoc/Highlighting.hs
index 896682389..113727750 100644
--- a/src/Text/Pandoc/Highlighting.hs
+++ b/src/Text/Pandoc/Highlighting.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Highlighting
- Copyright : Copyright (C) 2008-2016 John MacFarlane
+ Copyright : Copyright (C) 2008-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -28,7 +28,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Exports functions for syntax highlighting.
-}
-module Text.Pandoc.Highlighting ( languages
+module Text.Pandoc.Highlighting ( highlightingStyles
+ , languages
, languagesByExtension
, highlight
, formatLaTeXInline
@@ -48,14 +49,25 @@ module Text.Pandoc.Highlighting ( languages
, fromListingsLanguage
, toListingsLanguage
) where
-import Text.Pandoc.Definition
-import Text.Pandoc.Shared (safeRead)
-import Skylighting
-import Data.Maybe (fromMaybe)
+import Control.Monad
import Data.Char (toLower)
import qualified Data.Map as M
-import Control.Monad
+import Data.Maybe (fromMaybe)
import qualified Data.Text as T
+import Skylighting
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared (safeRead)
+
+highlightingStyles :: [(String, Style)]
+highlightingStyles =
+ [("pygments", pygments),
+ ("tango", tango),
+ ("espresso", espresso),
+ ("zenburn", zenburn),
+ ("kate", kate),
+ ("monochrome", monochrome),
+ ("breezedark", breezeDark),
+ ("haddock", haddock)]
languages :: [String]
languages = [T.unpack (T.toLower (sName s)) | s <- M.elems defaultSyntaxMap]
@@ -64,34 +76,39 @@ languagesByExtension :: String -> [String]
languagesByExtension ext =
[T.unpack (T.toLower (sName s)) | s <- syntaxesByExtension defaultSyntaxMap ext]
-highlight :: (FormatOptions -> [SourceLine] -> a) -- ^ Formatter
+highlight :: SyntaxMap
+ -> (FormatOptions -> [SourceLine] -> a) -- ^ Formatter
-> Attr -- ^ Attributes of the CodeBlock
-> String -- ^ Raw contents of the CodeBlock
- -> Maybe a -- ^ Maybe the formatted result
-highlight formatter (_, classes, keyvals) rawCode =
+ -> Either String a
+highlight syntaxmap formatter (ident, classes, keyvals) rawCode =
let firstNum = fromMaybe 1 (safeRead (fromMaybe "1" $ lookup "startFrom" keyvals))
fmtOpts = defaultFormatOpts{
startNumber = firstNum,
+ lineAnchors = any (`elem`
+ ["line-anchors", "lineAnchors"]) classes,
numberLines = any (`elem`
- ["number","numberLines", "number-lines"]) classes }
- tokenizeOpts = TokenizerConfig{ syntaxMap = defaultSyntaxMap
+ ["number","numberLines", "number-lines"]) classes,
+ lineIdPrefix = if null ident
+ then mempty
+ else T.pack (ident ++ "-") }
+ tokenizeOpts = TokenizerConfig{ syntaxMap = syntaxmap
, traceOutput = False }
classes' = map T.pack classes
rawCode' = T.pack rawCode
- in case msum (map (\l -> lookupSyntax l defaultSyntaxMap) classes') of
+ in case msum (map (`lookupSyntax` syntaxmap) classes') of
Nothing
- | numberLines fmtOpts -> Just
+ | numberLines fmtOpts -> Right
$ formatter fmtOpts{ codeClasses = [],
containerClasses = classes' }
- $ map (\ln -> [(NormalTok, ln)]) $ T.lines rawCode'
- | otherwise -> Nothing
+ $ map (\ln -> [(NormalTok, ln)])
+ $ T.lines rawCode'
+ | otherwise -> Left ""
Just syntax ->
- case tokenize tokenizeOpts syntax rawCode' of
- Right slines -> Just $
- formatter fmtOpts{ codeClasses =
- [T.toLower (sShortname syntax)],
- containerClasses = classes' } slines
- Left _ -> Nothing
+ formatter fmtOpts{ codeClasses =
+ [T.toLower (sShortname syntax)],
+ containerClasses = classes' } <$>
+ tokenize tokenizeOpts syntax rawCode'
-- Functions for correlating latex listings package's language names
-- with skylighting language names:
diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs
index e46c91eda..4c76aac13 100644
--- a/src/Text/Pandoc/ImageSize.hs
+++ b/src/Text/Pandoc/ImageSize.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, CPP #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-
- Copyright (C) 2011-2016 John MacFarlane <jgm@berkeley.edu>
+ Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
{- |
Module : Text.Pandoc.ImageSize
-Copyright : Copyright (C) 2011-2016 John MacFarlane
+Copyright : Copyright (C) 2011-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -38,8 +38,12 @@ module Text.Pandoc.ImageSize ( ImageType(..)
, Dimension(..)
, Direction(..)
, dimension
+ , lengthToDim
+ , scaleDimension
, inInch
+ , inPixel
, inPoints
+ , inEm
, numUnit
, showInInch
, showInPixel
@@ -53,11 +57,13 @@ import Control.Monad
import Data.Bits
import Data.Binary
import Data.Binary.Get
-import Text.Pandoc.Shared (safeRead, hush)
+import Text.Pandoc.Shared (safeRead)
import Data.Default (Default)
import Numeric (showFFloat)
import Text.Pandoc.Definition
import Text.Pandoc.Options
+import qualified Text.Pandoc.UTF8 as UTF8
+import qualified Text.XML.Light as Xml
import qualified Data.Map as M
import Control.Monad.Except
import Data.Maybe (fromMaybe)
@@ -65,7 +71,7 @@ import Data.Maybe (fromMaybe)
-- quick and dirty functions to get image sizes
-- algorithms borrowed from wwwis.pl
-data ImageType = Png | Gif | Jpeg | Pdf | Eps deriving Show
+data ImageType = Png | Gif | Jpeg | Svg | Pdf | Eps | Emf deriving Show
data Direction = Width | Height
instance Show Direction where
show Width = "width"
@@ -73,13 +79,19 @@ instance Show Direction where
data Dimension = Pixel Integer
| Centimeter Double
+ | Millimeter Double
| Inch Double
| Percent Double
+ | Em Double
+ deriving Eq
+
instance Show Dimension where
show (Pixel a) = show a ++ "px"
show (Centimeter a) = showFl a ++ "cm"
+ show (Millimeter a) = showFl a ++ "mm"
show (Inch a) = showFl a ++ "in"
show (Percent a) = show a ++ "%"
+ show (Em a) = showFl a ++ "em"
data ImageSize = ImageSize{
pxX :: Integer
@@ -91,7 +103,13 @@ instance Default ImageSize where
def = ImageSize 300 200 72 72
showFl :: (RealFloat a) => a -> String
-showFl a = showFFloat (Just 5) a ""
+showFl a = removeExtra0s $ showFFloat (Just 5) a ""
+
+removeExtra0s :: String -> String
+removeExtra0s s =
+ case dropWhile (=='0') $ reverse s of
+ '.':xs -> reverse xs
+ xs -> reverse xs
imageType :: ByteString -> Maybe ImageType
imageType img = case B.take 4 img of
@@ -100,19 +118,31 @@ imageType img = case B.take 4 img of
"\xff\xd8\xff\xe0" -> return Jpeg -- JFIF
"\xff\xd8\xff\xe1" -> return Jpeg -- Exif
"%PDF" -> return Pdf
+ "<svg" -> return Svg
+ "<?xm"
+ | findSvgTag img
+ -> return Svg
"%!PS"
- | (B.take 4 $ B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
+ | B.take 4 (B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
-> return Eps
+ "\x01\x00\x00\x00"
+ | B.take 4 (B.drop 40 img) == " EMF"
+ -> return Emf
_ -> mzero
-imageSize :: ByteString -> Either String ImageSize
-imageSize img =
+findSvgTag :: ByteString -> Bool
+findSvgTag img = "<svg" `B.isInfixOf` img || "<SVG" `B.isInfixOf` img
+
+imageSize :: WriterOptions -> ByteString -> Either String ImageSize
+imageSize opts img =
case imageType img of
Just Png -> mbToEither "could not determine PNG size" $ pngSize img
Just Gif -> mbToEither "could not determine GIF size" $ gifSize img
Just Jpeg -> jpegSize img
+ Just Svg -> mbToEither "could not determine SVG size" $ svgSize opts img
Just Eps -> mbToEither "could not determine EPS size" $ epsSize img
- Just Pdf -> Left "could not determine PDF size" -- TODO
+ Just Pdf -> mbToEither "could not determine PDF size" $ pdfSize img
+ Just Emf -> mbToEither "could not determine EMF size" $ emfSize img
Nothing -> Left "could not determine image type"
where mbToEither msg Nothing = Left msg
mbToEither _ (Just x) = Right x
@@ -145,7 +175,7 @@ desiredSizeInPoints opts attr s =
(Nothing, Nothing) -> sizeInPoints s
where
ratio = fromIntegral (pxX s) / fromIntegral (pxY s)
- getDim dir = case (dimension dir attr) of
+ getDim dir = case dimension dir attr of
Just (Percent _) -> Nothing
Just dim -> Just $ inPoints opts dim
Nothing -> Nothing
@@ -153,13 +183,30 @@ desiredSizeInPoints opts attr s =
inPoints :: WriterOptions -> Dimension -> Double
inPoints opts dim = 72 * inInch opts dim
+inEm :: WriterOptions -> Dimension -> Double
+inEm opts dim = (64/11) * inInch opts dim
+
inInch :: WriterOptions -> Dimension -> Double
inInch opts dim =
case dim of
- (Pixel a) -> fromIntegral a / (fromIntegral $ writerDpi opts)
+ (Pixel a) -> fromIntegral a / fromIntegral (writerDpi opts)
(Centimeter a) -> a * 0.3937007874
+ (Millimeter a) -> a * 0.03937007874
(Inch a) -> a
(Percent _) -> 0
+ (Em a) -> a * (11/64)
+
+inPixel :: WriterOptions -> Dimension -> Integer
+inPixel opts dim =
+ case dim of
+ (Pixel a) -> a
+ (Centimeter a) -> floor $ dpi * a * 0.3937007874 :: Integer
+ (Millimeter a) -> floor $ dpi * a * 0.03937007874 :: Integer
+ (Inch a) -> floor $ dpi * a :: Integer
+ (Percent _) -> 0
+ (Em a) -> floor $ dpi * a * (11/64) :: Integer
+ where
+ dpi = fromIntegral $ writerDpi opts
-- | Convert a Dimension to a String denoting its equivalent in inches, for example "2.00000".
-- Note: Dimensions in percentages are converted to the empty string.
@@ -170,14 +217,8 @@ showInInch opts dim = showFl $ inInch opts dim
-- | Convert a Dimension to a String denoting its equivalent in pixels, for example "600".
-- Note: Dimensions in percentages are converted to the empty string.
showInPixel :: WriterOptions -> Dimension -> String
-showInPixel opts dim =
- case dim of
- (Pixel a) -> show a
- (Centimeter a) -> show (floor $ dpi * a * 0.3937007874 :: Int)
- (Inch a) -> show (floor $ dpi * a :: Int)
- (Percent _) -> ""
- where
- dpi = fromIntegral $ writerDpi opts
+showInPixel _ (Percent _) = ""
+showInPixel opts dim = show $ inPixel opts dim
-- | Maybe split a string into a leading number and trailing unit, e.g. "3cm" to Just (3.0, "cm")
numUnit :: String -> Maybe (Double, String)
@@ -187,6 +228,17 @@ numUnit s =
Just n -> Just (n, unit)
Nothing -> Nothing
+-- | Scale a dimension by a factor.
+scaleDimension :: Double -> Dimension -> Dimension
+scaleDimension factor dim =
+ case dim of
+ Pixel x -> Pixel (round $ factor * fromIntegral x)
+ Centimeter x -> Centimeter (factor * x)
+ Millimeter x -> Millimeter (factor * x)
+ Inch x -> Inch (factor * x)
+ Percent x -> Percent (factor * x)
+ Em x -> Em (factor * x)
+
-- | Read a Dimension from an Attr attribute.
-- `dimension Width attr` might return `Just (Pixel 3)` or for example `Just (Centimeter 2.0)`, etc.
dimension :: Direction -> Attr -> Maybe Dimension
@@ -195,20 +247,21 @@ dimension dir (_, _, kvs) =
Width -> extractDim "width"
Height -> extractDim "height"
where
- extractDim key =
- case lookup key kvs of
- Just str ->
- case numUnit str of
- Just (num, unit) -> toDim num unit
- Nothing -> Nothing
- Nothing -> Nothing
+ extractDim key = lookup key kvs >>= lengthToDim
+
+lengthToDim :: String -> Maybe Dimension
+lengthToDim s = numUnit s >>= uncurry toDim
+ where
toDim a "cm" = Just $ Centimeter a
- toDim a "mm" = Just $ Centimeter (a / 10)
+ toDim a "mm" = Just $ Millimeter a
toDim a "in" = Just $ Inch a
toDim a "inch" = Just $ Inch a
toDim a "%" = Just $ Percent a
toDim a "px" = Just $ Pixel (floor a::Integer)
toDim a "" = Just $ Pixel (floor a::Integer)
+ toDim a "pt" = Just $ Inch (a / 72)
+ toDim a "pc" = Just $ Inch (a / 6)
+ toDim a "em" = Just $ Em a
toDim _ _ = Nothing
epsSize :: ByteString -> Maybe ImageSize
@@ -218,7 +271,7 @@ epsSize img = do
case ls' of
[] -> mzero
(x:_) -> case B.words x of
- (_:_:_:ux:uy:[]) -> do
+ [_, _, _, ux, uy] -> do
ux' <- safeRead $ B.unpack ux
uy' <- safeRead $ B.unpack uy
return ImageSize{
@@ -228,6 +281,29 @@ epsSize img = do
, dpiY = 72 }
_ -> mzero
+pdfSize :: ByteString -> Maybe ImageSize
+pdfSize img =
+ case dropWhile (\l -> not (l == "stream" ||
+ "/MediaBox" `B.isPrefixOf` l)) (B.lines img) of
+ (x:_)
+ | "/MediaBox" `B.isPrefixOf` x
+ -> case B.words . B.takeWhile (/=']')
+ . B.drop 1
+ . B.dropWhile (/='[')
+ $ x of
+ [x1, y1, x2, y2] -> do
+ x1' <- safeRead $ B.unpack x1
+ x2' <- safeRead $ B.unpack x2
+ y1' <- safeRead $ B.unpack y1
+ y2' <- safeRead $ B.unpack y2
+ return ImageSize{
+ pxX = x2' - x1'
+ , pxY = y2' - y1'
+ , dpiX = 72
+ , dpiY = 72 }
+ _ -> mzero
+ _ -> mzero
+
pngSize :: ByteString -> Maybe ImageSize
pngSize img = do
let (h, rest) = B.splitAt 8 img
@@ -236,27 +312,26 @@ pngSize img = do
let (i, rest') = B.splitAt 4 $ B.drop 4 rest
guard $ i == "MHDR" || i == "IHDR"
let (sizes, rest'') = B.splitAt 8 rest'
- (x,y) <- case map fromIntegral $ unpack $ sizes of
+ (x,y) <- case map fromIntegral $unpack sizes of
([w1,w2,w3,w4,h1,h2,h3,h4] :: [Integer]) -> return
- ((shift w1 24) + (shift w2 16) + (shift w3 8) + w4,
- (shift h1 24) + (shift h2 16) + (shift h3 8) + h4)
- _ -> (hush . Left) "PNG parse error"
+ (shift w1 24 + shift w2 16 + shift w3 8 + w4,
+ shift h1 24 + shift h2 16 + shift h3 8 + h4)
+ _ -> Nothing -- "PNG parse error"
let (dpix, dpiy) = findpHYs rest''
- return $ ImageSize { pxX = x, pxY = y, dpiX = dpix, dpiY = dpiy }
+ return ImageSize { pxX = x, pxY = y, dpiX = dpix, dpiY = dpiy }
findpHYs :: ByteString -> (Integer, Integer)
-findpHYs x =
- if B.null x || "IDAT" `B.isPrefixOf` x
- then (72,72) -- default, no pHYs
- else if "pHYs" `B.isPrefixOf` x
- then let [x1,x2,x3,x4,y1,y2,y3,y4,u] = map fromIntegral
- $ unpack $ B.take 9 $ B.drop 4 x
- factor = if u == 1 -- dots per meter
- then \z -> z * 254 `div` 10000
- else const 72
- in ( factor $ (shift x1 24) + (shift x2 16) + (shift x3 8) + x4,
- factor $ (shift y1 24) + (shift y2 16) + (shift y3 8) + y4 )
- else findpHYs $ B.drop 1 x -- read another byte
+findpHYs x
+ | B.null x || "IDAT" `B.isPrefixOf` x = (72,72)
+ | "pHYs" `B.isPrefixOf` x =
+ let [x1,x2,x3,x4,y1,y2,y3,y4,u] =
+ map fromIntegral $ unpack $ B.take 9 $ B.drop 4 x
+ factor = if u == 1 -- dots per meter
+ then \z -> z * 254 `div` 10000
+ else const 72
+ in ( factor $ shift x1 24 + shift x2 16 + shift x3 8 + x4,
+ factor $ shift y1 24 + shift y2 16 + shift y3 8 + y4 )
+ | otherwise = findpHYs $ B.drop 1 x -- read another byte
gifSize :: ByteString -> Maybe ImageSize
gifSize img = do
@@ -269,7 +344,55 @@ gifSize img = do
dpiX = 72,
dpiY = 72
}
- _ -> (hush . Left) "GIF parse error"
+ _ -> Nothing -- "GIF parse error"
+
+svgSize :: WriterOptions -> ByteString -> Maybe ImageSize
+svgSize opts img = do
+ doc <- Xml.parseXMLDoc $ UTF8.toString img
+ let dpi = fromIntegral $ writerDpi opts
+ let dirToInt dir = do
+ dim <- Xml.findAttrBy (== Xml.QName dir Nothing Nothing) doc >>= lengthToDim
+ return $ inPixel opts dim
+ w <- dirToInt "width"
+ h <- dirToInt "height"
+ return ImageSize {
+ pxX = w
+ , pxY = h
+ , dpiX = dpi
+ , dpiY = dpi
+ }
+
+emfSize :: ByteString -> Maybe ImageSize
+emfSize img =
+ let
+ parseheader = runGetOrFail $ do
+ skip 0x18 -- 0x00
+ frameL <- getWord32le -- 0x18 measured in 1/100 of a millimetre
+ frameT <- getWord32le -- 0x1C
+ frameR <- getWord32le -- 0x20
+ frameB <- getWord32le -- 0x24
+ skip 0x20 -- 0x28
+ deviceX <- getWord32le -- 0x48 pixels of reference device
+ deviceY <- getWord32le -- 0x4C
+ mmX <- getWord32le -- 0x50 real mm of reference device (always 320*240?)
+ mmY <- getWord32le -- 0x58
+ -- end of header
+ let
+ w = (deviceX * (frameR - frameL)) `quot` (mmX * 100)
+ h = (deviceY * (frameB - frameT)) `quot` (mmY * 100)
+ dpiW = (deviceX * 254) `quot` (mmX * 10)
+ dpiH = (deviceY * 254) `quot` (mmY * 10)
+ return $ ImageSize
+ { pxX = fromIntegral w
+ , pxY = fromIntegral h
+ , dpiX = fromIntegral dpiW
+ , dpiY = fromIntegral dpiH
+ }
+ in
+ case parseheader . BL.fromStrict $ img of
+ Left _ -> Nothing
+ Right (_, _, size) -> Just size
+
jpegSize :: ByteString -> Either String ImageSize
jpegSize img =
@@ -284,16 +407,16 @@ jpegSize img =
jfifSize :: ByteString -> Either String ImageSize
jfifSize rest =
let [dpiDensity,dpix1,dpix2,dpiy1,dpiy2] = map fromIntegral
- $ unpack $ B.take 5 $ B.drop 9 $ rest
+ $ unpack $ B.take 5 $B.drop 9 rest
factor = case dpiDensity of
1 -> id
- 2 -> \x -> (x * 254 `div` 10)
+ 2 -> \x -> x * 254 `div` 10
_ -> const 72
dpix = factor (shift dpix1 8 + dpix2)
dpiy = factor (shift dpiy1 8 + dpiy2)
in case findJfifSize rest of
Left msg -> Left msg
- Right (w,h) -> Right $ ImageSize { pxX = w
+ Right (w,h) ->Right ImageSize { pxX = w
, pxY = h
, dpiX = dpix
, dpiY = dpiy }
@@ -327,7 +450,7 @@ runGet' p bl =
exifSize :: ByteString -> Either String ImageSize
-exifSize bs = runGet' header $ bl
+exifSize bs =runGet' header bl
where bl = BL.fromChunks [bs]
header = runExceptT $ exifHeader bl
-- NOTE: It would be nicer to do
@@ -397,14 +520,13 @@ exifHeader hdr = do
Left msg -> throwError msg
Right x -> return x
return (tag, payload)
- entries <- sequence $ replicate (fromIntegral numentries) ifdEntry
+ entries <- replicateM (fromIntegral numentries) ifdEntry
subentries <- case lookup ExifOffset entries of
Just (UnsignedLong offset') -> do
pos <- lift bytesRead
lift $ skip (fromIntegral offset' - (fromIntegral pos - 8))
numsubentries <- lift getWord16
- sequence $
- replicate (fromIntegral numsubentries) ifdEntry
+ replicateM (fromIntegral numsubentries) ifdEntry
_ -> return []
let allentries = entries ++ subentries
(wdth, hght) <- case (lookup ExifImageWidth allentries,
@@ -415,13 +537,13 @@ exifHeader hdr = do
-- we return a default width and height when
-- the exif header doesn't contain these
let resfactor = case lookup ResolutionUnit allentries of
- Just (UnsignedShort 1) -> (100 / 254)
+ Just (UnsignedShort 1) -> 100 / 254
_ -> 1
let xres = maybe 72 (\(UnsignedRational x) -> floor $ x * resfactor)
$ lookup XResolution allentries
let yres = maybe 72 (\(UnsignedRational x) -> floor $ x * resfactor)
$ lookup YResolution allentries
- return $ ImageSize{
+ return ImageSize{
pxX = wdth
, pxY = hght
, dpiX = xres
diff --git a/src/Text/Pandoc/Logging.hs b/src/Text/Pandoc/Logging.hs
new file mode 100644
index 000000000..b22c08467
--- /dev/null
+++ b/src/Text/Pandoc/Logging.hs
@@ -0,0 +1,342 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-
+Copyright (C) 2016-17 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{- |
+ Module : Text.Pandoc.Logging
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+This module provides data types and functions for warnings
+and info messages.
+
+-}
+module Text.Pandoc.Logging (
+ Verbosity(..)
+ , LogMessage(..)
+ , encodeLogMessages
+ , showLogMessage
+ , messageVerbosity
+ ) where
+
+import Control.Monad (mzero)
+import Data.Aeson
+import Data.Aeson.Encode.Pretty (Config (..), defConfig, encodePretty',
+ keyOrder)
+import qualified Data.ByteString.Lazy as BL
+import Data.Data (Data, toConstr)
+import Data.List (isSuffixOf)
+import qualified Data.Text as Text
+import Data.Typeable (Typeable)
+import GHC.Generics (Generic)
+import Text.Pandoc.Definition
+import Text.Parsec.Pos
+
+-- | Verbosity level.
+data Verbosity = ERROR | WARNING | INFO
+ deriving (Show, Read, Eq, Data, Enum, Ord, Bounded, Typeable, Generic)
+
+instance ToJSON Verbosity where
+ toJSON x = toJSON (show x)
+instance FromJSON Verbosity where
+ parseJSON (String t) =
+ case t of
+ "ERROR" -> return ERROR
+ "WARNING" -> return WARNING
+ "INFO" -> return INFO
+ _ -> mzero
+ parseJSON _ = mzero
+
+data LogMessage =
+ SkippedContent String SourcePos
+ | CouldNotParseYamlMetadata String SourcePos
+ | DuplicateLinkReference String SourcePos
+ | DuplicateNoteReference String SourcePos
+ | NoteDefinedButNotUsed String SourcePos
+ | DuplicateIdentifier String SourcePos
+ | ReferenceNotFound String SourcePos
+ | CircularReference String SourcePos
+ | UndefinedToggle String SourcePos
+ | ParsingUnescaped String SourcePos
+ | CouldNotLoadIncludeFile String SourcePos
+ | MacroAlreadyDefined String SourcePos
+ | InlineNotRendered Inline
+ | BlockNotRendered Block
+ | DocxParserWarning String
+ | CouldNotFetchResource String String
+ | CouldNotDetermineImageSize String String
+ | CouldNotConvertImage String String
+ | CouldNotDetermineMimeType String
+ | CouldNotConvertTeXMath String String
+ | CouldNotParseCSS String
+ | Fetching String
+ | Extracting String
+ | NoTitleElement String
+ | NoLangSpecified
+ | InvalidLang String
+ | CouldNotHighlight String
+ | MissingCharacter String
+ | Deprecated String String
+ | NoTranslation String
+ | CouldNotLoadTranslations String String
+ deriving (Show, Eq, Data, Ord, Typeable, Generic)
+
+instance ToJSON LogMessage where
+ toJSON x = object $
+ "verbosity" .= toJSON (messageVerbosity x) :
+ "type" .= toJSON (show $ toConstr x) :
+ case x of
+ SkippedContent s pos ->
+ ["contents" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= sourceLine pos,
+ "column" .= sourceColumn pos]
+ CouldNotParseYamlMetadata s pos ->
+ ["message" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ DuplicateLinkReference s pos ->
+ ["contents" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ NoteDefinedButNotUsed s pos ->
+ ["key" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ DuplicateNoteReference s pos ->
+ ["contents" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ DuplicateIdentifier s pos ->
+ ["contents" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ ReferenceNotFound s pos ->
+ ["contents" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ CircularReference s pos ->
+ ["contents" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ UndefinedToggle s pos ->
+ ["contents" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ ParsingUnescaped s pos ->
+ ["contents" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ CouldNotLoadIncludeFile fp pos ->
+ ["path" .= Text.pack fp,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ MacroAlreadyDefined name pos ->
+ ["name" .= Text.pack name,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
+ InlineNotRendered il ->
+ ["contents" .= toJSON il]
+ BlockNotRendered bl ->
+ ["contents" .= toJSON bl]
+ DocxParserWarning s ->
+ ["contents" .= Text.pack s]
+ CouldNotFetchResource fp s ->
+ ["path" .= Text.pack fp,
+ "message" .= Text.pack s]
+ CouldNotDetermineImageSize fp s ->
+ ["path" .= Text.pack fp,
+ "message" .= Text.pack s]
+ CouldNotConvertImage fp s ->
+ ["path" .= Text.pack fp,
+ "message" .= Text.pack s]
+ CouldNotDetermineMimeType fp ->
+ ["path" .= Text.pack fp]
+ CouldNotConvertTeXMath s msg ->
+ ["contents" .= Text.pack s,
+ "message" .= Text.pack msg]
+ CouldNotParseCSS msg ->
+ ["message" .= Text.pack msg]
+ Fetching fp ->
+ ["path" .= Text.pack fp]
+ Extracting fp ->
+ ["path" .= Text.pack fp]
+ NoTitleElement fallback ->
+ ["fallback" .= Text.pack fallback]
+ NoLangSpecified -> []
+ InvalidLang s ->
+ ["lang" .= Text.pack s]
+ CouldNotHighlight msg ->
+ ["message" .= Text.pack msg]
+ MissingCharacter msg ->
+ ["message" .= Text.pack msg]
+ Deprecated thing msg ->
+ ["thing" .= Text.pack thing,
+ "message" .= Text.pack msg]
+ NoTranslation term ->
+ ["term" .= Text.pack term]
+ CouldNotLoadTranslations lang msg ->
+ ["lang" .= Text.pack lang,
+ "message" .= Text.pack msg]
+
+
+showPos :: SourcePos -> String
+showPos pos = sn ++ "line " ++
+ show (sourceLine pos) ++ " column " ++ show (sourceColumn pos)
+ where sn = if sourceName pos == "source" || sourceName pos == ""
+ then ""
+ else sourceName pos ++ " "
+
+encodeLogMessages :: [LogMessage] -> BL.ByteString
+encodeLogMessages ms =
+ encodePretty' defConfig{ confCompare =
+ keyOrder [ "type", "verbosity", "contents", "message", "path",
+ "source", "line", "column" ] } ms
+
+showLogMessage :: LogMessage -> String
+showLogMessage msg =
+ case msg of
+ SkippedContent s pos ->
+ "Skipped '" ++ s ++ "' at " ++ showPos pos
+ CouldNotParseYamlMetadata s pos ->
+ "Could not parse YAML metadata at " ++ showPos pos ++
+ if null s then "" else ": " ++ s
+ DuplicateLinkReference s pos ->
+ "Duplicate link reference '" ++ s ++ "' at " ++ showPos pos
+ DuplicateNoteReference s pos ->
+ "Duplicate note reference '" ++ s ++ "' at " ++ showPos pos
+ NoteDefinedButNotUsed s pos ->
+ "Note with key '" ++ s ++ "' defined at " ++ showPos pos ++
+ " but not used."
+ DuplicateIdentifier s pos ->
+ "Duplicate identifier '" ++ s ++ "' at " ++ showPos pos
+ ReferenceNotFound s pos ->
+ "Reference not found for '" ++ s ++ "' at " ++ showPos pos
+ CircularReference s pos ->
+ "Circular reference '" ++ s ++ "' at " ++ showPos pos
+ UndefinedToggle s pos ->
+ "Undefined toggle '" ++ s ++ "' at " ++ showPos pos
+ ParsingUnescaped s pos ->
+ "Parsing unescaped '" ++ s ++ "' at " ++ showPos pos
+ CouldNotLoadIncludeFile fp pos ->
+ "Could not load include file '" ++ fp ++ "' at " ++ showPos pos
+ MacroAlreadyDefined name pos ->
+ "Macro '" ++ name ++ "' already defined, ignoring at " ++ showPos pos
+ InlineNotRendered il ->
+ "Not rendering " ++ show il
+ BlockNotRendered bl ->
+ "Not rendering " ++ show bl
+ DocxParserWarning s ->
+ "Docx parser warning: " ++ s
+ CouldNotFetchResource fp s ->
+ "Could not fetch resource '" ++ fp ++ "'" ++
+ if null s then "" else ": " ++ s
+ CouldNotDetermineImageSize fp s ->
+ "Could not determine image size for '" ++ fp ++ "'" ++
+ if null s then "" else ": " ++ s
+ CouldNotConvertImage fp s ->
+ "Could not convert image '" ++ fp ++ "'" ++
+ if null s then "" else ": " ++ s
+ CouldNotDetermineMimeType fp ->
+ "Could not determine mime type for '" ++ fp ++ "'"
+ CouldNotConvertTeXMath s m ->
+ "Could not convert TeX math '" ++ s ++ "', rendering as TeX" ++
+ if null m then "" else ':' : '\n' : m
+ CouldNotParseCSS m ->
+ "Could not parse CSS" ++ if null m then "" else ':' : '\n' : m
+ Fetching fp ->
+ "Fetching " ++ fp ++ "..."
+ Extracting fp ->
+ "Extracting " ++ fp ++ "..."
+ NoTitleElement fallback ->
+ "This document format requires a nonempty <title> element.\n" ++
+ "Please specify either 'title' or 'pagetitle' in the metadata.\n" ++
+ "Falling back to '" ++ fallback ++ "'"
+ NoLangSpecified ->
+ "No value for 'lang' was specified in the metadata.\n" ++
+ "It is recommended that lang be specified for this format."
+ InvalidLang s ->
+ "Invalid 'lang' value '" ++ s ++ "'.\n" ++
+ "Use an IETF language tag like 'en-US'."
+ CouldNotHighlight m ->
+ "Could not highlight code block:\n" ++ m
+ MissingCharacter m ->
+ "Missing character: " ++ m
+ Deprecated t m ->
+ "Deprecated: " ++ t ++
+ if null m
+ then ""
+ else ". " ++ m
+ NoTranslation t ->
+ "The term " ++ t ++ " has no translation defined."
+ CouldNotLoadTranslations lang m ->
+ "Could not load translations for " ++ lang ++
+ if null m then "" else '\n' : m
+
+messageVerbosity:: LogMessage -> Verbosity
+messageVerbosity msg =
+ case msg of
+ SkippedContent{} -> INFO
+ CouldNotParseYamlMetadata{} -> WARNING
+ DuplicateLinkReference{} -> WARNING
+ DuplicateNoteReference{} -> WARNING
+ NoteDefinedButNotUsed{} -> WARNING
+ DuplicateIdentifier{} -> WARNING
+ ReferenceNotFound{} -> WARNING
+ CircularReference{} -> WARNING
+ UndefinedToggle{} -> WARNING
+ CouldNotLoadIncludeFile f _
+ | ".sty" `isSuffixOf` f -> INFO
+ | otherwise -> WARNING
+ MacroAlreadyDefined{} -> WARNING
+ ParsingUnescaped{} -> INFO
+ InlineNotRendered{} -> INFO
+ BlockNotRendered{} -> INFO
+ DocxParserWarning{} -> INFO
+ CouldNotFetchResource{} -> WARNING
+ CouldNotDetermineImageSize{} -> WARNING
+ CouldNotConvertImage{} -> WARNING
+ CouldNotDetermineMimeType{} -> WARNING
+ CouldNotConvertTeXMath{} -> WARNING
+ CouldNotParseCSS{} -> WARNING
+ Fetching{} -> INFO
+ Extracting{} -> INFO
+ NoTitleElement{} -> WARNING
+ NoLangSpecified -> INFO
+ InvalidLang{} -> WARNING
+ CouldNotHighlight{} -> WARNING
+ MissingCharacter{} -> WARNING
+ Deprecated{} -> WARNING
+ NoTranslation{} -> WARNING
+ CouldNotLoadTranslations{} -> WARNING
diff --git a/src/Text/Pandoc/Lua.hs b/src/Text/Pandoc/Lua.hs
new file mode 100644
index 000000000..79955509d
--- /dev/null
+++ b/src/Text/Pandoc/Lua.hs
@@ -0,0 +1,83 @@
+{-
+Copyright © 2017–2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{- |
+ Module : Text.Pandoc.Lua
+ Copyright : Copyright © 2017–2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+Running pandoc Lua filters.
+-}
+module Text.Pandoc.Lua
+ ( LuaException (..)
+ , runLuaFilter
+ , runPandocLua
+ ) where
+
+import Control.Monad ((>=>))
+import Foreign.Lua (FromLuaStack (peek), Lua, LuaException (..),
+ Status (OK), ToLuaStack (push))
+import Text.Pandoc.Class (PandocIO)
+import Text.Pandoc.Definition (Pandoc)
+import Text.Pandoc.Lua.Filter (LuaFilter, walkMWithLuaFilter)
+import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath)
+import Text.Pandoc.Lua.Util (popValue)
+import Text.Pandoc.Options (ReaderOptions)
+import qualified Foreign.Lua as Lua
+
+-- | Run the Lua filter in @filterPath@ for a transformation to target
+-- format @format@. Pandoc uses Lua init files to setup the Lua
+-- interpreter.
+runLuaFilter :: ReaderOptions -> FilePath -> String
+ -> Pandoc -> PandocIO (Either LuaException Pandoc)
+runLuaFilter ropts filterPath format doc =
+ runPandocLua (runLuaFilter' ropts filterPath format doc)
+
+runLuaFilter' :: ReaderOptions -> FilePath -> String
+ -> Pandoc -> Lua Pandoc
+runLuaFilter' ropts filterPath format pd = do
+ registerFormat
+ registerReaderOptions
+ registerScriptPath filterPath
+ top <- Lua.gettop
+ stat <- Lua.dofile filterPath
+ if stat /= OK
+ then do
+ luaErrMsg <- popValue
+ Lua.throwLuaError luaErrMsg
+ else do
+ newtop <- Lua.gettop
+ -- Use the returned filters, or the implicitly defined global filter if
+ -- nothing was returned.
+ luaFilters <- if newtop - top >= 1
+ then peek (-1)
+ else Lua.getglobal "_G" *> fmap (:[]) popValue
+ runAll luaFilters pd
+ where
+ registerFormat = do
+ push format
+ Lua.setglobal "FORMAT"
+
+ registerReaderOptions = do
+ push ropts
+ Lua.setglobal "PANDOC_READER_OPTIONS"
+
+runAll :: [LuaFilter] -> Pandoc -> Lua Pandoc
+runAll = foldr ((>=>) . walkMWithLuaFilter) return
diff --git a/src/Text/Pandoc/Lua/Filter.hs b/src/Text/Pandoc/Lua/Filter.hs
new file mode 100644
index 000000000..cc2b9d47e
--- /dev/null
+++ b/src/Text/Pandoc/Lua/Filter.hs
@@ -0,0 +1,170 @@
+{-# LANGUAGE FlexibleContexts #-}
+
+module Text.Pandoc.Lua.Filter ( LuaFilterFunction
+ , LuaFilter
+ , tryFilter
+ , runFilterFunction
+ , walkMWithLuaFilter
+ , walkInlines
+ , walkBlocks
+ , blockElementNames
+ , inlineElementNames
+ ) where
+import Control.Monad (mplus, unless, when, (>=>))
+import Control.Monad.Catch (finally)
+import Text.Pandoc.Definition
+import Data.Foldable (foldrM)
+import Data.Map (Map)
+import qualified Data.Map as Map
+import qualified Foreign.Lua as Lua
+import Foreign.Lua (FromLuaStack (peek), Lua, StackIndex,
+ Status (OK), ToLuaStack (push))
+import Text.Pandoc.Walk (walkM, Walkable)
+import Data.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf,
+ showConstr, toConstr, tyconUQname)
+import Text.Pandoc.Lua.StackInstances()
+import Text.Pandoc.Lua.Util (typeCheck)
+
+type FunctionMap = Map String LuaFilterFunction
+
+newtype LuaFilterFunction = LuaFilterFunction { functionIndex :: Int }
+
+instance ToLuaStack LuaFilterFunction where
+ push = pushFilterFunction
+
+instance FromLuaStack LuaFilterFunction where
+ peek = registerFilterFunction
+
+newtype LuaFilter = LuaFilter FunctionMap
+
+instance FromLuaStack LuaFilter where
+ peek idx =
+ let constrs = metaFilterName : pandocFilterNames
+ ++ blockElementNames
+ ++ inlineElementNames
+ fn c acc = do
+ Lua.getfield idx c
+ filterFn <- Lua.tryLua (peek (-1))
+ Lua.pop 1
+ return $ case filterFn of
+ Left _ -> acc
+ Right f -> (c, f) : acc
+ in LuaFilter . Map.fromList <$> foldrM fn [] constrs
+
+-- | Push the filter function to the top of the stack.
+pushFilterFunction :: LuaFilterFunction -> Lua ()
+pushFilterFunction lf =
+ -- The function is stored in a lua registry table, retrieve it from there.
+ Lua.rawgeti Lua.registryindex (functionIndex lf)
+
+registerFilterFunction :: StackIndex -> Lua LuaFilterFunction
+registerFilterFunction idx = do
+ isFn <- Lua.isfunction idx
+ unless isFn . Lua.throwLuaError $ "Not a function at index " ++ show idx
+ Lua.pushvalue idx
+ refIdx <- Lua.ref Lua.registryindex
+ return $ LuaFilterFunction refIdx
+
+elementOrList :: FromLuaStack a => a -> Lua [a]
+elementOrList x = do
+ let topOfStack = Lua.stackTop
+ elementUnchanged <- Lua.isnil topOfStack
+ if elementUnchanged
+ then [x] <$ Lua.pop 1
+ else do
+ mbres <- Lua.peekEither topOfStack
+ case mbres of
+ Right res -> [res] <$ Lua.pop 1
+ Left _ -> do
+ typeCheck Lua.stackTop Lua.TypeTable
+ Lua.toList topOfStack `finally` Lua.pop 1
+
+-- | Try running a filter for the given element
+tryFilter :: (Data a, FromLuaStack a, ToLuaStack a)
+ => LuaFilter -> a -> Lua [a]
+tryFilter (LuaFilter fnMap) x =
+ let filterFnName = showConstr (toConstr x)
+ catchAllName = tyconUQname $ dataTypeName (dataTypeOf x)
+ in
+ case Map.lookup filterFnName fnMap `mplus` Map.lookup catchAllName fnMap of
+ Just fn -> runFilterFunction fn x *> elementOrList x
+ Nothing -> return [x]
+
+-- | Push a value to the stack via a lua filter function. The filter function is
+-- called with given element as argument and is expected to return an element.
+-- Alternatively, the function can return nothing or nil, in which case the
+-- element is left unchanged.
+runFilterFunction :: ToLuaStack a => LuaFilterFunction -> a -> Lua ()
+runFilterFunction lf x = do
+ pushFilterFunction lf
+ push x
+ z <- Lua.pcall 1 1 Nothing
+ when (z /= OK) $ do
+ let addPrefix = ("Error while running filter function: " ++)
+ Lua.throwTopMessageAsError' addPrefix
+
+walkMWithLuaFilter :: LuaFilter -> Pandoc -> Lua Pandoc
+walkMWithLuaFilter f =
+ walkInlines f >=> walkBlocks f >=> walkMeta f >=> walkPandoc f
+
+mconcatMapM :: (Monad m, Functor m) => (a -> m [a]) -> [a] -> m [a]
+mconcatMapM f = fmap mconcat . mapM f
+
+hasOneOf :: LuaFilter -> [String] -> Bool
+hasOneOf (LuaFilter fnMap) = any (\k -> Map.member k fnMap)
+
+walkInlines :: Walkable [Inline] a => LuaFilter -> a -> Lua a
+walkInlines f =
+ if f `hasOneOf` inlineElementNames
+ then walkM (mconcatMapM (tryFilter f :: Inline -> Lua [Inline]))
+ else return
+
+walkBlocks :: Walkable [Block] a => LuaFilter -> a -> Lua a
+walkBlocks f =
+ if f `hasOneOf` blockElementNames
+ then walkM (mconcatMapM (tryFilter f :: Block -> Lua [Block]))
+ else return
+
+walkMeta :: LuaFilter -> Pandoc -> Lua Pandoc
+walkMeta (LuaFilter fnMap) =
+ case Map.lookup "Meta" fnMap of
+ Just fn -> walkM (\(Pandoc meta blocks) -> do
+ meta' <- runFilterFunction fn meta *> singleElement meta
+ return $ Pandoc meta' blocks)
+ Nothing -> return
+
+walkPandoc :: LuaFilter -> Pandoc -> Lua Pandoc
+walkPandoc (LuaFilter fnMap) =
+ case foldl mplus Nothing (map (`Map.lookup` fnMap) pandocFilterNames) of
+ Just fn -> \x -> runFilterFunction fn x *> singleElement x
+ Nothing -> return
+
+constructorsFor :: DataType -> [String]
+constructorsFor x = map show (dataTypeConstrs x)
+
+inlineElementNames :: [String]
+inlineElementNames = "Inline" : constructorsFor (dataTypeOf (Str []))
+
+blockElementNames :: [String]
+blockElementNames = "Block" : constructorsFor (dataTypeOf (Para []))
+
+metaFilterName :: String
+metaFilterName = "Meta"
+
+pandocFilterNames :: [String]
+pandocFilterNames = ["Pandoc", "Doc"]
+
+singleElement :: FromLuaStack a => a -> Lua a
+singleElement x = do
+ elementUnchanged <- Lua.isnil (-1)
+ if elementUnchanged
+ then x <$ Lua.pop 1
+ else do
+ mbres <- Lua.peekEither (-1)
+ case mbres of
+ Right res -> res <$ Lua.pop 1
+ Left err -> do
+ Lua.pop 1
+ Lua.throwLuaError $
+ "Error while trying to get a filter's return " ++
+ "value from lua stack.\n" ++ err
diff --git a/src/Text/Pandoc/Lua/Init.hs b/src/Text/Pandoc/Lua/Init.hs
new file mode 100644
index 000000000..8fa228837
--- /dev/null
+++ b/src/Text/Pandoc/Lua/Init.hs
@@ -0,0 +1,117 @@
+{-
+Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{- |
+ Module : Text.Pandoc.Lua
+ Copyright : Copyright © 2017-2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+Functions to initialize the Lua interpreter.
+-}
+module Text.Pandoc.Lua.Init
+ ( LuaException (..)
+ , LuaPackageParams (..)
+ , runPandocLua
+ , initLuaState
+ , luaPackageParams
+ , registerScriptPath
+ ) where
+
+import Control.Monad.Trans (MonadIO (..))
+import Data.Data (Data, dataTypeConstrs, dataTypeOf, showConstr)
+import Data.IORef (newIORef, readIORef)
+import Data.Version (Version (versionBranch))
+import Foreign.Lua (Lua, LuaException (..))
+import GHC.IO.Encoding (getForeignEncoding, setForeignEncoding, utf8)
+import Paths_pandoc (version)
+import Text.Pandoc.Class (PandocIO, getCommonState, getUserDataDir, getMediaBag,
+ setMediaBag)
+import Text.Pandoc.Definition (pandocTypesVersion)
+import Text.Pandoc.Lua.Packages (LuaPackageParams (..),
+ installPandocPackageSearcher)
+import Text.Pandoc.Lua.Util (loadScriptFromDataDir)
+
+import qualified Foreign.Lua as Lua
+import qualified Foreign.Lua.Module.Text as Lua
+import qualified Text.Pandoc.Definition as Pandoc
+
+-- | Run the lua interpreter, using pandoc's default way of environment
+-- initalization.
+runPandocLua :: Lua a -> PandocIO (Either LuaException a)
+runPandocLua luaOp = do
+ luaPkgParams <- luaPackageParams
+ enc <- liftIO $ getForeignEncoding <* setForeignEncoding utf8
+ res <- liftIO $ Lua.runLuaEither (initLuaState luaPkgParams *> luaOp)
+ liftIO $ setForeignEncoding enc
+ newMediaBag <- liftIO (readIORef (luaPkgMediaBag luaPkgParams))
+ setMediaBag newMediaBag
+ return res
+
+-- | Generate parameters required to setup pandoc's lua environment.
+luaPackageParams :: PandocIO LuaPackageParams
+luaPackageParams = do
+ commonState <- getCommonState
+ datadir <- getUserDataDir
+ mbRef <- liftIO . newIORef =<< getMediaBag
+ return LuaPackageParams
+ { luaPkgCommonState = commonState
+ , luaPkgDataDir = datadir
+ , luaPkgMediaBag = mbRef
+ }
+
+-- Initialize the lua state with all required values
+initLuaState :: LuaPackageParams -> Lua ()
+initLuaState luaPkgParams = do
+ Lua.openlibs
+ Lua.preloadTextModule "text"
+ Lua.push (versionBranch version)
+ Lua.setglobal "PANDOC_VERSION"
+ Lua.push (versionBranch pandocTypesVersion)
+ Lua.setglobal "PANDOC_API_VERSION"
+ installPandocPackageSearcher luaPkgParams
+ loadScriptFromDataDir (luaPkgDataDir luaPkgParams) "init.lua"
+ putConstructorsInRegistry
+
+registerScriptPath :: FilePath -> Lua ()
+registerScriptPath fp = do
+ Lua.push fp
+ Lua.setglobal "PANDOC_SCRIPT_FILE"
+
+putConstructorsInRegistry :: Lua ()
+putConstructorsInRegistry = do
+ Lua.getglobal "pandoc"
+ constrsToReg $ Pandoc.Pandoc mempty mempty
+ constrsToReg $ Pandoc.Str mempty
+ constrsToReg $ Pandoc.Para mempty
+ constrsToReg $ Pandoc.Meta mempty
+ constrsToReg $ Pandoc.MetaList mempty
+ constrsToReg $ Pandoc.Citation mempty mempty mempty Pandoc.AuthorInText 0 0
+ putInReg "Attr" -- used for Attr type alias
+ Lua.pop 1
+ where
+ constrsToReg :: Data a => a -> Lua ()
+ constrsToReg = mapM_ (putInReg . showConstr) . dataTypeConstrs . dataTypeOf
+
+ putInReg :: String -> Lua ()
+ putInReg name = do
+ Lua.push ("pandoc." ++ name) -- name in registry
+ Lua.push name -- in pandoc module
+ Lua.rawget (Lua.nthFromTop 3)
+ Lua.rawset Lua.registryindex
diff --git a/src/Text/Pandoc/Lua/Module/MediaBag.hs b/src/Text/Pandoc/Lua/Module/MediaBag.hs
new file mode 100644
index 000000000..7d942a452
--- /dev/null
+++ b/src/Text/Pandoc/Lua/Module/MediaBag.hs
@@ -0,0 +1,108 @@
+{-
+Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{- |
+ Module : Text.Pandoc.Lua.Module.MediaBag
+ Copyright : Copyright © 2017-2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+The lua module @pandoc.mediabag@.
+-}
+module Text.Pandoc.Lua.Module.MediaBag
+ ( pushModule
+ ) where
+
+import Control.Monad (zipWithM_)
+import Data.IORef (IORef, modifyIORef', readIORef)
+import Data.Maybe (fromMaybe)
+import Foreign.Lua (Lua, NumResults, Optional, liftIO)
+import Text.Pandoc.Class (CommonState (..), fetchItem, putCommonState,
+ runIOorExplode, setMediaBag)
+import Text.Pandoc.Lua.StackInstances ()
+import Text.Pandoc.Lua.Util (addFunction)
+import Text.Pandoc.MIME (MimeType)
+
+import qualified Data.ByteString.Lazy as BL
+import qualified Foreign.Lua as Lua
+import qualified Text.Pandoc.MediaBag as MB
+
+--
+-- MediaBag submodule
+--
+pushModule :: CommonState -> IORef MB.MediaBag -> Lua NumResults
+pushModule commonState mediaBagRef = do
+ Lua.newtable
+ addFunction "insert" (insertMediaFn mediaBagRef)
+ addFunction "lookup" (lookupMediaFn mediaBagRef)
+ addFunction "list" (mediaDirectoryFn mediaBagRef)
+ addFunction "fetch" (fetch commonState mediaBagRef)
+ return 1
+
+insertMediaFn :: IORef MB.MediaBag
+ -> FilePath
+ -> Optional MimeType
+ -> BL.ByteString
+ -> Lua NumResults
+insertMediaFn mbRef fp optionalMime contents = do
+ liftIO . modifyIORef' mbRef $
+ MB.insertMedia fp (Lua.fromOptional optionalMime) contents
+ return 0
+
+lookupMediaFn :: IORef MB.MediaBag
+ -> FilePath
+ -> Lua NumResults
+lookupMediaFn mbRef fp = do
+ res <- MB.lookupMedia fp <$> liftIO (readIORef mbRef)
+ case res of
+ Nothing -> Lua.pushnil *> return 1
+ Just (mimeType, contents) -> do
+ Lua.push mimeType
+ Lua.push contents
+ return 2
+
+mediaDirectoryFn :: IORef MB.MediaBag
+ -> Lua NumResults
+mediaDirectoryFn mbRef = do
+ dirContents <- MB.mediaDirectory <$> liftIO (readIORef mbRef)
+ Lua.newtable
+ zipWithM_ addEntry [1..] dirContents
+ return 1
+ where
+ addEntry :: Int -> (FilePath, MimeType, Int) -> Lua ()
+ addEntry idx (fp, mimeType, contentLength) = do
+ Lua.newtable
+ Lua.push "path" *> Lua.push fp *> Lua.rawset (-3)
+ Lua.push "type" *> Lua.push mimeType *> Lua.rawset (-3)
+ Lua.push "length" *> Lua.push contentLength *> Lua.rawset (-3)
+ Lua.rawseti (-2) idx
+
+fetch :: CommonState
+ -> IORef MB.MediaBag
+ -> String
+ -> Lua NumResults
+fetch commonState mbRef src = do
+ mediaBag <- liftIO $ readIORef mbRef
+ (bs, mimeType) <- liftIO . runIOorExplode $ do
+ putCommonState commonState
+ setMediaBag mediaBag
+ fetchItem src
+ Lua.push $ fromMaybe "" mimeType
+ Lua.push bs
+ return 2 -- returns 2 values: contents, mimetype
diff --git a/src/Text/Pandoc/Lua/Module/Pandoc.hs b/src/Text/Pandoc/Lua/Module/Pandoc.hs
new file mode 100644
index 000000000..b9410a353
--- /dev/null
+++ b/src/Text/Pandoc/Lua/Module/Pandoc.hs
@@ -0,0 +1,134 @@
+{-
+Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{-# LANGUAGE FlexibleContexts #-}
+{- |
+ Module : Text.Pandoc.Lua.Module.Pandoc
+ Copyright : Copyright © 2017-2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+Pandoc module for lua.
+-}
+module Text.Pandoc.Lua.Module.Pandoc
+ ( pushModule
+ ) where
+
+import Control.Monad (when)
+import Data.Default (Default (..))
+import Data.Maybe (fromMaybe)
+import Data.Text (pack)
+import Foreign.Lua (ToLuaStack, FromLuaStack, Lua, NumResults, Optional, liftIO)
+import System.Exit (ExitCode (..))
+import Text.Pandoc.Class (runIO)
+import Text.Pandoc.Definition (Block, Inline)
+import Text.Pandoc.Lua.Filter (walkInlines, walkBlocks, LuaFilter)
+import Text.Pandoc.Lua.StackInstances ()
+import Text.Pandoc.Lua.Util (addFunction, addValue, loadScriptFromDataDir)
+import Text.Pandoc.Walk (Walkable)
+import Text.Pandoc.Options (ReaderOptions (readerExtensions))
+import Text.Pandoc.Process (pipeProcess)
+import Text.Pandoc.Readers (Reader (..), getReader)
+
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.ByteString.Lazy.Char8 as BSL
+import qualified Foreign.Lua as Lua
+
+-- | Push the "pandoc" on the lua stack. Requires the `list` module to be
+-- loaded.
+pushModule :: Maybe FilePath -> Lua NumResults
+pushModule datadir = do
+ loadScriptFromDataDir datadir "pandoc.lua"
+ addFunction "read" readDoc
+ addFunction "pipe" pipeFn
+ addFunction "walk_block" walkBlock
+ addFunction "walk_inline" walkInline
+ return 1
+
+walkElement :: (ToLuaStack a, Walkable [Inline] a, Walkable [Block] a)
+ => a -> LuaFilter -> Lua a
+walkElement x f = walkInlines f x >>= walkBlocks f
+
+walkInline :: Inline -> LuaFilter -> Lua Inline
+walkInline = walkElement
+
+walkBlock :: Block -> LuaFilter -> Lua Block
+walkBlock = walkElement
+
+readDoc :: String -> Optional String -> Lua NumResults
+readDoc content formatSpecOrNil = do
+ let formatSpec = fromMaybe "markdown" (Lua.fromOptional formatSpecOrNil)
+ case getReader formatSpec of
+ Left s -> Lua.raiseError s -- Unknown reader
+ Right (reader, es) ->
+ case reader of
+ TextReader r -> do
+ res <- liftIO $ runIO $ r def{ readerExtensions = es } (pack content)
+ case res of
+ Right pd -> (1 :: NumResults) <$ Lua.push pd -- success, push Pandoc
+ Left s -> Lua.raiseError (show s) -- error while reading
+ _ -> Lua.raiseError "Only string formats are supported at the moment."
+
+-- | Pipes input through a command.
+pipeFn :: String
+ -> [String]
+ -> BL.ByteString
+ -> Lua NumResults
+pipeFn command args input = do
+ (ec, output) <- liftIO $ pipeProcess Nothing command args input
+ case ec of
+ ExitSuccess -> 1 <$ Lua.push output
+ ExitFailure n -> Lua.raiseError (PipeError command n output)
+
+data PipeError = PipeError
+ { pipeErrorCommand :: String
+ , pipeErrorCode :: Int
+ , pipeErrorOutput :: BL.ByteString
+ }
+
+instance FromLuaStack PipeError where
+ peek idx =
+ PipeError
+ <$> (Lua.getfield idx "command" *> Lua.peek (-1) <* Lua.pop 1)
+ <*> (Lua.getfield idx "error_code" *> Lua.peek (-1) <* Lua.pop 1)
+ <*> (Lua.getfield idx "output" *> Lua.peek (-1) <* Lua.pop 1)
+
+instance ToLuaStack PipeError where
+ push pipeErr = do
+ Lua.newtable
+ addValue "command" (pipeErrorCommand pipeErr)
+ addValue "error_code" (pipeErrorCode pipeErr)
+ addValue "output" (pipeErrorOutput pipeErr)
+ pushPipeErrorMetaTable
+ Lua.setmetatable (-2)
+ where
+ pushPipeErrorMetaTable :: Lua ()
+ pushPipeErrorMetaTable = do
+ v <- Lua.newmetatable "pandoc pipe error"
+ when v $ addFunction "__tostring" pipeErrorMessage
+
+ pipeErrorMessage :: PipeError -> Lua BL.ByteString
+ pipeErrorMessage (PipeError cmd errorCode output) = return $ mconcat
+ [ BSL.pack "Error running "
+ , BSL.pack cmd
+ , BSL.pack " (error code "
+ , BSL.pack $ show errorCode
+ , BSL.pack "): "
+ , if output == mempty then BSL.pack "<no output>" else output
+ ]
diff --git a/src/Text/Pandoc/Lua/Module/Utils.hs b/src/Text/Pandoc/Lua/Module/Utils.hs
new file mode 100644
index 000000000..f8eb96dc7
--- /dev/null
+++ b/src/Text/Pandoc/Lua/Module/Utils.hs
@@ -0,0 +1,126 @@
+{-
+Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{- |
+ Module : Text.Pandoc.Lua.Module.Utils
+ Copyright : Copyright © 2017-2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+Utility module for lua, exposing internal helper functions.
+-}
+module Text.Pandoc.Lua.Module.Utils
+ ( pushModule
+ ) where
+
+import Control.Applicative ((<|>))
+import Data.Default (def)
+import Foreign.Lua (FromLuaStack, Lua, LuaInteger, NumResults)
+import Text.Pandoc.Class (runIO, setUserDataDir)
+import Text.Pandoc.Definition (Pandoc, Meta, MetaValue, Block, Inline)
+import Text.Pandoc.Lua.StackInstances ()
+import Text.Pandoc.Lua.Util (addFunction, popValue)
+
+import qualified Data.Digest.Pure.SHA as SHA
+import qualified Data.ByteString.Lazy as BSL
+import qualified Foreign.Lua as Lua
+import qualified Text.Pandoc.Filter.JSON as JSONFilter
+import qualified Text.Pandoc.Shared as Shared
+
+-- | Push the "pandoc.utils" module to the lua stack.
+pushModule :: Maybe FilePath -> Lua NumResults
+pushModule mbDatadir = do
+ Lua.newtable
+ addFunction "hierarchicalize" hierarchicalize
+ addFunction "normalize_date" normalizeDate
+ addFunction "run_json_filter" (runJSONFilter mbDatadir)
+ addFunction "sha1" sha1
+ addFunction "stringify" stringify
+ addFunction "to_roman_numeral" toRomanNumeral
+ return 1
+
+-- | Convert list of Pandoc blocks into (hierarchical) list of Elements.
+hierarchicalize :: [Block] -> Lua [Shared.Element]
+hierarchicalize = return . Shared.hierarchicalize
+
+-- | Parse a date and convert (if possible) to "YYYY-MM-DD" format. We
+-- limit years to the range 1601-9999 (ISO 8601 accepts greater than
+-- or equal to 1583, but MS Word only accepts dates starting 1601).
+-- Returns nil instead of a string if the conversion failed.
+normalizeDate :: String -> Lua (Lua.Optional String)
+normalizeDate = return . Lua.Optional . Shared.normalizeDate
+
+-- | Run a JSON filter on the given document.
+runJSONFilter :: Maybe FilePath
+ -> Pandoc
+ -> FilePath
+ -> Lua.Optional [String]
+ -> Lua NumResults
+runJSONFilter mbDatadir doc filterFile optArgs = do
+ args <- case Lua.fromOptional optArgs of
+ Just x -> return x
+ Nothing -> do
+ Lua.getglobal "FORMAT"
+ (:[]) <$> popValue
+ filterRes <- Lua.liftIO . runIO $ do
+ setUserDataDir mbDatadir
+ JSONFilter.apply def args filterFile doc
+ case filterRes of
+ Left err -> Lua.raiseError (show err)
+ Right d -> (1 :: NumResults) <$ Lua.push d
+
+-- | Calculate the hash of the given contents.
+sha1 :: BSL.ByteString
+ -> Lua String
+sha1 = return . SHA.showDigest . SHA.sha1
+
+-- | Convert pandoc structure to a string with formatting removed.
+-- Footnotes are skipped (since we don't want their contents in link
+-- labels).
+stringify :: AstElement -> Lua String
+stringify el = return $ case el of
+ PandocElement pd -> Shared.stringify pd
+ InlineElement i -> Shared.stringify i
+ BlockElement b -> Shared.stringify b
+ MetaElement m -> Shared.stringify m
+ MetaValueElement m -> Shared.stringify m
+
+data AstElement
+ = PandocElement Pandoc
+ | MetaElement Meta
+ | BlockElement Block
+ | InlineElement Inline
+ | MetaValueElement MetaValue
+ deriving (Show)
+
+instance FromLuaStack AstElement where
+ peek idx = do
+ res <- Lua.tryLua $ (PandocElement <$> Lua.peek idx)
+ <|> (InlineElement <$> Lua.peek idx)
+ <|> (BlockElement <$> Lua.peek idx)
+ <|> (MetaElement <$> Lua.peek idx)
+ <|> (MetaValueElement <$> Lua.peek idx)
+ case res of
+ Right x -> return x
+ Left _ -> Lua.throwLuaError
+ "Expected an AST element, but could not parse value as such."
+
+-- | Convert a number < 4000 to uppercase roman numeral.
+toRomanNumeral :: LuaInteger -> Lua String
+toRomanNumeral = return . Shared.toRomanNumeral . fromIntegral
diff --git a/src/Text/Pandoc/Lua/Packages.hs b/src/Text/Pandoc/Lua/Packages.hs
new file mode 100644
index 000000000..1e6ff22fe
--- /dev/null
+++ b/src/Text/Pandoc/Lua/Packages.hs
@@ -0,0 +1,115 @@
+{-
+Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts #-}
+{- |
+ Module : Text.Pandoc.Lua.Packages
+ Copyright : Copyright © 2017-2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+Pandoc module for lua.
+-}
+module Text.Pandoc.Lua.Packages
+ ( LuaPackageParams (..)
+ , installPandocPackageSearcher
+ ) where
+
+import Control.Monad (forM_)
+import Data.ByteString.Char8 (unpack)
+import Data.IORef (IORef)
+import Foreign.Lua (Lua, NumResults, liftIO)
+import Text.Pandoc.Class (CommonState, readDataFile, runIO, setUserDataDir)
+import Text.Pandoc.MediaBag (MediaBag)
+import Text.Pandoc.Lua.Util (dostring')
+
+import qualified Foreign.Lua as Lua
+import Text.Pandoc.Lua.Module.Pandoc as Pandoc
+import Text.Pandoc.Lua.Module.MediaBag as MediaBag
+import Text.Pandoc.Lua.Module.Utils as Utils
+
+-- | Parameters used to create lua packages/modules.
+data LuaPackageParams = LuaPackageParams
+ { luaPkgCommonState :: CommonState
+ , luaPkgDataDir :: Maybe FilePath
+ , luaPkgMediaBag :: IORef MediaBag
+ }
+
+-- | Insert pandoc's package loader as the first loader, making it the default.
+installPandocPackageSearcher :: LuaPackageParams -> Lua ()
+installPandocPackageSearcher luaPkgParams = do
+ luaVersion <- Lua.getglobal "_VERSION" *> Lua.peek (-1)
+ if luaVersion == "Lua 5.1"
+ then Lua.getglobal' "package.loaders"
+ else Lua.getglobal' "package.searchers"
+ shiftArray
+ Lua.pushHaskellFunction (pandocPackageSearcher luaPkgParams)
+ Lua.wrapHaskellFunction
+ Lua.rawseti (-2) 1
+ Lua.pop 1 -- remove 'package.searchers' from stack
+ where
+ shiftArray = forM_ [4, 3, 2, 1] $ \i -> do
+ Lua.rawgeti (-1) i
+ Lua.rawseti (-2) (i + 1)
+
+-- | Load a pandoc module.
+pandocPackageSearcher :: LuaPackageParams -> String -> Lua NumResults
+pandocPackageSearcher luaPkgParams pkgName =
+ case pkgName of
+ "pandoc" -> let datadir = luaPkgDataDir luaPkgParams
+ in pushWrappedHsFun (Pandoc.pushModule datadir)
+ "pandoc.mediabag" -> let st = luaPkgCommonState luaPkgParams
+ mbRef = luaPkgMediaBag luaPkgParams
+ in pushWrappedHsFun (MediaBag.pushModule st mbRef)
+ "pandoc.utils" -> let datadirMb = luaPkgDataDir luaPkgParams
+ in pushWrappedHsFun (Utils.pushModule datadirMb)
+ _ -> searchPureLuaLoader
+ where
+ pushWrappedHsFun f = do
+ Lua.pushHaskellFunction f
+ Lua.wrapHaskellFunction
+ return 1
+ searchPureLuaLoader = do
+ let filename = pkgName ++ ".lua"
+ modScript <- liftIO (dataDirScript (luaPkgDataDir luaPkgParams) filename)
+ case modScript of
+ Just script -> pushWrappedHsFun (loadStringAsPackage pkgName script)
+ Nothing -> do
+ Lua.push ("no file '" ++ filename ++ "' in pandoc's datadir")
+ return 1
+
+loadStringAsPackage :: String -> String -> Lua NumResults
+loadStringAsPackage pkgName script = do
+ status <- dostring' script
+ if status == Lua.OK
+ then return (1 :: NumResults)
+ else do
+ msg <- Lua.peek (-1) <* Lua.pop 1
+ Lua.push ("Error while loading ``" ++ pkgName ++ "`.\n" ++ msg)
+ Lua.lerror
+ return (2 :: NumResults)
+
+-- | Get the string representation of the pandoc module
+dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe String)
+dataDirScript datadir moduleFile = do
+ res <- runIO $ setUserDataDir datadir >> readDataFile moduleFile
+ return $ case res of
+ Left _ -> Nothing
+ Right s -> Just (unpack s)
diff --git a/src/Text/Pandoc/Lua/StackInstances.hs b/src/Text/Pandoc/Lua/StackInstances.hs
new file mode 100644
index 000000000..7e0dc20c4
--- /dev/null
+++ b/src/Text/Pandoc/Lua/StackInstances.hs
@@ -0,0 +1,376 @@
+{-
+Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>
+ 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{- |
+ Module : Text.Pandoc.Lua.StackInstances
+ Copyright : © 2012-2018 John MacFarlane
+ © 2017-2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+StackValue instances for pandoc types.
+-}
+module Text.Pandoc.Lua.StackInstances () where
+
+import Control.Applicative ((<|>))
+import Control.Monad (when)
+import Control.Monad.Catch (finally)
+import Data.Data (showConstr, toConstr)
+import Data.Foldable (forM_)
+import Foreign.Lua (FromLuaStack (peek), Lua, LuaInteger, LuaNumber, StackIndex,
+ ToLuaStack (push), Type (..), throwLuaError, tryLua)
+import Text.Pandoc.Definition
+import Text.Pandoc.Extensions (Extensions)
+import Text.Pandoc.Lua.Util (getTable, getTag, pushViaConstructor, typeCheck)
+import Text.Pandoc.Options (ReaderOptions (..), TrackChanges)
+import Text.Pandoc.Shared (Element (Blk, Sec), safeRead)
+
+import qualified Foreign.Lua as Lua
+import qualified Data.Set as Set
+import qualified Text.Pandoc.Lua.Util as LuaUtil
+
+defineHowTo :: String -> Lua a -> Lua a
+defineHowTo ctx op = op `Lua.modifyLuaError` (("Could not " ++ ctx ++ ": ") ++)
+
+instance ToLuaStack Pandoc where
+ push (Pandoc meta blocks) =
+ pushViaConstructor "Pandoc" blocks meta
+
+instance FromLuaStack Pandoc where
+ peek idx = defineHowTo "get Pandoc value" $ do
+ typeCheck idx Lua.TypeTable
+ blocks <- getTable idx "blocks"
+ meta <- Lua.getfield idx "meta" *> (Lua.peek Lua.stackTop `finally` Lua.pop 1)
+ return $ Pandoc meta blocks
+
+instance ToLuaStack Meta where
+ push (Meta mmap) =
+ pushViaConstructor "Meta" mmap
+instance FromLuaStack Meta where
+ peek idx = defineHowTo "get Meta value" $ do
+ typeCheck idx Lua.TypeTable
+ Meta <$> peek idx
+
+instance ToLuaStack MetaValue where
+ push = pushMetaValue
+instance FromLuaStack MetaValue where
+ peek = peekMetaValue
+
+instance ToLuaStack Block where
+ push = pushBlock
+
+instance FromLuaStack Block where
+ peek = peekBlock
+
+-- Inline
+instance ToLuaStack Inline where
+ push = pushInline
+
+instance FromLuaStack Inline where
+ peek = peekInline
+
+-- Citation
+instance ToLuaStack Citation where
+ push (Citation cid prefix suffix mode noteNum hash) =
+ pushViaConstructor "Citation" cid mode prefix suffix noteNum hash
+
+instance FromLuaStack Citation where
+ peek idx = do
+ id' <- getTable idx "id"
+ prefix <- getTable idx "prefix"
+ suffix <- getTable idx "suffix"
+ mode <- getTable idx "mode"
+ num <- getTable idx "note_num"
+ hash <- getTable idx "hash"
+ return $ Citation id' prefix suffix mode num hash
+
+instance ToLuaStack Alignment where
+ push = push . show
+instance FromLuaStack Alignment where
+ peek idx = safeRead' =<< peek idx
+
+instance ToLuaStack CitationMode where
+ push = push . show
+instance FromLuaStack CitationMode where
+ peek idx = safeRead' =<< peek idx
+
+instance ToLuaStack Format where
+ push (Format f) = push f
+instance FromLuaStack Format where
+ peek idx = Format <$> peek idx
+
+instance ToLuaStack ListNumberDelim where
+ push = push . show
+instance FromLuaStack ListNumberDelim where
+ peek idx = safeRead' =<< peek idx
+
+instance ToLuaStack ListNumberStyle where
+ push = push . show
+instance FromLuaStack ListNumberStyle where
+ peek idx = safeRead' =<< peek idx
+
+instance ToLuaStack MathType where
+ push = push . show
+instance FromLuaStack MathType where
+ peek idx = safeRead' =<< peek idx
+
+instance ToLuaStack QuoteType where
+ push = push . show
+instance FromLuaStack QuoteType where
+ peek idx = safeRead' =<< peek idx
+
+instance ToLuaStack Double where
+ push = push . (realToFrac :: Double -> LuaNumber)
+instance FromLuaStack Double where
+ peek = fmap (realToFrac :: LuaNumber -> Double) . peek
+
+instance ToLuaStack Int where
+ push = push . (fromIntegral :: Int -> LuaInteger)
+instance FromLuaStack Int where
+ peek = fmap (fromIntegral :: LuaInteger-> Int) . peek
+
+safeRead' :: Read a => String -> Lua a
+safeRead' s = case safeRead s of
+ Nothing -> throwLuaError ("Could not read: " ++ s)
+ Just x -> return x
+
+-- | Push an meta value element to the top of the lua stack.
+pushMetaValue :: MetaValue -> Lua ()
+pushMetaValue = \case
+ MetaBlocks blcks -> pushViaConstructor "MetaBlocks" blcks
+ MetaBool bool -> push bool
+ MetaInlines inlns -> pushViaConstructor "MetaInlines" inlns
+ MetaList metalist -> pushViaConstructor "MetaList" metalist
+ MetaMap metamap -> pushViaConstructor "MetaMap" metamap
+ MetaString str -> push str
+
+-- | Interpret the value at the given stack index as meta value.
+peekMetaValue :: StackIndex -> Lua MetaValue
+peekMetaValue idx = defineHowTo "get MetaValue" $ do
+ -- Get the contents of an AST element.
+ let elementContent :: FromLuaStack a => Lua a
+ elementContent = peek idx
+ luatype <- Lua.ltype idx
+ case luatype of
+ TypeBoolean -> MetaBool <$> peek idx
+ TypeString -> MetaString <$> peek idx
+ TypeTable -> do
+ tag <- tryLua $ getTag idx
+ case tag of
+ Right "MetaBlocks" -> MetaBlocks <$> elementContent
+ Right "MetaBool" -> MetaBool <$> elementContent
+ Right "MetaMap" -> MetaMap <$> elementContent
+ Right "MetaInlines" -> MetaInlines <$> elementContent
+ Right "MetaList" -> MetaList <$> elementContent
+ Right "MetaString" -> MetaString <$> elementContent
+ Right t -> throwLuaError ("Unknown meta tag: " ++ t)
+ Left _ -> do
+ -- no meta value tag given, try to guess.
+ len <- Lua.rawlen idx
+ if len <= 0
+ then MetaMap <$> peek idx
+ else (MetaInlines <$> peek idx)
+ <|> (MetaBlocks <$> peek idx)
+ <|> (MetaList <$> peek idx)
+ _ -> throwLuaError "could not get meta value"
+
+-- | Push an block element to the top of the lua stack.
+pushBlock :: Block -> Lua ()
+pushBlock = \case
+ BlockQuote blcks -> pushViaConstructor "BlockQuote" blcks
+ BulletList items -> pushViaConstructor "BulletList" items
+ CodeBlock attr code -> pushViaConstructor "CodeBlock" code (LuaAttr attr)
+ DefinitionList items -> pushViaConstructor "DefinitionList" items
+ Div attr blcks -> pushViaConstructor "Div" blcks (LuaAttr attr)
+ Header lvl attr inlns -> pushViaConstructor "Header" lvl inlns (LuaAttr attr)
+ HorizontalRule -> pushViaConstructor "HorizontalRule"
+ LineBlock blcks -> pushViaConstructor "LineBlock" blcks
+ OrderedList lstAttr list -> pushViaConstructor "OrderedList" list lstAttr
+ Null -> pushViaConstructor "Null"
+ Para blcks -> pushViaConstructor "Para" blcks
+ Plain blcks -> pushViaConstructor "Plain" blcks
+ RawBlock f cs -> pushViaConstructor "RawBlock" f cs
+ Table capt aligns widths headers rows ->
+ pushViaConstructor "Table" capt aligns widths headers rows
+
+-- | Return the value at the given index as block if possible.
+peekBlock :: StackIndex -> Lua Block
+peekBlock idx = defineHowTo "get Block value" $ do
+ typeCheck idx Lua.TypeTable
+ tag <- getTag idx
+ case tag of
+ "BlockQuote" -> BlockQuote <$> elementContent
+ "BulletList" -> BulletList <$> elementContent
+ "CodeBlock" -> withAttr CodeBlock <$> elementContent
+ "DefinitionList" -> DefinitionList <$> elementContent
+ "Div" -> withAttr Div <$> elementContent
+ "Header" -> (\(lvl, LuaAttr attr, lst) -> Header lvl attr lst)
+ <$> elementContent
+ "HorizontalRule" -> return HorizontalRule
+ "LineBlock" -> LineBlock <$> elementContent
+ "OrderedList" -> uncurry OrderedList <$> elementContent
+ "Null" -> return Null
+ "Para" -> Para <$> elementContent
+ "Plain" -> Plain <$> elementContent
+ "RawBlock" -> uncurry RawBlock <$> elementContent
+ "Table" -> (\(capt, aligns, widths, headers, body) ->
+ Table capt aligns widths headers body)
+ <$> elementContent
+ _ -> throwLuaError ("Unknown block type: " ++ tag)
+ where
+ -- Get the contents of an AST element.
+ elementContent :: FromLuaStack a => Lua a
+ elementContent = getTable idx "c"
+
+-- | Push an inline element to the top of the lua stack.
+pushInline :: Inline -> Lua ()
+pushInline = \case
+ Cite citations lst -> pushViaConstructor "Cite" lst citations
+ Code attr lst -> pushViaConstructor "Code" lst (LuaAttr attr)
+ Emph inlns -> pushViaConstructor "Emph" inlns
+ Image attr alt (src,tit) -> pushViaConstructor "Image" alt src tit (LuaAttr attr)
+ LineBreak -> pushViaConstructor "LineBreak"
+ Link attr lst (src,tit) -> pushViaConstructor "Link" lst src tit (LuaAttr attr)
+ Note blcks -> pushViaConstructor "Note" blcks
+ Math mty str -> pushViaConstructor "Math" mty str
+ Quoted qt inlns -> pushViaConstructor "Quoted" qt inlns
+ RawInline f cs -> pushViaConstructor "RawInline" f cs
+ SmallCaps inlns -> pushViaConstructor "SmallCaps" inlns
+ SoftBreak -> pushViaConstructor "SoftBreak"
+ Space -> pushViaConstructor "Space"
+ Span attr inlns -> pushViaConstructor "Span" inlns (LuaAttr attr)
+ Str str -> pushViaConstructor "Str" str
+ Strikeout inlns -> pushViaConstructor "Strikeout" inlns
+ Strong inlns -> pushViaConstructor "Strong" inlns
+ Subscript inlns -> pushViaConstructor "Subscript" inlns
+ Superscript inlns -> pushViaConstructor "Superscript" inlns
+
+-- | Return the value at the given index as inline if possible.
+peekInline :: StackIndex -> Lua Inline
+peekInline idx = defineHowTo "get Inline value" $ do
+ typeCheck idx Lua.TypeTable
+ tag <- getTag idx
+ case tag of
+ "Cite" -> uncurry Cite <$> elementContent
+ "Code" -> withAttr Code <$> elementContent
+ "Emph" -> Emph <$> elementContent
+ "Image" -> (\(LuaAttr attr, lst, tgt) -> Image attr lst tgt)
+ <$> elementContent
+ "Link" -> (\(LuaAttr attr, lst, tgt) -> Link attr lst tgt)
+ <$> elementContent
+ "LineBreak" -> return LineBreak
+ "Note" -> Note <$> elementContent
+ "Math" -> uncurry Math <$> elementContent
+ "Quoted" -> uncurry Quoted <$> elementContent
+ "RawInline" -> uncurry RawInline <$> elementContent
+ "SmallCaps" -> SmallCaps <$> elementContent
+ "SoftBreak" -> return SoftBreak
+ "Space" -> return Space
+ "Span" -> withAttr Span <$> elementContent
+ "Str" -> Str <$> elementContent
+ "Strikeout" -> Strikeout <$> elementContent
+ "Strong" -> Strong <$> elementContent
+ "Subscript" -> Subscript <$> elementContent
+ "Superscript"-> Superscript <$> elementContent
+ _ -> throwLuaError ("Unknown inline type: " ++ tag)
+ where
+ -- Get the contents of an AST element.
+ elementContent :: FromLuaStack a => Lua a
+ elementContent = getTable idx "c"
+
+withAttr :: (Attr -> a -> b) -> (LuaAttr, a) -> b
+withAttr f (attributes, x) = f (fromLuaAttr attributes) x
+
+-- | Wrapper for Attr
+newtype LuaAttr = LuaAttr { fromLuaAttr :: Attr }
+
+instance ToLuaStack LuaAttr where
+ push (LuaAttr (id', classes, kv)) =
+ pushViaConstructor "Attr" id' classes kv
+
+instance FromLuaStack LuaAttr where
+ peek idx = defineHowTo "get Attr value" (LuaAttr <$> peek idx)
+
+--
+-- Hierarchical elements
+--
+instance ToLuaStack Element where
+ push (Blk blk) = push blk
+ push (Sec lvl num attr label contents) = do
+ Lua.newtable
+ LuaUtil.addValue "level" lvl
+ LuaUtil.addValue "numbering" num
+ LuaUtil.addValue "attr" (LuaAttr attr)
+ LuaUtil.addValue "label" label
+ LuaUtil.addValue "contents" contents
+ pushSecMetaTable
+ Lua.setmetatable (-2)
+ where
+ pushSecMetaTable :: Lua ()
+ pushSecMetaTable = do
+ inexistant <- Lua.newmetatable "PandocElementSec"
+ when inexistant $ do
+ LuaUtil.addValue "t" "Sec"
+ Lua.push "__index"
+ Lua.pushvalue (-2)
+ Lua.rawset (-3)
+
+
+--
+-- Reader Options
+--
+instance ToLuaStack Extensions where
+ push exts = push (show exts)
+
+instance ToLuaStack TrackChanges where
+ push = push . showConstr . toConstr
+
+instance ToLuaStack a => ToLuaStack (Set.Set a) where
+ push set = do
+ Lua.newtable
+ forM_ set (`LuaUtil.addValue` True)
+
+instance ToLuaStack ReaderOptions where
+ push ro = do
+ let ReaderOptions
+ (extensions :: Extensions)
+ (standalone :: Bool)
+ (columns :: Int)
+ (tabStop :: Int)
+ (indentedCodeClasses :: [String])
+ (abbreviations :: Set.Set String)
+ (defaultImageExtension :: String)
+ (trackChanges :: TrackChanges)
+ (stripComments :: Bool)
+ = ro
+ Lua.newtable
+ LuaUtil.addValue "extensions" extensions
+ LuaUtil.addValue "standalone" standalone
+ LuaUtil.addValue "columns" columns
+ LuaUtil.addValue "tabStop" tabStop
+ LuaUtil.addValue "indentedCodeClasses" indentedCodeClasses
+ LuaUtil.addValue "abbreviations" abbreviations
+ LuaUtil.addValue "defaultImageExtension" defaultImageExtension
+ LuaUtil.addValue "trackChanges" trackChanges
+ LuaUtil.addValue "stripComments" stripComments
diff --git a/src/Text/Pandoc/Lua/Util.hs b/src/Text/Pandoc/Lua/Util.hs
new file mode 100644
index 000000000..b7149af39
--- /dev/null
+++ b/src/Text/Pandoc/Lua/Util.hs
@@ -0,0 +1,187 @@
+{-
+Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>
+ 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{-# LANGUAGE FlexibleInstances #-}
+{- |
+ Module : Text.Pandoc.Lua.Util
+ Copyright : © 2012–2018 John MacFarlane,
+ © 2017-2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+Lua utility functions.
+-}
+module Text.Pandoc.Lua.Util
+ ( getTag
+ , getTable
+ , addValue
+ , addFunction
+ , getRawInt
+ , setRawInt
+ , addRawInt
+ , typeCheck
+ , raiseError
+ , popValue
+ , PushViaCall
+ , pushViaCall
+ , pushViaConstructor
+ , loadScriptFromDataDir
+ , dostring'
+ ) where
+
+import Control.Monad (when)
+import Control.Monad.Catch (finally)
+import Data.ByteString.Char8 (unpack)
+import Foreign.Lua (FromLuaStack (..), NumResults, Lua, NumArgs, StackIndex,
+ ToLuaStack (..), ToHaskellFunction)
+import Foreign.Lua.Api (Status, call, pop, rawget, rawgeti, rawset, rawseti)
+import Text.Pandoc.Class (readDataFile, runIOorExplode, setUserDataDir)
+
+import qualified Foreign.Lua as Lua
+
+-- | Adjust the stack index, assuming that @n@ new elements have been pushed on
+-- the stack.
+adjustIndexBy :: StackIndex -> StackIndex -> StackIndex
+adjustIndexBy idx n =
+ if idx < 0
+ then idx - n
+ else idx
+
+-- | Get value behind key from table at given index.
+getTable :: (ToLuaStack a, FromLuaStack b) => StackIndex -> a -> Lua b
+getTable idx key = do
+ push key
+ rawget (idx `adjustIndexBy` 1)
+ popValue
+
+-- | Add a key-value pair to the table at the top of the stack.
+addValue :: (ToLuaStack a, ToLuaStack b) => a -> b -> Lua ()
+addValue key value = do
+ push key
+ push value
+ rawset (-3)
+
+-- | Add a function to the table at the top of the stack, using the given name.
+addFunction :: ToHaskellFunction a => String -> a -> Lua ()
+addFunction name fn = do
+ Lua.push name
+ Lua.pushHaskellFunction fn
+ Lua.wrapHaskellFunction
+ Lua.rawset (-3)
+
+-- | Get value behind key from table at given index.
+getRawInt :: FromLuaStack a => StackIndex -> Int -> Lua a
+getRawInt idx key = do
+ rawgeti idx key
+ popValue
+
+-- | Set numeric key/value in table at the given index
+setRawInt :: ToLuaStack a => StackIndex -> Int -> a -> Lua ()
+setRawInt idx key value = do
+ push value
+ rawseti (idx `adjustIndexBy` 1) key
+
+-- | Set numeric key/value in table at the top of the stack.
+addRawInt :: ToLuaStack a => Int -> a -> Lua ()
+addRawInt = setRawInt (-1)
+
+typeCheck :: StackIndex -> Lua.Type -> Lua ()
+typeCheck idx expected = do
+ actual <- Lua.ltype idx
+ when (actual /= expected) $ do
+ expName <- Lua.typename expected
+ actName <- Lua.typename actual
+ Lua.throwLuaError $ "expected " ++ expName ++ " but got " ++ actName ++ "."
+
+raiseError :: ToLuaStack a => a -> Lua NumResults
+raiseError e = do
+ Lua.push e
+ fromIntegral <$> Lua.lerror
+
+-- | Get, then pop the value at the top of the stack.
+popValue :: FromLuaStack a => Lua a
+popValue = do
+ resOrError <- Lua.peekEither (-1)
+ pop 1
+ case resOrError of
+ Left err -> Lua.throwLuaError err
+ Right x -> return x
+
+-- | Helper class for pushing a single value to the stack via a lua function.
+-- See @pushViaCall@.
+class PushViaCall a where
+ pushViaCall' :: String -> Lua () -> NumArgs -> a
+
+instance PushViaCall (Lua ()) where
+ pushViaCall' fn pushArgs num = do
+ Lua.push fn
+ Lua.rawget (Lua.registryindex)
+ pushArgs
+ call num 1
+
+instance (ToLuaStack a, PushViaCall b) => PushViaCall (a -> b) where
+ pushViaCall' fn pushArgs num x =
+ pushViaCall' fn (pushArgs *> push x) (num + 1)
+
+-- | Push an value to the stack via a lua function. The lua function is called
+-- with all arguments that are passed to this function and is expected to return
+-- a single value.
+pushViaCall :: PushViaCall a => String -> a
+pushViaCall fn = pushViaCall' fn (return ()) 0
+
+-- | Call a pandoc element constructor within lua, passing all given arguments.
+pushViaConstructor :: PushViaCall a => String -> a
+pushViaConstructor pandocFn = pushViaCall ("pandoc." ++ pandocFn)
+
+-- | Load a file from pandoc's data directory.
+loadScriptFromDataDir :: Maybe FilePath -> FilePath -> Lua ()
+loadScriptFromDataDir datadir scriptFile = do
+ script <- fmap unpack . Lua.liftIO . runIOorExplode $
+ setUserDataDir datadir >> readDataFile scriptFile
+ status <- dostring' script
+ when (status /= Lua.OK) .
+ Lua.throwTopMessageAsError' $ \msg ->
+ "Couldn't load '" ++ scriptFile ++ "'.\n" ++ msg
+
+-- | Load a string and immediately perform a full garbage collection. This is
+-- important to keep the program from hanging: If the program contained a call
+-- to @require@, the a new loader function was created which then become
+-- garbage. If that function is collected at an inopportune times, i.e. when the
+-- Lua API is called via a function that doesn't allow calling back into Haskell
+-- (getraw, setraw, …), then the function's finalizer, and the full program,
+-- will hang.
+dostring' :: String -> Lua Status
+dostring' script = do
+ loadRes <- Lua.loadstring script
+ if loadRes == Lua.OK
+ then Lua.pcall 0 1 Nothing <* Lua.gc Lua.GCCOLLECT 0
+ else return loadRes
+
+-- | Get the tag of a value. This is an optimized and specialized version of
+-- @Lua.getfield idx "tag"@. It only checks for the field on the table at index
+-- @idx@ and on its metatable, also ignoring any @__index@ value on the
+-- metatable.
+getTag :: StackIndex -> Lua String
+getTag idx = do
+ top <- Lua.gettop
+ hasMT <- Lua.getmetatable idx
+ push "tag"
+ if hasMT then Lua.rawget (-2) else Lua.rawget (idx `adjustIndexBy` 1)
+ peek Lua.stackTop `finally` Lua.settop top
diff --git a/src/Text/Pandoc/MIME.hs b/src/Text/Pandoc/MIME.hs
index a08091217..43abe9b2f 100644
--- a/src/Text/Pandoc/MIME.hs
+++ b/src/Text/Pandoc/MIME.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2011-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.MIME
- Copyright : Copyright (C) 2011-2016 John MacFarlane
+ Copyright : Copyright (C) 2011-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,11 +29,11 @@ Mime type lookup for ODT writer.
-}
module Text.Pandoc.MIME ( MimeType, getMimeType, getMimeTypeDef,
extensionFromMimeType )where
-import System.FilePath
-import Data.Char ( toLower )
+import Data.Char (toLower)
import Data.List (isPrefixOf, isSuffixOf)
-import Data.Maybe (fromMaybe)
import qualified Data.Map as M
+import Data.Maybe (fromMaybe)
+import System.FilePath
type MimeType = String
@@ -168,6 +168,7 @@ mimeTypesList = -- List borrowed from happstack-server.
,("emb","chemical/x-embl-dl-nucleotide")
,("embl","chemical/x-embl-dl-nucleotide")
,("emf","image/x-emf")
+ ,("emz","application/x-msmetafile")
,("eml","message/rfc822")
,("ent","chemical/x-ncbi-asn1-ascii")
,("eot","application/vnd.ms-fontobject")
@@ -243,7 +244,7 @@ mimeTypesList = -- List borrowed from happstack-server.
,("jpeg","image/jpeg")
,("jfif","image/jpeg")
,("jpg","image/jpeg")
- ,("js","application/x-javascript")
+ ,("js","application/javascript")
,("kar","audio/midi")
,("key","application/pgp-keys")
,("kil","application/x-killustrator")
@@ -324,6 +325,7 @@ mimeTypesList = -- List borrowed from happstack-server.
,("ogv","video/ogg")
,("ogx","application/ogg")
,("old","application/x-trash")
+ ,("opus","audio/ogg")
,("otg","application/vnd.oasis.opendocument.graphics-template")
,("oth","application/vnd.oasis.opendocument.text-web")
,("otp","application/vnd.oasis.opendocument.presentation-template")
@@ -524,4 +526,3 @@ mimeTypesList = -- List borrowed from happstack-server.
,("zip","application/zip")
,("zmt","chemical/x-mopac-input")
]
-
diff --git a/src/Text/Pandoc/MediaBag.hs b/src/Text/Pandoc/MediaBag.hs
index eea25fadf..0d060fe1a 100644
--- a/src/Text/Pandoc/MediaBag.hs
+++ b/src/Text/Pandoc/MediaBag.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
-Copyright (C) 2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2014-2015, 2017–2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.MediaBag
- Copyright : Copyright (C) 2014 John MacFarlane
+ Copyright : Copyright (C) 2014-2015, 2017–2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,20 +35,15 @@ module Text.Pandoc.MediaBag (
lookupMedia,
insertMedia,
mediaDirectory,
- extractMediaBag
) where
-import System.FilePath
-import qualified System.FilePath.Posix as Posix
-import System.Directory (createDirectoryIfMissing)
-import qualified Data.Map as M
import qualified Data.ByteString.Lazy as BL
-import Control.Monad (when)
-import Text.Pandoc.MIME (MimeType, getMimeTypeDef)
-import qualified Text.Pandoc.UTF8 as UTF8
-import Data.Maybe (fromMaybe)
-import System.IO (stderr)
import Data.Data (Data)
+import qualified Data.Map as M
+import Data.Maybe (fromMaybe)
import Data.Typeable (Typeable)
+import System.FilePath
+import qualified System.FilePath.Posix as Posix
+import Text.Pandoc.MIME (MimeType, getMimeTypeDef)
-- | A container for a collection of binary resources, with names and
-- mime types. Note that a 'MediaBag' is a Monoid, so 'mempty'
@@ -70,8 +66,8 @@ insertMedia fp mbMime contents (MediaBag mediamap) =
MediaBag (M.insert (splitDirectories fp) (mime, contents) mediamap)
where mime = fromMaybe fallback mbMime
fallback = case takeExtension fp of
- ".gz" -> getMimeTypeDef $ dropExtension fp
- _ -> getMimeTypeDef fp
+ ".gz" -> getMimeTypeDef $ dropExtension fp
+ _ -> getMimeTypeDef fp
-- | Lookup a media item in a 'MediaBag', returning mime type and contents.
lookupMedia :: FilePath
@@ -83,27 +79,5 @@ lookupMedia fp (MediaBag mediamap) = M.lookup (splitDirectories fp) mediamap
-- their corresponding mime types and the lengths in bytes of the contents.
mediaDirectory :: MediaBag -> [(String, MimeType, Int)]
mediaDirectory (MediaBag mediamap) =
- M.foldWithKey (\fp (mime,contents) ->
- (((Posix.joinPath fp), mime, fromIntegral $ BL.length contents):)) [] mediamap
-
--- | Extract contents of MediaBag to a given directory. Print informational
--- messages if 'verbose' is true.
-extractMediaBag :: Bool
- -> FilePath
- -> MediaBag
- -> IO ()
-extractMediaBag verbose dir (MediaBag mediamap) = do
- sequence_ $ M.foldWithKey
- (\fp (_ ,contents) ->
- ((writeMedia verbose dir (Posix.joinPath fp, contents)):)) [] mediamap
-
-writeMedia :: Bool -> FilePath -> (FilePath, BL.ByteString) -> IO ()
-writeMedia verbose dir (subpath, bs) = do
- -- we join and split to convert a/b/c to a\b\c on Windows;
- -- in zip containers all paths use /
- let fullpath = dir </> normalise subpath
- createDirectoryIfMissing True $ takeDirectory fullpath
- when verbose $ UTF8.hPutStrLn stderr $ "pandoc: extracting " ++ fullpath
- BL.writeFile fullpath bs
-
-
+ M.foldrWithKey (\fp (mime,contents) ->
+ ((Posix.joinPath fp, mime, fromIntegral $ BL.length contents):)) [] mediamap
diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs
index 48bc5f4eb..bd4ab252b 100644
--- a/src/Text/Pandoc/Options.hs
+++ b/src/Text/Pandoc/Options.hs
@@ -1,6 +1,8 @@
-{-# LANGUAGE DeriveDataTypeable, DeriveGeneric #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TemplateHaskell #-}
{-
-Copyright (C) 2012-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Options
- Copyright : Copyright (C) 2012-2016 John MacFarlane
+ Copyright : Copyright (C) 2012-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,13 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Data structures and functions for representing parser and writer
options.
-}
-module Text.Pandoc.Options ( Extension(..)
- , pandocExtensions
- , plainExtensions
- , strictExtensions
- , phpMarkdownExtraExtensions
- , githubMarkdownExtensions
- , multimarkdownExtensions
+module Text.Pandoc.Options ( module Text.Pandoc.Extensions
, ReaderOptions(..)
, HTMLMathMethod (..)
, CiteMethod (..)
@@ -50,248 +46,57 @@ module Text.Pandoc.Options ( Extension(..)
, def
, isEnabled
) where
-import Data.Set (Set)
-import qualified Data.Set as Set
-import Data.Default
-import Text.Pandoc.Highlighting (Style, pygments)
-import Text.Pandoc.MediaBag (MediaBag)
+import Data.Aeson (defaultOptions)
+import Data.Aeson.TH (deriveJSON)
import Data.Data (Data)
+import Data.Default
+import qualified Data.Set as Set
import Data.Typeable (Typeable)
import GHC.Generics (Generic)
+import Skylighting (SyntaxMap, defaultSyntaxMap)
+import Text.Pandoc.Extensions
+import Text.Pandoc.Highlighting (Style, pygments)
--- | Individually selectable syntax extensions.
-data Extension =
- Ext_footnotes -- ^ Pandoc/PHP/MMD style footnotes
- | Ext_inline_notes -- ^ Pandoc-style inline notes
- | Ext_pandoc_title_block -- ^ Pandoc title block
- | Ext_yaml_metadata_block -- ^ YAML metadata block
- | Ext_mmd_title_block -- ^ Multimarkdown metadata block
- | Ext_table_captions -- ^ Pandoc-style table captions
- | Ext_implicit_figures -- ^ A paragraph with just an image is a figure
- | Ext_simple_tables -- ^ Pandoc-style simple tables
- | Ext_multiline_tables -- ^ Pandoc-style multiline tables
- | Ext_grid_tables -- ^ Grid tables (pandoc, reST)
- | Ext_pipe_tables -- ^ Pipe tables (as in PHP markdown extra)
- | Ext_citations -- ^ Pandoc/citeproc citations
- | Ext_raw_tex -- ^ Allow raw TeX (other than math)
- | Ext_raw_html -- ^ Allow raw HTML
- | Ext_tex_math_dollars -- ^ TeX math between $..$ or $$..$$
- | Ext_tex_math_single_backslash -- ^ TeX math btw \(..\) \[..\]
- | Ext_tex_math_double_backslash -- ^ TeX math btw \\(..\\) \\[..\\]
- | Ext_latex_macros -- ^ Parse LaTeX macro definitions (for math only)
- | Ext_fenced_code_blocks -- ^ Parse fenced code blocks
- | Ext_fenced_code_attributes -- ^ Allow attributes on fenced code blocks
- | Ext_backtick_code_blocks -- ^ GitHub style ``` code blocks
- | Ext_inline_code_attributes -- ^ Allow attributes on inline code
- | Ext_markdown_in_html_blocks -- ^ Interpret as markdown inside HTML blocks
- | Ext_native_divs -- ^ Use Div blocks for contents of <div> tags
- | Ext_native_spans -- ^ Use Span inlines for contents of <span>
- | Ext_bracketed_spans -- ^ Bracketed spans with attributes
- | Ext_markdown_attribute -- ^ Interpret text inside HTML as markdown
- -- iff container has attribute 'markdown'
- | Ext_escaped_line_breaks -- ^ Treat a backslash at EOL as linebreak
- | Ext_link_attributes -- ^ link and image attributes
- | Ext_mmd_link_attributes -- ^ MMD style reference link attributes
- | Ext_autolink_bare_uris -- ^ Make all absolute URIs into links
- | Ext_fancy_lists -- ^ Enable fancy list numbers and delimiters
- | Ext_lists_without_preceding_blankline -- ^ Allow lists without preceding blank
- | Ext_startnum -- ^ Make start number of ordered list significant
- | Ext_definition_lists -- ^ Definition lists as in pandoc, mmd, php
- | Ext_compact_definition_lists -- ^ Definition lists without
- -- space between items, and disallow laziness
- | Ext_example_lists -- ^ Markdown-style numbered examples
- | Ext_all_symbols_escapable -- ^ Make all non-alphanumerics escapable
- | Ext_angle_brackets_escapable -- ^ Make < and > escapable
- | Ext_intraword_underscores -- ^ Treat underscore inside word as literal
- | Ext_blank_before_blockquote -- ^ Require blank line before a blockquote
- | Ext_blank_before_header -- ^ Require blank line before a header
- | Ext_strikeout -- ^ Strikeout using ~~this~~ syntax
- | Ext_superscript -- ^ Superscript using ^this^ syntax
- | Ext_subscript -- ^ Subscript using ~this~ syntax
- | Ext_hard_line_breaks -- ^ All newlines become hard line breaks
- | Ext_ignore_line_breaks -- ^ Newlines in paragraphs are ignored
- | Ext_east_asian_line_breaks -- ^ Newlines in paragraphs are ignored between
- -- East Asian wide characters
- | Ext_literate_haskell -- ^ Enable literate Haskell conventions
- | Ext_abbreviations -- ^ PHP markdown extra abbreviation definitions
- | Ext_emoji -- ^ Support emoji like :smile:
- | Ext_auto_identifiers -- ^ Automatic identifiers for headers
- | Ext_ascii_identifiers -- ^ ascii-only identifiers for headers
- | Ext_header_attributes -- ^ Explicit header attributes {#id .class k=v}
- | Ext_mmd_header_identifiers -- ^ Multimarkdown style header identifiers [myid]
- | Ext_implicit_header_references -- ^ Implicit reference links for headers
- | Ext_line_blocks -- ^ RST style line blocks
- | Ext_epub_html_exts -- ^ Recognise the EPUB extended version of HTML
- | Ext_shortcut_reference_links -- ^ Shortcut reference links
- deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic)
-
-pandocExtensions :: Set Extension
-pandocExtensions = Set.fromList
- [ Ext_footnotes
- , Ext_inline_notes
- , Ext_pandoc_title_block
- , Ext_yaml_metadata_block
- , Ext_table_captions
- , Ext_implicit_figures
- , Ext_simple_tables
- , Ext_multiline_tables
- , Ext_grid_tables
- , Ext_pipe_tables
- , Ext_citations
- , Ext_raw_tex
- , Ext_raw_html
- , Ext_tex_math_dollars
- , Ext_latex_macros
- , Ext_fenced_code_blocks
- , Ext_fenced_code_attributes
- , Ext_backtick_code_blocks
- , Ext_inline_code_attributes
- , Ext_markdown_in_html_blocks
- , Ext_native_divs
- , Ext_native_spans
- , Ext_bracketed_spans
- , Ext_escaped_line_breaks
- , Ext_fancy_lists
- , Ext_startnum
- , Ext_definition_lists
- , Ext_example_lists
- , Ext_all_symbols_escapable
- , Ext_intraword_underscores
- , Ext_blank_before_blockquote
- , Ext_blank_before_header
- , Ext_strikeout
- , Ext_superscript
- , Ext_subscript
- , Ext_auto_identifiers
- , Ext_header_attributes
- , Ext_link_attributes
- , Ext_implicit_header_references
- , Ext_line_blocks
- , Ext_shortcut_reference_links
- ]
-
-plainExtensions :: Set Extension
-plainExtensions = Set.fromList
- [ Ext_table_captions
- , Ext_implicit_figures
- , Ext_simple_tables
- , Ext_multiline_tables
- , Ext_grid_tables
- , Ext_latex_macros
- , Ext_fancy_lists
- , Ext_startnum
- , Ext_definition_lists
- , Ext_example_lists
- , Ext_intraword_underscores
- , Ext_blank_before_blockquote
- , Ext_blank_before_header
- , Ext_strikeout
- ]
-
-phpMarkdownExtraExtensions :: Set Extension
-phpMarkdownExtraExtensions = Set.fromList
- [ Ext_footnotes
- , Ext_pipe_tables
- , Ext_raw_html
- , Ext_markdown_attribute
- , Ext_fenced_code_blocks
- , Ext_definition_lists
- , Ext_intraword_underscores
- , Ext_header_attributes
- , Ext_link_attributes
- , Ext_abbreviations
- , Ext_shortcut_reference_links
- ]
-
-githubMarkdownExtensions :: Set Extension
-githubMarkdownExtensions = Set.fromList
- [ Ext_angle_brackets_escapable
- , Ext_pipe_tables
- , Ext_raw_html
- , Ext_fenced_code_blocks
- , Ext_auto_identifiers
- , Ext_ascii_identifiers
- , Ext_backtick_code_blocks
- , Ext_autolink_bare_uris
- , Ext_intraword_underscores
- , Ext_strikeout
- , Ext_hard_line_breaks
- , Ext_emoji
- , Ext_lists_without_preceding_blankline
- , Ext_shortcut_reference_links
- ]
-
-multimarkdownExtensions :: Set Extension
-multimarkdownExtensions = Set.fromList
- [ Ext_pipe_tables
- , Ext_raw_html
- , Ext_markdown_attribute
- , Ext_mmd_link_attributes
- -- , Ext_raw_tex
- -- Note: MMD's raw TeX syntax requires raw TeX to be
- -- enclosed in HTML comment
- , Ext_tex_math_double_backslash
- , Ext_intraword_underscores
- , Ext_mmd_title_block
- , Ext_footnotes
- , Ext_definition_lists
- , Ext_all_symbols_escapable
- , Ext_implicit_header_references
- , Ext_auto_identifiers
- , Ext_mmd_header_identifiers
- , Ext_implicit_figures
- -- Note: MMD's syntax for superscripts and subscripts
- -- is a bit more permissive than pandoc's, allowing
- -- e^2 and a~1 instead of e^2^ and a~1~, so even with
- -- these options we don't have full support for MMD
- -- superscripts and subscripts, but there's no reason
- -- not to include these:
- , Ext_superscript
- , Ext_subscript
- ]
-
-strictExtensions :: Set Extension
-strictExtensions = Set.fromList
- [ Ext_raw_html
- , Ext_shortcut_reference_links
- ]
+class HasSyntaxExtensions a where
+ getExtensions :: a -> Extensions
data ReaderOptions = ReaderOptions{
- readerExtensions :: Set Extension -- ^ Syntax extensions
- , readerSmart :: Bool -- ^ Smart punctuation
- , readerStandalone :: Bool -- ^ Standalone document with header
- , readerParseRaw :: Bool -- ^ Parse raw HTML, LaTeX
- , readerColumns :: Int -- ^ Number of columns in terminal
- , readerTabStop :: Int -- ^ Tab stop
- , readerOldDashes :: Bool -- ^ Use pandoc <= 1.8.2.1 behavior
- -- in parsing dashes; -- is em-dash;
- -- - before numerial is en-dash
- , readerApplyMacros :: Bool -- ^ Apply macros to TeX math
- , readerIndentedCodeClasses :: [String] -- ^ Default classes for
+ readerExtensions :: Extensions -- ^ Syntax extensions
+ , readerStandalone :: Bool -- ^ Standalone document with header
+ , readerColumns :: Int -- ^ Number of columns in terminal
+ , readerTabStop :: Int -- ^ Tab stop
+ , readerIndentedCodeClasses :: [String] -- ^ Default classes for
-- indented code blocks
+ , readerAbbreviations :: Set.Set String -- ^ Strings to treat as abbreviations
, readerDefaultImageExtension :: String -- ^ Default extension for images
- , readerTrace :: Bool -- ^ Print debugging info
- , readerTrackChanges :: TrackChanges
- , readerFileScope :: Bool -- ^ Parse before combining
+ , readerTrackChanges :: TrackChanges -- ^ Track changes setting for docx
+ , readerStripComments :: Bool -- ^ Strip HTML comments instead of parsing as raw HTML
} deriving (Show, Read, Data, Typeable, Generic)
+instance HasSyntaxExtensions ReaderOptions where
+ getExtensions opts = readerExtensions opts
+
instance Default ReaderOptions
where def = ReaderOptions{
- readerExtensions = pandocExtensions
- , readerSmart = False
+ readerExtensions = emptyExtensions
, readerStandalone = False
- , readerParseRaw = False
, readerColumns = 80
, readerTabStop = 4
- , readerOldDashes = False
- , readerApplyMacros = True
, readerIndentedCodeClasses = []
+ , readerAbbreviations = defaultAbbrevs
, readerDefaultImageExtension = ""
- , readerTrace = False
, readerTrackChanges = AcceptChanges
- , readerFileScope = False
+ , readerStripComments = False
}
+defaultAbbrevs :: Set.Set String
+defaultAbbrevs = Set.fromList
+ [ "Mr.", "Mrs.", "Ms.", "Capt.", "Dr.", "Prof.",
+ "Gen.", "Gov.", "e.g.", "i.e.", "Sgt.", "St.",
+ "vol.", "vs.", "Sen.", "Rep.", "Pres.", "Hon.",
+ "Rev.", "Ph.D.", "M.D.", "M.A.", "p.", "pp.",
+ "ch.", "sec.", "cf.", "cp."]
+
--
-- Writer options
--
@@ -303,9 +108,9 @@ data HTMLMathMethod = PlainMath
| JsMath (Maybe String) -- url of jsMath load script
| GladTeX
| WebTeX String -- url of TeX->image script.
- | MathML (Maybe String) -- url of MathMLinHTML.js
+ | MathML
| MathJax String -- url of MathJax.js
- | KaTeX String String -- url of stylesheet and katex.js
+ | KaTeX String -- url of KaTeX files
deriving (Show, Read, Eq, Data, Typeable, Generic)
data CiteMethod = Citeproc -- use citeproc to render them
@@ -356,51 +161,39 @@ data ReferenceLocation = EndOfBlock -- ^ End of block
-- | Options for writers
data WriterOptions = WriterOptions
- { writerTemplate :: Maybe String -- ^ Template to use
- , writerVariables :: [(String, String)] -- ^ Variables to set in template
- , writerTabStop :: Int -- ^ Tabstop for conversion btw spaces and tabs
- , writerTableOfContents :: Bool -- ^ Include table of contents
- , writerSlideVariant :: HTMLSlideVariant -- ^ Are we writing S5, Slidy or Slideous?
- , writerIncremental :: Bool -- ^ True if lists should be incremental
- , writerHTMLMathMethod :: HTMLMathMethod -- ^ How to print math in HTML
- , writerIgnoreNotes :: Bool -- ^ Ignore footnotes (used in making toc)
- , writerNumberSections :: Bool -- ^ Number sections in LaTeX
- , writerNumberOffset :: [Int] -- ^ Starting number for section, subsection, ...
- , writerSectionDivs :: Bool -- ^ Put sections in div tags in HTML
- , writerExtensions :: Set Extension -- ^ Markdown extensions that can be used
- , writerReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
- , writerDpi :: Int -- ^ Dpi for pixel to/from inch/cm conversions
- , writerWrapText :: WrapOption -- ^ Option for wrapping text
- , writerColumns :: Int -- ^ Characters in a line (for text wrapping)
- , writerEmailObfuscation :: ObfuscationMethod -- ^ How to obfuscate emails
- , writerIdentifierPrefix :: String -- ^ Prefix for section & note ids in HTML
+ { writerTemplate :: Maybe String -- ^ Template to use
+ , writerVariables :: [(String, String)] -- ^ Variables to set in template
+ , writerTabStop :: Int -- ^ Tabstop for conversion btw spaces and tabs
+ , writerTableOfContents :: Bool -- ^ Include table of contents
+ , writerIncremental :: Bool -- ^ True if lists should be incremental
+ , writerHTMLMathMethod :: HTMLMathMethod -- ^ How to print math in HTML
+ , writerNumberSections :: Bool -- ^ Number sections in LaTeX
+ , writerNumberOffset :: [Int] -- ^ Starting number for section, subsection, ...
+ , writerSectionDivs :: Bool -- ^ Put sections in div tags in HTML
+ , writerExtensions :: Extensions -- ^ Markdown extensions that can be used
+ , writerReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
+ , writerDpi :: Int -- ^ Dpi for pixel to/from inch/cm conversions
+ , writerWrapText :: WrapOption -- ^ Option for wrapping text
+ , writerColumns :: Int -- ^ Characters in a line (for text wrapping)
+ , writerEmailObfuscation :: ObfuscationMethod -- ^ How to obfuscate emails
+ , writerIdentifierPrefix :: String -- ^ Prefix for section & note ids in HTML
-- and for footnote marks in markdown
- , writerSourceURL :: Maybe String -- ^ Absolute URL + directory of 1st source file
- , writerUserDataDir :: Maybe FilePath -- ^ Path of user data directory
- , writerCiteMethod :: CiteMethod -- ^ How to print cites
- , writerDocbook5 :: Bool -- ^ Produce DocBook5
- , writerHtml5 :: Bool -- ^ Produce HTML5
- , writerHtmlQTags :: Bool -- ^ Use @<q>@ tags for quotes in HTML
- , writerBeamer :: Bool -- ^ Produce beamer LaTeX slide show
- , writerSlideLevel :: Maybe Int -- ^ Force header level of slides
- , writerTopLevelDivision :: TopLevelDivision -- ^ Type of top-level divisions
- , writerListings :: Bool -- ^ Use listings package for code
- , writerHighlight :: Bool -- ^ Highlight source code
- , writerHighlightStyle :: Style -- ^ Style to use for highlighting
- , writerSetextHeaders :: Bool -- ^ Use setext headers for levels 1-2 in markdown
- , writerTeXLigatures :: Bool -- ^ Use tex ligatures quotes, dashes in latex
- , writerEpubVersion :: Maybe EPUBVersion -- ^ Nothing or EPUB version
- , writerEpubMetadata :: String -- ^ Metadata to include in EPUB
- , writerEpubStylesheet :: Maybe String -- ^ EPUB stylesheet specified at command line
- , writerEpubFonts :: [FilePath] -- ^ Paths to fonts to embed
- , writerEpubChapterLevel :: Int -- ^ Header level for chapters (separate files)
- , writerTOCDepth :: Int -- ^ Number of levels to include in TOC
- , writerReferenceODT :: Maybe FilePath -- ^ Path to reference ODT if specified
- , writerReferenceDocx :: Maybe FilePath -- ^ Path to reference DOCX if specified
- , writerMediaBag :: MediaBag -- ^ Media collected by docx or epub reader
- , writerVerbose :: Bool -- ^ Verbose debugging output
- , writerLaTeXArgs :: [String] -- ^ Flags to pass to latex-engine
+ , writerCiteMethod :: CiteMethod -- ^ How to print cites
+ , writerHtmlQTags :: Bool -- ^ Use @<q>@ tags for quotes in HTML
+ , writerSlideLevel :: Maybe Int -- ^ Force header level of slides
+ , writerTopLevelDivision :: TopLevelDivision -- ^ Type of top-level divisions
+ , writerListings :: Bool -- ^ Use listings package for code
+ , writerHighlightStyle :: Maybe Style -- ^ Style to use for highlighting
+ -- (Nothing = no highlighting)
+ , writerSetextHeaders :: Bool -- ^ Use setext headers for levels 1-2 in markdown
+ , writerEpubSubdirectory :: String -- ^ Subdir for epub in OCF
+ , writerEpubMetadata :: Maybe String -- ^ Metadata to include in EPUB
+ , writerEpubFonts :: [FilePath] -- ^ Paths to fonts to embed
+ , writerEpubChapterLevel :: Int -- ^ Header level for chapters (separate files)
+ , writerTOCDepth :: Int -- ^ Number of levels to include in TOC
+ , writerReferenceDoc :: Maybe FilePath -- ^ Path to reference document if specified
, writerReferenceLocation :: ReferenceLocation -- ^ Location of footnotes and references for writing markdown
+ , writerSyntaxMap :: SyntaxMap
} deriving (Show, Data, Typeable, Generic)
instance Default WriterOptions where
@@ -408,48 +201,48 @@ instance Default WriterOptions where
, writerVariables = []
, writerTabStop = 4
, writerTableOfContents = False
- , writerSlideVariant = NoSlides
, writerIncremental = False
, writerHTMLMathMethod = PlainMath
- , writerIgnoreNotes = False
, writerNumberSections = False
, writerNumberOffset = [0,0,0,0,0,0]
, writerSectionDivs = False
- , writerExtensions = pandocExtensions
+ , writerExtensions = emptyExtensions
, writerReferenceLinks = False
, writerDpi = 96
, writerWrapText = WrapAuto
, writerColumns = 72
, writerEmailObfuscation = NoObfuscation
, writerIdentifierPrefix = ""
- , writerSourceURL = Nothing
- , writerUserDataDir = Nothing
, writerCiteMethod = Citeproc
- , writerDocbook5 = False
- , writerHtml5 = False
, writerHtmlQTags = False
- , writerBeamer = False
, writerSlideLevel = Nothing
, writerTopLevelDivision = TopLevelDefault
, writerListings = False
- , writerHighlight = False
- , writerHighlightStyle = pygments
+ , writerHighlightStyle = Just pygments
, writerSetextHeaders = True
- , writerTeXLigatures = True
- , writerEpubVersion = Nothing
- , writerEpubMetadata = ""
- , writerEpubStylesheet = Nothing
+ , writerEpubSubdirectory = "EPUB"
+ , writerEpubMetadata = Nothing
, writerEpubFonts = []
, writerEpubChapterLevel = 1
, writerTOCDepth = 3
- , writerReferenceODT = Nothing
- , writerReferenceDocx = Nothing
- , writerMediaBag = mempty
- , writerVerbose = False
- , writerLaTeXArgs = []
+ , writerReferenceDoc = Nothing
, writerReferenceLocation = EndOfDocument
+ , writerSyntaxMap = defaultSyntaxMap
}
+instance HasSyntaxExtensions WriterOptions where
+ getExtensions opts = writerExtensions opts
+
-- | Returns True if the given extension is enabled.
-isEnabled :: Extension -> WriterOptions -> Bool
-isEnabled ext opts = ext `Set.member` (writerExtensions opts)
+isEnabled :: HasSyntaxExtensions a => Extension -> a -> Bool
+isEnabled ext opts = ext `extensionEnabled` getExtensions opts
+
+$(deriveJSON defaultOptions ''ReaderOptions)
+$(deriveJSON defaultOptions ''HTMLMathMethod)
+$(deriveJSON defaultOptions ''CiteMethod)
+$(deriveJSON defaultOptions ''ObfuscationMethod)
+$(deriveJSON defaultOptions ''HTMLSlideVariant)
+$(deriveJSON defaultOptions ''TrackChanges)
+$(deriveJSON defaultOptions ''WrapOption)
+$(deriveJSON defaultOptions ''TopLevelDivision)
+$(deriveJSON defaultOptions ''ReferenceLocation)
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
index 9faff1816..5f41d6c55 100644
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -1,6 +1,8 @@
-{-# LANGUAGE OverloadedStrings, CPP, ScopedTypeVariables #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2012-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.PDF
- Copyright : Copyright (C) 2012-2016 John MacFarlane
+ Copyright : Copyright (C) 2012-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,49 +32,60 @@ Conversion of LaTeX documents to PDF.
-}
module Text.Pandoc.PDF ( makePDF ) where
+import qualified Codec.Picture as JP
+import qualified Control.Exception as E
+import Control.Monad (unless, when)
+import Control.Monad.Trans (MonadIO (..))
+import qualified Data.ByteString as BS
import Data.ByteString.Lazy (ByteString)
-import qualified Data.ByteString.Lazy as B
+import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BC
-import qualified Data.ByteString as BS
+import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
-import System.Exit (ExitCode (..))
-import System.FilePath
-import System.IO (stderr, stdout)
-import System.IO.Temp (withTempFile)
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Text.IO as TextIO
import System.Directory
-import Data.Digest.Pure.SHA (showDigest, sha1)
import System.Environment
-import Control.Monad (unless, when, (<=<))
-import qualified Control.Exception as E
-import Data.List (isInfixOf)
-import Data.Maybe (fromMaybe)
-import qualified Text.Pandoc.UTF8 as UTF8
+import System.Exit (ExitCode (..))
+import System.FilePath
+import System.IO (stdout)
+import System.IO.Temp (withTempDirectory, withTempFile)
+#if MIN_VERSION_base(4,8,3)
+import System.IO.Error (IOError, isDoesNotExistError)
+#else
+import System.IO.Error (isDoesNotExistError)
+#endif
import Text.Pandoc.Definition
+import Text.Pandoc.Error (PandocError (PandocPDFProgramNotFoundError))
+import Text.Pandoc.MIME (getMimeType)
+import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..))
+import Text.Pandoc.Process (pipeProcess)
+import Text.Pandoc.Shared (inDirectory, stringify, withTempDir)
+import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Walk (walkM)
-import Text.Pandoc.Shared (fetchItem', warn, withTempDir, inDirectory,
- stringify)
import Text.Pandoc.Writers.Shared (getField, metaToJSON)
-import Text.Pandoc.Options (WriterOptions(..), HTMLMathMethod(..))
-import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
-import Text.Pandoc.Process (pipeProcess)
-import qualified Data.ByteString.Lazy as BL
-import qualified Codec.Picture as JP
#ifdef _WINDOWS
import Data.List (intercalate)
#endif
+import Text.Pandoc.Class (PandocIO, extractMedia, fillMediaBag, getCommonState,
+ getVerbosity, putCommonState, report, runIO,
+ runIOorExplode, setVerbosity)
+import Text.Pandoc.Logging
#ifdef _WINDOWS
changePathSeparators :: FilePath -> FilePath
changePathSeparators = intercalate "/" . splitDirectories
#endif
-makePDF :: String -- ^ pdf creator (pdflatex, lualatex,
- -- xelatex, context, wkhtmltopdf)
- -> (WriterOptions -> Pandoc -> String) -- ^ writer
+makePDF :: String -- ^ pdf creator (pdflatex, lualatex, xelatex,
+ -- wkhtmltopdf, weasyprint, prince, context, pdfroff)
+ -> [String] -- ^ arguments to pass to pdf creator
+ -> (WriterOptions -> Pandoc -> PandocIO Text) -- ^ writer
-> WriterOptions -- ^ options
-> Pandoc -- ^ document
- -> IO (Either ByteString ByteString)
-makePDF "wkhtmltopdf" writer opts doc@(Pandoc meta _) = do
+ -> PandocIO (Either ByteString ByteString)
+makePDF "wkhtmltopdf" pdfargs writer opts doc@(Pandoc meta _) = do
let mathArgs = case writerHTMLMathMethod opts of
-- with MathJax, wait til all math is rendered:
MathJax _ -> ["--run-script", "MathJax.Hub.Register.StartupHook('End Typeset', function() { window.status = 'mathjax_loaded' });",
@@ -80,8 +93,7 @@ makePDF "wkhtmltopdf" writer opts doc@(Pandoc meta _) = do
_ -> []
meta' <- metaToJSON opts (return . stringify) (return . stringify) meta
let toArgs (f, mbd) = maybe [] (\d -> ['-':'-':f, d]) mbd
- let args = mathArgs ++
- concatMap toArgs
+ let args = pdfargs ++ mathArgs ++ concatMap toArgs
[("page-size", getField "papersize" meta')
,("title", getField "title" meta')
,("margin-bottom", fromMaybe (Just "1.2in")
@@ -92,55 +104,61 @@ makePDF "wkhtmltopdf" writer opts doc@(Pandoc meta _) = do
(getField "margin-right" meta'))
,("margin-left", fromMaybe (Just "1.25in")
(getField "margin-left" meta'))
+ ,("footer-html", fromMaybe Nothing
+ (getField "footer-html" meta'))
+ ,("header-html", fromMaybe Nothing
+ (getField "header-html" meta'))
]
- let source = writer opts doc
- html2pdf (writerVerbose opts) args source
-makePDF program writer opts doc = withTempDir "tex2pdf." $ \tmpdir -> do
- doc' <- handleImages opts tmpdir doc
- let source = writer opts doc'
- args = writerLaTeXArgs opts
- case takeBaseName program of
- "context" -> context2pdf (writerVerbose opts) tmpdir source
- prog | prog `elem` ["pdflatex", "lualatex", "xelatex"]
- -> tex2pdf' (writerVerbose opts) args tmpdir program source
- _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program
+ source <- writer opts doc
+ verbosity <- getVerbosity
+ liftIO $ html2pdf verbosity "wkhtmltopdf" args source
+makePDF "weasyprint" pdfargs writer opts doc = do
+ source <- writer opts doc
+ verbosity <- getVerbosity
+ liftIO $ html2pdf verbosity "weasyprint" pdfargs source
+makePDF "prince" pdfargs writer opts doc = do
+ source <- writer opts doc
+ verbosity <- getVerbosity
+ liftIO $ html2pdf verbosity "prince" pdfargs source
+makePDF "pdfroff" pdfargs writer opts doc = do
+ source <- writer opts doc
+ let args = ["-ms", "-mpdfmark", "-e", "-t", "-k", "-KUTF-8", "-i",
+ "--no-toc-relocation"] ++ pdfargs
+ verbosity <- getVerbosity
+ liftIO $ ms2pdf verbosity args source
+makePDF program pdfargs writer opts doc = do
+ let withTemp = if takeBaseName program == "context"
+ then withTempDirectory "."
+ else withTempDir
+ commonState <- getCommonState
+ verbosity <- getVerbosity
+ liftIO $ withTemp "tex2pdf." $ \tmpdir -> do
+ source <- runIOorExplode $ do
+ putCommonState commonState
+ doc' <- handleImages tmpdir doc
+ writer opts doc'
+ case takeBaseName program of
+ "context" -> context2pdf verbosity tmpdir source
+ prog | prog `elem` ["pdflatex", "lualatex", "xelatex"]
+ -> tex2pdf' verbosity pdfargs tmpdir program source
+ _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program
-handleImages :: WriterOptions
- -> FilePath -- ^ temp dir to store images
+handleImages :: FilePath -- ^ temp dir to store images
-> Pandoc -- ^ document
- -> IO Pandoc
-handleImages opts tmpdir = walkM (convertImages tmpdir) <=< walkM (handleImage' opts tmpdir)
-
-handleImage' :: WriterOptions
- -> FilePath
- -> Inline
- -> IO Inline
-handleImage' opts tmpdir (Image attr ils (src,tit)) = do
- exists <- doesFileExist src
- if exists
- then return $ Image attr ils (src,tit)
- else do
- res <- fetchItem' (writerMediaBag opts) (writerSourceURL opts) src
- case res of
- Right (contents, Just mime) -> do
- let ext = fromMaybe (takeExtension src) $
- extensionFromMimeType mime
- let basename = showDigest $ sha1 $ BL.fromChunks [contents]
- let fname = tmpdir </> basename <.> ext
- BS.writeFile fname contents
- return $ Image attr ils (fname,tit)
- _ -> do
- warn $ "Could not find image `" ++ src ++ "', skipping..."
- -- return alt text
- return $ Emph ils
-handleImage' _ _ x = return x
+ -> PandocIO Pandoc
+handleImages tmpdir doc =
+ fillMediaBag doc >>=
+ extractMedia tmpdir >>=
+ walkM (convertImages tmpdir)
-convertImages :: FilePath -> Inline -> IO Inline
+convertImages :: FilePath -> Inline -> PandocIO Inline
convertImages tmpdir (Image attr ils (src, tit)) = do
- img <- convertImage tmpdir src
+ img <- liftIO $ convertImage tmpdir src
newPath <-
case img of
- Left e -> src <$ warn e
+ Left e -> do
+ report $ CouldNotConvertImage src e
+ return src
Right fp -> return fp
return (Image attr ils (newPath, tit))
convertImages _ x = return x
@@ -152,29 +170,43 @@ convertImage tmpdir fname =
Just "image/png" -> doNothing
Just "image/jpeg" -> doNothing
Just "application/pdf" -> doNothing
+ Just "image/svg+xml" -> E.catch (do
+ (exit, _) <- pipeProcess Nothing "rsvg-convert"
+ ["-f","pdf","-a","-o",pdfOut,fname] BL.empty
+ if exit == ExitSuccess
+ then return $ Right pdfOut
+ else return $ Left "conversion from SVG failed")
+ (\(e :: E.SomeException) -> return $ Left $
+ "check that rsvg2pdf is in path.\n" ++
+ show e)
_ -> JP.readImage fname >>= \res ->
case res of
- Left _ -> return $ Left $ "Unable to convert `" ++
- fname ++ "' for use with pdflatex."
+ Left e -> return $ Left e
Right img ->
- E.catch (Right fileOut <$ JP.savePngImage fileOut img) $
+ E.catch (Right pngOut <$ JP.savePngImage pngOut img) $
\(e :: E.SomeException) -> return (Left (show e))
where
- fileOut = replaceDirectory (replaceExtension fname ".png") tmpdir
+ pngOut = replaceDirectory (replaceExtension fname ".png") tmpdir
+ pdfOut = replaceDirectory (replaceExtension fname ".pdf") tmpdir
mime = getMimeType fname
doNothing = return (Right fname)
-tex2pdf' :: Bool -- ^ Verbose output
+tex2pdf' :: Verbosity -- ^ Verbosity level
-> [String] -- ^ Arguments to the latex-engine
-> FilePath -- ^ temp directory for output
-> String -- ^ tex program
- -> String -- ^ tex source
+ -> Text -- ^ tex source
-> IO (Either ByteString ByteString)
-tex2pdf' verbose args tmpDir program source = do
- let numruns = if "\\tableofcontents" `isInfixOf` source
+tex2pdf' verbosity args tmpDir program source = do
+ let numruns = if "\\tableofcontents" `T.isInfixOf` source
then 3 -- to get page numbers
else 2 -- 1 run won't give you PDF bookmarks
- (exit, log', mbPdf) <- runTeXProgram verbose program args 1 numruns tmpDir source
+ (exit, log', mbPdf) <- E.catch
+ (runTeXProgram verbosity program args 1 numruns tmpDir source)
+ (\(e :: IOError) -> if isDoesNotExistError e
+ then E.throwIO $
+ PandocPDFProgramNotFoundError program
+ else E.throwIO e)
case (exit, mbPdf) of
(ExitFailure _, _) -> do
let logmsg = extractMsg log'
@@ -182,11 +214,26 @@ tex2pdf' verbose args tmpDir program source = do
case logmsg of
x | "! Package inputenc Error" `BC.isPrefixOf` x
&& program /= "xelatex"
- -> "\nTry running pandoc with --latex-engine=xelatex."
+ -> "\nTry running pandoc with --pdf-engine=xelatex."
_ -> ""
return $ Left $ logmsg <> extramsg
(ExitSuccess, Nothing) -> return $ Left ""
- (ExitSuccess, Just pdf) -> return $ Right pdf
+ (ExitSuccess, Just pdf) -> do
+ missingCharacterWarnings verbosity log'
+ return $ Right pdf
+
+missingCharacterWarnings :: Verbosity -> ByteString -> IO ()
+missingCharacterWarnings verbosity log' = do
+ let ls = BC.lines log'
+ let isMissingCharacterWarning = BC.isPrefixOf "Missing character: "
+ let warnings = [ UTF8.toStringLazy (BC.drop 19 l)
+ | l <- ls
+ , isMissingCharacterWarning l
+ ]
+ runIO $ do
+ setVerbosity verbosity
+ mapM_ (report . MissingCharacter) warnings
+ return ()
-- parsing output
@@ -212,12 +259,12 @@ extractConTeXtMsg log' = do
-- Run a TeX program on an input bytestring and return (exit code,
-- contents of stdout, contents of produced PDF if any). Rerun
-- a fixed number of times to resolve references.
-runTeXProgram :: Bool -> String -> [String] -> Int -> Int -> FilePath -> String
- -> IO (ExitCode, ByteString, Maybe ByteString)
-runTeXProgram verbose program args runNumber numRuns tmpDir source = do
+runTeXProgram :: Verbosity -> String -> [String] -> Int -> Int -> FilePath
+ -> Text -> IO (ExitCode, ByteString, Maybe ByteString)
+runTeXProgram verbosity program args runNumber numRuns tmpDir source = do
let file = tmpDir </> "input.tex"
exists <- doesFileExist file
- unless exists $ UTF8.writeFile file source
+ unless exists $ BS.writeFile file $ UTF8.fromText source
#ifdef _WINDOWS
-- note: we want / even on Windows, for TexLive
let tmpDir' = changePathSeparators tmpDir
@@ -234,7 +281,7 @@ runTeXProgram verbose program args runNumber numRuns tmpDir source = do
$ lookup "TEXINPUTS" env'
let env'' = ("TEXINPUTS", texinputs) :
[(k,v) | (k,v) <- env', k /= "TEXINPUTS"]
- when (verbose && runNumber == 1) $ do
+ when (verbosity >= INFO && runNumber == 1) $ do
putStrLn "[makePDF] temp dir:"
putStrLn tmpDir'
putStrLn "[makePDF] Command line:"
@@ -244,16 +291,15 @@ runTeXProgram verbose program args runNumber numRuns tmpDir source = do
mapM_ print env''
putStr "\n"
putStrLn $ "[makePDF] Contents of " ++ file' ++ ":"
- B.readFile file' >>= B.putStr
+ BL.readFile file' >>= BL.putStr
putStr "\n"
- (exit, out, err) <- pipeProcess (Just env'') program programArgs BL.empty
- when verbose $ do
+ (exit, out) <- pipeProcess (Just env'') program programArgs BL.empty
+ when (verbosity >= INFO) $ do
putStrLn $ "[makePDF] Run #" ++ show runNumber
- B.hPutStr stdout out
- B.hPutStr stderr err
+ BL.hPutStr stdout out
putStr "\n"
if runNumber <= numRuns
- then runTeXProgram verbose program args (runNumber + 1) numRuns tmpDir source
+ then runTeXProgram verbosity program args (runNumber + 1) numRuns tmpDir source
else do
let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
pdfExists <- doesFileExist pdfFile
@@ -261,36 +307,75 @@ runTeXProgram verbose program args runNumber numRuns tmpDir source = do
-- We read PDF as a strict bytestring to make sure that the
-- temp directory is removed on Windows.
-- See https://github.com/jgm/pandoc/issues/1192.
- then (Just . B.fromChunks . (:[])) `fmap` BS.readFile pdfFile
+ then (Just . BL.fromChunks . (:[])) `fmap` BS.readFile pdfFile
else return Nothing
- return (exit, out <> err, pdf)
+ -- Note that some things like Missing character warnings
+ -- appear in the log but not on stderr, so we prefer the log:
+ let logFile = replaceExtension file ".log"
+ logExists <- doesFileExist logFile
+ log' <- if logExists
+ then BL.readFile logFile
+ else return out
+ return (exit, log', pdf)
+
+ms2pdf :: Verbosity
+ -> [String]
+ -> Text
+ -> IO (Either ByteString ByteString)
+ms2pdf verbosity args source = do
+ env' <- getEnvironment
+ when (verbosity >= INFO) $ do
+ putStrLn "[makePDF] Command line:"
+ putStrLn $ "pdfroff " ++ " " ++ unwords (map show args)
+ putStr "\n"
+ putStrLn "[makePDF] Environment:"
+ mapM_ print env'
+ putStr "\n"
+ putStrLn "[makePDF] Contents:\n"
+ putStr $ T.unpack source
+ putStr "\n"
+ (exit, out) <- E.catch
+ (pipeProcess (Just env') "pdfroff" args
+ (BL.fromStrict $ UTF8.fromText source))
+ (\(e :: IOError) -> if isDoesNotExistError e
+ then E.throwIO $
+ PandocPDFProgramNotFoundError "pdfroff"
+ else E.throwIO e)
+ when (verbosity >= INFO) $ do
+ BL.hPutStr stdout out
+ putStr "\n"
+ return $ case exit of
+ ExitFailure _ -> Left out
+ ExitSuccess -> Right out
-html2pdf :: Bool -- ^ Verbose output
- -> [String] -- ^ Args to wkhtmltopdf
- -> String -- ^ HTML5 source
+html2pdf :: Verbosity -- ^ Verbosity level
+ -> String -- ^ Program (wkhtmltopdf, weasyprint or prince)
+ -> [String] -- ^ Args to program
+ -> Text -- ^ HTML5 source
-> IO (Either ByteString ByteString)
-html2pdf verbose args source = do
- file <- withTempFile "." "html2pdf.html" $ \fp _ -> return fp
+html2pdf verbosity program args source = do
pdfFile <- withTempFile "." "html2pdf.pdf" $ \fp _ -> return fp
- UTF8.writeFile file source
- let programArgs = args ++ [file, pdfFile]
+ let pdfFileArgName = ["-o" | program == "prince"]
+ let programArgs = args ++ ["-"] ++ pdfFileArgName ++ [pdfFile]
env' <- getEnvironment
- when verbose $ do
+ when (verbosity >= INFO) $ do
putStrLn "[makePDF] Command line:"
- putStrLn $ "wkhtmltopdf" ++ " " ++ unwords (map show programArgs)
+ putStrLn $ program ++ " " ++ unwords (map show programArgs)
putStr "\n"
putStrLn "[makePDF] Environment:"
mapM_ print env'
putStr "\n"
- putStrLn $ "[makePDF] Contents of " ++ file ++ ":"
- B.readFile file >>= B.putStr
+ putStrLn "[makePDF] Contents of intermediate HTML:"
+ TextIO.putStr source
putStr "\n"
- (exit, out, err) <- pipeProcess (Just env') "wkhtmltopdf"
- programArgs BL.empty
- removeFile file
- when verbose $ do
- B.hPutStr stdout out
- B.hPutStr stderr err
+ (exit, out) <- E.catch
+ (pipeProcess (Just env') program programArgs $ BL.fromStrict $ UTF8.fromText source)
+ (\(e :: IOError) -> if isDoesNotExistError e
+ then E.throwIO $
+ PandocPDFProgramNotFoundError program
+ else E.throwIO e)
+ when (verbosity >= INFO) $ do
+ BL.hPutStr stdout out
putStr "\n"
pdfExists <- doesFileExist pdfFile
mbPdf <- if pdfExists
@@ -298,23 +383,22 @@ html2pdf verbose args source = do
-- temp directory is removed on Windows.
-- See https://github.com/jgm/pandoc/issues/1192.
then do
- res <- (Just . B.fromChunks . (:[])) `fmap` BS.readFile pdfFile
+ res <- (Just . BL.fromChunks . (:[])) `fmap` BS.readFile pdfFile
removeFile pdfFile
return res
else return Nothing
- let log' = out <> err
return $ case (exit, mbPdf) of
- (ExitFailure _, _) -> Left log'
+ (ExitFailure _, _) -> Left out
(ExitSuccess, Nothing) -> Left ""
(ExitSuccess, Just pdf) -> Right pdf
-context2pdf :: Bool -- ^ Verbose output
+context2pdf :: Verbosity -- ^ Verbosity level
-> FilePath -- ^ temp directory for output
- -> String -- ^ ConTeXt source
+ -> Text -- ^ ConTeXt source
-> IO (Either ByteString ByteString)
-context2pdf verbose tmpDir source = inDirectory tmpDir $ do
+context2pdf verbosity tmpDir source = inDirectory tmpDir $ do
let file = "input.tex"
- UTF8.writeFile file source
+ BS.writeFile file $ UTF8.fromText source
#ifdef _WINDOWS
-- note: we want / even on Windows, for TexLive
let tmpDir' = changePathSeparators tmpDir
@@ -323,27 +407,26 @@ context2pdf verbose tmpDir source = inDirectory tmpDir $ do
#endif
let programArgs = "--batchmode" : [file]
env' <- getEnvironment
- let sep = [searchPathSeparator]
- let texinputs = maybe (".." ++ sep) ((".." ++ sep) ++)
- $ lookup "TEXINPUTS" env'
- let env'' = ("TEXINPUTS", texinputs) :
- [(k,v) | (k,v) <- env', k /= "TEXINPUTS"]
- when verbose $ do
+ when (verbosity >= INFO) $ do
putStrLn "[makePDF] temp dir:"
putStrLn tmpDir'
putStrLn "[makePDF] Command line:"
putStrLn $ "context" ++ " " ++ unwords (map show programArgs)
putStr "\n"
putStrLn "[makePDF] Environment:"
- mapM_ print env''
+ mapM_ print env'
putStr "\n"
putStrLn $ "[makePDF] Contents of " ++ file ++ ":"
- B.readFile file >>= B.putStr
+ BL.readFile file >>= BL.putStr
putStr "\n"
- (exit, out, err) <- pipeProcess (Just env'') "context" programArgs BL.empty
- when verbose $ do
- B.hPutStr stdout out
- B.hPutStr stderr err
+ (exit, out) <- E.catch
+ (pipeProcess (Just env') "context" programArgs BL.empty)
+ (\(e :: IOError) -> if isDoesNotExistError e
+ then E.throwIO $
+ PandocPDFProgramNotFoundError "context"
+ else E.throwIO e)
+ when (verbosity >= INFO) $ do
+ BL.hPutStr stdout out
putStr "\n"
let pdfFile = replaceExtension file ".pdf"
pdfExists <- doesFileExist pdfFile
@@ -351,13 +434,11 @@ context2pdf verbose tmpDir source = inDirectory tmpDir $ do
-- We read PDF as a strict bytestring to make sure that the
-- temp directory is removed on Windows.
-- See https://github.com/jgm/pandoc/issues/1192.
- then (Just . B.fromChunks . (:[])) `fmap` BS.readFile pdfFile
+ then (Just . BL.fromChunks . (:[])) `fmap` BS.readFile pdfFile
else return Nothing
- let log' = out <> err
case (exit, mbPdf) of
(ExitFailure _, _) -> do
- let logmsg = extractConTeXtMsg log'
+ let logmsg = extractConTeXtMsg out
return $ Left logmsg
(ExitSuccess, Nothing) -> return $ Left ""
(ExitSuccess, Just pdf) -> return $ Right pdf
-
diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs
index 110e34c6a..82abcb440 100644
--- a/src/Text/Pandoc/Parsing.hs
+++ b/src/Text/Pandoc/Parsing.hs
@@ -1,11 +1,12 @@
-{-# LANGUAGE
- FlexibleContexts
-, GeneralizedNewtypeDeriving
-, TypeSynonymInstances
-, MultiParamTypeClasses
-, FlexibleInstances #-}
+{-# LANGUAGE ExplicitForAll #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE IncoherentInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeSynonymInstances #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Parsing
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -33,8 +34,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
A utility library with parsers used in pandoc readers.
-}
-module Text.Pandoc.Parsing ( anyLine,
+module Text.Pandoc.Parsing ( takeWhileP,
+ takeP,
+ anyLine,
+ anyLineNewline,
+ indentWith,
many1Till,
+ manyUntil,
+ sepBy1',
notFollowedBy',
oneOfStrings,
oneOfStringsCI,
@@ -43,9 +50,12 @@ module Text.Pandoc.Parsing ( anyLine,
skipSpaces,
blankline,
blanklines,
+ gobbleSpaces,
+ gobbleAtMostSpaces,
enclosed,
stringAnyCase,
parseFromString,
+ parseFromString',
lineClump,
charsInBalanced,
romanNumeral,
@@ -57,6 +67,11 @@ module Text.Pandoc.Parsing ( anyLine,
withRaw,
escaped,
characterReference,
+ upperRoman,
+ lowerRoman,
+ decimal,
+ lowerAlpha,
+ upperAlpha,
anyOrderedListMarker,
orderedListMarker,
charRef,
@@ -64,20 +79,24 @@ module Text.Pandoc.Parsing ( anyLine,
tableWith,
widthsFromIndices,
gridTableWith,
+ gridTableWith',
readWith,
- readWithWarnings,
readWithM,
testStringWith,
guardEnabled,
guardDisabled,
updateLastStrPos,
notAfterString,
+ logMessage,
+ reportLogMessages,
ParserState (..),
HasReaderOptions (..),
HasHeaderMap (..),
HasIdentifierList (..),
HasMacros (..),
+ HasLogMessages (..),
HasLastStrPosition (..),
+ HasIncludeFiles (..),
defaultParserState,
HeaderType (..),
ParserContext (..),
@@ -100,20 +119,26 @@ module Text.Pandoc.Parsing ( anyLine,
dash,
nested,
citeKey,
- macro,
- applyMacros',
Parser,
ParserT,
- F(..),
+ F,
+ Future(..),
runF,
askF,
asksF,
+ returnF,
+ trimInlinesF,
token,
+ (<+?>),
+ extractIdClass,
+ insertIncludedFile,
+ insertIncludedFileF,
-- * Re-exports from Text.Pandoc.Parsec
Stream,
runParser,
runParserT,
parse,
+ tokenPrim,
anyToken,
getInput,
setInput,
@@ -162,61 +187,106 @@ module Text.Pandoc.Parsing ( anyLine,
sourceLine,
setSourceColumn,
setSourceLine,
+ incSourceColumn,
newPos,
- addWarning,
- (<+?>),
- extractIdClass
+ Line,
+ Column
)
where
+import Control.Monad.Identity
+import Control.Monad.Reader
+import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper, isHexDigit,
+ isPunctuation, isSpace, ord, toLower, toUpper)
+import Data.Default
+import Data.List (intercalate, isSuffixOf, transpose)
+import qualified Data.Map as M
+import Data.Maybe (mapMaybe, fromMaybe)
+import Data.Monoid ((<>))
+import qualified Data.Set as Set
+import Data.Text (Text)
+import Text.HTML.TagSoup.Entity (lookupEntity)
+import Text.Pandoc.Asciify (toAsciiChar)
+import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad, readFileFromDirs, report)
import Text.Pandoc.Definition
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Builder (Blocks, Inlines, rawBlock, HasMeta(..))
-import qualified Text.Pandoc.Builder as B
-import Text.Pandoc.XML (fromEntities)
+import Text.Pandoc.Readers.LaTeX.Types (Macro)
+import Text.Pandoc.Shared
import qualified Text.Pandoc.UTF8 as UTF8 (putStrLn)
+import Text.Pandoc.XML (fromEntities)
import Text.Parsec hiding (token)
-import Text.Parsec.Pos (newPos)
-import Data.Char ( toLower, toUpper, ord, chr, isAscii, isAlphaNum,
- isHexDigit, isSpace, isPunctuation )
-import Data.List ( intercalate, transpose, isSuffixOf )
-import Text.Pandoc.Shared
-import qualified Data.Map as M
-import Text.TeXMath.Readers.TeX.Macros (applyMacros, Macro,
- parseMacroDefinitions)
-import Text.HTML.TagSoup.Entity ( lookupEntity )
-import Text.Pandoc.Asciify (toAsciiChar)
-import Data.Monoid ((<>))
-import Data.Default
-import qualified Data.Set as Set
-import Control.Monad.Reader
-import Control.Monad.Identity
-import Data.Maybe (catMaybes)
+import Text.Parsec.Pos (initialPos, newPos, updatePosString)
+import Control.Monad.Except
import Text.Pandoc.Error
type Parser t s = Parsec t s
type ParserT = ParsecT
-newtype F a = F { unF :: Reader ParserState a } deriving (Monad, Applicative, Functor)
+-- | Reader monad wrapping the parser state. This is used to possibly delay
+-- evaluation until all relevant information has been parsed and made available
+-- in the parser state.
+newtype Future s a = Future { runDelayed :: Reader s a }
+ deriving (Monad, Applicative, Functor)
+
+type F = Future ParserState
-runF :: F a -> ParserState -> a
-runF = runReader . unF
+runF :: Future s a -> s -> a
+runF = runReader . runDelayed
-askF :: F ParserState
-askF = F ask
+askF :: Future s s
+askF = Future ask
-asksF :: (ParserState -> a) -> F a
-asksF f = F $ asks f
+asksF :: (s -> a) -> Future s a
+asksF f = Future $ asks f
-instance Monoid a => Monoid (F a) where
+returnF :: Monad m => a -> m (Future s a)
+returnF = return . return
+
+trimInlinesF :: Future s Inlines -> Future s Inlines
+trimInlinesF = liftM trimInlines
+
+instance Monoid a => Monoid (Future s a) where
mempty = return mempty
mappend = liftM2 mappend
mconcat = liftM mconcat . sequence
+-- | Parse characters while a predicate is true.
+takeWhileP :: Monad m
+ => (Char -> Bool)
+ -> ParserT [Char] st m [Char]
+takeWhileP f = do
+ -- faster than 'many (satisfy f)'
+ inp <- getInput
+ pos <- getPosition
+ let (xs, rest) = span f inp
+ -- needed to persuade parsec that this won't match an empty string:
+ anyChar
+ setInput rest
+ setPosition $ updatePosString pos xs
+ return xs
+
+-- Parse n characters of input (or the rest of the input if
+-- there aren't n characters).
+takeP :: Monad m => Int -> ParserT [Char] st m [Char]
+takeP n = do
+ guard (n > 0)
+ -- faster than 'count n anyChar'
+ inp <- getInput
+ pos <- getPosition
+ let (xs, rest) = splitAt n inp
+ -- needed to persuade parsec that this won't match an empty string:
+ anyChar
+ setInput rest
+ setPosition $ updatePosString pos xs
+ return xs
+
-- | Parse any line of text
-anyLine :: Stream [Char] m Char => ParserT [Char] st m [Char]
+anyLine :: Monad m => ParserT [Char] st m [Char]
anyLine = do
-- This is much faster than:
-- manyTill anyChar newline
@@ -231,16 +301,54 @@ anyLine = do
return this
_ -> mzero
+-- | Parse any line, include the final newline in the output
+anyLineNewline :: Monad m => ParserT [Char] st m [Char]
+anyLineNewline = (++ "\n") <$> anyLine
+
+-- | Parse indent by specified number of spaces (or equiv. tabs)
+indentWith :: Stream s m Char
+ => HasReaderOptions st
+ => Int -> ParserT s st m [Char]
+indentWith num = do
+ tabStop <- getOption readerTabStop
+ if num < tabStop
+ then count num (char ' ')
+ else choice [ try (count num (char ' '))
+ , try (char '\t' >> indentWith (num - tabStop)) ]
+
-- | Like @manyTill@, but reads at least one item.
-many1Till :: Stream s m t
+many1Till :: (Show end, Stream s m t)
=> ParserT s st m a
-> ParserT s st m end
-> ParserT s st m [a]
many1Till p end = do
+ notFollowedBy' end
first <- p
rest <- manyTill p end
return (first:rest)
+-- | Like @manyTill@, but also returns the result of end parser.
+manyUntil :: (Stream s m t)
+ => ParserT s u m a
+ -> ParserT s u m b
+ -> ParserT s u m ([a], b)
+manyUntil p end = scan
+ where scan =
+ (do e <- end
+ return ([], e)
+ ) <|>
+ (do x <- p
+ (xs, e) <- scan
+ return (x:xs, e))
+
+-- | Like @sepBy1@ from Parsec,
+-- but does not fail if it @sep@ succeeds and @p@ fails.
+sepBy1' :: (Stream s m t)
+ => ParsecT s u m a
+ -> ParsecT s u m sep
+ -> ParsecT s u m [a]
+sepBy1' p sep = (:) <$> p <*> many (try $ sep >> p)
+
-- | A more general form of @notFollowedBy@. This one allows any
-- type of parser to be specified, and succeeds only if that parser fails.
-- It does not consume any input.
@@ -276,7 +384,7 @@ oneOfStringsCI = oneOfStrings' ciMatch
-- this optimizes toLower by checking common ASCII case
-- first, before calling the expensive unicode-aware
-- function:
- toLower' c | c >= 'A' && c <= 'Z' = chr (ord c + 32)
+ toLower' c | isAsciiUpper c = chr (ord c + 32)
| isAscii c = c
| otherwise = toLower c
@@ -300,8 +408,38 @@ blankline = try $ skipSpaces >> newline
blanklines :: Stream s m Char => ParserT s st m [Char]
blanklines = many1 blankline
+-- | Gobble n spaces; if tabs are encountered, expand them
+-- and gobble some or all of their spaces, leaving the rest.
+gobbleSpaces :: (HasReaderOptions st, Monad m)
+ => Int -> ParserT [Char] st m ()
+gobbleSpaces 0 = return ()
+gobbleSpaces n
+ | n < 0 = error "gobbleSpaces called with negative number"
+ | otherwise = try $ do
+ char ' ' <|> eatOneSpaceOfTab
+ gobbleSpaces (n - 1)
+
+eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT [Char] st m Char
+eatOneSpaceOfTab = do
+ char '\t'
+ tabstop <- getOption readerTabStop
+ inp <- getInput
+ setInput $ replicate (tabstop - 1) ' ' ++ inp
+ return ' '
+
+-- | Gobble up to n spaces; if tabs are encountered, expand them
+-- and gobble some or all of their spaces, leaving the rest.
+gobbleAtMostSpaces :: (HasReaderOptions st, Monad m)
+ => Int -> ParserT [Char] st m Int
+gobbleAtMostSpaces 0 = return 0
+gobbleAtMostSpaces n
+ | n < 0 = error "gobbleAtMostSpaces called with negative number"
+ | otherwise = option 0 $ do
+ char ' ' <|> eatOneSpaceOfTab
+ (+ 1) <$> gobbleAtMostSpaces (n - 1)
+
-- | Parses material enclosed between start and end parsers.
-enclosed :: Stream s m Char => ParserT s st m t -- ^ start parser
+enclosed :: (Show end, Stream s m Char) => ParserT s st m t -- ^ start parser
-> ParserT s st m end -- ^ end parser
-> ParserT s st m a -- ^ content parser (to be used repeatedly)
-> ParserT s st m [a]
@@ -317,9 +455,13 @@ stringAnyCase (x:xs) = do
return (firstChar:rest)
-- | Parse contents of 'str' using 'parser' and return result.
-parseFromString :: Monad m => ParserT String st m a -> String -> ParserT String st m a
+parseFromString :: Monad m
+ => ParserT [Char] st m a
+ -> String
+ -> ParserT [Char] st m a
parseFromString parser str = do
oldPos <- getPosition
+ setPosition $ initialPos "chunk"
oldInput <- getInput
setInput str
result <- parser
@@ -329,10 +471,22 @@ parseFromString parser str = do
setPosition oldPos
return result
+-- | Like 'parseFromString' but specialized for 'ParserState'.
+-- This resets 'stateLastStrPos', which is almost always what we want.
+parseFromString' :: Monad m
+ => ParserT String ParserState m a
+ -> String
+ -> ParserT String ParserState m a
+parseFromString' parser str = do
+ oldStrPos <- stateLastStrPos <$> getState
+ res <- parseFromString parser str
+ updateState $ \st -> st{ stateLastStrPos = oldStrPos }
+ return res
+
-- | Parse raw line block up to and including blank lines.
-lineClump :: Stream [Char] m Char => ParserT [Char] st m String
+lineClump :: Monad m => ParserT [Char] st m String
lineClump = blanklines
- <|> (many1 (notFollowedBy blankline >> anyLine) >>= return . unlines)
+ <|> (unlines <$> many1 (notFollowedBy blankline >> anyLine))
-- | Parse a string of characters between an open character
-- and a close character, including text between balanced
@@ -373,19 +527,19 @@ romanNumeral upperCase = do
lookAhead $ oneOf romanDigits
let [one, five, ten, fifty, hundred, fivehundred, thousand] =
map char romanDigits
- thousands <- many thousand >>= (return . (1000 *) . length)
+ thousands <- ((1000 *) . length) <$> many thousand
ninehundreds <- option 0 $ try $ hundred >> thousand >> return 900
- fivehundreds <- many fivehundred >>= (return . (500 *) . length)
+ fivehundreds <- ((500 *) . length) <$> many fivehundred
fourhundreds <- option 0 $ try $ hundred >> fivehundred >> return 400
- hundreds <- many hundred >>= (return . (100 *) . length)
+ hundreds <- ((100 *) . length) <$> many hundred
nineties <- option 0 $ try $ ten >> hundred >> return 90
- fifties <- many fifty >>= (return . (50 *) . length)
+ fifties <- ((50 *) . length) <$> many fifty
forties <- option 0 $ try $ ten >> fifty >> return 40
- tens <- many ten >>= (return . (10 *) . length)
+ tens <- ((10 *) . length) <$> many ten
nines <- option 0 $ try $ one >> ten >> return 9
- fives <- many five >>= (return . (5 *) . length)
+ fives <- ((5 *) . length) <$> many five
fours <- option 0 $ try $ one >> five >> return 4
- ones <- many one >>= (return . length)
+ ones <- length <$> many one
let total = thousands + ninehundreds + fivehundreds + fourhundreds +
hundreds + nineties + fifties + forties + tens + nines +
fives + fours + ones
@@ -401,8 +555,8 @@ emailAddress :: Stream s m Char => ParserT s st m (String, String)
emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
where toResult mbox dom = let full = fromEntities $ mbox ++ '@':dom
in (full, escapeURI $ "mailto:" ++ full)
- mailbox = intercalate "." <$> (emailWord `sepby1` dot)
- domain = intercalate "." <$> (subdomain `sepby1` dot)
+ mailbox = intercalate "." <$> (emailWord `sepBy1'` dot)
+ domain = intercalate "." <$> (subdomain `sepBy1'` dot)
dot = char '.'
subdomain = many1 $ alphaNum <|> innerPunct
-- this excludes some valid email addresses, since an
@@ -419,59 +573,33 @@ emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
return (x:xs)
isEmailChar c = isAlphaNum c || isEmailPunct c
isEmailPunct c = c `elem` "!\"#$%&'*+-/=?^_{|}~;"
- -- note: sepBy1 from parsec consumes input when sep
- -- succeeds and p fails, so we use this variant here.
- sepby1 p sep = (:) <$> p <*> (many (try $ sep >> p))
-
-
--- Schemes from http://www.iana.org/assignments/uri-schemes.html plus
--- the unofficial schemes coap, doi, javascript, isbn, pmid
-schemes :: [String]
-schemes = ["coap","doi","javascript","aaa","aaas","about","acap","cap","cid",
- "crid","data","dav","dict","dns","file","ftp","geo","go","gopher",
- "h323","http","https","iax","icap","im","imap","info","ipp","iris",
- "iris.beep","iris.xpc","iris.xpcs","iris.lwz","ldap","mailto","mid",
- "msrp","msrps","mtqp","mupdate","news","nfs","ni","nih","nntp",
- "opaquelocktoken","pop","pres","rtsp","service","session","shttp","sieve",
- "sip","sips","sms","snmp","soap.beep","soap.beeps","tag","tel","telnet",
- "tftp","thismessage","tn3270","tip","tv","urn","vemmi","ws","wss","xcon",
- "xcon-userid","xmlrpc.beep","xmlrpc.beeps","xmpp","z39.50r","z39.50s",
- "adiumxtra","afp","afs","aim","apt","attachment","aw","beshare","bitcoin",
- "bolo","callto","chrome","chrome-extension","com-eventbrite-attendee",
- "content", "cvs","dlna-playsingle","dlna-playcontainer","dtn","dvb",
- "ed2k","facetime","feed","finger","fish","gg","git","gizmoproject",
- "gtalk","hcp","icon","ipn","irc","irc6","ircs","itms","jar","jms",
- "keyparc","lastfm","ldaps","magnet","maps","market","message","mms",
- "ms-help","msnim","mumble","mvn","notes","oid","palm","paparazzi",
- "platform","proxy","psyc","query","res","resource","rmi","rsync",
- "rtmp","secondlife","sftp","sgn","skype","smb","soldat","spotify",
- "ssh","steam","svn","teamspeak","things","udp","unreal","ut2004",
- "ventrilo","view-source","webcal","wtai","wyciwyg","xfire","xri",
- "ymsgr", "isbn", "pmid"]
+
uriScheme :: Stream s m Char => ParserT s st m String
-uriScheme = oneOfStringsCI schemes
+uriScheme = oneOfStringsCI (Set.toList schemes)
-- | Parses a URI. Returns pair of original and URI-escaped version.
-uri :: Stream [Char] m Char => ParserT [Char] st m (String, String)
+uri :: Monad m => ParserT [Char] st m (String, String)
uri = try $ do
scheme <- uriScheme
char ':'
+ -- Avoid parsing e.g. "**Notes:**" as a raw URI:
+ notFollowedBy (oneOf "*_]")
-- We allow sentence punctuation except at the end, since
-- we don't want the trailing '.' in 'http://google.com.' We want to allow
-- http://en.wikipedia.org/wiki/State_of_emergency_(disambiguation)
-- as a URL, while NOT picking up the closing paren in
-- (http://wikipedia.org). So we include balanced parens in the URL.
- let isWordChar c = isAlphaNum c || c `elem` "#$%*+/@\\_-"
+ let isWordChar c = isAlphaNum c || c `elem` "#$%*+/@\\_-&="
let wordChar = satisfy isWordChar
let percentEscaped = try $ char '%' >> skipMany1 (satisfy isHexDigit)
let entity = () <$ characterReference
let punct = skipMany1 (char ',')
- <|> () <$ (satisfy (\c -> not (isSpace c) && c /= '<' && c /= '>'))
+ <|> () <$ satisfy (\c -> not (isSpace c) && c /= '<' && c /= '>')
let uriChunk = skipMany1 wordChar
<|> percentEscaped
<|> entity
- <|> (try $ punct >>
+ <|> try (punct >>
lookAhead (void (satisfy isWordChar) <|> percentEscaped))
str <- snd <$> withRaw (skipMany1 ( () <$
(enclosed (char '(') (char ')') uriChunk
@@ -485,7 +613,7 @@ uri = try $ do
mathInlineWith :: Stream s m Char => String -> String -> ParserT s st m String
mathInlineWith op cl = try $ do
string op
- notFollowedBy space
+ when (op == "$") $ notFollowedBy space
words' <- many1Till (count 1 (noneOf " \t\n\\")
<|> (char '\\' >>
-- This next clause is needed because \text{..} can
@@ -499,7 +627,7 @@ mathInlineWith op cl = try $ do
return " "
) (try $ string cl)
notFollowedBy digit -- to prevent capture of $5
- return $ concat words'
+ return $ trim $ concat words'
where
inBalancedBraces :: Stream s m Char => Int -> String -> ParserT s st m String
inBalancedBraces 0 "" = do
@@ -556,7 +684,9 @@ withHorizDisplacement parser = do
-- | Applies a parser and returns the raw string that was parsed,
-- along with the value produced by the parser.
-withRaw :: Stream [Char] m Char => ParsecT [Char] st m a -> ParsecT [Char] st m (a, [Char])
+withRaw :: Monad m
+ => ParsecT [Char] st m a
+ -> ParsecT [Char] st m (a, [Char])
withRaw parser = do
pos1 <- getPosition
inp <- getInput
@@ -566,9 +696,9 @@ withRaw parser = do
let (l2,c2) = (sourceLine pos2, sourceColumn pos2)
let inplines = take ((l2 - l1) + 1) $ lines inp
let raw = case inplines of
- [] -> ""
- [l] -> take (c2 - c1) l
- ls -> unlines (init ls) ++ take (c2 - 1) (last ls)
+ [] -> ""
+ [l] -> take (c2 - c1) l
+ ls -> unlines (init ls) ++ take (c2 - 1) (last ls)
return (result, raw)
-- | Parses backslash, then applies character parser.
@@ -584,11 +714,11 @@ characterReference = try $ do
ent <- many1Till nonspaceChar (char ';')
let ent' = case ent of
'#':'X':xs -> '#':'x':xs -- workaround tagsoup bug
- '#':_ -> ent
- _ -> ent ++ ";"
+ '#':_ -> ent
+ _ -> ent ++ ";"
case lookupEntity ent' of
- Just (c : _) -> return c
- _ -> fail "entity not found"
+ Just (c : _) -> return c
+ _ -> fail "entity not found"
-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
upperRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
@@ -651,7 +781,7 @@ romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
-- | Parses an ordered list marker and returns list attributes.
anyOrderedListMarker :: Stream s m Char => ParserT s ParserState m ListAttributes
-anyOrderedListMarker = choice $
+anyOrderedListMarker = choice
[delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
numParser <- [decimal, exampleNum, defaultNum, romanOne,
lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
@@ -717,7 +847,7 @@ charRef = do
c <- characterReference
return $ Str [c]
-lineBlockLine :: Stream [Char] m Char => ParserT [Char] st m String
+lineBlockLine :: Monad m => ParserT [Char] st m String
lineBlockLine = try $ do
char '|'
char ' '
@@ -727,33 +857,48 @@ lineBlockLine = try $ do
continuations <- many (try $ char ' ' >> anyLine)
return $ white ++ unwords (line : continuations)
-blankLineBlockLine :: Stream [Char] m Char => ParserT [Char] st m Char
+blankLineBlockLine :: Stream s m Char => ParserT s st m Char
blankLineBlockLine = try (char '|' >> blankline)
-- | Parses an RST-style line block and returns a list of strings.
-lineBlockLines :: Stream [Char] m Char => ParserT [Char] st m [String]
+lineBlockLines :: Monad m => ParserT [Char] st m [String]
lineBlockLines = try $ do
lines' <- many1 (lineBlockLine <|> ((:[]) <$> blankLineBlockLine))
- skipMany1 $ blankline <|> blankLineBlockLine
+ skipMany blankline
return lines'
-- | Parse a table using 'headerParser', 'rowParser',
-- 'lineParser', and 'footerParser'.
-tableWith :: Stream s m Char
- => ParserT s ParserState m ([[Block]], [Alignment], [Int])
- -> ([Int] -> ParserT s ParserState m [[Block]])
- -> ParserT s ParserState m sep
- -> ParserT s ParserState m end
- -> ParserT s ParserState m Block
+tableWith :: (Stream s m Char, HasReaderOptions st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT s st m (mf [Blocks], [Alignment], [Int])
+ -> ([Int] -> ParserT s st m (mf [Blocks]))
+ -> ParserT s st m sep
+ -> ParserT s st m end
+ -> ParserT s st m (mf Blocks)
tableWith headerParser rowParser lineParser footerParser = try $ do
+ (aligns, widths, heads, rows) <- tableWith' headerParser rowParser
+ lineParser footerParser
+ return $ B.table mempty (zip aligns widths) <$> heads <*> rows
+
+type TableComponents mf = ([Alignment], [Double], mf [Blocks], mf [[Blocks]])
+
+tableWith' :: (Stream s m Char, HasReaderOptions st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT s st m (mf [Blocks], [Alignment], [Int])
+ -> ([Int] -> ParserT s st m (mf [Blocks]))
+ -> ParserT s st m sep
+ -> ParserT s st m end
+ -> ParserT s st m (TableComponents mf)
+tableWith' headerParser rowParser lineParser footerParser = try $ do
(heads, aligns, indices) <- headerParser
- lines' <- rowParser indices `sepEndBy1` lineParser
+ lines' <- sequence <$> rowParser indices `sepEndBy1` lineParser
footerParser
numColumns <- getOption readerColumns
- let widths = if (indices == [])
+ let widths = if null indices
then replicate (length aligns) 0.0
else widthsFromIndices numColumns indices
- return $ Table [] aligns widths heads lines'
+ return (aligns, widths, heads, lines')
-- Calculate relative widths of table columns, based on indices
widthsFromIndices :: Int -- Number of columns on terminal
@@ -777,7 +922,7 @@ widthsFromIndices numColumns' indices =
quotient = if totLength > numColumns
then fromIntegral totLength
else fromIntegral numColumns
- fracs = map (\l -> (fromIntegral l) / quotient) lengths in
+ fracs = map (\l -> fromIntegral l / quotient) lengths in
tail fracs
---
@@ -786,25 +931,44 @@ widthsFromIndices numColumns' indices =
-- (which may be grid), then the rows,
-- which may be grid, separated by blank lines, and
-- ending with a footer (dashed line followed by blank line).
-gridTableWith :: Stream [Char] m Char
- => ParserT [Char] ParserState m [Block] -- ^ Block list parser
- -> Bool -- ^ Headerless table
- -> ParserT [Char] ParserState m Block
+gridTableWith :: (Monad m, HasReaderOptions st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT [Char] st m (mf Blocks) -- ^ Block list parser
+ -> Bool -- ^ Headerless table
+ -> ParserT [Char] st m (mf Blocks)
gridTableWith blocks headless =
tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
(gridTableSep '-') gridTableFooter
+gridTableWith' :: (Monad m, HasReaderOptions st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT [Char] st m (mf Blocks) -- ^ Block list parser
+ -> Bool -- ^ Headerless table
+ -> ParserT [Char] st m (TableComponents mf)
+gridTableWith' blocks headless =
+ tableWith' (gridTableHeader headless blocks) (gridTableRow blocks)
+ (gridTableSep '-') gridTableFooter
+
gridTableSplitLine :: [Int] -> String -> [String]
gridTableSplitLine indices line = map removeFinalBar $ tail $
splitStringByIndices (init indices) $ trimr line
-gridPart :: Stream s m Char => Char -> ParserT s st m (Int, Int)
+gridPart :: Stream s m Char => Char -> ParserT s st m ((Int, Int), Alignment)
gridPart ch = do
+ leftColon <- option False (True <$ char ':')
dashes <- many1 (char ch)
+ rightColon <- option False (True <$ char ':')
char '+'
- return (length dashes, length dashes + 1)
-
-gridDashedLines :: Stream s m Char => Char -> ParserT s st m [(Int,Int)]
+ let lengthDashes = length dashes + (if leftColon then 1 else 0) +
+ (if rightColon then 1 else 0)
+ let alignment = case (leftColon, rightColon) of
+ (True, True) -> AlignCenter
+ (True, False) -> AlignLeft
+ (False, True) -> AlignRight
+ (False, False) -> AlignDefault
+ return ((lengthDashes, lengthDashes + 1), alignment)
+
+gridDashedLines :: Stream s m Char => Char -> ParserT s st m [((Int, Int), Alignment)]
gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
removeFinalBar :: String -> String
@@ -812,14 +976,14 @@ removeFinalBar =
reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse
-- | Separator between rows of grid table.
-gridTableSep :: Stream s m Char => Char -> ParserT s ParserState m Char
+gridTableSep :: Stream s m Char => Char -> ParserT s st m Char
gridTableSep ch = try $ gridDashedLines ch >> return '\n'
-- | Parse header for a grid table.
-gridTableHeader :: Stream [Char] m Char
+gridTableHeader :: (Monad m, Functor mf, Applicative mf, Monad mf)
=> Bool -- ^ Headerless table
- -> ParserT [Char] ParserState m [Block]
- -> ParserT [Char] ParserState m ([[Block]], [Alignment], [Int])
+ -> ParserT [Char] st m (mf Blocks)
+ -> ParserT [Char] st m (mf [Blocks], [Alignment], [Int])
gridTableHeader headless blocks = try $ do
optional blanklines
dashes <- gridDashedLines '-'
@@ -828,62 +992,63 @@ gridTableHeader headless blocks = try $ do
else many1
(notFollowedBy (gridTableSep '=') >> char '|' >>
many1Till anyChar newline)
- if headless
- then return ()
- else gridTableSep '=' >> return ()
- let lines' = map snd dashes
+ underDashes <- if headless
+ then return dashes
+ else gridDashedLines '='
+ guard $ length dashes == length underDashes
+ let lines' = map (snd . fst) underDashes
let indices = scanl (+) 0 lines'
- let aligns = replicate (length lines') AlignDefault
- -- RST does not have a notion of alignments
+ let aligns = map snd underDashes
let rawHeads = if headless
- then replicate (length dashes) ""
- else map (intercalate " ") $ transpose
+ then replicate (length underDashes) ""
+ else map (unlines . map trim) $ transpose
$ map (gridTableSplitLine indices) rawContent
- heads <- mapM (parseFromString blocks) $ map trim rawHeads
+ heads <- sequence <$> mapM (parseFromString blocks . trim) rawHeads
return (heads, aligns, indices)
-gridTableRawLine :: Stream s m Char => [Int] -> ParserT s ParserState m [String]
+gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [String]
gridTableRawLine indices = do
char '|'
line <- many1Till anyChar newline
return (gridTableSplitLine indices line)
-- | Parse row of grid table.
-gridTableRow :: Stream [Char] m Char
- => ParserT [Char] ParserState m [Block]
+gridTableRow :: (Monad m, Functor mf, Applicative mf, Monad mf)
+ => ParserT [Char] st m (mf Blocks)
-> [Int]
- -> ParserT [Char] ParserState m [[Block]]
+ -> ParserT [Char] st m (mf [Blocks])
gridTableRow blocks indices = do
colLines <- many1 (gridTableRawLine indices)
let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $
transpose colLines
- mapM (liftM compactifyCell . parseFromString blocks) cols
+ compactifyCell bs = case compactify [bs] of
+ [] -> mempty
+ x:_ -> x
+ cells <- sequence <$> mapM (parseFromString blocks) cols
+ return $ fmap (map compactifyCell) cells
removeOneLeadingSpace :: [String] -> [String]
removeOneLeadingSpace xs =
if all startsWithSpace xs
then map (drop 1) xs
else xs
- where startsWithSpace "" = True
+ where startsWithSpace "" = True
startsWithSpace (y:_) = y == ' '
-compactifyCell :: [Block] -> [Block]
-compactifyCell bs = head $ compactify [bs]
-
-- | Parse footer for a grid table.
-gridTableFooter :: Stream s m Char => ParserT s ParserState m [Char]
+gridTableFooter :: Stream s m Char => ParserT s st m [Char]
gridTableFooter = blanklines
---
-- | Removes the ParsecT layer from the monad transformer stack
-readWithM :: (Monad m)
- => ParserT [Char] st m a -- ^ parser
+readWithM :: Monad m
+ => ParserT [Char] st m a -- ^ parser
-> st -- ^ initial state
-> String -- ^ input
-> m (Either PandocError a)
readWithM parser state input =
- mapLeft (ParsecError input) `liftM` runParserT parser state "source" input
+ mapLeft (PandocParsecError input) `liftM` runParserT parser state "source" input
-- | Parse a string with a given parser and state
@@ -893,17 +1058,8 @@ readWith :: Parser [Char] st a
-> Either PandocError a
readWith p t inp = runIdentity $ readWithM p t inp
-readWithWarnings :: Parser [Char] ParserState a
- -> ParserState
- -> String
- -> Either PandocError (a, [String])
-readWithWarnings p = readWith $ do
- doc <- p
- warnings <- stateWarnings <$> getState
- return (doc, warnings)
-
-- | Parse a string with @parser@ (for testing).
-testStringWith :: (Show a)
+testStringWith :: Show a
=> ParserT [Char] ParserState Identity a
-> [Char]
-> IO ()
@@ -912,34 +1068,37 @@ testStringWith parser str = UTF8.putStrLn $ show $
-- | Parsing options.
data ParserState = ParserState
- { stateOptions :: ReaderOptions, -- ^ User options
- stateParserContext :: ParserContext, -- ^ Inside list?
- stateQuoteContext :: QuoteContext, -- ^ Inside quoted environment?
- stateAllowLinks :: Bool, -- ^ Allow parsing of links
- stateMaxNestingLevel :: Int, -- ^ Max # of nested Strong/Emph
- stateLastStrPos :: Maybe SourcePos, -- ^ Position after last str parsed
- stateKeys :: KeyTable, -- ^ List of reference keys
- stateHeaderKeys :: KeyTable, -- ^ List of implicit header ref keys
- stateSubstitutions :: SubstTable, -- ^ List of substitution references
- stateNotes :: NoteTable, -- ^ List of notes (raw bodies)
- stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
- stateMeta :: Meta, -- ^ Document metadata
- stateMeta' :: F Meta, -- ^ Document metadata
- stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
- stateHeaders :: M.Map Inlines String, -- ^ List of headers and ids (used for implicit ref links)
- stateIdentifiers :: Set.Set String, -- ^ Header identifiers used
- stateNextExample :: Int, -- ^ Number of next example
- stateExamples :: M.Map String Int, -- ^ Map from example labels to numbers
- stateHasChapters :: Bool, -- ^ True if \chapter encountered
- stateMacros :: [Macro], -- ^ List of macros defined so far
- stateRstDefaultRole :: String, -- ^ Current rST default interpreted text role
- stateRstCustomRoles :: M.Map String (String, Maybe String, Attr), -- ^ Current rST custom text roles
+ { stateOptions :: ReaderOptions, -- ^ User options
+ stateParserContext :: ParserContext, -- ^ Inside list?
+ stateQuoteContext :: QuoteContext, -- ^ Inside quoted environment?
+ stateAllowLinks :: Bool, -- ^ Allow parsing of links
+ stateMaxNestingLevel :: Int, -- ^ Max # of nested Strong/Emph
+ stateLastStrPos :: Maybe SourcePos, -- ^ Position after last str parsed
+ stateKeys :: KeyTable, -- ^ List of reference keys
+ stateHeaderKeys :: KeyTable, -- ^ List of implicit header ref keys
+ stateSubstitutions :: SubstTable, -- ^ List of substitution references
+ stateNotes :: NoteTable, -- ^ List of notes (raw bodies)
+ stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
+ stateNoteRefs :: Set.Set String, -- ^ List of note references used
+ stateMeta :: Meta, -- ^ Document metadata
+ stateMeta' :: F Meta, -- ^ Document metadata
+ stateCitations :: M.Map String String, -- ^ RST-style citations
+ stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
+ stateHeaders :: M.Map Inlines String, -- ^ List of headers and ids (used for implicit ref links)
+ stateIdentifiers :: Set.Set String, -- ^ Header identifiers used
+ stateNextExample :: Int, -- ^ Number of next example
+ stateExamples :: M.Map String Int, -- ^ Map from example labels to numbers
+ stateMacros :: M.Map Text Macro, -- ^ Table of macros defined so far
+ stateRstDefaultRole :: String, -- ^ Current rST default interpreted text role
+ stateRstCustomRoles :: M.Map String (String, Maybe String, Attr), -- ^ Current rST custom text roles
-- Triple represents: 1) Base role, 2) Optional format (only for :raw:
-- roles), 3) Additional classes (rest of Attr is unused)).
- stateCaption :: Maybe Inlines, -- ^ Caption in current environment
- stateInHtmlBlock :: Maybe String, -- ^ Tag type of HTML block being parsed
- stateMarkdownAttribute :: Bool, -- ^ True if in markdown=1 context
- stateWarnings :: [String] -- ^ Warnings generated by the parser
+ stateCaption :: Maybe Inlines, -- ^ Caption in current environment
+ stateInHtmlBlock :: Maybe String, -- ^ Tag type of HTML block being parsed
+ stateFencedDivLevel :: Int, -- ^ Depth of fenced div
+ stateContainers :: [String], -- ^ parent include files
+ stateLogMessages :: [LogMessage], -- ^ log messages
+ stateMarkdownAttribute :: Bool -- ^ True if in markdown=1 context
}
instance Default ParserState where
@@ -957,6 +1116,9 @@ class HasReaderOptions st where
-- default
getOption f = (f . extractReaderOptions) <$> getState
+instance HasReaderOptions ParserState where
+ extractReaderOptions = stateOptions
+
class HasQuoteContext st m where
getQuoteContext :: (Stream s m t) => ParsecT s st m QuoteContext
withQuoteContext :: QuoteContext -> ParsecT s st m a -> ParsecT s st m a
@@ -972,9 +1134,6 @@ instance Monad m => HasQuoteContext ParserState m where
setState newState { stateQuoteContext = oldQuoteContext }
return result
-instance HasReaderOptions ParserState where
- extractReaderOptions = stateOptions
-
class HasHeaderMap st where
extractHeaderMap :: st -> M.Map Inlines String
updateHeaderMap :: (M.Map Inlines String -> M.Map Inlines String) ->
@@ -993,8 +1152,8 @@ instance HasIdentifierList ParserState where
updateIdentifierList f st = st{ stateIdentifiers = f $ stateIdentifiers st }
class HasMacros st where
- extractMacros :: st -> [Macro]
- updateMacros :: ([Macro] -> [Macro]) -> st -> st
+ extractMacros :: st -> M.Map Text Macro
+ updateMacros :: (M.Map Text Macro -> M.Map Text Macro) -> st -> st
instance HasMacros ParserState where
extractMacros = stateMacros
@@ -1008,6 +1167,24 @@ instance HasLastStrPosition ParserState where
setLastStrPos pos st = st{ stateLastStrPos = Just pos }
getLastStrPos st = stateLastStrPos st
+class HasLogMessages st where
+ addLogMessage :: LogMessage -> st -> st
+ getLogMessages :: st -> [LogMessage]
+
+instance HasLogMessages ParserState where
+ addLogMessage msg st = st{ stateLogMessages = msg : stateLogMessages st }
+ getLogMessages st = reverse $ stateLogMessages st
+
+class HasIncludeFiles st where
+ getIncludeFiles :: st -> [String]
+ addIncludeFile :: String -> st -> st
+ dropLatestIncludeFile :: st -> st
+
+instance HasIncludeFiles ParserState where
+ getIncludeFiles = stateContainers
+ addIncludeFile f s = s{ stateContainers = f : stateContainers s }
+ dropLatestIncludeFile s = s { stateContainers = drop 1 $ stateContainers s }
+
defaultParserState :: ParserState
defaultParserState =
ParserState { stateOptions = def,
@@ -1020,30 +1197,45 @@ defaultParserState =
stateHeaderKeys = M.empty,
stateSubstitutions = M.empty,
stateNotes = [],
- stateNotes' = [],
+ stateNotes' = M.empty,
+ stateNoteRefs = Set.empty,
stateMeta = nullMeta,
stateMeta' = return nullMeta,
+ stateCitations = M.empty,
stateHeaderTable = [],
stateHeaders = M.empty,
stateIdentifiers = Set.empty,
stateNextExample = 1,
stateExamples = M.empty,
- stateHasChapters = False,
- stateMacros = [],
+ stateMacros = M.empty,
stateRstDefaultRole = "title-reference",
stateRstCustomRoles = M.empty,
stateCaption = Nothing,
stateInHtmlBlock = Nothing,
- stateMarkdownAttribute = False,
- stateWarnings = []}
+ stateFencedDivLevel = 0,
+ stateContainers = [],
+ stateLogMessages = [],
+ stateMarkdownAttribute = False
+ }
+
+-- | Add a log message.
+logMessage :: (Stream s m a, HasLogMessages st)
+ => LogMessage -> ParserT s st m ()
+logMessage msg = updateState (addLogMessage msg)
+
+-- | Report all the accumulated log messages, according to verbosity level.
+reportLogMessages :: (PandocMonad m, HasLogMessages st) => ParserT s st m ()
+reportLogMessages = do
+ msgs <- getLogMessages <$> getState
+ mapM_ report msgs
-- | Succeed only if the extension is enabled.
guardEnabled :: (Stream s m a, HasReaderOptions st) => Extension -> ParserT s st m ()
-guardEnabled ext = getOption readerExtensions >>= guard . Set.member ext
+guardEnabled ext = getOption readerExtensions >>= guard . extensionEnabled ext
-- | Succeed only if the extension is disabled.
guardDisabled :: (Stream s m a, HasReaderOptions st) => Extension -> ParserT s st m ()
-guardDisabled ext = getOption readerExtensions >>= guard . not . Set.member ext
+guardDisabled ext = getOption readerExtensions >>= guard . not . extensionEnabled ext
-- | Update the position on which the last string ended.
updateLastStrPos :: (Stream s m a, HasLastStrPosition st) => ParserT s st m ()
@@ -1074,7 +1266,8 @@ data QuoteContext
type NoteTable = [(String, String)]
-type NoteTable' = [(String, F Blocks)] -- used in markdown reader
+type NoteTable' = M.Map String (SourcePos, F Blocks)
+-- used in markdown reader
newtype Key = Key String deriving (Show, Read, Eq, Ord)
@@ -1091,37 +1284,40 @@ type SubstTable = M.Map Key Inlines
-- with its associated identifier. If the identifier is null
-- and the auto_identifers extension is set, generate a new
-- unique identifier, and update the list of identifiers
--- in state.
-registerHeader :: (Stream s m a, HasReaderOptions st, HasHeaderMap st, HasIdentifierList st)
+-- in state. Issue a warning if an explicit identifier
+-- is encountered that duplicates an earlier identifier
+-- (explict or automatically generated).
+registerHeader :: (Stream s m a, HasReaderOptions st,
+ HasHeaderMap st, HasLogMessages st, HasIdentifierList st)
=> Attr -> Inlines -> ParserT s st m Attr
registerHeader (ident,classes,kvs) header' = do
ids <- extractIdentifierList <$> getState
exts <- getOption readerExtensions
let insert' = M.insertWith (\_new old -> old)
- if null ident && Ext_auto_identifiers `Set.member` exts
+ if null ident && Ext_auto_identifiers `extensionEnabled` exts
then do
let id' = uniqueIdent (B.toList header') ids
- let id'' = if Ext_ascii_identifiers `Set.member` exts
- then catMaybes $ map toAsciiChar id'
+ let id'' = if Ext_ascii_identifiers `extensionEnabled` exts
+ then mapMaybe toAsciiChar id'
else id'
updateState $ updateIdentifierList $ Set.insert id'
updateState $ updateIdentifierList $ Set.insert id''
updateState $ updateHeaderMap $ insert' header' id'
return (id'',classes,kvs)
else do
- unless (null ident) $
+ unless (null ident) $ do
+ when (ident `Set.member` ids) $ do
+ pos <- getPosition
+ logMessage $ DuplicateIdentifier ident pos
+ updateState $ updateIdentifierList $ Set.insert ident
updateState $ updateHeaderMap $ insert' header' ident
return (ident,classes,kvs)
--- | Fail unless we're in "smart typography" mode.
-failUnlessSmart :: (Stream s m a, HasReaderOptions st) => ParserT s st m ()
-failUnlessSmart = getOption readerSmart >>= guard
-
smartPunctuation :: (HasReaderOptions st, HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
=> ParserT s st m Inlines
-> ParserT s st m Inlines
smartPunctuation inlineParser = do
- failUnlessSmart
+ guardEnabled Ext_smart
choice [ quoted inlineParser, apostrophe, dash, ellipses ]
apostrophe :: Stream s m Char => ParserT s st m Inlines
@@ -1153,9 +1349,7 @@ failIfInQuoteContext :: (HasQuoteContext st m, Stream s m t)
-> ParserT s st m ()
failIfInQuoteContext context = do
context' <- getQuoteContext
- if context' == context
- then fail "already inside quotes"
- else return ()
+ when (context' == context) $ fail "already inside quotes"
charOrRef :: Stream s m Char => String -> ParserT s st m Char
charOrRef cs =
@@ -1195,7 +1389,7 @@ ellipses = try (string "..." >> return (B.str "\8230"))
dash :: (HasReaderOptions st, Stream s m Char)
=> ParserT s st m Inlines
dash = try $ do
- oldDashes <- getOption readerOldDashes
+ oldDashes <- extensionEnabled Ext_old_dashes <$> getOption readerExtensions
if oldDashes
then do
char '-'
@@ -1241,43 +1435,6 @@ token :: (Stream s m t)
-> ParsecT s st m a
token pp pos match = tokenPrim pp (\_ t _ -> pos t) match
---
--- Macros
---
-
--- | Parse a \newcommand or \renewcommand macro definition.
-macro :: (Stream [Char] m Char, HasMacros st, HasReaderOptions st)
- => ParserT [Char] st m Blocks
-macro = do
- apply <- getOption readerApplyMacros
- inp <- getInput
- case parseMacroDefinitions inp of
- ([], _) -> mzero
- (ms, rest) -> do def' <- count (length inp - length rest) anyChar
- if apply
- then do
- updateState $ \st ->
- updateMacros (ms ++) st
- return mempty
- else return $ rawBlock "latex" def'
-
--- | Apply current macros to string.
-applyMacros' :: (HasReaderOptions st, HasMacros st, Stream [Char] m Char)
- => String
- -> ParserT [Char] st m String
-applyMacros' target = do
- apply <- getOption readerApplyMacros
- if apply
- then do macros <- extractMacros <$> getState
- return $ applyMacros macros target
- else return target
-
--- | Append a warning to the log.
-addWarning :: Maybe SourcePos -> String -> Parser [Char] ParserState ()
-addWarning mbpos msg =
- updateState $ \st -> st{
- stateWarnings = (msg ++ maybe "" (\pos -> " " ++ show pos) mbpos) :
- stateWarnings st }
infixr 5 <+?>
(<+?>) :: (Monoid a) => ParserT s st m a -> ParserT s st m a -> ParserT s st m a
a <+?> b = a >>= flip fmap (try b <|> return mempty) . (<>)
@@ -1285,10 +1442,53 @@ a <+?> b = a >>= flip fmap (try b <|> return mempty) . (<>)
extractIdClass :: Attr -> Attr
extractIdClass (ident, cls, kvs) = (ident', cls', kvs')
where
- ident' = case (lookup "id" kvs) of
- Just v -> v
- Nothing -> ident
- cls' = case (lookup "class" kvs) of
+ ident' = fromMaybe ident (lookup "id" kvs)
+ cls' = case lookup "class" kvs of
Just cl -> words cl
Nothing -> cls
kvs' = filter (\(k,_) -> k /= "id" || k /= "class") kvs
+
+insertIncludedFile' :: (PandocMonad m, HasIncludeFiles st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT [a] st m (mf Blocks)
+ -> (String -> [a])
+ -> [FilePath] -> FilePath
+ -> ParserT [a] st m (mf Blocks)
+insertIncludedFile' blocks totoks dirs f = do
+ oldPos <- getPosition
+ oldInput <- getInput
+ containers <- getIncludeFiles <$> getState
+ when (f `elem` containers) $
+ throwError $ PandocParseError $ "Include file loop at " ++ show oldPos
+ updateState $ addIncludeFile f
+ mbcontents <- readFileFromDirs dirs f
+ contents <- case mbcontents of
+ Just s -> return s
+ Nothing -> do
+ report $ CouldNotLoadIncludeFile f oldPos
+ return ""
+ setPosition $ newPos f 1 1
+ setInput $ totoks contents
+ bs <- blocks
+ setInput oldInput
+ setPosition oldPos
+ updateState dropLatestIncludeFile
+ return bs
+
+-- | Parse content of include file as blocks. Circular includes result in an
+-- @PandocParseError@.
+insertIncludedFile :: (PandocMonad m, HasIncludeFiles st)
+ => ParserT [a] st m Blocks
+ -> (String -> [a])
+ -> [FilePath] -> FilePath
+ -> ParserT [a] st m Blocks
+insertIncludedFile blocks totoks dirs f =
+ runIdentity <$> insertIncludedFile' (Identity <$> blocks) totoks dirs f
+
+-- | Parse content of include file as future blocks. Circular includes result in
+-- an @PandocParseError@.
+insertIncludedFileF :: (PandocMonad m, HasIncludeFiles st)
+ => ParserT String st m (Future st Blocks)
+ -> [FilePath] -> FilePath
+ -> ParserT String st m (Future st Blocks)
+insertIncludedFileF p = insertIncludedFile' p id
diff --git a/src/Text/Pandoc/Pretty.hs b/src/Text/Pandoc/Pretty.hs
index 256f38b0c..25c2373a6 100644
--- a/src/Text/Pandoc/Pretty.hs
+++ b/src/Text/Pandoc/Pretty.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving, CPP #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
-Copyright (C) 2010-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111(-1)307 USA
{- |
Module : Text.Pandoc.Pretty
- Copyright : Copyright (C) 2010-2016 John MacFarlane
+ Copyright : Copyright (C) 2010-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -76,22 +77,24 @@ module Text.Pandoc.Pretty (
)
where
-import Data.Sequence (Seq, fromList, (<|), singleton, mapWithIndex, viewl, ViewL(..))
-import qualified Data.Sequence as Seq
+import Control.Monad
+import Control.Monad.State.Strict
+import Data.Char (isSpace)
import Data.Foldable (toList)
import Data.List (intersperse)
-import Data.String
-import Control.Monad.State
-import Data.Char (isSpace)
import Data.Monoid ((<>))
+import Data.Sequence (Seq, ViewL (..), fromList, mapWithIndex, singleton, viewl,
+ (<|))
+import qualified Data.Sequence as Seq
+import Data.String
data RenderState a = RenderState{
- output :: [a] -- ^ In reverse order
- , prefix :: String
- , usePrefix :: Bool
- , lineLength :: Maybe Int -- ^ 'Nothing' means no wrapping
- , column :: Int
- , newlines :: Int -- ^ Number of preceding newlines
+ output :: [a] -- ^ In reverse order
+ , prefix :: String
+ , usePrefix :: Bool
+ , lineLength :: Maybe Int -- ^ 'Nothing' means no wrapping
+ , column :: Int
+ , newlines :: Int -- ^ Number of preceding newlines
}
type DocState a = State (RenderState a) ()
@@ -106,10 +109,10 @@ data D = Text Int String
| CarriageReturn
| NewLine
| BlankLines Int -- number of blank lines
- deriving (Show)
+ deriving (Show, Eq)
newtype Doc = Doc { unDoc :: Seq D }
- deriving (Monoid, Show)
+ deriving (Monoid, Show, Eq)
instance IsString Doc where
fromString = text
@@ -142,11 +145,10 @@ hcat = mconcat
-- between them.
infixr 6 <+>
(<+>) :: Doc -> Doc -> Doc
-(<+>) x y = if isEmpty x
- then y
- else if isEmpty y
- then x
- else x <> space <> y
+(<+>) x y
+ | isEmpty x = y
+ | isEmpty y = x
+ | otherwise = x <> space <> y
-- | Same as 'cat', but putting breakable spaces between the
-- 'Doc's.
@@ -156,20 +158,18 @@ hsep = foldr (<+>) empty
infixr 5 $$
-- | @a $$ b@ puts @a@ above @b@.
($$) :: Doc -> Doc -> Doc
-($$) x y = if isEmpty x
- then y
- else if isEmpty y
- then x
- else x <> cr <> y
+($$) x y
+ | isEmpty x = y
+ | isEmpty y = x
+ | otherwise = x <> cr <> y
infixr 5 $+$
-- | @a $+$ b@ puts @a@ above @b@, with a blank line between.
($+$) :: Doc -> Doc -> Doc
-($+$) x y = if isEmpty x
- then y
- else if isEmpty y
- then x
- else x <> blankline <> y
+($+$) x y
+ | isEmpty x = y
+ | isEmpty y = x
+ | otherwise = x <> blankline <> y
-- | List version of '$$'.
vcat :: [Doc] -> Doc
@@ -184,21 +184,21 @@ nestle :: Doc -> Doc
nestle (Doc d) = Doc $ go d
where go x = case viewl x of
(BlankLines _ :< rest) -> go rest
- (NewLine :< rest) -> go rest
- _ -> x
+ (NewLine :< rest) -> go rest
+ _ -> x
-- | Chomps trailing blank space off of a 'Doc'.
chomp :: Doc -> Doc
chomp d = Doc (fromList dl')
where dl = toList (unDoc d)
dl' = reverse $ go $ reverse dl
- go [] = []
- go (BreakingSpace : xs) = go xs
+ go [] = []
+ go (BreakingSpace : xs) = go xs
go (CarriageReturn : xs) = go xs
- go (NewLine : xs) = go xs
- go (BlankLines _ : xs) = go xs
- go (Prefixed s d' : xs) = Prefixed s (chomp d') : xs
- go xs = xs
+ go (NewLine : xs) = go xs
+ go (BlankLines _ : xs) = go xs
+ go (Prefixed s d' : xs) = Prefixed s (chomp d') : xs
+ go xs = xs
outp :: (IsString a) => Int -> String -> DocState a
outp off s | off < 0 = do -- offset < 0 means newline characters
@@ -215,9 +215,9 @@ outp off s | off < 0 = do -- offset < 0 means newline characters
outp off s = do -- offset >= 0 (0 might be combining char)
st' <- get
let pref = prefix st'
- when (column st' == 0 && usePrefix st' && not (null pref)) $ do
+ when (column st' == 0 && usePrefix st' && not (null pref)) $
modify $ \st -> st{ output = fromString pref : output st
- , column = column st + realLength pref }
+ , column = column st + realLength pref }
modify $ \st -> st{ output = fromString s : output st
, column = column st + off
, newlines = 0 }
@@ -306,10 +306,10 @@ renderList (BreakingSpace : NewLine : xs) = renderList (NewLine:xs)
renderList (BreakingSpace : BlankLines n : xs) = renderList (BlankLines n:xs)
renderList (BreakingSpace : BreakingSpace : xs) = renderList (BreakingSpace:xs)
renderList (BreakingSpace : xs) = do
- let isText (Text _ _) = True
- isText (Block _ _) = True
- isText (AfterBreak _) = True
- isText _ = False
+ let isText (Text _ _) = True
+ isText (Block _ _) = True
+ isText (AfterBreak _) = True
+ isText _ = False
let isBreakingSpace BreakingSpace = True
isBreakingSpace _ = False
let xs' = dropWhile isBreakingSpace xs
@@ -326,9 +326,7 @@ renderList (BreakingSpace : xs) = do
renderList (AfterBreak s : xs) = do
st <- get
- if newlines st > 0
- then outp (realLength s) s
- else return ()
+ when (newlines st > 0) $ outp (realLength s) s
renderList xs
renderList (Block i1 s1 : Block i2 s2 : xs) =
@@ -342,7 +340,7 @@ renderList (Block _width lns : xs) = do
let oldPref = prefix st
case column st - realLength oldPref of
n | n > 0 -> modify $ \s -> s{ prefix = oldPref ++ replicate n ' ' }
- _ -> return ()
+ _ -> return ()
renderList $ intersperse CarriageReturn (map (Text 0) lns)
modify $ \s -> s{ prefix = oldPref }
renderList xs
@@ -359,13 +357,13 @@ mergeBlocks addSpace (IsBlock w1 lns1) (IsBlock w2 lns2) =
| otherwise -> (lns1, lns2)
pad n s = s ++ replicate (n - realLength s) ' '
sp "" = ""
- sp xs = if addSpace then (' ' : xs) else xs
+ sp xs = if addSpace then ' ' : xs else xs
offsetOf :: D -> Int
-offsetOf (Text o _) = o
-offsetOf (Block w _) = w
-offsetOf BreakingSpace = 1
-offsetOf _ = 0
+offsetOf (Text o _) = o
+offsetOf (Block w _) = w
+offsetOf BreakingSpace = 1
+offsetOf _ = 0
-- | A literal string.
text :: String -> Doc
@@ -396,8 +394,8 @@ cr = Doc $ singleton CarriageReturn
blankline :: Doc
blankline = Doc $ singleton (BlankLines 1)
--- | Inserts a blank lines unless they exists already.
--- (@blanklines m <> blanklines n@ has the same effect as @blankline (max m n)@.
+-- | Inserts blank lines unless they exist already.
+-- (@blanklines m <> blanklines n@ has the same effect as @blanklines (max m n)@.
blanklines :: Int -> Doc
blanklines n = Doc $ singleton (BlankLines n)
@@ -430,7 +428,7 @@ beforeNonBlank d = Doc $ singleton (BeforeNonBlank d)
nowrap :: Doc -> Doc
nowrap doc = Doc $ mapWithIndex replaceSpace $ unDoc doc
where replaceSpace _ BreakingSpace = Text 1 " "
- replaceSpace _ x = x
+ replaceSpace _ x = x
-- | Content to print only if it comes at the beginning of a line,
-- to be used e.g. for escaping line-initial `.` in groff man.
@@ -440,8 +438,8 @@ afterBreak s = Doc $ singleton (AfterBreak s)
-- | Returns the width of a 'Doc'.
offset :: Doc -> Int
offset d = case map realLength . lines . render Nothing $ d of
- [] -> 0
- os -> maximum os
+ [] -> 0
+ os -> maximum os
-- | Returns the minimal width of a 'Doc' when reflowed at breakable spaces.
minOffset :: Doc -> Int
@@ -466,7 +464,7 @@ height = length . lines . render Nothing
block :: (String -> String) -> Int -> Doc -> Doc
block filler width d
- | width < 1 && not (isEmpty d) = error "Text.Pandoc.Pretty.block: width < 1"
+ | width < 1 && not (isEmpty d) = block filler 1 d
| otherwise = Doc $ singleton $ Block width $ map filler
$ chop width $ render (Just width) d
@@ -554,4 +552,4 @@ charWidth c =
-- | Get real length of string, taking into account combining and double-wide
-- characters.
realLength :: String -> Int
-realLength = foldr (\a b -> charWidth a + b) 0
+realLength = sum . map charWidth
diff --git a/src/Text/Pandoc/Process.hs b/src/Text/Pandoc/Process.hs
index bc71f1392..27807a8c8 100644
--- a/src/Text/Pandoc/Process.hs
+++ b/src/Text/Pandoc/Process.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2013-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Process
- Copyright : Copyright (C) 2013-2016 John MacFarlane
+ Copyright : Copyright (C) 2013-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,22 +29,22 @@ ByteString variant of 'readProcessWithExitCode'.
-}
module Text.Pandoc.Process (pipeProcess)
where
-import System.Process
-import System.Exit (ExitCode (..))
+import Control.Concurrent (forkIO, newEmptyMVar, putMVar, takeMVar)
import Control.Exception
-import System.IO (hClose, hFlush)
-import Control.Concurrent (putMVar, takeMVar, newEmptyMVar, forkIO)
import Control.Monad (unless)
import qualified Data.ByteString.Lazy as BL
+import System.Exit (ExitCode (..))
+import System.IO (hClose, hFlush)
+import System.Process
{- |
Version of 'System.Process.readProcessWithExitCode' that uses lazy bytestrings
instead of strings and allows setting environment variables.
@readProcessWithExitCode@ creates an external process, reads its
-standard output and standard error strictly, waits until the process
-terminates, and then returns the 'ExitCode' of the process,
-the standard output, and the standard error.
+standard output strictly, waits until the process
+terminates, and then returns the 'ExitCode' of the process
+and the standard output. stderr is inherited from the parent.
If an asynchronous exception is thrown to the thread executing
@readProcessWithExitCode@, the forked process will be terminated and
@@ -57,25 +57,21 @@ pipeProcess
-> FilePath -- ^ Filename of the executable (see 'proc' for details)
-> [String] -- ^ any arguments
-> BL.ByteString -- ^ standard input
- -> IO (ExitCode,BL.ByteString,BL.ByteString) -- ^ exitcode, stdout, stderr
+ -> IO (ExitCode,BL.ByteString) -- ^ exitcode, stdout
pipeProcess mbenv cmd args input =
mask $ \restore -> do
- (Just inh, Just outh, Just errh, pid) <- createProcess (proc cmd args)
+ (Just inh, Just outh, Nothing, pid) <- createProcess (proc cmd args)
{ env = mbenv,
std_in = CreatePipe,
std_out = CreatePipe,
- std_err = CreatePipe }
+ std_err = Inherit }
flip onException
- (do hClose inh; hClose outh; hClose errh;
+ (do hClose inh; hClose outh;
terminateProcess pid; waitForProcess pid) $ restore $ do
-- fork off a thread to start consuming stdout
out <- BL.hGetContents outh
waitOut <- forkWait $ evaluate $ BL.length out
- -- fork off a thread to start consuming stderr
- err <- BL.hGetContents errh
- waitErr <- forkWait $ evaluate $ BL.length err
-
-- now write and flush any input
let writeInput = do
unless (BL.null input) $ do
@@ -87,15 +83,13 @@ pipeProcess mbenv cmd args input =
-- wait on the output
waitOut
- waitErr
hClose outh
- hClose errh
-- wait on the process
ex <- waitForProcess pid
- return (ex, out, err)
+ return (ex, out)
forkWait :: IO a -> IO (IO a)
forkWait a = do
diff --git a/src/Text/Pandoc/Readers.hs b/src/Text/Pandoc/Readers.hs
new file mode 100644
index 000000000..b9374ba06
--- /dev/null
+++ b/src/Text/Pandoc/Readers.hs
@@ -0,0 +1,160 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+This helper module exports the readers.
+
+Note: all of the readers assume that the input text has @'\n'@
+line endings. So if you get your input text from a web form,
+you should remove @'\r'@ characters using @filter (/='\r')@.
+
+-}
+
+module Text.Pandoc.Readers
+ (
+ -- * Readers: converting /to/ Pandoc format
+ Reader (..)
+ , readers
+ , readDocx
+ , readOdt
+ , readMarkdown
+ , readCommonMark
+ , readCreole
+ , readMediaWiki
+ , readVimwiki
+ , readRST
+ , readOrg
+ , readLaTeX
+ , readHtml
+ , readJATS
+ , readTextile
+ , readDocBook
+ , readOPML
+ , readHaddock
+ , readNative
+ , readJSON
+ , readTWiki
+ , readTikiWiki
+ , readTxt2Tags
+ , readEPUB
+ , readMuse
+ -- * Miscellaneous
+ , getReader
+ , getDefaultExtensions
+ ) where
+
+import Control.Monad.Except (throwError)
+import Data.Aeson
+import qualified Data.ByteString.Lazy as BL
+import Data.List (intercalate)
+import Data.Text (Text)
+import Text.Pandoc.Class
+import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Text.Pandoc.Extensions
+import Text.Pandoc.Options
+import Text.Pandoc.Readers.CommonMark
+import Text.Pandoc.Readers.Creole
+import Text.Pandoc.Readers.DocBook
+import Text.Pandoc.Readers.Docx
+import Text.Pandoc.Readers.EPUB
+import Text.Pandoc.Readers.Haddock
+import Text.Pandoc.Readers.HTML (readHtml)
+import Text.Pandoc.Readers.JATS (readJATS)
+import Text.Pandoc.Readers.LaTeX
+import Text.Pandoc.Readers.Markdown
+import Text.Pandoc.Readers.MediaWiki
+import Text.Pandoc.Readers.Muse
+import Text.Pandoc.Readers.Native
+import Text.Pandoc.Readers.Odt
+import Text.Pandoc.Readers.OPML
+import Text.Pandoc.Readers.Org
+import Text.Pandoc.Readers.RST
+import Text.Pandoc.Readers.Textile
+import Text.Pandoc.Readers.TikiWiki
+import Text.Pandoc.Readers.TWiki
+import Text.Pandoc.Readers.Txt2Tags
+import Text.Pandoc.Readers.Vimwiki
+import Text.Pandoc.Shared (mapLeft)
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.Parsec.Error
+
+data Reader m = TextReader (ReaderOptions -> Text -> m Pandoc)
+ | ByteStringReader (ReaderOptions -> BL.ByteString -> m Pandoc)
+
+-- | Association list of formats and readers.
+readers :: PandocMonad m => [(String, Reader m)]
+readers = [ ("native" , TextReader readNative)
+ ,("json" , TextReader $ \o s ->
+ case readJSON o s of
+ Right doc -> return doc
+ Left _ -> throwError $ PandocParseError "JSON parse error")
+ ,("markdown" , TextReader readMarkdown)
+ ,("markdown_strict" , TextReader readMarkdown)
+ ,("markdown_phpextra" , TextReader readMarkdown)
+ ,("markdown_github" , TextReader readMarkdown)
+ ,("markdown_mmd", TextReader readMarkdown)
+ ,("commonmark" , TextReader readCommonMark)
+ ,("creole" , TextReader readCreole)
+ ,("gfm" , TextReader readCommonMark)
+ ,("rst" , TextReader readRST)
+ ,("mediawiki" , TextReader readMediaWiki)
+ ,("vimwiki" , TextReader readVimwiki)
+ ,("docbook" , TextReader readDocBook)
+ ,("opml" , TextReader readOPML)
+ ,("org" , TextReader readOrg)
+ ,("textile" , TextReader readTextile) -- TODO : textile+lhs
+ ,("html" , TextReader readHtml)
+ ,("jats" , TextReader readJATS)
+ ,("latex" , TextReader readLaTeX)
+ ,("haddock" , TextReader readHaddock)
+ ,("twiki" , TextReader readTWiki)
+ ,("tikiwiki" , TextReader readTikiWiki)
+ ,("docx" , ByteStringReader readDocx)
+ ,("odt" , ByteStringReader readOdt)
+ ,("t2t" , TextReader readTxt2Tags)
+ ,("epub" , ByteStringReader readEPUB)
+ ,("muse" , TextReader readMuse)
+ ]
+
+-- | Retrieve reader, extensions based on formatSpec (format+extensions).
+getReader :: PandocMonad m => String -> Either String (Reader m, Extensions)
+getReader s =
+ case parseFormatSpec s of
+ Left e -> Left $ intercalate "\n" [m | Message m <- errorMessages e]
+ Right (readerName, setExts) ->
+ case lookup readerName readers of
+ Nothing -> Left $ "Unknown reader: " ++ readerName
+ Just r -> Right (r, setExts $
+ getDefaultExtensions readerName)
+
+-- | Read pandoc document from JSON format.
+readJSON :: ReaderOptions -> Text -> Either PandocError Pandoc
+readJSON _ =
+ mapLeft PandocParseError . eitherDecode' . BL.fromStrict . UTF8.fromText
diff --git a/src/Text/Pandoc/Readers/CommonMark.hs b/src/Text/Pandoc/Readers/CommonMark.hs
index d20d386e7..6fbc09c17 100644
--- a/src/Text/Pandoc/Readers/CommonMark.hs
+++ b/src/Text/Pandoc/Readers/CommonMark.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2015-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.CommonMark
- Copyright : Copyright (C) 2015 John MacFarlane
+ Copyright : Copyright (C) 2015-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -32,48 +32,94 @@ CommonMark is a strongly specified variant of Markdown: http://commonmark.org.
module Text.Pandoc.Readers.CommonMark (readCommonMark)
where
-import CMark
-import Data.Text (unpack, pack)
+import CMarkGFM
+import Control.Monad.State
+import Data.Char (isAlphaNum, isLetter, isSpace, toLower)
import Data.List (groupBy)
+import qualified Data.Map as Map
+import Data.Text (Text, unpack)
+import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
+import Text.Pandoc.Emoji (emojis)
import Text.Pandoc.Options
-import Text.Pandoc.Error
+import Text.Pandoc.Shared (stringify)
+import Text.Pandoc.Walk (walkM)
-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
-readCommonMark :: ReaderOptions -> String -> Either PandocError Pandoc
-readCommonMark opts = Right . nodeToPandoc . commonmarkToNode opts' . pack
- where opts' = if readerSmart opts
- then [optNormalize, optSmart]
- else [optNormalize]
-
-nodeToPandoc :: Node -> Pandoc
-nodeToPandoc (Node _ DOCUMENT nodes) =
- Pandoc nullMeta $ foldr addBlock [] nodes
-nodeToPandoc n = -- shouldn't happen
- Pandoc nullMeta $ foldr addBlock [] [n]
-
-addBlocks :: [Node] -> [Block]
-addBlocks = foldr addBlock []
-
-addBlock :: Node -> [Block] -> [Block]
-addBlock (Node _ PARAGRAPH nodes) =
- (Para (addInlines nodes) :)
-addBlock (Node _ THEMATIC_BREAK _) =
+readCommonMark :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
+readCommonMark opts s = return $
+ (if isEnabled Ext_gfm_auto_identifiers opts
+ then addHeaderIdentifiers
+ else id) $
+ nodeToPandoc opts $ commonmarkToNode opts' exts s
+ where opts' = [ optSmart | isEnabled Ext_smart opts ]
+ exts = [ extStrikethrough | isEnabled Ext_strikeout opts ] ++
+ [ extTable | isEnabled Ext_pipe_tables opts ] ++
+ [ extAutolink | isEnabled Ext_autolink_bare_uris opts ]
+
+convertEmojis :: String -> String
+convertEmojis (':':xs) =
+ case break (==':') xs of
+ (ys,':':zs) ->
+ case Map.lookup ys emojis of
+ Just s -> s ++ convertEmojis zs
+ Nothing -> ':' : ys ++ convertEmojis (':':zs)
+ _ -> ':':xs
+convertEmojis (x:xs) = x : convertEmojis xs
+convertEmojis [] = []
+
+addHeaderIdentifiers :: Pandoc -> Pandoc
+addHeaderIdentifiers doc = evalState (walkM addHeaderId doc) mempty
+
+addHeaderId :: Block -> State (Map.Map String Int) Block
+addHeaderId (Header lev (_,classes,kvs) ils) = do
+ idmap <- get
+ let ident = toIdent ils
+ ident' <- case Map.lookup ident idmap of
+ Nothing -> do
+ put (Map.insert ident 1 idmap)
+ return ident
+ Just i -> do
+ put (Map.adjust (+ 1) ident idmap)
+ return (ident ++ "-" ++ show i)
+ return $ Header lev (ident',classes,kvs) ils
+addHeaderId x = return x
+
+toIdent :: [Inline] -> String
+toIdent = map (\c -> if isSpace c then '-' else c)
+ . filter (\c -> isLetter c || isAlphaNum c || isSpace c ||
+ c == '_' || c == '-')
+ . map toLower . stringify
+
+nodeToPandoc :: ReaderOptions -> Node -> Pandoc
+nodeToPandoc opts (Node _ DOCUMENT nodes) =
+ Pandoc nullMeta $ foldr (addBlock opts) [] nodes
+nodeToPandoc opts n = -- shouldn't happen
+ Pandoc nullMeta $ foldr (addBlock opts) [] [n]
+
+addBlocks :: ReaderOptions -> [Node] -> [Block]
+addBlocks opts = foldr (addBlock opts) []
+
+addBlock :: ReaderOptions -> Node -> [Block] -> [Block]
+addBlock opts (Node _ PARAGRAPH nodes) =
+ (Para (addInlines opts nodes) :)
+addBlock _ (Node _ THEMATIC_BREAK _) =
(HorizontalRule :)
-addBlock (Node _ BLOCK_QUOTE nodes) =
- (BlockQuote (addBlocks nodes) :)
-addBlock (Node _ (HTML_BLOCK t) _) =
- (RawBlock (Format "html") (unpack t) :)
+addBlock opts (Node _ BLOCK_QUOTE nodes) =
+ (BlockQuote (addBlocks opts nodes) :)
+addBlock opts (Node _ (HTML_BLOCK t) _)
+ | isEnabled Ext_raw_html opts = (RawBlock (Format "html") (unpack t) :)
+ | otherwise = id
-- Note: the cmark parser will never generate CUSTOM_BLOCK,
-- so we don't need to handle it:
-addBlock (Node _ (CUSTOM_BLOCK _onEnter _onExit) _nodes) =
+addBlock _ (Node _ (CUSTOM_BLOCK _onEnter _onExit) _nodes) =
id
-addBlock (Node _ (CODE_BLOCK info t) _) =
+addBlock _ (Node _ (CODE_BLOCK info t) _) =
(CodeBlock ("", take 1 (words (unpack info)), []) (unpack t) :)
-addBlock (Node _ (HEADING lev) nodes) =
- (Header lev ("",[],[]) (addInlines nodes) :)
-addBlock (Node _ (LIST listAttrs) nodes) =
- (constructor (map (setTightness . addBlocks . children) nodes) :)
+addBlock opts (Node _ (HEADING lev) nodes) =
+ (Header lev ("",[],[]) (addInlines opts nodes) :)
+addBlock opts (Node _ (LIST listAttrs) nodes) =
+ (constructor (map (setTightness . addBlocks opts . children) nodes) :)
where constructor = case listType listAttrs of
BULLET_LIST -> BulletList
ORDERED_LIST -> OrderedList
@@ -82,46 +128,108 @@ addBlock (Node _ (LIST listAttrs) nodes) =
setTightness = if listTight listAttrs
then map paraToPlain
else id
- paraToPlain (Para xs) = Plain (xs)
+ paraToPlain (Para xs) = Plain xs
paraToPlain x = x
delim = case listDelim listAttrs of
- PERIOD_DELIM -> Period
- PAREN_DELIM -> OneParen
-addBlock (Node _ ITEM _) = id -- handled in LIST
-addBlock _ = id
+ PERIOD_DELIM -> Period
+ PAREN_DELIM -> OneParen
+addBlock opts (Node _ (TABLE alignments) nodes) =
+ (Table [] aligns widths headers rows :)
+ where aligns = map fromTableCellAlignment alignments
+ fromTableCellAlignment NoAlignment = AlignDefault
+ fromTableCellAlignment LeftAligned = AlignLeft
+ fromTableCellAlignment RightAligned = AlignRight
+ fromTableCellAlignment CenterAligned = AlignCenter
+ widths = replicate numcols 0.0
+ numcols = if null rows'
+ then 0
+ else maximum $ map length rows'
+ rows' = map toRow $ filter isRow nodes
+ (headers, rows) = case rows' of
+ (h:rs) -> (h, rs)
+ [] -> ([], [])
+ isRow (Node _ TABLE_ROW _) = True
+ isRow _ = False
+ isCell (Node _ TABLE_CELL _) = True
+ isCell _ = False
+ toRow (Node _ TABLE_ROW ns) = map toCell $ filter isCell ns
+ toRow (Node _ t _) = error $ "toRow encountered non-row " ++ show t
+ toCell (Node _ TABLE_CELL []) = []
+ toCell (Node _ TABLE_CELL (n:ns))
+ | isBlockNode n = addBlocks opts (n:ns)
+ | otherwise = [Plain (addInlines opts (n:ns))]
+ toCell (Node _ t _) = error $ "toCell encountered non-cell " ++ show t
+addBlock _ (Node _ TABLE_ROW _) = id -- handled in TABLE
+addBlock _ (Node _ TABLE_CELL _) = id -- handled in TABLE
+addBlock _ _ = id
+
+isBlockNode :: Node -> Bool
+isBlockNode (Node _ nodetype _) =
+ case nodetype of
+ DOCUMENT -> True
+ THEMATIC_BREAK -> True
+ PARAGRAPH -> True
+ BLOCK_QUOTE -> True
+ HTML_BLOCK _ -> True
+ CUSTOM_BLOCK _ _ -> True
+ CODE_BLOCK _ _ -> True
+ HEADING _ -> True
+ LIST _ -> True
+ ITEM -> True
+ TEXT _ -> False
+ SOFTBREAK -> False
+ LINEBREAK -> False
+ HTML_INLINE _ -> False
+ CUSTOM_INLINE _ _ -> False
+ CODE _ -> False
+ EMPH -> False
+ STRONG -> False
+ LINK _ _ -> False
+ IMAGE _ _ -> False
+ STRIKETHROUGH -> False
+ TABLE _ -> False
+ TABLE_ROW -> False
+ TABLE_CELL -> False
children :: Node -> [Node]
children (Node _ _ ns) = ns
-addInlines :: [Node] -> [Inline]
-addInlines = foldr addInline []
+addInlines :: ReaderOptions -> [Node] -> [Inline]
+addInlines opts = foldr (addInline opts) []
-addInline :: Node -> [Inline] -> [Inline]
-addInline (Node _ (TEXT t) _) = (map toinl clumps ++)
+addInline :: ReaderOptions -> Node -> [Inline] -> [Inline]
+addInline opts (Node _ (TEXT t) _) = (map toinl clumps ++)
where raw = unpack t
clumps = groupBy samekind raw
samekind ' ' ' ' = True
samekind ' ' _ = False
samekind _ ' ' = False
samekind _ _ = True
- toinl (' ':_) = Space
- toinl xs = Str xs
-addInline (Node _ LINEBREAK _) = (LineBreak :)
-addInline (Node _ SOFTBREAK _) = (SoftBreak :)
-addInline (Node _ (HTML_INLINE t) _) =
- (RawInline (Format "html") (unpack t) :)
+ toinl (' ':_) = Space
+ toinl xs = Str $ if isEnabled Ext_emoji opts
+ then convertEmojis xs
+ else xs
+addInline _ (Node _ LINEBREAK _) = (LineBreak :)
+addInline opts (Node _ SOFTBREAK _)
+ | isEnabled Ext_hard_line_breaks opts = (LineBreak :)
+ | otherwise = (SoftBreak :)
+addInline opts (Node _ (HTML_INLINE t) _)
+ | isEnabled Ext_raw_html opts = (RawInline (Format "html") (unpack t) :)
+ | otherwise = id
-- Note: the cmark parser will never generate CUSTOM_BLOCK,
-- so we don't need to handle it:
-addInline (Node _ (CUSTOM_INLINE _onEnter _onExit) _nodes) =
+addInline _ (Node _ (CUSTOM_INLINE _onEnter _onExit) _nodes) =
id
-addInline (Node _ (CODE t) _) =
+addInline _ (Node _ (CODE t) _) =
(Code ("",[],[]) (unpack t) :)
-addInline (Node _ EMPH nodes) =
- (Emph (addInlines nodes) :)
-addInline (Node _ STRONG nodes) =
- (Strong (addInlines nodes) :)
-addInline (Node _ (LINK url title) nodes) =
- (Link nullAttr (addInlines nodes) (unpack url, unpack title) :)
-addInline (Node _ (IMAGE url title) nodes) =
- (Image nullAttr (addInlines nodes) (unpack url, unpack title) :)
-addInline _ = id
+addInline opts (Node _ EMPH nodes) =
+ (Emph (addInlines opts nodes) :)
+addInline opts (Node _ STRONG nodes) =
+ (Strong (addInlines opts nodes) :)
+addInline opts (Node _ STRIKETHROUGH nodes) =
+ (Strikeout (addInlines opts nodes) :)
+addInline opts (Node _ (LINK url title) nodes) =
+ (Link nullAttr (addInlines opts nodes) (unpack url, unpack title) :)
+addInline opts (Node _ (IMAGE url title) nodes) =
+ (Image nullAttr (addInlines opts nodes) (unpack url, unpack title) :)
+addInline _ _ = id
diff --git a/src/Text/Pandoc/Readers/Creole.hs b/src/Text/Pandoc/Readers/Creole.hs
new file mode 100644
index 000000000..505d1686d
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Creole.hs
@@ -0,0 +1,320 @@
+{-
+ Copyright (C) 2017 Sascha Wilde <wilde@sha-bang.de>
+
+ partly based on all the other readers, especialy the work by
+ John MacFarlane <jgm@berkeley.edu> and
+ Alexander Sulfrian <alexander.sulfrian@fu-berlin.de>
+ all bugs are solely created by me.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Creole
+ Copyright : Copyright (C) 2017 Sascha Wilde
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Sascha Wilde <wilde@sha-bang.de>
+ Stability : alpha
+ Portability : portable
+
+Conversion of creole text to 'Pandoc' document.
+-}
+module Text.Pandoc.Readers.Creole ( readCreole
+ ) where
+
+import Control.Monad.Except (guard, liftM2, throwError)
+import qualified Data.Foldable as F
+import Data.Maybe (fromMaybe)
+import Data.Monoid
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad (..))
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (enclosed)
+import Text.Pandoc.Shared (crFilter)
+
+
+-- | Read creole from an input string and return a Pandoc document.
+readCreole :: PandocMonad m
+ => ReaderOptions
+ -> Text
+ -> m Pandoc
+readCreole opts s = do
+ res <- readWithM parseCreole def{ stateOptions = opts }
+ (T.unpack (crFilter s) ++ "\n\n")
+ case res of
+ Left e -> throwError e
+ Right d -> return d
+
+type CRLParser = ParserT [Char] ParserState
+
+--
+-- Utility functions
+--
+
+(<+>) :: (Monad m, Monoid a) => m a -> m a -> m a
+(<+>) = liftM2 (<>)
+
+-- we have to redefine `enclosed' from Text.Pandoc.Parsing, because it
+-- assumes, that there can't be a space after the start parser, but
+-- with creole this is possible.
+enclosed :: (Show end, PandocMonad m) => CRLParser m start -- ^ start parser
+ -> CRLParser m end -- ^ end parser
+ -> CRLParser m a -- ^ content parser (to be used repeatedly)
+ -> CRLParser m [a]
+enclosed start end parser = try $ start >> many1Till parser end
+
+--
+-- main parser
+--
+
+specialChars :: [Char]
+specialChars = "*/~{}\\|[]()<>\"'"
+
+parseCreole :: PandocMonad m => CRLParser m Pandoc
+parseCreole = do
+ bs <- mconcat <$> many block
+ spaces
+ eof
+ return $ B.doc bs
+
+
+--
+-- block parsers
+--
+
+block :: PandocMonad m => CRLParser m B.Blocks
+block = do
+ res <- mempty <$ skipMany1 blankline
+ <|> nowiki
+ <|> header
+ <|> horizontalRule
+ <|> anyList 1
+ <|> table
+ <|> para
+ skipMany blankline
+ return res
+
+nowiki :: PandocMonad m => CRLParser m B.Blocks
+nowiki = try $ fmap (B.codeBlock . mconcat) (nowikiStart
+ >> manyTill content nowikiEnd)
+ where
+ content = brackets <|> line
+ brackets = try $ option "" ((:[]) <$> newline)
+ <+> (char ' ' >> (many (char ' ') <+> string "}}}") <* eol)
+ line = option "" ((:[]) <$> newline) <+> manyTill anyChar eol
+ eol = lookAhead $ try $ nowikiEnd <|> newline
+ nowikiStart = optional newline >> string "{{{" >> skipMany spaceChar >> newline
+ nowikiEnd = try $ linebreak >> string "}}}" >> skipMany spaceChar >> newline
+
+header :: PandocMonad m => CRLParser m B.Blocks
+header = try $ do
+ skipSpaces
+ level <-
+ fmap length (many1 (char '='))
+ guard $ level <= 6
+ skipSpaces
+ content <- B.str <$> manyTill (noneOf "\n") headerEnd
+ return $ B.header level content
+ where
+ headerEnd = try $ skipSpaces >> many (char '=') >> skipSpaces >> newline
+
+unorderedList :: PandocMonad m => Int -> CRLParser m B.Blocks
+unorderedList = list '*' B.bulletList
+
+orderedList :: PandocMonad m => Int -> CRLParser m B.Blocks
+orderedList = list '#' B.orderedList
+
+anyList :: PandocMonad m => Int -> CRLParser m B.Blocks
+anyList n = unorderedList n <|> orderedList n
+
+anyListItem :: PandocMonad m => Int -> CRLParser m B.Blocks
+anyListItem n = listItem '*' n <|> listItem '#' n
+
+list :: PandocMonad m => Char -> ([B.Blocks] -> B.Blocks) -> Int -> CRLParser m B.Blocks
+list c f n =
+ fmap f (many1 (itemPlusSublist <|> listItem c n))
+ where itemPlusSublist = try $ listItem c n <+> anyList (n+1)
+
+listItem :: PandocMonad m => Char -> Int -> CRLParser m B.Blocks
+listItem c n =
+ fmap (B.plain . B.trimInlines .mconcat) (listStart >> many1Till inline itemEnd)
+ where
+ listStart = try $ skipSpaces >> optional newline >> skipSpaces
+ >> count n (char c)
+ >> lookAhead (noneOf [c]) >> skipSpaces
+ itemEnd = endOfParaElement <|> nextItem n
+ <|> if n < 3 then nextItem (n+1)
+ else nextItem (n+1) <|> nextItem (n-1)
+ nextItem x = lookAhead $ try $ blankline >> anyListItem x >> return mempty
+
+table :: PandocMonad m => CRLParser m B.Blocks
+table = try $ do
+ headers <- optionMaybe headerRow
+ rows <- many1 row
+ return $ B.simpleTable (fromMaybe [mempty] headers) rows
+ where
+ headerRow = try $ skipSpaces >> many1Till headerCell rowEnd
+ headerCell = B.plain . B.trimInlines . mconcat
+ <$> (string "|=" >> many1Till inline cellEnd)
+ row = try $ skipSpaces >> many1Till cell rowEnd
+ cell = B.plain . B.trimInlines . mconcat
+ <$> (char '|' >> many1Till inline cellEnd)
+ rowEnd = try $ optional (char '|') >> skipSpaces >> newline
+ cellEnd = lookAhead $ try $ char '|' <|> rowEnd
+
+para :: PandocMonad m => CRLParser m B.Blocks
+para = fmap (result . mconcat) (many1Till inline endOfParaElement)
+ where
+ result content = if F.all (==Space) content
+ then mempty
+ else B.para $ B.trimInlines content
+
+endOfParaElement :: PandocMonad m => CRLParser m ()
+endOfParaElement = lookAhead $ endOfInput <|> endOfPara
+ <|> startOfList <|> startOfTable
+ <|> startOfHeader <|> hr <|> startOfNowiki
+ where
+ endOfInput = try $ skipMany blankline >> skipSpaces >> eof
+ endOfPara = try $ blankline >> skipMany1 blankline
+ startOf :: PandocMonad m => CRLParser m a -> CRLParser m ()
+ startOf p = try $ blankline >> p >> return mempty
+ startOfList = startOf $ anyListItem 1
+ startOfTable = startOf table
+ startOfHeader = startOf header
+ startOfNowiki = startOf nowiki
+ hr = startOf horizontalRule
+
+horizontalRule :: PandocMonad m => CRLParser m B.Blocks
+horizontalRule = try $ skipSpaces >> string "----" >> skipSpaces >> newline
+ >> return B.horizontalRule
+
+--
+-- inline parsers
+--
+
+inline :: PandocMonad m => CRLParser m B.Inlines
+inline = choice [ whitespace
+ , escapedLink
+ , escapedChar
+ , link
+ , inlineNowiki
+ , placeholder
+ , image
+ , forcedLinebreak
+ , bold
+ , finalBold
+ , italics
+ , finalItalics
+ , str
+ , symbol
+ ] <?> "inline"
+
+escapedChar :: PandocMonad m => CRLParser m B.Inlines
+escapedChar =
+ fmap (B.str . (:[])) (try $ char '~' >> noneOf "\t\n ")
+
+escapedLink :: PandocMonad m => CRLParser m B.Inlines
+escapedLink = try $ do
+ char '~'
+ (orig, _) <- uri
+ return $ B.str orig
+
+image :: PandocMonad m => CRLParser m B.Inlines
+image = try $ do
+ (orig, src) <- wikiImg
+ return $ B.image src "" (B.str orig)
+ where
+ linkSrc = many $ noneOf "|}\n\r\t"
+ linkDsc = char '|' >> many (noneOf "}\n\r\t")
+ wikiImg = try $ do
+ string "{{"
+ src <- linkSrc
+ dsc <- option "" linkDsc
+ string "}}"
+ return (dsc, src)
+
+link :: PandocMonad m => CRLParser m B.Inlines
+link = try $ do
+ (orig, src) <- uriLink <|> wikiLink
+ return $ B.link src "" orig
+ where
+ linkSrc = many $ noneOf "|]\n\r\t"
+ linkDsc :: PandocMonad m => String -> CRLParser m B.Inlines
+ linkDsc otxt = B.str
+ <$> try (option otxt
+ (char '|' >> many (noneOf "]\n\r\t")))
+ linkImg = try $ char '|' >> image
+ wikiLink = try $ do
+ string "[["
+ src <- linkSrc
+ dsc <- linkImg <|> linkDsc src
+ string "]]"
+ return (dsc, src)
+ uriLink = try $ do
+ (orig, src) <- uri
+ return (B.str orig, src)
+
+inlineNowiki :: PandocMonad m => CRLParser m B.Inlines
+inlineNowiki = B.code <$> (start >> manyTill (noneOf "\n\r") end)
+ where
+ start = try $ string "{{{"
+ end = try $ string "}}}" >> lookAhead (noneOf "}")
+
+placeholder :: PandocMonad m => CRLParser m B.Inlines
+-- The semantics of the placeholder is basicallly implementation
+-- dependent, so there is no way to DTRT for all cases.
+-- So for now we just drop them.
+placeholder = B.text <$> try (string "<<<" >> manyTill anyChar (string ">>>")
+ >> return "")
+
+whitespace :: PandocMonad m => CRLParser m B.Inlines
+whitespace = lb <|> regsp
+ where lb = try $ skipMany spaceChar >> linebreak >> return B.space
+ regsp = try $ skipMany1 spaceChar >> return B.space
+
+linebreak :: PandocMonad m => CRLParser m B.Inlines
+linebreak = newline >> notFollowedBy newline >> (lastNewline <|> innerNewline)
+ where lastNewline = eof >> return mempty
+ innerNewline = return B.space
+
+symbol :: PandocMonad m => CRLParser m B.Inlines
+symbol = fmap (B.str . (:[])) (oneOf specialChars)
+
+str :: PandocMonad m => CRLParser m B.Inlines
+str = let strChar = noneOf ("\t\n " ++ specialChars) in
+ fmap B.str (many1 strChar)
+
+bold :: PandocMonad m => CRLParser m B.Inlines
+bold = B.strong . mconcat <$>
+ enclosed (string "**") (try $ string "**") inline
+
+italics :: PandocMonad m => CRLParser m B.Inlines
+italics = B.emph . mconcat <$>
+ enclosed (string "//") (try $ string "//") inline
+
+finalBold :: PandocMonad m => CRLParser m B.Inlines
+finalBold = B.strong . mconcat <$>
+ try (string "**" >> many1Till inline endOfParaElement)
+
+finalItalics :: PandocMonad m => CRLParser m B.Inlines
+finalItalics = B.emph . mconcat <$>
+ try (string "//" >> many1Till inline endOfParaElement)
+
+forcedLinebreak :: PandocMonad m => CRLParser m B.Inlines
+forcedLinebreak = try $ string "\\\\" >> return B.linebreak
diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs
index 68552ccb3..728f77a05 100644
--- a/src/Text/Pandoc/Readers/DocBook.hs
+++ b/src/Text/Pandoc/Readers/DocBook.hs
@@ -1,22 +1,22 @@
+{-# LANGUAGE ExplicitForAll #-}
module Text.Pandoc.Readers.DocBook ( readDocBook ) where
-import Data.Char (toUpper)
-import Text.Pandoc.Shared (safeRead)
-import Text.Pandoc.Options
-import Text.Pandoc.Definition
-import Text.Pandoc.Builder
-import Text.XML.Light
-import Text.HTML.TagSoup.Entity (lookupEntity)
+import Control.Monad.State.Strict
+import Data.Char (isSpace, toUpper)
+import Data.Default
import Data.Either (rights)
+import Data.Foldable (asum)
import Data.Generics
-import Data.Char (isSpace)
-import Control.Monad.State
import Data.List (intersperse)
import Data.Maybe (fromMaybe)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.HTML.TagSoup.Entity (lookupEntity)
+import Text.Pandoc.Builder
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Options
+import Text.Pandoc.Shared (crFilter, safeRead)
import Text.TeXMath (readMathML, writeTeX)
-import Text.Pandoc.Error (PandocError)
-import Control.Monad.Except
-import Data.Default
-import Data.Foldable (asum)
+import Text.XML.Light
{-
@@ -50,7 +50,7 @@ List of all DocBook tags, with [x] indicating implemented,
[x] author - The name of an individual author
[ ] authorblurb - A short description or note about an author
[x] authorgroup - Wrapper for author information when a document has
- multiple authors or collabarators
+ multiple authors or collaborators
[x] authorinitials - The initials or other short identifier for an author
[o] beginpage - The location of a page break in a print version of the document
[ ] bibliocoverage - The spatial or temporal coverage of a document
@@ -502,7 +502,7 @@ List of all DocBook tags, with [x] indicating implemented,
[x] ?asciidoc-br? - line break from asciidoc docbook output
-}
-type DB = ExceptT PandocError (State DBState)
+type DB m = StateT DBState m
data DBState = DBState{ dbSectionLevel :: Int
, dbQuoteType :: QuoteType
@@ -523,10 +523,12 @@ instance Default DBState where
, dbContent = [] }
-readDocBook :: ReaderOptions -> String -> Either PandocError Pandoc
-readDocBook _ inp = (\blocks -> Pandoc (dbMeta st') (toList . mconcat $ blocks)) <$> bs
- where (bs , st') = flip runState (def{ dbContent = tree }) . runExceptT . mapM parseBlock $ tree
- tree = normalizeTree . parseXML . handleInstructions $ inp
+readDocBook :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
+readDocBook _ inp = do
+ let tree = normalizeTree . parseXML . handleInstructions
+ $ T.unpack $ crFilter inp
+ (bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock tree
+ return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
-- We treat <?asciidoc-br?> specially (issue #1236), converting it
-- to <br/>, since xml-light doesn't parse the instruction correctly.
@@ -536,12 +538,12 @@ handleInstructions ('<':'?':'a':'s':'c':'i':'i':'d':'o':'c':'-':'b':'r':'?':'>':
handleInstructions xs = case break (=='<') xs of
(ys, []) -> ys
([], '<':zs) -> '<' : handleInstructions zs
- (ys, zs) -> ys ++ handleInstructions zs
+ (ys, zs) -> ys ++ handleInstructions zs
-getFigure :: Element -> DB Blocks
+getFigure :: PandocMonad m => Element -> DB m Blocks
getFigure e = do
tit <- case filterChild (named "title") e of
- Just t -> getInlines t
+ Just t -> getInlines t
Nothing -> return mempty
modify $ \st -> st{ dbFigureTitle = tit }
res <- getBlocks e
@@ -564,14 +566,12 @@ normalizeTree = everywhere (mkT go)
go xs = xs
convertEntity :: String -> String
-convertEntity e = maybe (map toUpper e) id (lookupEntity e)
+convertEntity e = Data.Maybe.fromMaybe (map toUpper e) (lookupEntity e)
-- convenience function to get an attribute value, defaulting to ""
attrValue :: String -> Element -> String
attrValue attr elt =
- case lookupAttrBy (\x -> qName x == attr) (elAttribs elt) of
- Just z -> z
- Nothing -> ""
+ fromMaybe "" (lookupAttrBy (\x -> qName x == attr) (elAttribs elt))
-- convenience function
named :: String -> Element -> Bool
@@ -579,20 +579,20 @@ named s e = qName (elName e) == s
--
-acceptingMetadata :: DB a -> DB a
+acceptingMetadata :: PandocMonad m => DB m a -> DB m a
acceptingMetadata p = do
modify (\s -> s { dbAcceptsMeta = True } )
res <- p
modify (\s -> s { dbAcceptsMeta = False })
return res
-checkInMeta :: Monoid a => DB () -> DB a
+checkInMeta :: (PandocMonad m, Monoid a) => DB m () -> DB m a
checkInMeta p = do
accepts <- dbAcceptsMeta <$> get
when accepts p
return mempty
-addMeta :: ToMetaValue a => String -> a -> DB ()
+addMeta :: PandocMonad m => ToMetaValue a => String -> a -> DB m ()
addMeta field val = modify (setMeta field val)
instance HasMeta DBState where
@@ -631,7 +631,7 @@ addToStart toadd bs =
-- function that is used by both mediaobject (in parseBlock)
-- and inlinemediaobject (in parseInline)
-- A DocBook mediaobject is a wrapper around a set of alternative presentations
-getMediaobject :: Element -> DB Inlines
+getMediaobject :: PandocMonad m => Element -> DB m Inlines
getMediaobject e = do
(imageUrl, attr) <-
case filterChild (named "imageobject") e of
@@ -651,18 +651,20 @@ getMediaobject e = do
|| named "textobject" x
|| named "alt" x) el of
Nothing -> return mempty
- Just z -> mconcat <$> (mapM parseInline $ elContent z)
+ Just z -> mconcat <$>
+ mapM parseInline (elContent z)
figTitle <- gets dbFigureTitle
let (caption, title) = if isNull figTitle
then (getCaption e, "")
else (return figTitle, "fig:")
- liftM (imageWith attr imageUrl title) caption
+ fmap (imageWith attr imageUrl title) caption
-getBlocks :: Element -> DB Blocks
-getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
+getBlocks :: PandocMonad m => Element -> DB m Blocks
+getBlocks e = mconcat <$>
+ mapM parseBlock (elContent e)
-parseBlock :: Content -> DB Blocks
+parseBlock :: PandocMonad m => Content -> DB m Blocks
parseBlock (Text (CData CDataRaw _ _)) = return mempty -- DOCTYPE
parseBlock (Text (CData _ s _)) = if all isSpace s
then return mempty
@@ -795,15 +797,16 @@ parseBlock (Elem e) =
return $ p <> b <> x
codeBlockWithLang = do
let classes' = case attrValue "language" e of
- "" -> []
- x -> [x]
+ "" -> []
+ x -> [x]
return $ codeBlockWith (attrValue "id" e, classes', [])
$ trimNl $ strContentRecursive e
parseBlockquote = do
attrib <- case filterChild (named "attribution") e of
Nothing -> return mempty
Just z -> (para . (str "— " <>) . mconcat)
- <$> (mapM parseInline $ elContent z)
+ <$>
+ mapM parseInline (elContent z)
contents <- getBlocks e
return $ blockQuote (contents <> attrib)
listitems = mapM getBlocks $ filterChildren (named "listitem") e
@@ -868,11 +871,11 @@ parseBlock (Elem e) =
|| x == '.') w
Nothing -> 0 :: Double
let numrows = case bodyrows of
- [] -> 0
- xs -> maximum $ map length xs
+ [] -> 0
+ xs -> maximum $ map length xs
let aligns = case colspecs of
- [] -> replicate numrows AlignDefault
- cs -> map toAlignment cs
+ [] -> replicate numrows AlignDefault
+ cs -> map toAlignment cs
let widths = case colspecs of
[] -> replicate numrows 0
cs -> let ws = map toWidth cs
@@ -892,7 +895,7 @@ parseBlock (Elem e) =
headerText <- case filterChild (named "title") e `mplus`
(filterChild (named "info") e >>=
filterChild (named "title")) of
- Just t -> getInlines t
+ Just t -> getInlines t
Nothing -> return mempty
modify $ \st -> st{ dbSectionLevel = n }
b <- getBlocks e
@@ -902,8 +905,9 @@ parseBlock (Elem e) =
lineItems = mapM getInlines $ filterChildren (named "line") e
metaBlock = acceptingMetadata (getBlocks e) >> return mempty
-getInlines :: Element -> DB Inlines
-getInlines e' = (trimInlines . mconcat) <$> (mapM parseInline $ elContent e')
+getInlines :: PandocMonad m => Element -> DB m Inlines
+getInlines e' = (trimInlines . mconcat) <$>
+ mapM parseInline (elContent e')
strContentRecursive :: Element -> String
strContentRecursive = strContent .
@@ -913,10 +917,10 @@ elementToStr :: Content -> Content
elementToStr (Elem e') = Text $ CData CDataText (strContentRecursive e') Nothing
elementToStr x = x
-parseInline :: Content -> DB Inlines
+parseInline :: PandocMonad m => Content -> DB m Inlines
parseInline (Text (CData _ s _)) = return $ text s
parseInline (CRef ref) =
- return $ maybe (text $ map toUpper ref) (text) $ lookupEntity ref
+ return $ maybe (text $ map toUpper ref) text $ lookupEntity ref
parseInline (Elem e) =
case qName (elName e) of
"equation" -> equation displayMath
@@ -957,8 +961,10 @@ parseInline (Elem e) =
"userinput" -> codeWithLang
"varargs" -> return $ code "(...)"
"keycap" -> return (str $ strContent e)
- "keycombo" -> keycombo <$> (mapM parseInline $ elContent e)
- "menuchoice" -> menuchoice <$> (mapM parseInline $
+ "keycombo" -> keycombo <$>
+ mapM parseInline (elContent e)
+ "menuchoice" -> menuchoice <$>
+ mapM parseInline (
filter isGuiMenu $ elContent e)
"xref" -> do
content <- dbContent <$> get
@@ -977,17 +983,18 @@ parseInline (Elem e) =
ils <- innerInlines
let href = case findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e of
Just h -> h
- _ -> ('#' : attrValue "linkend" e)
+ _ -> '#' : attrValue "linkend" e
let ils' = if ils == mempty then str href else ils
let attr = (attrValue "id" e, words $ attrValue "role" e, [])
return $ linkWith attr href "" ils'
"foreignphrase" -> emph <$> innerInlines
"emphasis" -> case attrValue "role" e of
- "bold" -> strong <$> innerInlines
- "strong" -> strong <$> innerInlines
+ "bold" -> strong <$> innerInlines
+ "strong" -> strong <$> innerInlines
"strikethrough" -> strikeout <$> innerInlines
- _ -> emph <$> innerInlines
- "footnote" -> (note . mconcat) <$> (mapM parseBlock $ elContent e)
+ _ -> emph <$> innerInlines
+ "footnote" -> (note . mconcat) <$>
+ mapM parseBlock (elContent e)
"title" -> return mempty
"affiliation" -> return mempty
-- Note: this isn't a real docbook tag; it's what we convert
@@ -996,7 +1003,7 @@ parseInline (Elem e) =
"br" -> return linebreak
_ -> innerInlines
where innerInlines = (trimInlines . mconcat) <$>
- (mapM parseInline $ elContent e)
+ mapM parseInline (elContent e)
equation constructor = return $ mconcat $
map (constructor . writeTeX)
$ rights
diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs
index 595c805bf..e58b0a905 100644
--- a/src/Text/Pandoc/Readers/Docx.hs
+++ b/src/Text/Pandoc/Readers/Docx.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE PatternGuards, OverloadedStrings, CPP #-}
-
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2014-2016 Jesse Rosenthal <jrosenthal@jhu.edu>
+Copyright (C) 2014-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Docx
- Copyright : Copyright (C) 2014-2016 Jesse Rosenthal
+ Copyright : Copyright (C) 2014-2018 Jesse Rosenthal
License : GNU GPL, version 2 or above
Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -50,12 +51,13 @@ implemented, [-] means partially implemented):
* Inlines
- [X] Str
- - [X] Emph (italics and underline both read as Emph)
+ - [X] Emph
- [X] Strong
- [X] Strikeout
- [X] Superscript
- [X] Subscript
- [X] SmallCaps
+ - [-] Underline (was previously converted to Emph)
- [ ] Quoted
- [ ] Cite
- [X] Code (styled with `VerbatimChar`)
@@ -64,88 +66,91 @@ implemented, [-] means partially implemented):
- [X] Math
- [X] Link (links to an arbitrary bookmark create a span with the target as
id and "anchor" class)
- - [X] Image
+ - [X] Image
- [X] Note (Footnotes and Endnotes are silently combined.)
-}
module Text.Pandoc.Readers.Docx
- ( readDocxWithWarnings
- , readDocx
+ ( readDocx
) where
import Codec.Archive.Zip
-import Text.Pandoc.Definition
-import Text.Pandoc.Options
+import Control.Monad.Reader
+import Control.Monad.State.Strict
+import qualified Data.ByteString.Lazy as B
+import Data.Default (Default)
+import Data.List (delete, intersect)
+import qualified Data.Map as M
+import Data.Maybe (isJust, fromMaybe)
+import Data.Sequence (ViewL (..), viewl)
+import qualified Data.Sequence as Seq
+import qualified Data.Set as Set
import Text.Pandoc.Builder
-import Text.Pandoc.Walk
-import Text.Pandoc.Readers.Docx.Parse
-import Text.Pandoc.Readers.Docx.Lists
+-- import Text.Pandoc.Definition
+import Text.Pandoc.MediaBag (MediaBag)
+import Text.Pandoc.Options
import Text.Pandoc.Readers.Docx.Combine
+import Text.Pandoc.Readers.Docx.Lists
+import Text.Pandoc.Readers.Docx.Parse
import Text.Pandoc.Shared
-import Text.Pandoc.MediaBag (insertMedia, MediaBag)
-import Data.List (delete, intersect)
+import Text.Pandoc.Walk
import Text.TeXMath (writeTeX)
-import Data.Default (Default)
-import qualified Data.ByteString.Lazy as B
-import qualified Data.Map as M
-import qualified Data.Set as Set
-import Control.Monad.Reader
-import Control.Monad.State
-import Data.Sequence (ViewL(..), viewl)
-import qualified Data.Sequence as Seq (null)
#if !(MIN_VERSION_base(4,8,0))
import Data.Traversable (traverse)
#endif
-
+import Control.Monad.Except (throwError)
+import Text.Pandoc.Class (PandocMonad)
+import qualified Text.Pandoc.Class as P
import Text.Pandoc.Error
-import Control.Monad.Except
+import Text.Pandoc.Logging
-readDocxWithWarnings :: ReaderOptions
- -> B.ByteString
- -> Either PandocError (Pandoc, MediaBag, [String])
-readDocxWithWarnings opts bytes
+readDocx :: PandocMonad m
+ => ReaderOptions
+ -> B.ByteString
+ -> m Pandoc
+readDocx opts bytes
| Right archive <- toArchiveOrFail bytes
, Right (docx, parserWarnings) <- archiveToDocxWithWarnings archive = do
- (meta, blks, mediaBag, warnings) <- docxToOutput opts docx
- return (Pandoc meta blks, mediaBag, parserWarnings ++ warnings)
-readDocxWithWarnings _ _ =
- Left (ParseFailure "couldn't parse docx file")
-
-readDocx :: ReaderOptions
- -> B.ByteString
- -> Either PandocError (Pandoc, MediaBag)
-readDocx opts bytes = do
- (pandoc, mediaBag, _) <- readDocxWithWarnings opts bytes
- return (pandoc, mediaBag)
+ mapM_ (P.report . DocxParserWarning) parserWarnings
+ (meta, blks) <- docxToOutput opts docx
+ return $ Pandoc meta blks
+readDocx _ _ =
+ throwError $ PandocSomeError "couldn't parse docx file"
data DState = DState { docxAnchorMap :: M.Map String String
- , docxMediaBag :: MediaBag
- , docxDropCap :: Inlines
- , docxWarnings :: [String]
+ , docxAnchorSet :: Set.Set String
+ , docxImmedPrevAnchor :: Maybe String
+ , docxMediaBag :: MediaBag
+ , docxDropCap :: Inlines
+ , docxWarnings :: [String]
+ -- keep track of (numId, lvl) values for
+ -- restarting
+ , docxListState :: M.Map (String, String) Integer
+ , docxPrevPara :: Inlines
}
instance Default DState where
def = DState { docxAnchorMap = M.empty
+ , docxAnchorSet = mempty
+ , docxImmedPrevAnchor = Nothing
, docxMediaBag = mempty
, docxDropCap = mempty
, docxWarnings = []
+ , docxListState = M.empty
+ , docxPrevPara = mempty
}
-data DEnv = DEnv { docxOptions :: ReaderOptions
- , docxInHeaderBlock :: Bool }
+data DEnv = DEnv { docxOptions :: ReaderOptions
+ , docxInHeaderBlock :: Bool
+ }
instance Default DEnv where
def = DEnv def False
-type DocxContext = ExceptT PandocError (ReaderT DEnv (State DState))
-
-evalDocxContext :: DocxContext a -> DEnv -> DState -> Either PandocError a
-evalDocxContext ctx env st = flip evalState st . flip runReaderT env . runExceptT $ ctx
+type DocxContext m = ReaderT DEnv (StateT DState m)
-addDocxWarning :: String -> DocxContext ()
-addDocxWarning msg = do
- warnings <- gets docxWarnings
- modify $ \s -> s {docxWarnings = msg : warnings}
+evalDocxContext :: PandocMonad m => DocxContext m a -> DEnv -> DState -> m a
+evalDocxContext ctx env st = flip evalStateT st $flip runReaderT env ctx
-- This is empty, but we put it in for future-proofing.
spansToKeep :: [String]
@@ -162,7 +167,7 @@ metaStyles = M.fromList [ ("Title", "title")
, ("Abstract", "abstract")]
sepBodyParts :: [BodyPart] -> ([BodyPart], [BodyPart])
-sepBodyParts = span (\bp -> (isMetaPar bp || isEmptyPar bp))
+sepBodyParts = span (\bp -> isMetaPar bp || isEmptyPar bp)
isMetaPar :: BodyPart -> Bool
isMetaPar (Paragraph pPr _) =
@@ -174,28 +179,28 @@ isEmptyPar (Paragraph _ parParts) =
all isEmptyParPart parParts
where
isEmptyParPart (PlainRun (Run _ runElems)) = all isEmptyElem runElems
- isEmptyParPart _ = False
+ isEmptyParPart _ = False
isEmptyElem (TextRun s) = trim s == ""
isEmptyElem _ = True
isEmptyPar _ = False
-bodyPartsToMeta' :: [BodyPart] -> DocxContext (M.Map String MetaValue)
+bodyPartsToMeta' :: PandocMonad m => [BodyPart] -> DocxContext m (M.Map String MetaValue)
bodyPartsToMeta' [] = return M.empty
bodyPartsToMeta' (bp : bps)
| (Paragraph pPr parParts) <- bp
- , (c : _)<- intersect (pStyle pPr) (M.keys metaStyles)
+ , (c : _)<- (pStyle pPr) `intersect` (M.keys metaStyles)
, (Just metaField) <- M.lookup c metaStyles = do
inlines <- smushInlines <$> mapM parPartToInlines parParts
remaining <- bodyPartsToMeta' bps
let
f (MetaInlines ils) (MetaInlines ils') = MetaBlocks [Para ils, Para ils']
- f (MetaInlines ils) (MetaBlocks blks) = MetaBlocks ((Para ils) : blks)
+ f (MetaInlines ils) (MetaBlocks blks) = MetaBlocks (Para ils : blks)
f m (MetaList mv) = MetaList (m : mv)
f m n = MetaList [m, n]
return $ M.insertWith f metaField (MetaInlines (toList inlines)) remaining
bodyPartsToMeta' (_ : bps) = bodyPartsToMeta' bps
-bodyPartsToMeta :: [BodyPart] -> DocxContext Meta
+bodyPartsToMeta :: PandocMonad m => [BodyPart] -> DocxContext m Meta
bodyPartsToMeta bps = do
mp <- bodyPartsToMeta' bps
let mp' =
@@ -208,7 +213,7 @@ fixAuthors :: MetaValue -> MetaValue
fixAuthors (MetaBlocks blks) =
MetaList $ map g $ filter f blks
where f (Para _) = True
- f _ = False
+ f _ = False
g (Para ils) = MetaInlines ils
g _ = MetaInlines []
fixAuthors mv = mv
@@ -220,106 +225,122 @@ codeDivs :: [String]
codeDivs = ["SourceCode"]
runElemToInlines :: RunElem -> Inlines
-runElemToInlines (TextRun s) = text s
-runElemToInlines (LnBrk) = linebreak
-runElemToInlines (Tab) = space
-runElemToInlines (SoftHyphen) = text "\xad"
-runElemToInlines (NoBreakHyphen) = text "\x2011"
+runElemToInlines (TextRun s) = text s
+runElemToInlines LnBrk = linebreak
+runElemToInlines Tab = space
+runElemToInlines SoftHyphen = text "\xad"
+runElemToInlines NoBreakHyphen = text "\x2011"
runElemToString :: RunElem -> String
-runElemToString (TextRun s) = s
-runElemToString (LnBrk) = ['\n']
-runElemToString (Tab) = ['\t']
-runElemToString (SoftHyphen) = ['\xad']
-runElemToString (NoBreakHyphen) = ['\x2011']
+runElemToString (TextRun s) = s
+runElemToString LnBrk = ['\n']
+runElemToString Tab = ['\t']
+runElemToString SoftHyphen = ['\xad']
+runElemToString NoBreakHyphen = ['\x2011']
runToString :: Run -> String
runToString (Run _ runElems) = concatMap runElemToString runElems
-runToString _ = ""
+runToString _ = ""
parPartToString :: ParPart -> String
-parPartToString (PlainRun run) = runToString run
+parPartToString (PlainRun run) = runToString run
parPartToString (InternalHyperLink _ runs) = concatMap runToString runs
parPartToString (ExternalHyperLink _ runs) = concatMap runToString runs
-parPartToString _ = ""
+parPartToString _ = ""
blacklistedCharStyles :: [String]
blacklistedCharStyles = ["Hyperlink"]
-resolveDependentRunStyle :: RunStyle -> RunStyle
+resolveDependentRunStyle :: PandocMonad m => RunStyle -> DocxContext m RunStyle
resolveDependentRunStyle rPr
| Just (s, _) <- rStyle rPr, s `elem` blacklistedCharStyles =
- rPr
- | Just (_, cs) <- rStyle rPr =
- let rPr' = resolveDependentRunStyle cs
- in
- RunStyle { isBold = case isBold rPr of
- Just bool -> Just bool
- Nothing -> isBold rPr'
- , isItalic = case isItalic rPr of
- Just bool -> Just bool
- Nothing -> isItalic rPr'
- , isSmallCaps = case isSmallCaps rPr of
- Just bool -> Just bool
- Nothing -> isSmallCaps rPr'
- , isStrike = case isStrike rPr of
- Just bool -> Just bool
- Nothing -> isStrike rPr'
- , rVertAlign = case rVertAlign rPr of
- Just valign -> Just valign
- Nothing -> rVertAlign rPr'
- , rUnderline = case rUnderline rPr of
- Just ulstyle -> Just ulstyle
- Nothing -> rUnderline rPr'
- , rStyle = rStyle rPr }
- | otherwise = rPr
-
-runStyleToTransform :: RunStyle -> (Inlines -> Inlines)
+ return rPr
+ | Just (_, cs) <- rStyle rPr = do
+ opts <- asks docxOptions
+ if isEnabled Ext_styles opts
+ then return rPr
+ else do rPr' <- resolveDependentRunStyle cs
+ return $
+ RunStyle { isBold = case isBold rPr of
+ Just bool -> Just bool
+ Nothing -> isBold rPr'
+ , isItalic = case isItalic rPr of
+ Just bool -> Just bool
+ Nothing -> isItalic rPr'
+ , isSmallCaps = case isSmallCaps rPr of
+ Just bool -> Just bool
+ Nothing -> isSmallCaps rPr'
+ , isStrike = case isStrike rPr of
+ Just bool -> Just bool
+ Nothing -> isStrike rPr'
+ , rVertAlign = case rVertAlign rPr of
+ Just valign -> Just valign
+ Nothing -> rVertAlign rPr'
+ , rUnderline = case rUnderline rPr of
+ Just ulstyle -> Just ulstyle
+ Nothing -> rUnderline rPr'
+ , rStyle = rStyle rPr }
+ | otherwise = return rPr
+
+runStyleToTransform :: PandocMonad m => RunStyle -> DocxContext m (Inlines -> Inlines)
runStyleToTransform rPr
| Just (s, _) <- rStyle rPr
- , s `elem` spansToKeep =
- let rPr' = rPr{rStyle = Nothing}
- in
- (spanWith ("", [s], [])) . (runStyleToTransform rPr')
- | Just True <- isItalic rPr =
- emph . (runStyleToTransform rPr {isItalic = Nothing})
- | Just True <- isBold rPr =
- strong . (runStyleToTransform rPr {isBold = Nothing})
- | Just True <- isSmallCaps rPr =
- smallcaps . (runStyleToTransform rPr {isSmallCaps = Nothing})
- | Just True <- isStrike rPr =
- strikeout . (runStyleToTransform rPr {isStrike = Nothing})
- | Just SupScrpt <- rVertAlign rPr =
- superscript . (runStyleToTransform rPr {rVertAlign = Nothing})
- | Just SubScrpt <- rVertAlign rPr =
- subscript . (runStyleToTransform rPr {rVertAlign = Nothing})
- | Just "single" <- rUnderline rPr =
- emph . (runStyleToTransform rPr {rUnderline = Nothing})
- | otherwise = id
-
-runToInlines :: Run -> DocxContext Inlines
+ , s `elem` spansToKeep = do
+ transform <- runStyleToTransform rPr{rStyle = Nothing}
+ return $ spanWith ("", [s], []) . transform
+ | Just (s, _) <- rStyle rPr = do
+ opts <- asks docxOptions
+ let extraInfo = if isEnabled Ext_styles opts
+ then spanWith ("", [], [("custom-style", s)])
+ else id
+ transform <- runStyleToTransform rPr{rStyle = Nothing}
+ return $ extraInfo . transform
+ | Just True <- isItalic rPr = do
+ transform <- runStyleToTransform rPr{isItalic = Nothing}
+ return $ emph . transform
+ | Just True <- isBold rPr = do
+ transform <- runStyleToTransform rPr{isBold = Nothing}
+ return $ strong . transform
+ | Just True <- isSmallCaps rPr = do
+ transform <- runStyleToTransform rPr{isSmallCaps = Nothing}
+ return $ smallcaps . transform
+ | Just True <- isStrike rPr = do
+ transform <- runStyleToTransform rPr{isStrike = Nothing}
+ return $ strikeout . transform
+ | Just SupScrpt <- rVertAlign rPr = do
+ transform <- runStyleToTransform rPr{rVertAlign = Nothing}
+ return $ superscript . transform
+ | Just SubScrpt <- rVertAlign rPr = do
+ transform <- runStyleToTransform rPr{rVertAlign = Nothing}
+ return $ subscript . transform
+ | Just "single" <- rUnderline rPr = do
+ transform <- runStyleToTransform rPr{rUnderline = Nothing}
+ return $ underlineSpan . transform
+ | otherwise = return id
+
+runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
runToInlines (Run rs runElems)
| Just (s, _) <- rStyle rs
- , s `elem` codeStyles =
- let rPr = resolveDependentRunStyle rs
- codeString = code $ concatMap runElemToString runElems
- in
- return $ case rVertAlign rPr of
- Just SupScrpt -> superscript codeString
- Just SubScrpt -> subscript codeString
- _ -> codeString
+ , s `elem` codeStyles = do
+ rPr <- resolveDependentRunStyle rs
+ let codeString = code $ concatMap runElemToString runElems
+ return $ case rVertAlign rPr of
+ Just SupScrpt -> superscript codeString
+ Just SubScrpt -> subscript codeString
+ _ -> codeString
| otherwise = do
- let ils = smushInlines (map runElemToInlines runElems)
- return $ (runStyleToTransform $ resolveDependentRunStyle rs) ils
+ rPr <- resolveDependentRunStyle rs
+ let ils = smushInlines (map runElemToInlines runElems)
+ transform <- runStyleToTransform rPr
+ return $ transform ils
runToInlines (Footnote bps) = do
- blksList <- smushBlocks <$> (mapM bodyPartToBlocks bps)
+ blksList <- smushBlocks <$> mapM bodyPartToBlocks bps
return $ note blksList
runToInlines (Endnote bps) = do
- blksList <- smushBlocks <$> (mapM bodyPartToBlocks bps)
+ blksList <- smushBlocks <$> mapM bodyPartToBlocks bps
return $ note blksList
runToInlines (InlineDrawing fp title alt bs ext) = do
- mediaBag <- gets docxMediaBag
- modify $ \s -> s { docxMediaBag = insertMedia fp Nothing bs mediaBag }
+ (lift . lift) $ P.insertMedia fp Nothing bs
return $ imageWith (extentToAttr ext) fp title $ text alt
runToInlines InlineChart = return $ spanWith ("", ["chart"], []) $ text "[CHART]"
@@ -330,20 +351,39 @@ extentToAttr (Just (w, h)) =
showDim d = show (d / 914400) ++ "in"
extentToAttr _ = nullAttr
-blocksToInlinesWarn :: String -> Blocks -> DocxContext Inlines
+blocksToInlinesWarn :: PandocMonad m => String -> Blocks -> DocxContext m Inlines
blocksToInlinesWarn cmtId blks = do
let blkList = toList blks
notParaOrPlain :: Block -> Bool
- notParaOrPlain (Para _) = False
+ notParaOrPlain (Para _) = False
notParaOrPlain (Plain _) = False
- notParaOrPlain _ = True
- when (not $ null $ filter notParaOrPlain blkList)
- (addDocxWarning $ "Docx comment " ++ cmtId ++ " will not retain formatting")
- return $ fromList $ blocksToInlines blkList
-
-parPartToInlines :: ParPart -> DocxContext Inlines
-parPartToInlines (PlainRun r) = runToInlines r
-parPartToInlines (Insertion _ author date runs) = do
+ notParaOrPlain _ = True
+ unless ( not (any notParaOrPlain blkList)) $
+ lift $ P.report $ DocxParserWarning $
+ "Docx comment " ++ cmtId ++ " will not retain formatting"
+ return $ blocksToInlines' blkList
+
+-- The majority of work in this function is done in the primed
+-- subfunction `partPartToInlines'`. We make this wrapper so that we
+-- don't have to modify `docxImmedPrevAnchor` state after every function.
+parPartToInlines :: PandocMonad m => ParPart -> DocxContext m Inlines
+parPartToInlines parPart =
+ case parPart of
+ (BookMark _ anchor) | notElem anchor dummyAnchors -> do
+ inHdrBool <- asks docxInHeaderBlock
+ ils <- parPartToInlines' parPart
+ immedPrevAnchor <- gets docxImmedPrevAnchor
+ unless (isJust immedPrevAnchor || inHdrBool)
+ (modify $ \s -> s{ docxImmedPrevAnchor = Just anchor})
+ return ils
+ _ -> do
+ ils <- parPartToInlines' parPart
+ modify $ \s -> s{ docxImmedPrevAnchor = Nothing}
+ return ils
+
+parPartToInlines' :: PandocMonad m => ParPart -> DocxContext m Inlines
+parPartToInlines' (PlainRun r) = runToInlines r
+parPartToInlines' (ChangedRuns (TrackedChange Insertion (ChangeInfo _ author date)) runs) = do
opts <- asks docxOptions
case readerTrackChanges opts of
AcceptChanges -> smushInlines <$> mapM runToInlines runs
@@ -352,7 +392,7 @@ parPartToInlines (Insertion _ author date runs) = do
ils <- smushInlines <$> mapM runToInlines runs
let attr = ("", ["insertion"], [("author", author), ("date", date)])
return $ spanWith attr ils
-parPartToInlines (Deletion _ author date runs) = do
+parPartToInlines' (ChangedRuns (TrackedChange Deletion (ChangeInfo _ author date)) runs) = do
opts <- asks docxOptions
case readerTrackChanges opts of
AcceptChanges -> return mempty
@@ -361,7 +401,7 @@ parPartToInlines (Deletion _ author date runs) = do
ils <- smushInlines <$> mapM runToInlines runs
let attr = ("", ["deletion"], [("author", author), ("date", date)])
return $ spanWith attr ils
-parPartToInlines (CommentStart cmtId author date bodyParts) = do
+parPartToInlines' (CommentStart cmtId author date bodyParts) = do
opts <- asks docxOptions
case readerTrackChanges opts of
AllChanges -> do
@@ -370,16 +410,16 @@ parPartToInlines (CommentStart cmtId author date bodyParts) = do
let attr = ("", ["comment-start"], [("id", cmtId), ("author", author), ("date", date)])
return $ spanWith attr ils
_ -> return mempty
-parPartToInlines (CommentEnd cmtId) = do
+parPartToInlines' (CommentEnd cmtId) = do
opts <- asks docxOptions
case readerTrackChanges opts of
AllChanges -> do
let attr = ("", ["comment-end"], [("id", cmtId)])
return $ spanWith attr mempty
_ -> return mempty
-parPartToInlines (BookMark _ anchor) | anchor `elem` dummyAnchors =
+parPartToInlines' (BookMark _ anchor) | anchor `elem` dummyAnchors =
return mempty
-parPartToInlines (BookMark _ anchor) =
+parPartToInlines' (BookMark _ anchor) =
-- We record these, so we can make sure not to overwrite
-- user-defined anchor links with header auto ids.
do
@@ -395,27 +435,40 @@ parPartToInlines (BookMark _ anchor) =
-- of rewriting user-defined anchor links. However, since these
-- are not defined in pandoc, it seems like a necessary evil to
-- avoid an extra pass.
- let newAnchor =
- if not inHdrBool && anchor `elem` (M.elems anchorMap)
- then uniqueIdent [Str anchor] (Set.fromList $ M.elems anchorMap)
- else anchor
- unless inHdrBool
- (modify $ \s -> s { docxAnchorMap = M.insert anchor newAnchor anchorMap})
- return $ spanWith (newAnchor, ["anchor"], []) mempty
-parPartToInlines (Drawing fp title alt bs ext) = do
- mediaBag <- gets docxMediaBag
- modify $ \s -> s { docxMediaBag = insertMedia fp Nothing bs mediaBag }
+ immedPrevAnchor <- gets docxImmedPrevAnchor
+ case immedPrevAnchor of
+ Just prevAnchor -> do
+ unless inHdrBool
+ (modify $ \s -> s { docxAnchorMap = M.insert anchor prevAnchor anchorMap})
+ return mempty
+ Nothing -> do
+ let newAnchor =
+ if not inHdrBool && anchor `elem` M.elems anchorMap
+ then uniqueIdent [Str anchor] (Set.fromList $ M.elems anchorMap)
+ else anchor
+ unless inHdrBool
+ (modify $ \s -> s { docxAnchorMap = M.insert anchor newAnchor anchorMap})
+ return $ spanWith (newAnchor, ["anchor"], []) mempty
+parPartToInlines' (Drawing fp title alt bs ext) = do
+ (lift . lift) $ P.insertMedia fp Nothing bs
return $ imageWith (extentToAttr ext) fp title $ text alt
-parPartToInlines Chart = do
+parPartToInlines' Chart =
return $ spanWith ("", ["chart"], []) $ text "[CHART]"
-parPartToInlines (InternalHyperLink anchor runs) = do
+parPartToInlines' (InternalHyperLink anchor runs) = do
ils <- smushInlines <$> mapM runToInlines runs
return $ link ('#' : anchor) "" ils
-parPartToInlines (ExternalHyperLink target runs) = do
+parPartToInlines' (ExternalHyperLink target runs) = do
ils <- smushInlines <$> mapM runToInlines runs
return $ link target "" ils
-parPartToInlines (PlainOMath exps) = do
+parPartToInlines' (PlainOMath exps) =
return $ math $ writeTeX exps
+parPartToInlines' (SmartTag runs) =
+ smushInlines <$> mapM runToInlines runs
+parPartToInlines' (Field info runs) =
+ case info of
+ HyperlinkField url -> parPartToInlines' $ ExternalHyperLink url runs
+ UnknownField -> smushInlines <$> mapM runToInlines runs
+parPartToInlines' NullParPart = return mempty
isAnchorSpan :: Inline -> Bool
isAnchorSpan (Span (_, classes, kvs) _) =
@@ -426,10 +479,10 @@ isAnchorSpan _ = False
dummyAnchors :: [String]
dummyAnchors = ["_GoBack"]
-makeHeaderAnchor :: Blocks -> DocxContext Blocks
+makeHeaderAnchor :: PandocMonad m => Blocks -> DocxContext m Blocks
makeHeaderAnchor bs = traverse makeHeaderAnchor' bs
-makeHeaderAnchor' :: Block -> DocxContext Block
+makeHeaderAnchor' :: PandocMonad m => Block -> DocxContext m Block
-- If there is an anchor already there (an anchor span in the header,
-- to be exact), we rename and associate the new id with the old one.
makeHeaderAnchor' (Header n (ident, classes, kvs) ils)
@@ -458,126 +511,184 @@ makeHeaderAnchor' blk = return blk
-- Rewrite a standalone paragraph block as a plain
singleParaToPlain :: Blocks -> Blocks
singleParaToPlain blks
- | (Para (ils) :< seeq) <- viewl $ unMany blks
+ | (Para ils :< seeq) <- viewl $ unMany blks
, Seq.null seeq =
singleton $ Plain ils
singleParaToPlain blks = blks
-cellToBlocks :: Cell -> DocxContext Blocks
+cellToBlocks :: PandocMonad m => Cell -> DocxContext m Blocks
cellToBlocks (Cell bps) = do
blks <- smushBlocks <$> mapM bodyPartToBlocks bps
return $ fromList $ blocksToDefinitions $ blocksToBullets $ toList blks
-rowToBlocksList :: Row -> DocxContext [Blocks]
+rowToBlocksList :: PandocMonad m => Row -> DocxContext m [Blocks]
rowToBlocksList (Row cells) = do
blksList <- mapM cellToBlocks cells
return $ map singleParaToPlain blksList
-trimLineBreaks :: [Inline] -> [Inline]
-trimLineBreaks [] = []
-trimLineBreaks (LineBreak : ils) = trimLineBreaks ils
-trimLineBreaks ils
- | (LineBreak : ils') <- reverse ils = trimLineBreaks (reverse ils')
-trimLineBreaks ils = ils
+-- like trimInlines, but also take out linebreaks
+trimSps :: Inlines -> Inlines
+trimSps (Many ils) = Many $ Seq.dropWhileL isSp $Seq.dropWhileR isSp ils
+ where isSp Space = True
+ isSp SoftBreak = True
+ isSp LineBreak = True
+ isSp _ = False
-parStyleToTransform :: ParagraphStyle -> (Blocks -> Blocks)
+parStyleToTransform :: PandocMonad m => ParagraphStyle -> DocxContext m (Blocks -> Blocks)
parStyleToTransform pPr
| (c:cs) <- pStyle pPr
- , c `elem` divsToKeep =
- let pPr' = pPr { pStyle = cs }
- in
- (divWith ("", [c], [])) . (parStyleToTransform pPr')
+ , c `elem` divsToKeep = do
+ let pPr' = pPr { pStyle = cs }
+ transform <- parStyleToTransform pPr'
+ return $ divWith ("", [c], []) . transform
| (c:cs) <- pStyle pPr,
- c `elem` listParagraphDivs =
+ c `elem` listParagraphDivs = do
let pPr' = pPr { pStyle = cs, indentation = Nothing}
- in
- (divWith ("", [c], [])) . (parStyleToTransform pPr')
- | (_:cs) <- pStyle pPr
- , Just True <- pBlockQuote pPr =
- let pPr' = pPr { pStyle = cs }
- in
- blockQuote . (parStyleToTransform pPr')
- | (_:cs) <- pStyle pPr =
+ transform <- parStyleToTransform pPr'
+ return $ divWith ("", [c], []) . transform
+ | (c:cs) <- pStyle pPr
+ , Just True <- pBlockQuote pPr = do
+ opts <- asks docxOptions
+ let pPr' = pPr { pStyle = cs }
+ transform <- parStyleToTransform pPr'
+ let extraInfo = if isEnabled Ext_styles opts
+ then divWith ("", [], [("custom-style", c)])
+ else id
+ return $ extraInfo . blockQuote . transform
+ | (c:cs) <- pStyle pPr = do
+ opts <- asks docxOptions
let pPr' = pPr { pStyle = cs}
- in
- parStyleToTransform pPr'
+ transform <- parStyleToTransform pPr'
+ let extraInfo = if isEnabled Ext_styles opts
+ then divWith ("", [], [("custom-style", c)])
+ else id
+ return $ extraInfo . transform
| null (pStyle pPr)
, Just left <- indentation pPr >>= leftParIndent
- , Just hang <- indentation pPr >>= hangingParIndent =
+ , Just hang <- indentation pPr >>= hangingParIndent = do
let pPr' = pPr { indentation = Nothing }
- in
- case (left - hang) > 0 of
- True -> blockQuote . (parStyleToTransform pPr')
- False -> parStyleToTransform pPr'
+ transform <- parStyleToTransform pPr'
+ return $ case (left - hang) > 0 of
+ True -> blockQuote . transform
+ False -> transform
| null (pStyle pPr),
- Just left <- indentation pPr >>= leftParIndent =
+ Just left <- indentation pPr >>= leftParIndent = do
let pPr' = pPr { indentation = Nothing }
- in
- case left > 0 of
- True -> blockQuote . (parStyleToTransform pPr')
- False -> parStyleToTransform pPr'
-parStyleToTransform _ = id
+ transform <- parStyleToTransform pPr'
+ return $ case left > 0 of
+ True -> blockQuote . transform
+ False -> transform
+parStyleToTransform _ = return id
-bodyPartToBlocks :: BodyPart -> DocxContext Blocks
+bodyPartToBlocks :: PandocMonad m => BodyPart -> DocxContext m Blocks
bodyPartToBlocks (Paragraph pPr parparts)
- | not $ null $ codeDivs `intersect` (pStyle pPr) =
- return
- $ parStyleToTransform pPr
- $ codeBlock
- $ concatMap parPartToString parparts
+ | not $ null $ codeDivs `intersect` (pStyle pPr) = do
+ transform <- parStyleToTransform pPr
+ return $
+ transform $
+ codeBlock $
+ concatMap parPartToString parparts
| Just (style, n) <- pHeading pPr = do
- ils <- local (\s-> s{docxInHeaderBlock=True}) $
+ ils <-local (\s-> s{docxInHeaderBlock=True})
(smushInlines <$> mapM parPartToInlines parparts)
makeHeaderAnchor $
headerWith ("", delete style (pStyle pPr), []) n ils
| otherwise = do
- ils <- smushInlines <$> mapM parPartToInlines parparts >>=
- (return . fromList . trimLineBreaks . normalizeSpaces . toList)
+ ils <- (trimSps . smushInlines) <$> mapM parPartToInlines parparts
+ prevParaIls <- gets docxPrevPara
dropIls <- gets docxDropCap
let ils' = dropIls <> ils
if dropCap pPr
then do modify $ \s -> s { docxDropCap = ils' }
return mempty
else do modify $ \s -> s { docxDropCap = mempty }
- return $ case isNull ils' of
- True -> mempty
- _ -> parStyleToTransform pPr $ para ils'
+ let ils'' = prevParaIls <>
+ (if isNull prevParaIls then mempty else space) <>
+ ils'
+ opts <- asks docxOptions
+ case () of
+
+ _ | isNull ils'' && not (isEnabled Ext_empty_paragraphs opts) ->
+ return mempty
+ _ | Just (TrackedChange Insertion _) <- pChange pPr
+ , AcceptChanges <- readerTrackChanges opts -> do
+ modify $ \s -> s {docxPrevPara = mempty}
+ transform <- parStyleToTransform pPr
+ return $ transform $ para ils''
+ _ | Just (TrackedChange Insertion _) <- pChange pPr
+ , RejectChanges <- readerTrackChanges opts -> do
+ modify $ \s -> s {docxPrevPara = ils''}
+ return mempty
+ _ | Just (TrackedChange Insertion cInfo) <- pChange pPr
+ , AllChanges <- readerTrackChanges opts
+ , ChangeInfo _ cAuthor cDate <- cInfo -> do
+ let attr = ("", ["paragraph-insertion"], [("author", cAuthor), ("date", cDate)])
+ insertMark = spanWith attr mempty
+ transform <- parStyleToTransform pPr
+ return $ transform $
+ para $ ils'' <> insertMark
+ _ | Just (TrackedChange Deletion _) <- pChange pPr
+ , AcceptChanges <- readerTrackChanges opts -> do
+ modify $ \s -> s {docxPrevPara = ils''}
+ return mempty
+ _ | Just (TrackedChange Deletion _) <- pChange pPr
+ , RejectChanges <- readerTrackChanges opts -> do
+ modify $ \s -> s {docxPrevPara = mempty}
+ transform <- parStyleToTransform pPr
+ return $ transform $ para ils''
+ _ | Just (TrackedChange Deletion cInfo) <- pChange pPr
+ , AllChanges <- readerTrackChanges opts
+ , ChangeInfo _ cAuthor cDate <- cInfo -> do
+ let attr = ("", ["paragraph-deletion"], [("author", cAuthor), ("date", cDate)])
+ insertMark = spanWith attr mempty
+ transform <- parStyleToTransform pPr
+ return $ transform $
+ para $ ils'' <> insertMark
+ _ | otherwise -> do
+ modify $ \s -> s {docxPrevPara = mempty}
+ transform <- parStyleToTransform pPr
+ return $ transform $ para ils''
bodyPartToBlocks (ListItem pPr numId lvl (Just levelInfo) parparts) = do
- let
- kvs = case levelInfo of
- (_, fmt, txt, Just start) -> [ ("level", lvl)
- , ("num-id", numId)
- , ("format", fmt)
- , ("text", txt)
- , ("start", (show start))
- ]
-
- (_, fmt, txt, Nothing) -> [ ("level", lvl)
- , ("num-id", numId)
- , ("format", fmt)
- , ("text", txt)
- ]
+ -- We check whether this current numId has previously been used,
+ -- since Docx expects us to pick up where we left off.
+ listState <- gets docxListState
+ let startFromState = M.lookup (numId, lvl) listState
+ (_, fmt,txt, startFromLevelInfo) = levelInfo
+ start = case startFromState of
+ Just n -> n + 1
+ Nothing -> fromMaybe 1 startFromLevelInfo
+ kvs = [ ("level", lvl)
+ , ("num-id", numId)
+ , ("format", fmt)
+ , ("text", txt)
+ , ("start", show start)
+ ]
+ modify $ \st -> st{ docxListState = M.insert (numId, lvl) start listState}
blks <- bodyPartToBlocks (Paragraph pPr parparts)
return $ divWith ("", ["list-item"], kvs) blks
-bodyPartToBlocks (ListItem pPr _ _ _ parparts) =
- let pPr' = pPr {pStyle = "ListParagraph": (pStyle pPr)}
+bodyPartToBlocks (ListItem pPr _ _ _ parparts) =
+ let pPr' = pPr {pStyle = "ListParagraph": pStyle pPr}
in
bodyPartToBlocks $ Paragraph pPr' parparts
bodyPartToBlocks (Tbl _ _ _ []) =
return $ para mempty
-bodyPartToBlocks (Tbl cap _ look (r:rs)) = do
+bodyPartToBlocks (Tbl cap _ look parts@(r:rs)) = do
let caption = text cap
(hdr, rows) = case firstRowFormatting look of
True | null rs -> (Nothing, [r])
| otherwise -> (Just r, rs)
False -> (Nothing, r:rs)
- cells <- mapM rowToBlocksList rows
+ cells <- mapM rowToBlocksList rows
- let width = case cells of
- r':_ -> length r'
- -- shouldn't happen
- [] -> 0
+ let width = maybe 0 maximum $ nonEmpty $ map rowLength parts
+ -- Data.List.NonEmpty is not available with ghc 7.10 so we roll out
+ -- our own, see
+ -- https://github.com/jgm/pandoc/pull/4361#issuecomment-365416155
+ nonEmpty [] = Nothing
+ nonEmpty l = Just l
+ rowLength :: Row -> Int
+ rowLength (Row c) = length c
hdrCells <- case hdr of
Just r' -> rowToBlocksList r'
@@ -592,36 +703,54 @@ bodyPartToBlocks (Tbl cap _ look (r:rs)) = do
widths = replicate width 0 :: [Double]
return $ table caption (zip alignments widths) hdrCells cells
-bodyPartToBlocks (OMathPara e) = do
+bodyPartToBlocks (OMathPara e) =
return $ para $ displayMath (writeTeX e)
-- replace targets with generated anchors.
-rewriteLink' :: Inline -> DocxContext Inline
+rewriteLink' :: PandocMonad m => Inline -> DocxContext m Inline
rewriteLink' l@(Link attr ils ('#':target, title)) = do
anchorMap <- gets docxAnchorMap
- return $ case M.lookup target anchorMap of
- Just newTarget -> (Link attr ils ('#':newTarget, title))
- Nothing -> l
+ case M.lookup target anchorMap of
+ Just newTarget -> do
+ modify $ \s -> s{docxAnchorSet = Set.insert newTarget (docxAnchorSet s)}
+ return $ Link attr ils ('#':newTarget, title)
+ Nothing -> do
+ modify $ \s -> s{docxAnchorSet = Set.insert target (docxAnchorSet s)}
+ return l
rewriteLink' il = return il
-rewriteLinks :: [Block] -> DocxContext [Block]
+rewriteLinks :: PandocMonad m => [Block] -> DocxContext m [Block]
rewriteLinks = mapM (walkM rewriteLink')
-bodyToOutput :: Body -> DocxContext (Meta, [Block], MediaBag, [String])
+removeOrphanAnchors'' :: PandocMonad m => Inline -> DocxContext m [Inline]
+removeOrphanAnchors'' s@(Span (ident, classes, _) ils)
+ | "anchor" `elem` classes = do
+ anchorSet <- gets docxAnchorSet
+ return $ if ident `Set.member` anchorSet
+ then [s]
+ else ils
+removeOrphanAnchors'' il = return [il]
+
+removeOrphanAnchors' :: PandocMonad m => [Inline] -> DocxContext m [Inline]
+removeOrphanAnchors' ils = liftM concat $ mapM removeOrphanAnchors'' ils
+
+removeOrphanAnchors :: PandocMonad m => [Block] -> DocxContext m [Block]
+removeOrphanAnchors = mapM (walkM removeOrphanAnchors')
+
+bodyToOutput :: PandocMonad m => Body -> DocxContext m (Meta, [Block])
bodyToOutput (Body bps) = do
let (metabps, blkbps) = sepBodyParts bps
meta <- bodyPartsToMeta metabps
blks <- smushBlocks <$> mapM bodyPartToBlocks blkbps
blks' <- rewriteLinks $ blocksToDefinitions $ blocksToBullets $ toList blks
- mediaBag <- gets docxMediaBag
- warnings <- gets docxWarnings
- return $ (meta,
- blks',
- mediaBag,
- warnings)
-
-docxToOutput :: ReaderOptions -> Docx -> Either PandocError (Meta, [Block], MediaBag, [String])
+ blks'' <- removeOrphanAnchors blks'
+ return (meta, blks'')
+
+docxToOutput :: PandocMonad m
+ => ReaderOptions
+ -> Docx
+ -> m (Meta, [Block])
docxToOutput opts (Docx (Document _ body)) =
let dEnv = def { docxOptions = opts} in
evalDocxContext (bodyToOutput body) dEnv def
diff --git a/src/Text/Pandoc/Readers/Docx/Combine.hs b/src/Text/Pandoc/Readers/Docx/Combine.hs
index 39e0df825..003265e6e 100644
--- a/src/Text/Pandoc/Readers/Docx/Combine.hs
+++ b/src/Text/Pandoc/Readers/Docx/Combine.hs
@@ -1,15 +1,16 @@
-{-# LANGUAGE TypeSynonymInstances, FlexibleInstances,
- PatternGuards #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE TypeSynonymInstances #-}
module Text.Pandoc.Readers.Docx.Combine ( smushInlines
, smushBlocks
)
where
-import Text.Pandoc.Builder
import Data.List
-import Data.Sequence (ViewR(..), ViewL(..), viewl, viewr, (><), (|>))
+import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr, (><), (|>))
import qualified Data.Sequence as Seq (null)
+import Text.Pandoc.Builder
data Modifier a = Modifier (a -> a)
| AttrModifier (Attr -> a -> a) Attr
@@ -35,16 +36,16 @@ spaceOutInlines ils =
right = case viewr contents of
(_ :> Space) -> space
_ -> mempty in
- (left, (stackInlines fs $ trimInlines . Many $ contents), right)
+ (left, stackInlines fs $ trimInlines . Many $ contents, right)
stackInlines :: [Modifier Inlines] -> Inlines -> Inlines
stackInlines [] ms = ms
stackInlines (NullModifier : fs) ms = stackInlines fs ms
-stackInlines ((Modifier f) : fs) ms =
+stackInlines (Modifier f : fs) ms =
if isEmpty ms
then stackInlines fs ms
else f $ stackInlines fs ms
-stackInlines ((AttrModifier f attr) : fs) ms = f attr $ stackInlines fs ms
+stackInlines (AttrModifier f attr : fs) ms = f attr $ stackInlines fs ms
unstackInlines :: Inlines -> ([Modifier Inlines], Inlines)
unstackInlines ms = case ilModifier ms of
@@ -56,15 +57,15 @@ unstackInlines ms = case ilModifier ms of
ilModifier :: Inlines -> Modifier Inlines
ilModifier ils = case viewl (unMany ils) of
(x :< xs) | Seq.null xs -> case x of
- (Emph _) -> Modifier emph
- (Strong _) -> Modifier strong
- (SmallCaps _) -> Modifier smallcaps
- (Strikeout _) -> Modifier strikeout
- (Superscript _) -> Modifier superscript
- (Subscript _) -> Modifier subscript
+ (Emph _) -> Modifier emph
+ (Strong _) -> Modifier strong
+ (SmallCaps _) -> Modifier smallcaps
+ (Strikeout _) -> Modifier strikeout
+ (Superscript _) -> Modifier superscript
+ (Subscript _) -> Modifier subscript
(Link attr _ tgt) -> Modifier $ linkWith attr (fst tgt) (snd tgt)
- (Span attr _) -> AttrModifier spanWith attr
- _ -> NullModifier
+ (Span attr _) -> AttrModifier spanWith attr
+ _ -> NullModifier
_ -> NullModifier
ilInnards :: Inlines -> Inlines
@@ -78,25 +79,25 @@ ilInnards ils = case viewl (unMany ils) of
(Subscript lst) -> fromList lst
(Link _ lst _) -> fromList lst
(Span _ lst) -> fromList lst
- _ -> ils
+ _ -> ils
_ -> ils
inlinesL :: Inlines -> (Inlines, Inlines)
inlinesL ils = case viewl $ unMany ils of
(s :< sq) -> (singleton s, Many sq)
- _ -> (mempty, ils)
+ _ -> (mempty, ils)
inlinesR :: Inlines -> (Inlines, Inlines)
inlinesR ils = case viewr $ unMany ils of
(sq :> s) -> (Many sq, singleton s)
- _ -> (ils, mempty)
+ _ -> (ils, mempty)
combineInlines :: Inlines -> Inlines -> Inlines
combineInlines x y =
let (xs', x') = inlinesR x
(y', ys') = inlinesL y
in
- xs' <> (combineSingletonInlines x' y') <> ys'
+ xs' <> combineSingletonInlines x' y' <> ys'
combineSingletonInlines :: Inlines -> Inlines -> Inlines
combineSingletonInlines x y =
@@ -113,10 +114,10 @@ combineSingletonInlines x y =
stackInlines (x_rem_attr ++ y_rem_attr) mempty
| isEmpty xs ->
let (sp, y') = spaceOutInlinesL y in
- (stackInlines x_rem_attr mempty) <> sp <> y'
+ stackInlines x_rem_attr mempty <> sp <> y'
| isEmpty ys ->
let (x', sp) = spaceOutInlinesR x in
- x' <> sp <> (stackInlines y_rem_attr mempty)
+ x' <> sp <> stackInlines y_rem_attr mempty
| otherwise ->
let (x', xsp) = spaceOutInlinesR x
(ysp, y') = spaceOutInlinesL y
@@ -129,15 +130,15 @@ combineSingletonInlines x y =
combineBlocks :: Blocks -> Blocks -> Blocks
combineBlocks bs cs
- | bs' :> (BlockQuote bs'') <- viewr (unMany bs)
- , (BlockQuote cs'') :< cs' <- viewl (unMany cs) =
- Many $ (bs' |> (BlockQuote (bs'' <> cs''))) >< cs'
+ | bs' :> BlockQuote bs'' <- viewr (unMany bs)
+ , BlockQuote cs'' :< cs' <- viewl (unMany cs) =
+ Many $ (bs' |> BlockQuote (bs'' <> cs'')) >< cs'
combineBlocks bs cs = bs <> cs
instance (Monoid a, Eq a) => Eq (Modifier a) where
- (Modifier f) == (Modifier g) = (f mempty == g mempty)
- (AttrModifier f attr) == (AttrModifier g attr') = (f attr mempty == g attr' mempty)
- (NullModifier) == (NullModifier) = True
+ (Modifier f) == (Modifier g) = f mempty == g mempty
+ (AttrModifier f attr) == (AttrModifier g attr') = f attr mempty == g attr' mempty
+ NullModifier == NullModifier = True
_ == _ = False
isEmpty :: (Monoid a, Eq a) => a -> Bool
diff --git a/src/Text/Pandoc/Readers/Docx/Fields.hs b/src/Text/Pandoc/Readers/Docx/Fields.hs
new file mode 100644
index 000000000..6eeb55d2f
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Docx/Fields.hs
@@ -0,0 +1,89 @@
+{-
+Copyright (C) 2014-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Docx.Fields
+ Copyright : Copyright (C) 2014-2018 Jesse Rosenthal
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
+ Stability : alpha
+ Portability : portable
+
+For parsing Field definitions in instText tags, as described in
+ECMA-376-1:2016, §17.16.5 -}
+
+module Text.Pandoc.Readers.Docx.Fields ( FieldInfo(..)
+ , parseFieldInfo
+ ) where
+
+import Text.Parsec
+import Text.Parsec.String (Parser)
+
+type URL = String
+
+data FieldInfo = HyperlinkField URL
+ | UnknownField
+ deriving (Show)
+
+parseFieldInfo :: String -> Either ParseError FieldInfo
+parseFieldInfo = parse fieldInfo ""
+
+fieldInfo :: Parser FieldInfo
+fieldInfo =
+ try (HyperlinkField <$> hyperlink)
+ <|>
+ return UnknownField
+
+escapedQuote :: Parser String
+escapedQuote = string "\\\""
+
+inQuotes :: Parser String
+inQuotes =
+ (try escapedQuote) <|> (anyChar >>= (\c -> return [c]))
+
+quotedString :: Parser String
+quotedString = do
+ char '"'
+ concat <$> manyTill inQuotes (try (char '"'))
+
+unquotedString :: Parser String
+unquotedString = manyTill anyChar (try $ lookAhead space *> return () <|> eof)
+
+fieldArgument :: Parser String
+fieldArgument = quotedString <|> unquotedString
+
+-- there are other switches, but this is the only one I've seen in the wild so far, so it's the first one I'll implement. See §17.16.5.25
+hyperlinkSwitch :: Parser (String, String)
+hyperlinkSwitch = do
+ sw <- string "\\l"
+ spaces
+ farg <- fieldArgument
+ return (sw, farg)
+
+hyperlink :: Parser URL
+hyperlink = do
+ many space
+ string "HYPERLINK"
+ spaces
+ farg <- fieldArgument
+ switches <- spaces *> many hyperlinkSwitch
+ let url = case switches of
+ ("\\l", s) : _ -> farg ++ ('#': s)
+ _ -> farg
+ return url
diff --git a/src/Text/Pandoc/Readers/Docx/Lists.hs b/src/Text/Pandoc/Readers/Docx/Lists.hs
index 395a53907..c0f05094a 100644
--- a/src/Text/Pandoc/Readers/Docx/Lists.hs
+++ b/src/Text/Pandoc/Readers/Docx/Lists.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Jesse Rosenthal <jrosenthal@jhu.edu>
+Copyright (C) 2014-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Docx.Lists
- Copyright : Copyright (C) 2014-2016 Jesse Rosenthal
+ Copyright : Copyright (C) 2014-2018 Jesse Rosenthal
License : GNU GPL, version 2 or above
Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -33,38 +33,33 @@ module Text.Pandoc.Readers.Docx.Lists ( blocksToBullets
, listParagraphDivs
) where
-import Text.Pandoc.JSON
-import Text.Pandoc.Generic (bottomUp)
-import Text.Pandoc.Shared (trim)
-import Control.Monad
import Data.List
import Data.Maybe
+import Text.Pandoc.Generic (bottomUp)
+import Text.Pandoc.JSON
+import Text.Pandoc.Shared (trim)
isListItem :: Block -> Bool
isListItem (Div (_, classes, _) _) | "list-item" `elem` classes = True
-isListItem _ = False
+isListItem _ = False
getLevel :: Block -> Maybe Integer
-getLevel (Div (_, _, kvs) _) = liftM read $ lookup "level" kvs
-getLevel _ = Nothing
+getLevel (Div (_, _, kvs) _) = read <$> lookup "level" kvs
+getLevel _ = Nothing
getLevelN :: Block -> Integer
-getLevelN b = case getLevel b of
- Just n -> n
- Nothing -> -1
+getLevelN b = fromMaybe (-1) (getLevel b)
getNumId :: Block -> Maybe Integer
-getNumId (Div (_, _, kvs) _) = liftM read $ lookup "num-id" kvs
-getNumId _ = Nothing
+getNumId (Div (_, _, kvs) _) = read <$> lookup "num-id" kvs
+getNumId _ = Nothing
getNumIdN :: Block -> Integer
-getNumIdN b = case getNumId b of
- Just n -> n
- Nothing -> -1
+getNumIdN b = fromMaybe (-1) (getNumId b)
getText :: Block -> Maybe String
getText (Div (_, _, kvs) _) = lookup "text" kvs
-getText _ = Nothing
+getText _ = Nothing
data ListType = Itemized | Enumerated ListAttributes
@@ -109,27 +104,27 @@ listParagraphDivs = ["ListParagraph"]
handleListParagraphs :: [Block] -> [Block]
handleListParagraphs [] = []
handleListParagraphs (
- (Div attr1@(_, classes1, _) blks1) :
- (Div (ident2, classes2, kvs2) blks2) :
+ Div attr1@(_, classes1, _) blks1 :
+ Div (ident2, classes2, kvs2) blks2 :
blks
) | "list-item" `elem` classes1 &&
- not ("list-item" `elem` classes2) &&
+ notElem "list-item" classes2 &&
(not . null) (listParagraphDivs `intersect` classes2) =
-- We don't want to keep this indent.
let newDiv2 =
- (Div (ident2, classes2, filter (\kv -> fst kv /= "indent") kvs2) blks2)
+ Div (ident2, classes2, filter (\kv -> fst kv /= "indent") kvs2) blks2
in
- handleListParagraphs ((Div attr1 (blks1 ++ [newDiv2])) : blks)
-handleListParagraphs (blk:blks) = blk : (handleListParagraphs blks)
+ handleListParagraphs (Div attr1 (blks1 ++ [newDiv2]) : blks)
+handleListParagraphs (blk:blks) = blk : handleListParagraphs blks
separateBlocks' :: Block -> [[Block]] -> [[Block]]
-separateBlocks' blk ([] : []) = [[blk]]
-separateBlocks' b@(BulletList _) acc = (init acc) ++ [(last acc) ++ [b]]
-separateBlocks' b@(OrderedList _ _) acc = (init acc) ++ [(last acc) ++ [b]]
+separateBlocks' blk [[]] = [[blk]]
+separateBlocks' b@(BulletList _) acc = init acc ++ [last acc ++ [b]]
+separateBlocks' b@(OrderedList _ _) acc = init acc ++ [last acc ++ [b]]
-- The following is for the invisible bullet lists. This is how
-- pandoc-generated ooxml does multiparagraph item lists.
-separateBlocks' b acc | liftM trim (getText b) == Just "" =
- (init acc) ++ [(last acc) ++ [b]]
+separateBlocks' b acc | fmap trim (getText b) == Just "" =
+ init acc ++ [last acc ++ [b]]
separateBlocks' b acc = acc ++ [[b]]
separateBlocks :: [Block] -> [[Block]]
@@ -138,63 +133,60 @@ separateBlocks blks = foldr separateBlocks' [[]] (reverse blks)
flatToBullets' :: Integer -> [Block] -> [Block]
flatToBullets' _ [] = []
flatToBullets' num xs@(b : elems)
- | getLevelN b == num = b : (flatToBullets' num elems)
+ | getLevelN b == num = b : flatToBullets' num elems
| otherwise =
let bNumId = getNumIdN b
bLevel = getLevelN b
(children, remaining) =
span
(\b' ->
- ((getLevelN b') > bLevel ||
- ((getLevelN b') == bLevel && (getNumIdN b') == bNumId)))
+ getLevelN b' > bLevel ||
+ (getLevelN b' == bLevel && getNumIdN b' == bNumId))
xs
in
case getListType b of
Just (Enumerated attr) ->
- (OrderedList attr (separateBlocks $ flatToBullets' bLevel children)) :
- (flatToBullets' num remaining)
+ OrderedList attr (separateBlocks $ flatToBullets' bLevel children) :
+ flatToBullets' num remaining
_ ->
- (BulletList (separateBlocks $ flatToBullets' bLevel children)) :
- (flatToBullets' num remaining)
+ BulletList (separateBlocks $ flatToBullets' bLevel children) :
+ flatToBullets' num remaining
flatToBullets :: [Block] -> [Block]
flatToBullets elems = flatToBullets' (-1) elems
singleItemHeaderToHeader :: Block -> Block
-singleItemHeaderToHeader (OrderedList _ [[h@(Header _ _ _)]]) = h
-singleItemHeaderToHeader blk = blk
+singleItemHeaderToHeader (OrderedList _ [[h@Header{}]]) = h
+singleItemHeaderToHeader blk = blk
blocksToBullets :: [Block] -> [Block]
blocksToBullets blks =
map singleItemHeaderToHeader $
- bottomUp removeListDivs $
- flatToBullets $ (handleListParagraphs blks)
+ bottomUp removeListDivs $flatToBullets (handleListParagraphs blks)
plainParaInlines :: Block -> [Inline]
plainParaInlines (Plain ils) = ils
-plainParaInlines (Para ils) = ils
-plainParaInlines _ = []
+plainParaInlines (Para ils) = ils
+plainParaInlines _ = []
blocksToDefinitions' :: [([Inline], [[Block]])] -> [Block] -> [Block] -> [Block]
blocksToDefinitions' [] acc [] = reverse acc
blocksToDefinitions' defAcc acc [] =
- reverse $ (DefinitionList (reverse defAcc)) : acc
+ reverse $ DefinitionList (reverse defAcc) : acc
blocksToDefinitions' defAcc acc
- ((Div (_, classes1, _) blks1) : (Div (ident2, classes2, kvs2) blks2) : blks)
+ (Div (_, classes1, _) blks1 : Div (ident2, classes2, kvs2) blks2 : blks)
| "DefinitionTerm" `elem` classes1 && "Definition" `elem` classes2 =
let remainingAttr2 = (ident2, delete "Definition" classes2, kvs2)
- pair = case remainingAttr2 == ("", [], []) of
- True -> (concatMap plainParaInlines blks1, [blks2])
- False -> (concatMap plainParaInlines blks1, [[Div remainingAttr2 blks2]])
+ pair = if remainingAttr2 == ("", [], []) then (concatMap plainParaInlines blks1, [blks2]) else (concatMap plainParaInlines blks1, [[Div remainingAttr2 blks2]])
in
blocksToDefinitions' (pair : defAcc) acc blks
blocksToDefinitions' defAcc acc
- ((Div (ident2, classes2, kvs2) blks2) : blks)
+ (Div (ident2, classes2, kvs2) blks2 : blks)
| (not . null) defAcc && "Definition" `elem` classes2 =
let remainingAttr2 = (ident2, delete "Definition" classes2, kvs2)
defItems2 = case remainingAttr2 == ("", [], []) of
- True -> blks2
+ True -> blks2
False -> [Div remainingAttr2 blks2]
((defTerm, defItems):defs) = defAcc
defAcc' = case null defItems of
@@ -205,18 +197,18 @@ blocksToDefinitions' defAcc acc
blocksToDefinitions' [] acc (b:blks) =
blocksToDefinitions' [] (b:acc) blks
blocksToDefinitions' defAcc acc (b:blks) =
- blocksToDefinitions' [] (b : (DefinitionList (reverse defAcc)) : acc) blks
+ blocksToDefinitions' [] (b : DefinitionList (reverse defAcc) : acc) blks
removeListDivs' :: Block -> [Block]
removeListDivs' (Div (ident, classes, kvs) blks)
| "list-item" `elem` classes =
case delete "list-item" classes of
- [] -> blks
- classes' -> [Div (ident, classes', kvs) $ blks]
+ [] -> blks
+ classes' -> [Div (ident, classes', kvs) blks]
removeListDivs' (Div (ident, classes, kvs) blks)
| not $ null $ listParagraphDivs `intersect` classes =
case classes \\ listParagraphDivs of
- [] -> blks
+ [] -> blks
classes' -> [Div (ident, classes', kvs) blks]
removeListDivs' blk = [blk]
diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs
index deb2caccf..1f7f07e36 100644
--- a/src/Text/Pandoc/Readers/Docx/Parse.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse.hs
@@ -1,7 +1,9 @@
-{-# LANGUAGE PatternGuards, ViewPatterns, FlexibleInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ViewPatterns #-}
{-
-Copyright (C) 2014-2016 Jesse Rosenthal <jrosenthal@jhu.edu>
+Copyright (C) 2014-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Docx.Parse
- Copyright : Copyright (C) 2014-2016 Jesse Rosenthal
+ Copyright : Copyright (C) 2014-2018 Jesse Rosenthal
License : GNU GPL, version 2 or above
Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -49,28 +51,34 @@ module Text.Pandoc.Readers.Docx.Parse ( Docx(..)
, ParagraphStyle(..)
, Row(..)
, Cell(..)
+ , TrackedChange(..)
+ , ChangeType(..)
+ , ChangeInfo(..)
+ , FieldInfo(..)
, archiveToDocx
, archiveToDocxWithWarnings
) where
import Codec.Archive.Zip
-import Text.XML.Light
-import Data.Maybe
-import Data.List
-import System.FilePath
+import Control.Applicative ((<|>))
+import Control.Monad.Except
+import Control.Monad.Reader
+import Control.Monad.State.Strict
import Data.Bits ((.|.))
import qualified Data.ByteString.Lazy as B
-import qualified Text.Pandoc.UTF8 as UTF8
-import Control.Monad.Reader
-import Control.Monad.State
-import Control.Applicative ((<|>))
+import Data.Char (chr, ord, readLitChar)
+import Data.List
import qualified Data.Map as M
-import Control.Monad.Except
-import Text.Pandoc.Shared (safeRead, filteredFilesFromArchive)
-import Text.TeXMath.Readers.OMML (readOMML)
-import Text.TeXMath.Unicode.Fonts (getUnicode, stringToFont, Font(..))
-import Text.TeXMath (Exp)
+import Data.Maybe
+import System.FilePath
import Text.Pandoc.Readers.Docx.Util
-import Data.Char (readLitChar, ord, chr, isDigit)
+import Text.Pandoc.Readers.Docx.Fields
+import Text.Pandoc.Shared (filteredFilesFromArchive, safeRead)
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.TeXMath (Exp)
+import Text.TeXMath.Readers.OMML (readOMML)
+import Text.TeXMath.Unicode.Fonts (Font (..), getUnicode, stringToFont)
+import Text.XML.Light
+import qualified Text.XML.Light.Cursor as XMLC
data ReaderEnv = ReaderEnv { envNotes :: Notes
, envComments :: Comments
@@ -84,10 +92,19 @@ data ReaderEnv = ReaderEnv { envNotes :: Notes
}
deriving Show
-data ReaderState = ReaderState { stateWarnings :: [String] }
+data ReaderState = ReaderState { stateWarnings :: [String]
+ , stateFldCharState :: FldCharState
+ }
deriving Show
-data DocxError = DocxError | WrongElem
+data FldCharState = FldCharOpen
+ | FldCharFieldInfo FieldInfo
+ | FldCharContent FieldInfo [Run]
+ | FldCharClosed
+ deriving (Show)
+
+data DocxError = DocxError
+ | WrongElem
deriving Show
type D = ExceptT DocxError (ReaderT ReaderEnv (State ReaderState))
@@ -97,7 +114,7 @@ runD dx re rs = runState (runReaderT (runExceptT dx) re) rs
maybeToD :: Maybe a -> D a
maybeToD (Just a) = return a
-maybeToD Nothing = throwError DocxError
+maybeToD Nothing = throwError DocxError
eitherToD :: Either a b -> D b
eitherToD (Right b) = return b
@@ -115,6 +132,36 @@ mapD f xs =
in
concatMapM handler xs
+unwrapSDT :: NameSpaces -> Content -> [Content]
+unwrapSDT ns (Elem element)
+ | isElem ns "w" "sdt" element
+ , Just sdtContent <- findChildByName ns "w" "sdtContent" element
+ = concatMap (unwrapSDT ns) $ map Elem $ elChildren sdtContent
+unwrapSDT _ content = [content]
+
+unwrapSDTchild :: NameSpaces -> Content -> Content
+unwrapSDTchild ns (Elem element) =
+ Elem $ element { elContent = concatMap (unwrapSDT ns) (elContent element) }
+unwrapSDTchild _ content = content
+
+walkDocument' :: NameSpaces -> XMLC.Cursor -> XMLC.Cursor
+walkDocument' ns cur =
+ let modifiedCur = XMLC.modifyContent (unwrapSDTchild ns) cur
+ in
+ case XMLC.nextDF modifiedCur of
+ Just cur' -> walkDocument' ns cur'
+ Nothing -> XMLC.root modifiedCur
+
+walkDocument :: NameSpaces -> Element -> Maybe Element
+walkDocument ns element =
+ let cur = XMLC.fromContent (Elem element)
+ cur' = walkDocument' ns cur
+ in
+ case XMLC.toTree cur' of
+ Elem element' -> Just element'
+ _ -> Nothing
+
+
data Docx = Docx Document
deriving Show
@@ -160,17 +207,27 @@ data Notes = Notes NameSpaces
data Comments = Comments NameSpaces (M.Map String Element)
deriving Show
-data ParIndentation = ParIndentation { leftParIndent :: Maybe Integer
- , rightParIndent :: Maybe Integer
+data ParIndentation = ParIndentation { leftParIndent :: Maybe Integer
+ , rightParIndent :: Maybe Integer
, hangingParIndent :: Maybe Integer}
deriving Show
-data ParagraphStyle = ParagraphStyle { pStyle :: [String]
+data ChangeType = Insertion | Deletion
+ deriving Show
+
+data ChangeInfo = ChangeInfo ChangeId Author ChangeDate
+ deriving Show
+
+data TrackedChange = TrackedChange ChangeType ChangeInfo
+ deriving Show
+
+data ParagraphStyle = ParagraphStyle { pStyle :: [String]
, indentation :: Maybe ParIndentation
, dropCap :: Bool
, pHeading :: Maybe (String, Int)
, pNumInfo :: Maybe (String, String)
, pBlockQuote :: Maybe Bool
+ , pChange :: Maybe TrackedChange
}
deriving Show
@@ -181,6 +238,7 @@ defaultParagraphStyle = ParagraphStyle { pStyle = []
, pHeading = Nothing
, pNumInfo = Nothing
, pBlockQuote = Nothing
+ , pChange = Nothing
}
@@ -208,8 +266,7 @@ data Cell = Cell [BodyPart]
type Extent = Maybe (Double, Double)
data ParPart = PlainRun Run
- | Insertion ChangeId Author ChangeDate [Run]
- | Deletion ChangeId Author ChangeDate [Run]
+ | ChangedRuns TrackedChange [Run]
| CommentStart CommentId Author CommentDate [BodyPart]
| CommentEnd CommentId
| BookMark BookMarkId Anchor
@@ -218,6 +275,10 @@ data ParPart = PlainRun Run
| Drawing FilePath String String B.ByteString Extent -- title, alt
| Chart -- placeholder for now
| PlainOMath [Exp]
+ | SmartTag [Run]
+ | Field FieldInfo [Run]
+ | NullParPart -- when we need to return nothing, but
+ -- not because of an error.
deriving Show
data Run = Run RunStyle [RunElem]
@@ -233,19 +294,19 @@ data RunElem = TextRun String | LnBrk | Tab | SoftHyphen | NoBreakHyphen
data VertAlign = BaseLn | SupScrpt | SubScrpt
deriving Show
-data RunStyle = RunStyle { isBold :: Maybe Bool
- , isItalic :: Maybe Bool
+data RunStyle = RunStyle { isBold :: Maybe Bool
+ , isItalic :: Maybe Bool
, isSmallCaps :: Maybe Bool
- , isStrike :: Maybe Bool
- , rVertAlign :: Maybe VertAlign
- , rUnderline :: Maybe String
- , rStyle :: Maybe CharStyle}
+ , isStrike :: Maybe Bool
+ , rVertAlign :: Maybe VertAlign
+ , rUnderline :: Maybe String
+ , rStyle :: Maybe CharStyle}
deriving Show
-data ParStyleData = ParStyleData { headingLev :: Maybe (String, Int)
+data ParStyleData = ParStyleData { headingLev :: Maybe (String, Int)
, isBlockQuote :: Maybe Bool
- , numInfo :: Maybe (String, String)
- , psStyle :: Maybe ParStyle}
+ , numInfo :: Maybe (String, String)
+ , psStyle :: Maybe ParStyle}
deriving Show
defaultRunStyle :: RunStyle
@@ -281,7 +342,9 @@ archiveToDocxWithWarnings archive = do
(styles, parstyles) = archiveToStyles archive
rEnv =
ReaderEnv notes comments numbering rels media Nothing styles parstyles InDocument
- rState = ReaderState { stateWarnings = [] }
+ rState = ReaderState { stateWarnings = []
+ , stateFldCharState = FldCharClosed
+ }
(eitherDoc, st) = runD (archiveToDocument archive) rEnv rState
case eitherDoc of
Right doc -> Right (Docx doc, stateWarnings st)
@@ -294,14 +357,14 @@ archiveToDocument zf = do
entry <- maybeToD $ findEntryByPath "word/document.xml" zf
docElem <- maybeToD $ (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
let namespaces = elemToNameSpaces docElem
- bodyElem <- maybeToD $ findChild (elemName namespaces "w" "body") docElem
- body <- elemToBody namespaces bodyElem
+ bodyElem <- maybeToD $ findChildByName namespaces "w" "body" docElem
+ let bodyElem' = fromMaybe bodyElem (walkDocument namespaces bodyElem)
+ body <- elemToBody namespaces bodyElem'
return $ Document namespaces body
elemToBody :: NameSpaces -> Element -> D Body
elemToBody ns element | isElem ns "w" "body" element =
- mapD (elemToBodyPart ns) (elChildren element) >>=
- (\bps -> return $ Body bps)
+ fmap Body (mapD (elemToBodyPart ns) (elChildren element))
elemToBody _ _ = throwError WrongElem
archiveToStyles :: Archive -> (CharStyleMap, ParStyleMap)
@@ -322,15 +385,15 @@ archiveToStyles zf =
isBasedOnStyle :: (ElemToStyle a) => NameSpaces -> Element -> Maybe a -> Bool
isBasedOnStyle ns element parentStyle
| isElem ns "w" "style" element
- , Just styleType <- findAttr (elemName ns "w" "type") element
+ , Just styleType <- findAttrByName ns "w" "type" element
, styleType == cStyleType parentStyle
- , Just basedOnVal <- findChild (elemName ns "w" "basedOn") element >>=
- findAttr (elemName ns "w" "val")
- , Just ps <- parentStyle = (basedOnVal == getStyleId ps)
+ , Just basedOnVal <- findChildByName ns "w" "basedOn" element >>=
+ findAttrByName ns "w" "val"
+ , Just ps <- parentStyle = basedOnVal == getStyleId ps
| isElem ns "w" "style" element
- , Just styleType <- findAttr (elemName ns "w" "type") element
+ , Just styleType <- findAttrByName ns "w" "type" element
, styleType == cStyleType parentStyle
- , Nothing <- findChild (elemName ns "w" "basedOn") element
+ , Nothing <- findChildByName ns "w" "basedOn" element
, Nothing <- parentStyle = True
| otherwise = False
@@ -343,8 +406,8 @@ instance ElemToStyle CharStyle where
cStyleType _ = "character"
elemToStyle ns element parentStyle
| isElem ns "w" "style" element
- , Just "character" <- findAttr (elemName ns "w" "type") element
- , Just styleId <- findAttr (elemName ns "w" "styleId") element =
+ , Just "character" <- findAttrByName ns "w" "type" element
+ , Just styleId <- findAttrByName ns "w" "styleId" element =
Just (styleId, elemToRunStyle ns element parentStyle)
| otherwise = Nothing
getStyleId s = fst s
@@ -353,8 +416,8 @@ instance ElemToStyle ParStyle where
cStyleType _ = "paragraph"
elemToStyle ns element parentStyle
| isElem ns "w" "style" element
- , Just "paragraph" <- findAttr (elemName ns "w" "type") element
- , Just styleId <- findAttr (elemName ns "w" "styleId") element =
+ , Just "paragraph" <- findAttrByName ns "w" "type" element
+ , Just styleId <- findAttrByName ns "w" "styleId" element =
Just (styleId, elemToParStyleData ns element parentStyle)
| otherwise = Nothing
getStyleId s = fst s
@@ -368,10 +431,10 @@ getStyleChildren ns element parentStyle
buildBasedOnList :: (ElemToStyle a) => NameSpaces -> Element -> Maybe a -> [a]
buildBasedOnList ns element rootStyle =
- case (getStyleChildren ns element rootStyle) of
+ case getStyleChildren ns element rootStyle of
[] -> []
stys -> stys ++
- (concatMap (\s -> buildBasedOnList ns element (Just s)) stys)
+ concatMap (buildBasedOnList ns element . Just) stys
archiveToNotes :: Archive -> Notes
archiveToNotes zf =
@@ -380,14 +443,14 @@ archiveToNotes zf =
enElem = findEntryByPath "word/endnotes.xml" zf
>>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
fn_namespaces = case fnElem of
- Just e -> elemToNameSpaces e
+ Just e -> elemToNameSpaces e
Nothing -> []
en_namespaces = case enElem of
- Just e -> elemToNameSpaces e
+ Just e -> elemToNameSpaces e
Nothing -> []
ns = unionBy (\x y -> fst x == fst y) fn_namespaces en_namespaces
- fn = fnElem >>= (elemToNotes ns "footnote")
- en = enElem >>= (elemToNotes ns "endnote")
+ fn = fnElem >>= elemToNotes ns "footnote"
+ en = enElem >>= elemToNotes ns "endnote"
in
Notes ns fn en
@@ -396,19 +459,19 @@ archiveToComments zf =
let cmtsElem = findEntryByPath "word/comments.xml" zf
>>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
cmts_namespaces = case cmtsElem of
- Just e -> elemToNameSpaces e
+ Just e -> elemToNameSpaces e
Nothing -> []
- cmts = (elemToComments cmts_namespaces) <$> cmtsElem
+ cmts = elemToComments cmts_namespaces <$> cmtsElem
in
case cmts of
- Just c -> Comments cmts_namespaces c
+ Just c -> Comments cmts_namespaces c
Nothing -> Comments cmts_namespaces M.empty
filePathToRelType :: FilePath -> Maybe DocumentLocation
-filePathToRelType "word/_rels/document.xml.rels" = Just InDocument
+filePathToRelType "word/_rels/document.xml.rels" = Just InDocument
filePathToRelType "word/_rels/footnotes.xml.rels" = Just InFootnote
-filePathToRelType "word/_rels/endnotes.xml.rels" = Just InEndnote
-filePathToRelType _ = Nothing
+filePathToRelType "word/_rels/endnotes.xml.rels" = Just InEndnote
+filePathToRelType _ = Nothing
relElemToRelationship :: DocumentLocation -> Element -> Maybe Relationship
relElemToRelationship relType element | qName (elName element) == "Relationship" =
@@ -439,24 +502,23 @@ lookupLevel :: String -> String -> Numbering -> Maybe Level
lookupLevel numId ilvl (Numbering _ numbs absNumbs) = do
absNumId <- lookup numId $ map (\(Numb nid absnumid) -> (nid, absnumid)) numbs
lvls <- lookup absNumId $ map (\(AbstractNumb aid ls) -> (aid, ls)) absNumbs
- lvl <- lookup ilvl $ map (\l@(i, _, _, _) -> (i, l)) lvls
- return lvl
+ lookup ilvl $ map (\l@(i, _, _, _) -> (i, l)) lvls
numElemToNum :: NameSpaces -> Element -> Maybe Numb
numElemToNum ns element
| isElem ns "w" "num" element = do
- numId <- findAttr (elemName ns "w" "numId") element
- absNumId <- findChild (elemName ns "w" "abstractNumId") element
- >>= findAttr (elemName ns "w" "val")
+ numId <- findAttrByName ns "w" "numId" element
+ absNumId <- findChildByName ns "w" "abstractNumId" element
+ >>= findAttrByName ns "w" "val"
return $ Numb numId absNumId
numElemToNum _ _ = Nothing
absNumElemToAbsNum :: NameSpaces -> Element -> Maybe AbstractNumb
absNumElemToAbsNum ns element
| isElem ns "w" "abstractNum" element = do
- absNumId <- findAttr (elemName ns "w" "abstractNumId") element
- let levelElems = findChildren (elemName ns "w" "lvl") element
+ absNumId <- findAttrByName ns "w" "abstractNumId" element
+ let levelElems = findChildrenByName ns "w" "lvl" element
levels = mapMaybe (levelElemToLevel ns) levelElems
return $ AbstractNumb absNumId levels
absNumElemToAbsNum _ _ = Nothing
@@ -464,26 +526,26 @@ absNumElemToAbsNum _ _ = Nothing
levelElemToLevel :: NameSpaces -> Element -> Maybe Level
levelElemToLevel ns element
| isElem ns "w" "lvl" element = do
- ilvl <- findAttr (elemName ns "w" "ilvl") element
- fmt <- findChild (elemName ns "w" "numFmt") element
- >>= findAttr (elemName ns "w" "val")
- txt <- findChild (elemName ns "w" "lvlText") element
- >>= findAttr (elemName ns "w" "val")
- let start = findChild (elemName ns "w" "start") element
- >>= findAttr (elemName ns "w" "val")
+ ilvl <- findAttrByName ns "w" "ilvl" element
+ fmt <- findChildByName ns "w" "numFmt" element
+ >>= findAttrByName ns "w" "val"
+ txt <- findChildByName ns "w" "lvlText" element
+ >>= findAttrByName ns "w" "val"
+ let start = findChildByName ns "w" "start" element
+ >>= findAttrByName ns "w" "val"
>>= (\s -> listToMaybe (map fst (reads s :: [(Integer, String)])))
return (ilvl, fmt, txt, start)
levelElemToLevel _ _ = Nothing
archiveToNumbering' :: Archive -> Maybe Numbering
-archiveToNumbering' zf = do
+archiveToNumbering' zf =
case findEntryByPath "word/numbering.xml" zf of
Nothing -> Just $ Numbering [] [] []
Just entry -> do
numberingElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
let namespaces = elemToNameSpaces numberingElem
- numElems = findChildren (elemName namespaces "w" "num") numberingElem
- absNumElems = findChildren (elemName namespaces "w" "abstractNum") numberingElem
+ numElems = findChildrenByName namespaces "w" "num" numberingElem
+ absNumElems = findChildrenByName namespaces "w" "abstractNum" numberingElem
nums = mapMaybe (numElemToNum namespaces) numElems
absNums = mapMaybe (absNumElemToAbsNum namespaces) absNumElems
return $ Numbering namespaces nums absNums
@@ -496,22 +558,23 @@ elemToNotes :: NameSpaces -> String -> Element -> Maybe (M.Map String Element)
elemToNotes ns notetype element
| isElem ns "w" (notetype ++ "s") element =
let pairs = mapMaybe
- (\e -> findAttr (elemName ns "w" "id") e >>=
+ (\e -> findAttrByName ns "w" "id" e >>=
(\a -> Just (a, e)))
- (findChildren (elemName ns "w" notetype) element)
+ (findChildrenByName ns "w" notetype element)
in
- Just $ M.fromList $ pairs
+ Just $
+ M.fromList pairs
elemToNotes _ _ _ = Nothing
elemToComments :: NameSpaces -> Element -> M.Map String Element
elemToComments ns element
| isElem ns "w" "comments" element =
let pairs = mapMaybe
- (\e -> findAttr (elemName ns "w" "id") e >>=
+ (\e -> findAttrByName ns "w" "id" e >>=
(\a -> Just (a, e)))
- (findChildren (elemName ns "w" "comment") element)
+ (findChildrenByName ns "w" "comment" element)
in
- M.fromList $ pairs
+ M.fromList pairs
elemToComments _ _ = M.empty
@@ -520,16 +583,16 @@ elemToComments _ _ = M.empty
elemToTblGrid :: NameSpaces -> Element -> D TblGrid
elemToTblGrid ns element | isElem ns "w" "tblGrid" element =
- let cols = findChildren (elemName ns "w" "gridCol") element
+ let cols = findChildrenByName ns "w" "gridCol" element
in
- mapD (\e -> maybeToD (findAttr (elemName ns "w" "val") e >>= stringToInteger))
+ mapD (\e -> maybeToD (findAttrByName ns "w" "val" e >>= stringToInteger))
cols
elemToTblGrid _ _ = throwError WrongElem
elemToTblLook :: NameSpaces -> Element -> D TblLook
elemToTblLook ns element | isElem ns "w" "tblLook" element =
- let firstRow = findAttr (elemName ns "w" "firstRow") element
- val = findAttr (elemName ns "w" "val") element
+ let firstRow = findAttrByName ns "w" "firstRow" element
+ val = findAttrByName ns "w" "val" element
firstRowFmt =
case firstRow of
Just "1" -> True
@@ -538,13 +601,13 @@ elemToTblLook ns element | isElem ns "w" "tblLook" element =
Just bitMask -> testBitMask bitMask 0x020
Nothing -> False
in
- return $ TblLook{firstRowFormatting = firstRowFmt}
+ return TblLook{firstRowFormatting = firstRowFmt}
elemToTblLook _ _ = throwError WrongElem
elemToRow :: NameSpaces -> Element -> D Row
elemToRow ns element | isElem ns "w" "tr" element =
do
- let cellElems = findChildren (elemName ns "w" "tc") element
+ let cellElems = findChildrenByName ns "w" "tc" element
cells <- mapD (elemToCell ns) cellElems
return $ Row cells
elemToRow _ _ = throwError WrongElem
@@ -558,15 +621,15 @@ elemToCell _ _ = throwError WrongElem
elemToParIndentation :: NameSpaces -> Element -> Maybe ParIndentation
elemToParIndentation ns element | isElem ns "w" "ind" element =
- Just $ ParIndentation {
+ Just ParIndentation {
leftParIndent =
- findAttr (elemName ns "w" "left") element >>=
+ findAttrByName ns "w" "left" element >>=
stringToInteger
, rightParIndent =
- findAttr (elemName ns "w" "right") element >>=
+ findAttrByName ns "w" "right" element >>=
stringToInteger
, hangingParIndent =
- findAttr (elemName ns "w" "hanging") element >>=
+ findAttrByName ns "w" "hanging" element >>=
stringToInteger}
elemToParIndentation _ _ = Nothing
@@ -574,7 +637,7 @@ testBitMask :: String -> Int -> Bool
testBitMask bitMaskS n =
case (reads ("0x" ++ bitMaskS) :: [(Int, String)]) of
[] -> False
- ((n', _) : _) -> ((n' .|. n) /= 0)
+ ((n', _) : _) -> (n' .|. n) /= 0
stringToInteger :: String -> Maybe Integer
stringToInteger s = listToMaybe $ map fst (reads s :: [(Integer, String)])
@@ -582,7 +645,7 @@ stringToInteger s = listToMaybe $ map fst (reads s :: [(Integer, String)])
elemToBodyPart :: NameSpaces -> Element -> D BodyPart
elemToBodyPart ns element
| isElem ns "w" "p" element
- , (c:_) <- findChildren (elemName ns "m" "oMathPara") element =
+ , (c:_) <- findChildrenByName ns "m" "oMathPara" element =
do
expsLst <- eitherToD $ readOMML $ showElement c
return $ OMathPara expsLst
@@ -610,17 +673,17 @@ elemToBodyPart ns element
_ -> return $ Paragraph parstyle parparts
elemToBodyPart ns element
| isElem ns "w" "tbl" element = do
- let caption' = findChild (elemName ns "w" "tblPr") element
- >>= findChild (elemName ns "w" "tblCaption")
- >>= findAttr (elemName ns "w" "val")
+ let caption' = findChildByName ns "w" "tblPr" element
+ >>= findChildByName ns "w" "tblCaption"
+ >>= findAttrByName ns "w" "val"
caption = (fromMaybe "" caption')
- grid' = case findChild (elemName ns "w" "tblGrid") element of
- Just g -> elemToTblGrid ns g
+ grid' = case findChildByName ns "w" "tblGrid" element of
+ Just g -> elemToTblGrid ns g
Nothing -> return []
- tblLook' = case findChild (elemName ns "w" "tblPr") element >>=
- findChild (elemName ns "w" "tblLook")
+ tblLook' = case findChildByName ns "w" "tblPr" element >>=
+ findChildByName ns "w" "tblLook"
of
- Just l -> elemToTblLook ns l
+ Just l -> elemToTblLook ns l
Nothing -> return defaultTblLook
grid <- grid'
@@ -649,26 +712,22 @@ expandDrawingId s = do
getTitleAndAlt :: NameSpaces -> Element -> (String, String)
getTitleAndAlt ns element =
- let mbDocPr = findChild (elemName ns "wp" "inline") element >>=
- findChild (elemName ns "wp" "docPr")
- title = case mbDocPr >>= findAttr (elemName ns "" "title") of
- Just title' -> title'
- Nothing -> ""
- alt = case mbDocPr >>= findAttr (elemName ns "" "descr") of
- Just alt' -> alt'
- Nothing -> ""
+ let mbDocPr = findChildByName ns "wp" "inline" element >>=
+ findChildByName ns "wp" "docPr"
+ title = fromMaybe "" (mbDocPr >>= findAttrByName ns "" "title")
+ alt = fromMaybe "" (mbDocPr >>= findAttrByName ns "" "descr")
in (title, alt)
elemToParPart :: NameSpaces -> Element -> D ParPart
elemToParPart ns element
| isElem ns "w" "r" element
- , Just drawingElem <- findChild (elemName ns "w" "drawing") element
+ , Just drawingElem <- findChildByName ns "w" "drawing" element
, pic_ns <- "http://schemas.openxmlformats.org/drawingml/2006/picture"
, Just picElem <- findElement (QName "pic" (Just pic_ns) (Just "pic")) drawingElem
= let (title, alt) = getTitleAndAlt ns drawingElem
a_ns = "http://schemas.openxmlformats.org/drawingml/2006/main"
drawing = findElement (QName "blip" (Just a_ns) (Just "a")) picElem
- >>= findAttr (elemName ns "r" "embed")
+ >>= findAttrByName ns "r" "embed"
in
case drawing of
Just s -> expandDrawingId s >>= (\(fp, bs) -> return $ Drawing fp title alt bs $ elemToExtent drawingElem)
@@ -676,9 +735,9 @@ elemToParPart ns element
-- The below is an attempt to deal with images in deprecated vml format.
elemToParPart ns element
| isElem ns "w" "r" element
- , Just _ <- findChild (elemName ns "w" "pict") element =
+ , Just _ <- findChildByName ns "w" "pict" element =
let drawing = findElement (elemName ns "v" "imagedata") element
- >>= findAttr (elemName ns "r" "id")
+ >>= findAttrByName ns "r" "id"
in
case drawing of
-- Todo: check out title and attr for deprecated format.
@@ -687,86 +746,148 @@ elemToParPart ns element
-- Chart
elemToParPart ns element
| isElem ns "w" "r" element
- , Just drawingElem <- findChild (elemName ns "w" "drawing") element
+ , Just drawingElem <- findChildByName ns "w" "drawing" element
, c_ns <- "http://schemas.openxmlformats.org/drawingml/2006/chart"
, Just _ <- findElement (QName "chart" (Just c_ns) (Just "c")) drawingElem
- = return Chart
+ = return Chart
+{-
+The next one is a bit complicated. fldChar fields work by first
+having a <w:fldChar fldCharType="begin"> in a run, then a run with
+<w:instrText>, then a <w:fldChar fldCharType="separate"> run, then the
+content runs, and finally a <w:fldChar fldCharType="end"> run. For
+example (omissions and my comments in brackets):
+
+ <w:r>
+ [...]
+ <w:fldChar w:fldCharType="begin"/>
+ </w:r>
+ <w:r>
+ [...]
+ <w:instrText xml:space="preserve"> HYPERLINK [hyperlink url] </w:instrText>
+ </w:r>
+ <w:r>
+ [...]
+ <w:fldChar w:fldCharType="separate"/>
+ </w:r>
+ <w:r w:rsidRPr=[...]>
+ [...]
+ <w:t>Foundations of Analysis, 2nd Edition</w:t>
+ </w:r>
+ <w:r>
+ [...]
+ <w:fldChar w:fldCharType="end"/>
+ </w:r>
+
+So we do this in a number of steps. If we encounter the fldchar begin
+tag, we start open a fldchar state variable (see state above). We add
+the instrtext to it as FieldInfo. Then we close that and start adding
+the runs when we get to separate. Then when we get to end, we produce
+the Field type with approriate FieldInfo and Runs.
+-}
elemToParPart ns element
- | isElem ns "w" "r" element =
- elemToRun ns element >>= (\r -> return $ PlainRun r)
+ | isElem ns "w" "r" element
+ , Just fldChar <- findChildByName ns "w" "fldChar" element
+ , Just fldCharType <- findAttrByName ns "w" "fldCharType" fldChar = do
+ fldCharState <- gets stateFldCharState
+ case fldCharState of
+ FldCharClosed | fldCharType == "begin" -> do
+ modify $ \st -> st {stateFldCharState = FldCharOpen}
+ return NullParPart
+ FldCharFieldInfo info | fldCharType == "separate" -> do
+ modify $ \st -> st {stateFldCharState = FldCharContent info []}
+ return NullParPart
+ FldCharContent info runs | fldCharType == "end" -> do
+ modify $ \st -> st {stateFldCharState = FldCharClosed}
+ return $ Field info $ reverse runs
+ _ -> throwError WrongElem
elemToParPart ns element
- | isElem ns "w" "ins" element || isElem ns "w" "moveTo" element
- , Just cId <- findAttr (elemName ns "w" "id") element
- , Just cAuthor <- findAttr (elemName ns "w" "author") element
- , Just cDate <- findAttr (elemName ns "w" "date") element = do
- runs <- mapD (elemToRun ns) (elChildren element)
- return $ Insertion cId cAuthor cDate runs
+ | isElem ns "w" "r" element
+ , Just instrText <- findChildByName ns "w" "instrText" element = do
+ fldCharState <- gets stateFldCharState
+ case fldCharState of
+ FldCharOpen -> do
+ info <- eitherToD $ parseFieldInfo $ strContent instrText
+ modify $ \st -> st{stateFldCharState = FldCharFieldInfo info}
+ return NullParPart
+ _ -> return NullParPart
elemToParPart ns element
- | isElem ns "w" "del" element || isElem ns "w" "moveFrom" element
- , Just cId <- findAttr (elemName ns "w" "id") element
- , Just cAuthor <- findAttr (elemName ns "w" "author") element
- , Just cDate <- findAttr (elemName ns "w" "date") element = do
+ | isElem ns "w" "r" element = do
+ run <- elemToRun ns element
+ -- we check to see if we have an open FldChar in state that we're
+ -- recording.
+ fldCharState <- gets stateFldCharState
+ case fldCharState of
+ FldCharContent info runs -> do
+ modify $ \st -> st{stateFldCharState = FldCharContent info (run : runs)}
+ return NullParPart
+ _ -> return $ PlainRun run
+elemToParPart ns element
+ | Just change <- getTrackedChange ns element = do
+ runs <- mapD (elemToRun ns) (elChildren element)
+ return $ ChangedRuns change runs
+elemToParPart ns element
+ | isElem ns "w" "smartTag" element = do
runs <- mapD (elemToRun ns) (elChildren element)
- return $ Deletion cId cAuthor cDate runs
+ return $ SmartTag runs
elemToParPart ns element
| isElem ns "w" "bookmarkStart" element
- , Just bmId <- findAttr (elemName ns "w" "id") element
- , Just bmName <- findAttr (elemName ns "w" "name") element =
+ , Just bmId <- findAttrByName ns "w" "id" element
+ , Just bmName <- findAttrByName ns "w" "name" element =
return $ BookMark bmId bmName
elemToParPart ns element
| isElem ns "w" "hyperlink" element
- , Just relId <- findAttr (elemName ns "r" "id") element = do
+ , Just relId <- findAttrByName ns "r" "id" element = do
location <- asks envLocation
runs <- mapD (elemToRun ns) (elChildren element)
rels <- asks envRelationships
case lookupRelationship location relId rels of
- Just target -> do
- case findAttr (elemName ns "w" "anchor") element of
+ Just target ->
+ case findAttrByName ns "w" "anchor" element of
Just anchor -> return $ ExternalHyperLink (target ++ '#':anchor) runs
Nothing -> return $ ExternalHyperLink target runs
Nothing -> return $ ExternalHyperLink "" runs
elemToParPart ns element
| isElem ns "w" "hyperlink" element
- , Just anchor <- findAttr (elemName ns "w" "anchor") element = do
+ , Just anchor <- findAttrByName ns "w" "anchor" element = do
runs <- mapD (elemToRun ns) (elChildren element)
return $ InternalHyperLink anchor runs
elemToParPart ns element
| isElem ns "w" "commentRangeStart" element
- , Just cmtId <- findAttr (elemName ns "w" "id") element = do
+ , Just cmtId <- findAttrByName ns "w" "id" element = do
(Comments _ commentMap) <- asks envComments
case M.lookup cmtId commentMap of
Just cmtElem -> elemToCommentStart ns cmtElem
- Nothing -> throwError WrongElem
+ Nothing -> throwError WrongElem
elemToParPart ns element
| isElem ns "w" "commentRangeEnd" element
- , Just cmtId <- findAttr (elemName ns "w" "id") element =
+ , Just cmtId <- findAttrByName ns "w" "id" element =
return $ CommentEnd cmtId
elemToParPart ns element
| isElem ns "m" "oMath" element =
- (eitherToD $ readOMML $ showElement element) >>= (return . PlainOMath)
+ fmap PlainOMath (eitherToD $ readOMML $ showElement element)
elemToParPart _ _ = throwError WrongElem
elemToCommentStart :: NameSpaces -> Element -> D ParPart
elemToCommentStart ns element
| isElem ns "w" "comment" element
- , Just cmtId <- findAttr (elemName ns "w" "id") element
- , Just cmtAuthor <- findAttr (elemName ns "w" "author") element
- , Just cmtDate <- findAttr (elemName ns "w" "date") element = do
+ , Just cmtId <- findAttrByName ns "w" "id" element
+ , Just cmtAuthor <- findAttrByName ns "w" "author" element
+ , Just cmtDate <- findAttrByName ns "w" "date" element = do
bps <- mapD (elemToBodyPart ns) (elChildren element)
return $ CommentStart cmtId cmtAuthor cmtDate bps
elemToCommentStart _ _ = throwError WrongElem
lookupFootnote :: String -> Notes -> Maybe Element
-lookupFootnote s (Notes _ fns _) = fns >>= (M.lookup s)
+lookupFootnote s (Notes _ fns _) = fns >>= M.lookup s
lookupEndnote :: String -> Notes -> Maybe Element
-lookupEndnote s (Notes _ _ ens) = ens >>= (M.lookup s)
+lookupEndnote s (Notes _ _ ens) = ens >>= M.lookup s
elemToExtent :: Element -> Extent
elemToExtent drawingElem =
case (getDim "cx", getDim "cy") of
(Just w, Just h) -> Just (w, h)
- _ -> Nothing
+ _ -> Nothing
where
wp_ns = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
getDim at = findElement (QName "extent" (Just wp_ns) (Just "wp")) drawingElem
@@ -794,7 +915,7 @@ childElemToRun ns element
= return InlineChart
childElemToRun ns element
| isElem ns "w" "footnoteReference" element
- , Just fnId <- findAttr (elemName ns "w" "id") element = do
+ , Just fnId <- findAttrByName ns "w" "id" element = do
notes <- asks envNotes
case lookupFootnote fnId notes of
Just e -> do bps <- local (\r -> r {envLocation=InFootnote}) $ mapD (elemToBodyPart ns) (elChildren e)
@@ -802,7 +923,7 @@ childElemToRun ns element
Nothing -> return $ Footnote []
childElemToRun ns element
| isElem ns "w" "endnoteReference" element
- , Just enId <- findAttr (elemName ns "w" "id") element = do
+ , Just enId <- findAttrByName ns "w" "id" element = do
notes <- asks envNotes
case lookupEndnote enId notes of
Just e -> do bps <- local (\r -> r {envLocation=InEndnote}) $ mapD (elemToBodyPart ns) (elChildren e)
@@ -813,8 +934,8 @@ childElemToRun _ _ = throwError WrongElem
elemToRun :: NameSpaces -> Element -> D Run
elemToRun ns element
| isElem ns "w" "r" element
- , Just altCont <- findChild (elemName ns "mc" "AlternateContent") element =
- do let choices = findChildren (elemName ns "mc" "Choice") altCont
+ , Just altCont <- findChildByName ns "mc" "AlternateContent" element =
+ do let choices = findChildrenByName ns "mc" "Choice" altCont
choiceChildren = map head $ filter (not . null) $ map elChildren choices
outputs <- mapD (childElemToRun ns) choiceChildren
case outputs of
@@ -822,15 +943,15 @@ elemToRun ns element
[] -> throwError WrongElem
elemToRun ns element
| isElem ns "w" "r" element
- , Just drawingElem <- findChild (elemName ns "w" "drawing") element =
+ , Just drawingElem <- findChildByName ns "w" "drawing" element =
childElemToRun ns drawingElem
elemToRun ns element
| isElem ns "w" "r" element
- , Just ref <- findChild (elemName ns "w" "footnoteReference") element =
+ , Just ref <- findChildByName ns "w" "footnoteReference" element =
childElemToRun ns ref
elemToRun ns element
| isElem ns "w" "r" element
- , Just ref <- findChild (elemName ns "w" "endnoteReference") element =
+ , Just ref <- findChildByName ns "w" "endnoteReference" element =
childElemToRun ns ref
elemToRun ns element
| isElem ns "w" "r" element = do
@@ -854,22 +975,37 @@ getParStyleField field stylemap styles
= Just y
getParStyleField _ _ _ = Nothing
+getTrackedChange :: NameSpaces -> Element -> Maybe TrackedChange
+getTrackedChange ns element
+ | isElem ns "w" "ins" element || isElem ns "w" "moveTo" element
+ , Just cId <- findAttrByName ns "w" "id" element
+ , Just cAuthor <- findAttrByName ns "w" "author" element
+ , Just cDate <- findAttrByName ns "w" "date" element =
+ Just $ TrackedChange Insertion (ChangeInfo cId cAuthor cDate)
+getTrackedChange ns element
+ | isElem ns "w" "del" element || isElem ns "w" "moveFrom" element
+ , Just cId <- findAttrByName ns "w" "id" element
+ , Just cAuthor <- findAttrByName ns "w" "author" element
+ , Just cDate <- findAttrByName ns "w" "date" element =
+ Just $ TrackedChange Deletion (ChangeInfo cId cAuthor cDate)
+getTrackedChange _ _ = Nothing
+
elemToParagraphStyle :: NameSpaces -> Element -> ParStyleMap -> ParagraphStyle
elemToParagraphStyle ns element sty
- | Just pPr <- findChild (elemName ns "w" "pPr") element =
+ | Just pPr <- findChildByName ns "w" "pPr" element =
let style =
mapMaybe
- (findAttr (elemName ns "w" "val"))
- (findChildren (elemName ns "w" "pStyle") pPr)
+ (findAttrByName ns "w" "val")
+ (findChildrenByName ns "w" "pStyle" pPr)
in ParagraphStyle
{pStyle = style
, indentation =
- findChild (elemName ns "w" "ind") pPr >>=
+ findChildByName ns "w" "ind" pPr >>=
elemToParIndentation ns
, dropCap =
case
- findChild (elemName ns "w" "framePr") pPr >>=
- findAttr (elemName ns "w" "dropCap")
+ findChildByName ns "w" "framePr" pPr >>=
+ findAttrByName ns "w" "dropCap"
of
Just "none" -> False
Just _ -> True
@@ -877,13 +1013,20 @@ elemToParagraphStyle ns element sty
, pHeading = getParStyleField headingLev sty style
, pNumInfo = getParStyleField numInfo sty style
, pBlockQuote = getParStyleField isBlockQuote sty style
+ , pChange = findChildByName ns "w" "rPr" pPr >>=
+ filterChild (\e -> isElem ns "w" "ins" e ||
+ isElem ns "w" "moveTo" e ||
+ isElem ns "w" "del" e ||
+ isElem ns "w" "moveFrom" e
+ ) >>=
+ getTrackedChange ns
}
elemToParagraphStyle _ _ _ = defaultParagraphStyle
checkOnOff :: NameSpaces -> Element -> QName -> Maybe Bool
checkOnOff ns rPr tag
| Just t <- findChild tag rPr
- , Just val <- findAttr (elemName ns "w" "val") t =
+ , Just val <- findAttrByName ns "w" "val" t =
Just $ case val of
"true" -> True
"false" -> False
@@ -897,11 +1040,11 @@ checkOnOff _ _ _ = Nothing
elemToRunStyleD :: NameSpaces -> Element -> D RunStyle
elemToRunStyleD ns element
- | Just rPr <- findChild (elemName ns "w" "rPr") element = do
+ | Just rPr <- findChildByName ns "w" "rPr" element = do
charStyles <- asks envCharStyles
let parentSty = case
- findChild (elemName ns "w" "rStyle") rPr >>=
- findAttr (elemName ns "w" "val")
+ findChildByName ns "w" "rStyle" rPr >>=
+ findAttrByName ns "w" "val"
of
Just styName | Just style <- M.lookup styName charStyles ->
Just (styName, style)
@@ -911,7 +1054,7 @@ elemToRunStyleD _ _ = return defaultRunStyle
elemToRunStyle :: NameSpaces -> Element -> Maybe CharStyle -> RunStyle
elemToRunStyle ns element parentStyle
- | Just rPr <- findChild (elemName ns "w" "rPr") element =
+ | Just rPr <- findChildByName ns "w" "rPr" element =
RunStyle
{
isBold = checkOnOff ns rPr (elemName ns "w" "b")
@@ -919,32 +1062,31 @@ elemToRunStyle ns element parentStyle
, isSmallCaps = checkOnOff ns rPr (elemName ns "w" "smallCaps")
, isStrike = checkOnOff ns rPr (elemName ns "w" "strike")
, rVertAlign =
- findChild (elemName ns "w" "vertAlign") rPr >>=
- findAttr (elemName ns "w" "val") >>=
+ findChildByName ns "w" "vertAlign" rPr >>=
+ findAttrByName ns "w" "val" >>=
\v -> Just $ case v of
"superscript" -> SupScrpt
"subscript" -> SubScrpt
_ -> BaseLn
, rUnderline =
- findChild (elemName ns "w" "u") rPr >>=
- findAttr (elemName ns "w" "val")
+ findChildByName ns "w" "u" rPr >>=
+ findAttrByName ns "w" "val"
, rStyle = parentStyle
}
elemToRunStyle _ _ _ = defaultRunStyle
-isNumericNotNull :: String -> Bool
-isNumericNotNull str = (str /= []) && (all isDigit str)
-
getHeaderLevel :: NameSpaces -> Element -> Maybe (String,Int)
getHeaderLevel ns element
- | Just styleId <- findAttr (elemName ns "w" "styleId") element
+ | Just styleId <- findAttrByName ns "w" "styleId" element
, Just index <- stripPrefix "Heading" styleId
- , isNumericNotNull index = Just (styleId, read index)
- | Just styleId <- findAttr (elemName ns "w" "styleId") element
- , Just index <- findChild (elemName ns "w" "name") element >>=
- findAttr (elemName ns "w" "val") >>=
+ , Just n <- stringToInteger index
+ , n > 0 = Just (styleId, fromInteger n)
+ | Just styleId <- findAttrByName ns "w" "styleId" element
+ , Just index <- findChildByName ns "w" "name" element >>=
+ findAttrByName ns "w" "val" >>=
stripPrefix "heading "
- , isNumericNotNull index = Just (styleId, read index)
+ , Just n <- stringToInteger index
+ , n > 0 = Just (styleId, fromInteger n)
getHeaderLevel _ _ = Nothing
blockQuoteStyleIds :: [String]
@@ -955,23 +1097,23 @@ blockQuoteStyleNames = ["Quote", "Block Text"]
getBlockQuote :: NameSpaces -> Element -> Maybe Bool
getBlockQuote ns element
- | Just styleId <- findAttr (elemName ns "w" "styleId") element
+ | Just styleId <- findAttrByName ns "w" "styleId" element
, styleId `elem` blockQuoteStyleIds = Just True
- | Just styleName <- findChild (elemName ns "w" "name") element >>=
- findAttr (elemName ns "w" "val")
+ | Just styleName <- findChildByName ns "w" "name" element >>=
+ findAttrByName ns "w" "val"
, styleName `elem` blockQuoteStyleNames = Just True
getBlockQuote _ _ = Nothing
getNumInfo :: NameSpaces -> Element -> Maybe (String, String)
getNumInfo ns element = do
- let numPr = findChild (elemName ns "w" "pPr") element >>=
- findChild (elemName ns "w" "numPr")
+ let numPr = findChildByName ns "w" "pPr" element >>=
+ findChildByName ns "w" "numPr"
lvl = fromMaybe "0" (numPr >>=
- findChild (elemName ns "w" "ilvl") >>=
- findAttr (elemName ns "w" "val"))
+ findChildByName ns "w" "ilvl" >>=
+ findAttrByName ns "w" "val")
numId <- numPr >>=
- findChild (elemName ns "w" "numId") >>=
- findAttr (elemName ns "w" "val")
+ findChildByName ns "w" "numId" >>=
+ findAttrByName ns "w" "val"
return (numId, lvl)
@@ -1015,10 +1157,10 @@ getSymChar ns element
let [(char, _)] = readLitChar ("\\x" ++ s) in
TextRun . maybe "" (:[]) $ getUnicode font char
where
- getCodepoint = findAttr (elemName ns "w" "char") element
- getFont = stringToFont =<< findAttr (elemName ns "w" "font") element
+ getCodepoint = findAttrByName ns "w" "char" element
+ getFont = stringToFont =<< findAttrByName ns "w" "font" element
lowerFromPrivate ('F':xs) = '0':xs
- lowerFromPrivate xs = xs
+ lowerFromPrivate xs = xs
getSymChar _ _ = TextRun ""
elemToRunElems :: NameSpaces -> Element -> D [RunElem]
@@ -1029,11 +1171,9 @@ elemToRunElems ns element
let font = do
fontElem <- findElement (qualName "rFonts") element
stringToFont =<<
- (foldr (<|>) Nothing $
- map (flip findAttr fontElem . qualName) ["ascii", "hAnsi"])
+ foldr ((<|>) . (flip findAttr fontElem . qualName)) Nothing ["ascii", "hAnsi"]
local (setFont font) (mapD (elemToRunElem ns) (elChildren element))
elemToRunElems _ _ = throwError WrongElem
setFont :: Maybe Font -> ReaderEnv -> ReaderEnv
setFont f s = s{envFont = f}
-
diff --git a/src/Text/Pandoc/Readers/Docx/StyleMap.hs b/src/Text/Pandoc/Readers/Docx/StyleMap.hs
index 00906cf07..b32a73770 100644
--- a/src/Text/Pandoc/Readers/Docx/StyleMap.hs
+++ b/src/Text/Pandoc/Readers/Docx/StyleMap.hs
@@ -7,11 +7,11 @@ module Text.Pandoc.Readers.Docx.StyleMap ( StyleMaps(..)
, hasStyleName
) where
-import Text.XML.Light
-import Text.Pandoc.Readers.Docx.Util
-import Control.Monad.State
-import Data.Char (toLower)
-import qualified Data.Map as M
+import Control.Monad.State.Strict
+import Data.Char (toLower)
+import qualified Data.Map as M
+import Text.Pandoc.Readers.Docx.Util
+import Text.XML.Light
newtype ParaStyleMap = ParaStyleMap ( M.Map String String )
newtype CharStyleMap = CharStyleMap ( M.Map String String )
@@ -30,7 +30,7 @@ instance StyleMap CharStyleMap where
insert :: (StyleMap a) => Maybe String -> Maybe String -> a -> a
insert (Just k) (Just v) m = alterMap (M.insert k v) m
-insert _ _ m = m
+insert _ _ m = m
getStyleId :: (StyleMap a) => String -> a -> String
getStyleId s = M.findWithDefault (filter (/=' ') s) (map toLower s) . getMap
diff --git a/src/Text/Pandoc/Readers/Docx/Util.hs b/src/Text/Pandoc/Readers/Docx/Util.hs
index 33d69ccf3..d9d65bc07 100644
--- a/src/Text/Pandoc/Readers/Docx/Util.hs
+++ b/src/Text/Pandoc/Readers/Docx/Util.hs
@@ -3,10 +3,13 @@ module Text.Pandoc.Readers.Docx.Util (
, elemName
, isElem
, elemToNameSpaces
+ , findChildByName
+ , findChildrenByName
+ , findAttrByName
) where
-import Text.XML.Light
import Data.Maybe (mapMaybe)
+import Text.XML.Light
type NameSpaces = [(String, String)]
@@ -15,7 +18,7 @@ elemToNameSpaces = mapMaybe attrToNSPair . elAttribs
attrToNSPair :: Attr -> Maybe (String, String)
attrToNSPair (Attr (QName s _ (Just "xmlns")) val) = Just (s, val)
-attrToNSPair _ = Nothing
+attrToNSPair _ = Nothing
elemName :: NameSpaces -> String -> String -> QName
elemName ns prefix name =
@@ -23,5 +26,21 @@ elemName ns prefix name =
isElem :: NameSpaces -> String -> String -> Element -> Bool
isElem ns prefix name element =
- qName (elName element) == name &&
- qURI (elName element) == lookup prefix ns
+ let ns' = ns ++ elemToNameSpaces element
+ in qName (elName element) == name &&
+ qURI (elName element) == lookup prefix ns'
+
+findChildByName :: NameSpaces -> String -> String -> Element -> Maybe Element
+findChildByName ns pref name el =
+ let ns' = ns ++ elemToNameSpaces el
+ in findChild (elemName ns' pref name) el
+
+findChildrenByName :: NameSpaces -> String -> String -> Element -> [Element]
+findChildrenByName ns pref name el =
+ let ns' = ns ++ elemToNameSpaces el
+ in findChildren (elemName ns' pref name) el
+
+findAttrByName :: NameSpaces -> String -> String -> Element -> Maybe String
+findAttrByName ns pref name el =
+ let ns' = ns ++ elemToNameSpaces el
+ in findAttr (elemName ns' pref name) el
diff --git a/src/Text/Pandoc/Readers/EPUB.hs b/src/Text/Pandoc/Readers/EPUB.hs
index 4c31bf1ae..3b13bbe13 100644
--- a/src/Text/Pandoc/Readers/EPUB.hs
+++ b/src/Text/Pandoc/Readers/EPUB.hs
@@ -1,55 +1,54 @@
-{-# LANGUAGE
- ViewPatterns
- , StandaloneDeriving
- , TupleSections
- , FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
+
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
module Text.Pandoc.Readers.EPUB
(readEPUB)
where
-import Text.XML.Light
+import Codec.Archive.Zip (Archive (..), Entry, findEntryByPath, fromEntry,
+ toArchiveOrFail)
+import Control.DeepSeq (NFData, deepseq)
+import Control.Monad (guard, liftM)
+import Control.Monad.Except (throwError)
+import qualified Data.ByteString.Lazy as BL (ByteString)
+import Data.List (isInfixOf, isPrefixOf)
+import qualified Data.Map as M (Map, elems, fromList, lookup)
+import Data.Maybe (fromMaybe, mapMaybe)
+import Data.Monoid ((<>))
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as TL
+import Network.URI (unEscapeString)
+import System.FilePath (dropFileName, dropFileName, normalise, splitFileName,
+ takeFileName, (</>))
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad, insertMedia)
import Text.Pandoc.Definition hiding (Attr)
-import Text.Pandoc.Readers.HTML (readHtml)
import Text.Pandoc.Error
-import Text.Pandoc.Walk (walk, query)
-import Text.Pandoc.Options ( ReaderOptions(..), readerTrace)
-import Text.Pandoc.Shared (escapeURI, collapseFilePath, addMetaField)
-import Network.URI (unEscapeString)
-import Text.Pandoc.MediaBag (MediaBag, insertMedia)
-import Control.Monad.Except (MonadError, throwError, runExcept, Except)
+import Text.Pandoc.Extensions (Extension (Ext_raw_html), enableExtension)
import Text.Pandoc.MIME (MimeType)
-import qualified Text.Pandoc.Builder as B
-import Codec.Archive.Zip ( Archive (..), toArchiveOrFail, fromEntry
- , findEntryByPath, Entry)
-import qualified Data.ByteString.Lazy as BL (ByteString)
-import System.FilePath ( takeFileName, (</>), dropFileName, normalise
- , dropFileName
- , splitFileName )
+import Text.Pandoc.Options (ReaderOptions (..))
+import Text.Pandoc.Readers.HTML (readHtml)
+import Text.Pandoc.Shared (addMetaField, collapseFilePath, escapeURI)
import qualified Text.Pandoc.UTF8 as UTF8 (toStringLazy)
-import Control.Monad (guard, liftM, when)
-import Data.List (isPrefixOf, isInfixOf)
-import Data.Maybe (mapMaybe, fromMaybe)
-import qualified Data.Map as M (Map, lookup, fromList, elems)
-import Data.Monoid ((<>))
-import Control.DeepSeq (deepseq, NFData)
-
-import Debug.Trace (trace)
+import Text.Pandoc.Walk (query, walk)
+import Text.XML.Light
type Items = M.Map String (FilePath, MimeType)
-readEPUB :: ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag)
+readEPUB :: PandocMonad m => ReaderOptions -> BL.ByteString -> m Pandoc
readEPUB opts bytes = case toArchiveOrFail bytes of
- Right archive -> runEPUB $ archiveToEPUB opts $ archive
- Left _ -> Left $ ParseFailure "Couldn't extract ePub file"
+ Right archive -> archiveToEPUB opts archive
+ Left _ -> throwError $ PandocParseError "Couldn't extract ePub file"
-runEPUB :: Except PandocError a -> Either PandocError a
-runEPUB = runExcept
+-- runEPUB :: Except PandocError a -> Either PandocError a
+-- runEPUB = runExcept
-- Note that internal reference are aggresively normalised so that all ids
-- are of the form "filename#id"
--
-archiveToEPUB :: (MonadError PandocError m) => ReaderOptions -> Archive -> m (Pandoc, MediaBag)
+archiveToEPUB :: (PandocMonad m) => ReaderOptions -> Archive -> m Pandoc
archiveToEPUB os archive = do
-- root is path to folder with manifest file in
(root, content) <- getManifest archive
@@ -62,40 +61,36 @@ archiveToEPUB os archive = do
Pandoc _ bs <-
foldM' (\a b -> ((a <>) . walk (prependHash escapedSpine))
`liftM` parseSpineElem root b) mempty spine
- let ast = coverDoc <> (Pandoc meta bs)
- let mediaBag = fetchImages (M.elems items) root archive ast
- return $ (ast, mediaBag)
+ let ast = coverDoc <> Pandoc meta bs
+ fetchImages (M.elems items) root archive ast
+ return ast
where
- os' = os {readerParseRaw = True}
- parseSpineElem :: MonadError PandocError m => FilePath -> (FilePath, MimeType) -> m Pandoc
+ os' = os {readerExtensions = enableExtension Ext_raw_html (readerExtensions os)}
+ parseSpineElem :: PandocMonad m => FilePath -> (FilePath, MimeType) -> m Pandoc
parseSpineElem (normalise -> r) (normalise -> path, mime) = do
- when (readerTrace os) (traceM path)
doc <- mimeToReader mime r path
let docSpan = B.doc $ B.para $ B.spanWith (takeFileName path, [], []) mempty
return $ docSpan <> doc
- mimeToReader :: MonadError PandocError m => MimeType -> FilePath -> FilePath -> m Pandoc
+ mimeToReader :: PandocMonad m => MimeType -> FilePath -> FilePath -> m Pandoc
mimeToReader "application/xhtml+xml" (unEscapeString -> root)
(unEscapeString -> path) = do
fname <- findEntryByPathE (root </> path) archive
- html <- either throwError return .
- readHtml os' .
- UTF8.toStringLazy $
- fromEntry fname
+ html <- readHtml os' . TL.toStrict . TL.decodeUtf8 $ fromEntry fname
return $ fixInternalReferences path html
mimeToReader s _ (unEscapeString -> path)
| s `elem` imageMimes = return $ imageToPandoc path
- | otherwise = return $ mempty
+ | otherwise = return mempty
-- paths should be absolute when this function is called
-- renameImages should do this
-fetchImages :: [(FilePath, MimeType)]
+fetchImages :: PandocMonad m
+ => [(FilePath, MimeType)]
-> FilePath -- ^ Root
-> Archive
-> Pandoc
- -> MediaBag
+ -> m ()
fetchImages mimes root arc (query iq -> links) =
- foldr (uncurry3 insertMedia) mempty
- (mapMaybe getEntry links)
+ mapM_ (uncurry3 insertMedia) (mapMaybe getEntry links)
where
getEntry link =
let abslink = normalise (root </> link) in
@@ -104,7 +99,7 @@ fetchImages mimes root arc (query iq -> links) =
iq :: Inline -> [FilePath]
iq (Image _ _ (url, _)) = [url]
-iq _ = []
+iq _ = []
-- Remove relative paths
renameImages :: FilePath -> Inline -> Inline
@@ -121,13 +116,13 @@ imageMimes = ["image/gif", "image/jpeg", "image/png"]
type CoverImage = FilePath
-parseManifest :: (MonadError PandocError m) => Element -> m (Maybe CoverImage, Items)
+parseManifest :: (PandocMonad m) => Element -> m (Maybe CoverImage, Items)
parseManifest content = do
manifest <- findElementE (dfName "manifest") content
let items = findChildren (dfName "item") manifest
r <- mapM parseItem items
let cover = findAttr (emptyName "href") =<< filterChild findCover manifest
- return (cover, (M.fromList r))
+ return (cover, M.fromList r)
where
findCover e = maybe False (isInfixOf "cover-image")
(findAttr (emptyName "properties") e)
@@ -137,18 +132,18 @@ parseManifest content = do
mime <- findAttrE (emptyName "media-type") e
return (uid, (href, mime))
-parseSpine :: MonadError PandocError m => Items -> Element -> m [(FilePath, MimeType)]
+parseSpine :: PandocMonad m => Items -> Element -> m [(FilePath, MimeType)]
parseSpine is e = do
spine <- findElementE (dfName "spine") e
let itemRefs = findChildren (dfName "itemref") spine
- mapM (mkE "parseSpine" . (flip M.lookup is)) $ mapMaybe parseItemRef itemRefs
+ mapM (mkE "parseSpine" . flip M.lookup is) $ mapMaybe parseItemRef itemRefs
where
parseItemRef ref = do
let linear = maybe True (== "yes") (findAttr (emptyName "linear") ref)
guard linear
findAttr (emptyName "idref") ref
-parseMeta :: MonadError PandocError m => Element -> m Meta
+parseMeta :: PandocMonad m => Element -> m Meta
parseMeta content = do
meta <- findElementE (dfName "metadata") content
let dcspace (QName _ (Just "http://purl.org/dc/elements/1.1/") (Just "dc")) = True
@@ -164,29 +159,29 @@ parseMetaItem e@(stripNamespace . elName -> field) meta =
renameMeta :: String -> String
renameMeta "creator" = "author"
-renameMeta s = s
+renameMeta s = s
-getManifest :: MonadError PandocError m => Archive -> m (String, Element)
+getManifest :: PandocMonad m => Archive -> m (String, Element)
getManifest archive = do
metaEntry <- findEntryByPathE ("META-INF" </> "container.xml") archive
docElem <- (parseXMLDocE . UTF8.toStringLazy . fromEntry) metaEntry
let namespaces = mapMaybe attrToNSPair (elAttribs docElem)
ns <- mkE "xmlns not in namespaces" (lookup "xmlns" namespaces)
- as <- liftM ((map attrToPair) . elAttribs)
+ as <- fmap (map attrToPair . elAttribs)
(findElementE (QName "rootfile" (Just ns) Nothing) docElem)
manifestFile <- mkE "Root not found" (lookup "full-path" as)
let rootdir = dropFileName manifestFile
--mime <- lookup "media-type" as
manifest <- findEntryByPathE manifestFile archive
- liftM ((,) rootdir) (parseXMLDocE . UTF8.toStringLazy . fromEntry $ manifest)
+ fmap ((,) rootdir) (parseXMLDocE . UTF8.toStringLazy . fromEntry $ manifest)
-- Fixup
fixInternalReferences :: FilePath -> Pandoc -> Pandoc
fixInternalReferences pathToFile =
- (walk $ renameImages root)
- . (walk $ fixBlockIRs filename)
- . (walk $ fixInlineIRs filename)
+ walk (renameImages root)
+ . walk (fixBlockIRs filename)
+ . walk (fixInlineIRs filename)
where
(root, escapeURI -> filename) = splitFileName pathToFile
@@ -221,7 +216,7 @@ fixAttrs :: FilePath -> B.Attr -> B.Attr
fixAttrs s (ident, cs, kvs) = (addHash s ident, filter (not . null) cs, removeEPUBAttrs kvs)
addHash :: String -> String -> String
-addHash _ "" = ""
+addHash _ "" = ""
addHash s ident = takeFileName s ++ "#" ++ ident
removeEPUBAttrs :: [(String, String)] -> [(String, String)]
@@ -242,9 +237,6 @@ foldM' f z (x:xs) = do
uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
uncurry3 f (a, b, c) = f a b c
-traceM :: Monad m => String -> m ()
-traceM = flip trace (return ())
-
-- Utility
stripNamespace :: QName -> String
@@ -252,7 +244,7 @@ stripNamespace (QName v _ _) = v
attrToNSPair :: Attr -> Maybe (String, String)
attrToNSPair (Attr (QName "xmlns" _ _) val) = Just ("xmlns", val)
-attrToNSPair _ = Nothing
+attrToNSPair _ = Nothing
attrToPair :: Attr -> (String, String)
attrToPair (Attr (QName name _ _) val) = (name, val)
@@ -268,18 +260,18 @@ emptyName s = QName s Nothing Nothing
-- Convert Maybe interface to Either
-findAttrE :: MonadError PandocError m => QName -> Element -> m String
+findAttrE :: PandocMonad m => QName -> Element -> m String
findAttrE q e = mkE "findAttr" $ findAttr q e
-findEntryByPathE :: MonadError PandocError m => FilePath -> Archive -> m Entry
+findEntryByPathE :: PandocMonad m => FilePath -> Archive -> m Entry
findEntryByPathE (normalise -> path) a =
mkE ("No entry on path: " ++ path) $ findEntryByPath path a
-parseXMLDocE :: MonadError PandocError m => String -> m Element
+parseXMLDocE :: PandocMonad m => String -> m Element
parseXMLDocE doc = mkE "Unable to parse XML doc" $ parseXMLDoc doc
-findElementE :: MonadError PandocError m => QName -> Element -> m Element
+findElementE :: PandocMonad m => QName -> Element -> m Element
findElementE e x = mkE ("Unable to find element: " ++ show e) $ findElement e x
-mkE :: MonadError PandocError m => String -> Maybe a -> m a
-mkE s = maybe (throwError . ParseFailure $ s) return
+mkE :: PandocMonad m => String -> Maybe a -> m a
+mkE s = maybe (throwError . PandocParseError $ s) return
diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs
index abe5f66ce..0e79f9ec3 100644
--- a/src/Text/Pandoc/Readers/HTML.hs
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -1,7 +1,10 @@
-{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses,
-ViewPatterns#-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.HTML
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,66 +37,79 @@ module Text.Pandoc.Readers.HTML ( readHtml
, htmlInBalanced
, isInlineTag
, isBlockTag
+ , NamedTag(..)
, isTextTag
, isCommentTag
) where
+import Control.Applicative ((<|>))
+import Control.Arrow (first)
+import Control.Monad (guard, mplus, msum, mzero, unless, void)
+import Control.Monad.Except (throwError)
+import Control.Monad.Reader (ReaderT, ask, asks, lift, local, runReaderT)
+import Data.Char (isAlphaNum, isDigit, isLetter)
+import Data.Default (Default (..), def)
+import Data.Foldable (for_)
+import Data.List (isPrefixOf)
+import Data.List.Split (wordsBy, splitWhen)
+import qualified Data.Map as M
+import Data.Maybe (fromMaybe, isJust, isNothing)
+import Data.Monoid (First (..), (<>))
+import qualified Data.Set as Set
+import Data.Text (Text)
+import qualified Data.Text as T
+import Network.URI (URI, nonStrictRelativeTo, parseURIReference)
import Text.HTML.TagSoup
import Text.HTML.TagSoup.Match
-import Text.Pandoc.Definition
+import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
import qualified Text.Pandoc.Builder as B
-import Text.Pandoc.Builder (Blocks, Inlines, trimInlines, HasMeta(..))
-import Text.Pandoc.Shared ( extractSpaces, renderTags', addMetaField
- , escapeURI, safeRead, mapLeft )
-import Text.Pandoc.Options (ReaderOptions(readerParseRaw, readerTrace)
- , Extension (Ext_epub_html_exts,
- Ext_native_divs, Ext_native_spans))
+import Text.Pandoc.Class (PandocMonad (..))
+import Text.Pandoc.CSS (foldOrElse, pickStyleAttrProps)
+import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Text.Pandoc.Logging
+import Text.Pandoc.Options (
+ Extension (Ext_epub_html_exts, Ext_empty_paragraphs, Ext_native_divs,
+ Ext_native_spans, Ext_raw_html, Ext_line_blocks),
+ ReaderOptions (readerExtensions, readerStripComments),
+ extensionEnabled)
import Text.Pandoc.Parsing hiding ((<|>))
+import Text.Pandoc.Shared (addMetaField, blocksToInlines', crFilter, escapeURI,
+ extractSpaces, safeRead, underlineSpan)
import Text.Pandoc.Walk
-import qualified Data.Map as M
-import Data.Maybe ( fromMaybe, isJust)
-import Data.List ( intercalate, isInfixOf, isPrefixOf )
-import Data.Char ( isDigit )
-import Control.Monad ( guard, when, mzero, void, unless )
-import Control.Arrow ((***))
-import Control.Applicative ( (<|>) )
-import Data.Monoid (First (..))
-import Text.Printf (printf)
-import Debug.Trace (trace)
-import Text.TeXMath (readMathML, writeTeX)
-import Data.Default (Default (..), def)
-import Control.Monad.Reader (Reader,ask, asks, local, runReader)
-import Network.URI (URI, parseURIReference, nonStrictRelativeTo)
-import Text.Pandoc.Error
-import Text.Pandoc.CSS (foldOrElse, pickStyleAttrProps)
-import Data.Monoid ((<>))
import Text.Parsec.Error
-import qualified Data.Set as Set
+import Text.TeXMath (readMathML, writeTeX)
-- | Convert HTML-formatted string to 'Pandoc' document.
-readHtml :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assumes @'\n'@ line endings)
- -> Either PandocError Pandoc
-readHtml opts inp =
- mapLeft (ParseFailure . getError) . flip runReader def $
- runParserT parseDoc
- (HTMLState def{ stateOptions = opts } [] Nothing Set.empty M.empty)
- "source" tags
- where tags = stripPrefixes . canonicalizeTags $
- parseTagsOptions parseOptions{ optTagPosition = True } inp
- parseDoc = do
- blocks <- (fixPlains False) . mconcat <$> manyTill block eof
- meta <- stateMeta . parserState <$> getState
- bs' <- replaceNotes (B.toList blocks)
- return $ Pandoc meta bs'
- getError (errorMessages -> ms) = case ms of
- [] -> ""
- (m:_) -> messageString m
-
-replaceNotes :: [Block] -> TagParser [Block]
+readHtml :: PandocMonad m
+ => ReaderOptions -- ^ Reader options
+ -> Text -- ^ String to parse (assumes @'\n'@ line endings)
+ -> m Pandoc
+readHtml opts inp = do
+ let tags = stripPrefixes . canonicalizeTags $
+ parseTagsOptions parseOptions{ optTagPosition = True }
+ (crFilter inp)
+ parseDoc = do
+ blocks <- fixPlains False . mconcat <$> manyTill block eof
+ meta <- stateMeta . parserState <$> getState
+ bs' <- replaceNotes (B.toList blocks)
+ reportLogMessages
+ return $ Pandoc meta bs'
+ getError (errorMessages -> ms) = case ms of
+ [] -> ""
+ (m:_) -> messageString m
+ result <- flip runReaderT def $
+ runParserT parseDoc
+ (HTMLState def{ stateOptions = opts } [] Nothing Set.empty M.empty [])
+ "source" tags
+ case result of
+ Right doc -> return doc
+ Left err -> throwError $ PandocParseError $ getError err
+
+replaceNotes :: PandocMonad m => [Block] -> TagParser m [Block]
replaceNotes = walkM replaceNotes'
-replaceNotes' :: Inline -> TagParser Inline
+replaceNotes' :: PandocMonad m => Inline -> TagParser m Inline
replaceNotes' (RawInline (Format "noteref") ref) = maybe (Str "") (Note . B.toList) . lookup ref <$> getNotes
where
getNotes = noteTable <$> getState
@@ -105,38 +121,46 @@ data HTMLState =
noteTable :: [(String, Blocks)],
baseHref :: Maybe URI,
identifiers :: Set.Set String,
- headerMap :: M.Map Inlines String
+ headerMap :: M.Map Inlines String,
+ logMessages :: [LogMessage]
}
data HTMLLocal = HTMLLocal { quoteContext :: QuoteContext
- , inChapter :: Bool -- ^ Set if in chapter section
- , inPlain :: Bool -- ^ Set if in pPlain
+ , inChapter :: Bool -- ^ Set if in chapter section
+ , inPlain :: Bool -- ^ Set if in pPlain
}
-setInChapter :: HTMLParser s a -> HTMLParser s a
+setInChapter :: PandocMonad m => HTMLParser m s a -> HTMLParser m s a
setInChapter = local (\s -> s {inChapter = True})
-setInPlain :: HTMLParser s a -> HTMLParser s a
+setInPlain :: PandocMonad m => HTMLParser m s a -> HTMLParser m s a
setInPlain = local (\s -> s {inPlain = True})
-type HTMLParser s = ParserT s HTMLState (Reader HTMLLocal)
+type HTMLParser m s = ParserT s HTMLState (ReaderT HTMLLocal m)
-type TagParser = HTMLParser [Tag String]
+type TagParser m = HTMLParser m [Tag Text]
-pBody :: TagParser Blocks
+pHtml :: PandocMonad m => TagParser m Blocks
+pHtml = try $ do
+ (TagOpen "html" attr) <- lookAhead pAnyTag
+ for_ (lookup "lang" attr) $
+ updateState . B.setMeta "lang" . B.text . T.unpack
+ pInTags "html" block
+
+pBody :: PandocMonad m => TagParser m Blocks
pBody = pInTags "body" block
-pHead :: TagParser Blocks
+pHead :: PandocMonad m => TagParser m Blocks
pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAnyTag)
where pTitle = pInTags "title" inline >>= setTitle . trimInlines
- setTitle t = mempty <$ (updateState $ B.setMeta "title" t)
+ setTitle t = mempty <$ updateState (B.setMeta "title" t)
pMetaTag = do
- mt <- pSatisfy (~== TagOpen "meta" [])
- let name = fromAttrib "name" mt
+ mt <- pSatisfy (matchTagOpen "meta" [])
+ let name = T.unpack $ fromAttrib "name" mt
if null name
then return mempty
else do
- let content = fromAttrib "content" mt
+ let content = T.unpack $ fromAttrib "content" mt
updateState $ \s ->
let ps = parserState s in
s{ parserState = ps{
@@ -144,15 +168,13 @@ pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAnyTag
(stateMeta ps) } }
return mempty
pBaseTag = do
- bt <- pSatisfy (~== TagOpen "base" [])
+ bt <- pSatisfy (matchTagOpen "base" [])
updateState $ \st -> st{ baseHref =
- parseURIReference $ fromAttrib "href" bt }
+ parseURIReference $ T.unpack $ fromAttrib "href" bt }
return mempty
-block :: TagParser Blocks
+block :: PandocMonad m => TagParser m Blocks
block = do
- tr <- getOption readerTrace
- pos <- getPosition
res <- choice
[ eSection
, eSwitch B.para block
@@ -166,94 +188,107 @@ block = do
, pList
, pHrule
, pTable
+ , pHtml
, pHead
, pBody
+ , pLineBlock
, pDiv
, pPlain
+ , pFigure
, pRawHtmlBlock
]
- when tr $ trace (printf "line %d: %s" (sourceLine pos)
- (take 60 $ show $ B.toList res)) (return ())
+ trace (take 60 $ show $ B.toList res)
return res
-namespaces :: [(String, TagParser Inlines)]
+namespaces :: PandocMonad m => [(String, TagParser m Inlines)]
namespaces = [(mathMLNamespace, pMath True)]
mathMLNamespace :: String
mathMLNamespace = "http://www.w3.org/1998/Math/MathML"
-eSwitch :: Monoid a => (Inlines -> a) -> TagParser a -> TagParser a
+eSwitch :: (PandocMonad m, Monoid a)
+ => (Inlines -> a)
+ -> TagParser m a
+ -> TagParser m a
eSwitch constructor parser = try $ do
guardEnabled Ext_epub_html_exts
- pSatisfy (~== TagOpen "switch" [])
+ pSatisfy (matchTagOpen "switch" [])
cases <- getFirst . mconcat <$>
manyTill (First <$> (eCase <* skipMany pBlank) )
- (lookAhead $ try $ pSatisfy (~== TagOpen "default" []))
+ (lookAhead $ try $ pSatisfy (matchTagOpen "default" []))
skipMany pBlank
fallback <- pInTags "default" (skipMany pBlank *> parser <* skipMany pBlank)
skipMany pBlank
- pSatisfy (~== TagClose "switch")
+ pSatisfy (matchTagClose "switch")
return $ maybe fallback constructor cases
-eCase :: TagParser (Maybe Inlines)
+eCase :: PandocMonad m => TagParser m (Maybe Inlines)
eCase = do
skipMany pBlank
- TagOpen _ attr <- lookAhead $ pSatisfy $ (~== TagOpen "case" [])
- case (flip lookup namespaces) =<< lookup "required-namespace" attr of
- Just p -> Just <$> (pInTags "case" (skipMany pBlank *> p <* skipMany pBlank))
- Nothing -> Nothing <$ manyTill pAnyTag (pSatisfy (~== TagClose "case"))
+ TagOpen _ attr' <- lookAhead $ pSatisfy (matchTagOpen "case" [])
+ let attr = toStringAttr attr'
+ case flip lookup namespaces =<< lookup "required-namespace" attr of
+ Just p -> Just <$> pInTags "case" (skipMany pBlank *> p <* skipMany pBlank)
+ Nothing -> Nothing <$ manyTill pAnyTag (pSatisfy (matchTagClose "case"))
-eFootnote :: TagParser ()
+eFootnote :: PandocMonad m => TagParser m ()
eFootnote = try $ do
let notes = ["footnote", "rearnote"]
guardEnabled Ext_epub_html_exts
- (TagOpen tag attr) <- lookAhead $ pAnyTag
- guard (maybe False (flip elem notes) (lookup "type" attr))
+ (TagOpen tag attr') <- lookAhead pAnyTag
+ let attr = toStringAttr attr'
+ guard $ maybe False (`elem` notes) (lookup "type" attr)
let ident = fromMaybe "" (lookup "id" attr)
content <- pInTags tag block
addNote ident content
-addNote :: String -> Blocks -> TagParser ()
-addNote uid cont = updateState (\s -> s {noteTable = (uid, cont) : (noteTable s)})
+addNote :: PandocMonad m => String -> Blocks -> TagParser m ()
+addNote uid cont = updateState (\s -> s {noteTable = (uid, cont) : noteTable s})
-eNoteref :: TagParser Inlines
+eNoteref :: PandocMonad m => TagParser m Inlines
eNoteref = try $ do
guardEnabled Ext_epub_html_exts
- TagOpen tag attr <- lookAhead $ pAnyTag
- guard (maybe False (== "noteref") (lookup "type" attr))
+ TagOpen tag attr' <- lookAhead pAnyTag
+ let attr = toStringAttr attr'
+ guard $ lookup "type" attr == Just "noteref"
let ident = maybe "" (dropWhile (== '#')) (lookup "href" attr)
guard (not (null ident))
pInTags tag block
return $ B.rawInline "noteref" ident
-- Strip TOC if there is one, better to generate again
-eTOC :: TagParser ()
+eTOC :: PandocMonad m => TagParser m ()
eTOC = try $ do
guardEnabled Ext_epub_html_exts
- (TagOpen tag attr) <- lookAhead $ pAnyTag
- guard (maybe False (== "toc") (lookup "type" attr))
+ (TagOpen tag attr) <- lookAhead pAnyTag
+ guard $ lookup "type" attr == Just "toc"
void (pInTags tag block)
-pList :: TagParser Blocks
+pList :: PandocMonad m => TagParser m Blocks
pList = pBulletList <|> pOrderedList <|> pDefinitionList
-pBulletList :: TagParser Blocks
+pBulletList :: PandocMonad m => TagParser m Blocks
pBulletList = try $ do
- pSatisfy (~== TagOpen "ul" [])
+ pSatisfy (matchTagOpen "ul" [])
let nonItem = pSatisfy (\t ->
not (tagOpen (`elem` ["li","ol","ul","dl"]) (const True) t) &&
- not (t ~== TagClose "ul"))
+ not (matchTagClose "ul" t))
-- note: if they have an <ol> or <ul> not in scope of a <li>,
-- treat it as a list item, though it's not valid xhtml...
skipMany nonItem
items <- manyTill (pListItem nonItem) (pCloses "ul")
return $ B.bulletList $ map (fixPlains True) items
-pListItem :: TagParser a -> TagParser Blocks
+pListItem :: PandocMonad m => TagParser m a -> TagParser m Blocks
pListItem nonItem = do
- TagOpen _ attr <- lookAhead $ pSatisfy (~== TagOpen "li" [])
- let liDiv = maybe mempty (\x -> B.divWith (x, [], []) mempty) (lookup "id" attr)
- (liDiv <>) <$> pInTags "li" block <* skipMany nonItem
+ TagOpen _ attr' <- lookAhead $ pSatisfy (matchTagOpen "li" [])
+ let attr = toStringAttr attr'
+ let addId ident bs = case B.toList bs of
+ (Plain ils:xs) -> B.fromList (Plain
+ [Span (ident, [], []) ils] : xs)
+ _ -> B.divWith (ident, [], []) bs
+ maybe id addId (lookup "id" attr) <$>
+ pInTags "li" block <* skipMany nonItem
parseListStyleType :: String -> ListNumberStyle
parseListStyleType "lower-roman" = LowerRoman
@@ -271,9 +306,10 @@ parseTypeAttr "A" = UpperAlpha
parseTypeAttr "1" = Decimal
parseTypeAttr _ = DefaultStyle
-pOrderedList :: TagParser Blocks
+pOrderedList :: PandocMonad m => TagParser m Blocks
pOrderedList = try $ do
- TagOpen _ attribs <- pSatisfy (~== TagOpen "ol" [])
+ TagOpen _ attribs' <- pSatisfy (matchTagOpen "ol" [])
+ let attribs = toStringAttr attribs'
let (start, style) = (sta', sty')
where sta = fromMaybe "1" $
lookup "start" attribs
@@ -295,23 +331,23 @@ pOrderedList = try $ do
]
let nonItem = pSatisfy (\t ->
not (tagOpen (`elem` ["li","ol","ul","dl"]) (const True) t) &&
- not (t ~== TagClose "ol"))
+ not (matchTagClose "ol" t))
-- note: if they have an <ol> or <ul> not in scope of a <li>,
-- treat it as a list item, though it's not valid xhtml...
skipMany nonItem
items <- manyTill (pListItem nonItem) (pCloses "ol")
return $ B.orderedListWith (start, style, DefaultDelim) $ map (fixPlains True) items
-pDefinitionList :: TagParser Blocks
+pDefinitionList :: PandocMonad m => TagParser m Blocks
pDefinitionList = try $ do
- pSatisfy (~== TagOpen "dl" [])
+ pSatisfy (matchTagOpen "dl" [])
items <- manyTill pDefListItem (pCloses "dl")
return $ B.definitionList items
-pDefListItem :: TagParser (Inlines, [Blocks])
+pDefListItem :: PandocMonad m => TagParser m (Inlines, [Blocks])
pDefListItem = try $ do
- let nonItem = pSatisfy (\t -> not (t ~== TagOpen "dt" []) &&
- not (t ~== TagOpen "dd" []) && not (t ~== TagClose "dl"))
+ let nonItem = pSatisfy (\t -> not (matchTagOpen "dt" [] t) &&
+ not (matchTagOpen "dd" [] t) && not (matchTagClose "dl" t))
terms <- many1 (try $ skipMany nonItem >> pInTags "dt" inline)
defs <- many1 (try $ skipMany nonItem >> pInTags "dd" block)
skipMany nonItem
@@ -322,133 +358,165 @@ fixPlains :: Bool -> Blocks -> Blocks
fixPlains inList bs = if any isParaish bs'
then B.fromList $ map plainToPara bs'
else bs
- where isParaish (Para _) = True
- isParaish (CodeBlock _ _) = True
- isParaish (Header _ _ _) = True
- isParaish (BlockQuote _) = True
- isParaish (BulletList _) = not inList
- isParaish (OrderedList _ _) = not inList
- isParaish (DefinitionList _) = not inList
- isParaish _ = False
+ where isParaish Para{} = True
+ isParaish CodeBlock{} = True
+ isParaish Header{} = True
+ isParaish BlockQuote{} = True
+ isParaish BulletList{} = not inList
+ isParaish OrderedList{} = not inList
+ isParaish DefinitionList{} = not inList
+ isParaish _ = False
plainToPara (Plain xs) = Para xs
- plainToPara x = x
+ plainToPara x = x
bs' = B.toList bs
-pRawTag :: TagParser String
+pRawTag :: PandocMonad m => TagParser m Text
pRawTag = do
tag <- pAnyTag
let ignorable x = x `elem` ["html","head","body","!DOCTYPE","?xml"]
if tagOpen ignorable (const True) tag || tagClose ignorable tag
- then return []
+ then return mempty
else return $ renderTags' [tag]
-pDiv :: TagParser Blocks
+pLineBlock :: PandocMonad m => TagParser m Blocks
+pLineBlock = try $ do
+ guardEnabled Ext_line_blocks
+ _ <- pSatisfy $ tagOpen (=="div") (== [("class","line-block")])
+ ils <- trimInlines . mconcat <$> manyTill inline (pSatisfy (tagClose (=="div")))
+ let lns = map B.fromList $
+ splitWhen (== LineBreak) $ filter (/= SoftBreak) $
+ B.toList ils
+ return $ B.lineBlock lns
+
+pDiv :: PandocMonad m => TagParser m Blocks
pDiv = try $ do
guardEnabled Ext_native_divs
- let isDivLike "div" = True
+ let isDivLike "div" = True
isDivLike "section" = True
- isDivLike _ = False
- TagOpen tag attr <- lookAhead $ pSatisfy $ tagOpen isDivLike (const True)
+ isDivLike "main" = True
+ isDivLike _ = False
+ TagOpen tag attr' <- lookAhead $ pSatisfy $ tagOpen isDivLike (const True)
+ let attr = toStringAttr attr'
contents <- pInTags tag block
let (ident, classes, kvs) = mkAttr attr
let classes' = if tag == "section"
then "section":classes
else classes
- return $ B.divWith (ident, classes', kvs) contents
+ kvs' = if tag == "main" && isNothing (lookup "role" kvs)
+ then ("role", "main"):kvs
+ else kvs
+ return $ B.divWith (ident, classes', kvs') contents
-pRawHtmlBlock :: TagParser Blocks
+pRawHtmlBlock :: PandocMonad m => TagParser m Blocks
pRawHtmlBlock = do
- raw <- pHtmlBlock "script" <|> pHtmlBlock "style" <|> pRawTag
- parseRaw <- getOption readerParseRaw
- if parseRaw && not (null raw)
+ raw <- T.unpack <$> (pHtmlBlock "script" <|> pHtmlBlock "style" <|> pRawTag)
+ exts <- getOption readerExtensions
+ if extensionEnabled Ext_raw_html exts && not (null raw)
then return $ B.rawBlock "html" raw
- else return mempty
+ else ignore raw
+
+ignore :: (Monoid a, PandocMonad m) => String -> TagParser m a
+ignore raw = do
+ pos <- getPosition
+ -- raw can be null for tags like <!DOCTYPE>; see paRawTag
+ -- in this case we don't want a warning:
+ unless (null raw) $
+ logMessage $ SkippedContent raw pos
+ return mempty
-pHtmlBlock :: String -> TagParser String
+pHtmlBlock :: PandocMonad m => Text -> TagParser m Text
pHtmlBlock t = try $ do
- open <- pSatisfy (~== TagOpen t [])
- contents <- manyTill pAnyTag (pSatisfy (~== TagClose t))
- return $ renderTags' $ [open] ++ contents ++ [TagClose t]
+ open <- pSatisfy (matchTagOpen t [])
+ contents <- manyTill pAnyTag (pSatisfy (matchTagClose t))
+ return $ renderTags' $ [open] <> contents <> [TagClose t]
-- Sets chapter context
-eSection :: TagParser Blocks
+eSection :: PandocMonad m => TagParser m Blocks
eSection = try $ do
- let matchChapter as = maybe False (isInfixOf "chapter") (lookup "type" as)
+ let matchChapter as = maybe False (T.isInfixOf "chapter") (lookup "type" as)
let sectTag = tagOpen (`elem` sectioningContent) matchChapter
TagOpen tag _ <- lookAhead $ pSatisfy sectTag
setInChapter (pInTags tag block)
-headerLevel :: String -> TagParser Int
-headerLevel tagtype = do
- let level = read (drop 1 tagtype)
- (try $ do
- guardEnabled Ext_epub_html_exts
- asks inChapter >>= guard
- return (level - 1))
- <|>
- return level
-
-eTitlePage :: TagParser ()
+headerLevel :: PandocMonad m => Text -> TagParser m Int
+headerLevel tagtype =
+ case safeRead (T.unpack (T.drop 1 tagtype)) of
+ Just level ->
+-- try (do
+-- guardEnabled Ext_epub_html_exts
+-- asks inChapter >>= guard
+-- return (level - 1))
+-- <|>
+ return level
+ Nothing -> fail "Could not retrieve header level"
+
+eTitlePage :: PandocMonad m => TagParser m ()
eTitlePage = try $ do
- let isTitlePage as = maybe False (isInfixOf "titlepage") (lookup "type" as)
+ let isTitlePage as = maybe False (T.isInfixOf "titlepage") (lookup "type" as)
let groupTag = tagOpen (\x -> x `elem` groupingContent || x == "section")
isTitlePage
TagOpen tag _ <- lookAhead $ pSatisfy groupTag
() <$ pInTags tag block
-pHeader :: TagParser Blocks
+pHeader :: PandocMonad m => TagParser m Blocks
pHeader = try $ do
- TagOpen tagtype attr <- pSatisfy $
+ TagOpen tagtype attr' <- pSatisfy $
tagOpen (`elem` ["h1","h2","h3","h4","h5","h6"])
(const True)
- let bodyTitle = TagOpen tagtype attr ~== TagOpen "h1" [("class","title")]
+ let attr = toStringAttr attr'
+ let bodyTitle = TagOpen tagtype attr' ~== TagOpen ("h1" :: Text)
+ [("class","title")]
level <- headerLevel tagtype
contents <- trimInlines . mconcat <$> manyTill inline (pCloses tagtype <|> eof)
let ident = fromMaybe "" $ lookup "id" attr
let classes = maybe [] words $ lookup "class" attr
let keyvals = [(k,v) | (k,v) <- attr, k /= "class", k /= "id"]
- attr' <- registerHeader (ident, classes, keyvals) contents
+ attr'' <- registerHeader (ident, classes, keyvals) contents
return $ if bodyTitle
then mempty -- skip a representation of the title in the body
- else B.headerWith attr' level contents
+ else B.headerWith attr'' level contents
-pHrule :: TagParser Blocks
+pHrule :: PandocMonad m => TagParser m Blocks
pHrule = do
pSelfClosing (=="hr") (const True)
return B.horizontalRule
-pTable :: TagParser Blocks
+pTable :: PandocMonad m => TagParser m Blocks
pTable = try $ do
- TagOpen _ _ <- pSatisfy (~== TagOpen "table" [])
+ TagOpen _ _ <- pSatisfy (matchTagOpen "table" [])
skipMany pBlank
caption <- option mempty $ pInTags "caption" inline <* skipMany pBlank
widths' <- (mconcat <$> many1 pColgroup) <|> many pCol
let pTh = option [] $ pInTags "tr" (pCell "th")
- pTr = try $ skipMany pBlank >> pInTags "tr" (pCell "td" <|> pCell "th")
- pTBody = do pOptInTag "tbody" $ many1 pTr
+ pTr = try $ skipMany pBlank >>
+ pInTags "tr" (pCell "td" <|> pCell "th")
+ pTBody = pOptInTag "tbody" $ many1 pTr
head'' <- pOptInTag "thead" pTh
- head' <- pOptInTag "tbody" $ do
- if null head''
- then pTh
- else return head''
+ head' <- map snd <$>
+ pOptInTag "tbody"
+ (if null head'' then pTh else return head'')
rowsLs <- many pTBody
rows' <- pOptInTag "tfoot" $ many pTr
- TagClose _ <- pSatisfy (~== TagClose "table")
- let rows'' = (concat rowsLs) ++ rows'
+ TagClose _ <- pSatisfy (matchTagClose "table")
+ let rows'' = concat rowsLs <> rows'
+ let rows''' = map (map snd) rows''
+ -- let rows''' = map (map snd) rows''
-- fail on empty table
- guard $ not $ null head' && null rows''
+ guard $ not $ null head' && null rows'''
let isSinglePlain x = case B.toList x of
[] -> True
[Plain _] -> True
_ -> False
- let isSimple = all isSinglePlain $ concat (head':rows'')
- let cols = length $ if null head' then head rows'' else head'
+ let isSimple = all isSinglePlain $ concat (head':rows''')
+ let cols = length $ if null head' then head rows''' else head'
-- add empty cells to short rows
let addEmpties r = case cols - length r of
- n | n > 0 -> r ++ replicate n mempty
+ n | n > 0 -> r <> replicate n mempty
| otherwise -> r
- let rows = map addEmpties rows''
- let aligns = replicate cols AlignDefault
+ let rows = map addEmpties rows'''
+ let aligns = case rows'' of
+ (cs:_) -> map fst cs
+ _ -> replicate cols AlignDefault
let widths = if null widths'
then if isSimple
then replicate cols 0
@@ -456,80 +524,120 @@ pTable = try $ do
else widths'
return $ B.table caption (zip aligns widths) head' rows
-pCol :: TagParser Double
+pCol :: PandocMonad m => TagParser m Double
pCol = try $ do
- TagOpen _ attribs <- pSatisfy (~== TagOpen "col" [])
+ TagOpen _ attribs' <- pSatisfy (matchTagOpen "col" [])
+ let attribs = toStringAttr attribs'
skipMany pBlank
- optional $ pSatisfy (~== TagClose "col")
+ optional $ pSatisfy (matchTagClose "col")
skipMany pBlank
- return $ case lookup "width" attribs of
+ let width = case lookup "width" attribs of
Nothing -> case lookup "style" attribs of
Just ('w':'i':'d':'t':'h':':':xs) | '%' `elem` xs ->
- fromMaybe 0.0 $ safeRead ('0':'.':filter
- (`notElem` " \t\r\n%'\";") xs)
+ fromMaybe 0.0 $ safeRead (filter
+ (`notElem` (" \t\r\n%'\";" :: [Char])) xs)
_ -> 0.0
Just x | not (null x) && last x == '%' ->
- fromMaybe 0.0 $ safeRead ('0':'.':init x)
+ fromMaybe 0.0 $ safeRead (init x)
_ -> 0.0
+ if width > 0.0
+ then return $ width / 100.0
+ else return 0.0
-pColgroup :: TagParser [Double]
+pColgroup :: PandocMonad m => TagParser m [Double]
pColgroup = try $ do
- pSatisfy (~== TagOpen "colgroup" [])
+ pSatisfy (matchTagOpen "colgroup" [])
skipMany pBlank
manyTill pCol (pCloses "colgroup" <|> eof) <* skipMany pBlank
-noColOrRowSpans :: Tag String -> Bool
+noColOrRowSpans :: Tag Text -> Bool
noColOrRowSpans t = isNullOrOne "colspan" && isNullOrOne "rowspan"
where isNullOrOne x = case fromAttrib x t of
"" -> True
"1" -> True
_ -> False
-pCell :: String -> TagParser [Blocks]
+pCell :: PandocMonad m => Text -> TagParser m [(Alignment, Blocks)]
pCell celltype = try $ do
skipMany pBlank
+ tag <- lookAhead $
+ pSatisfy (\t -> t ~== TagOpen celltype [] && noColOrRowSpans t)
+ let extractAlign' [] = ""
+ extractAlign' ("text-align":x:_) = x
+ extractAlign' (_:xs) = extractAlign' xs
+ let extractAlign = extractAlign' . wordsBy (`elem` [' ','\t',';',':'])
+ let align = case maybeFromAttrib "align" tag `mplus`
+ (extractAlign <$> maybeFromAttrib "style" tag) of
+ Just "left" -> AlignLeft
+ Just "right" -> AlignRight
+ Just "center" -> AlignCenter
+ _ -> AlignDefault
res <- pInTags' celltype noColOrRowSpans block
skipMany pBlank
- return [res]
+ return [(align, res)]
-pBlockQuote :: TagParser Blocks
+pBlockQuote :: PandocMonad m => TagParser m Blocks
pBlockQuote = do
contents <- pInTags "blockquote" block
return $ B.blockQuote $ fixPlains False contents
-pPlain :: TagParser Blocks
+pPlain :: PandocMonad m => TagParser m Blocks
pPlain = do
contents <- setInPlain $ trimInlines . mconcat <$> many1 inline
if B.isNull contents
then return mempty
else return $ B.plain contents
-pPara :: TagParser Blocks
+pPara :: PandocMonad m => TagParser m Blocks
pPara = do
contents <- trimInlines <$> pInTags "p" inline
- return $ B.para contents
+ (do guardDisabled Ext_empty_paragraphs
+ guard (B.isNull contents)
+ return mempty)
+ <|> return (B.para contents)
+
+pFigure :: PandocMonad m => TagParser m Blocks
+pFigure = try $ do
+ TagOpen _ _ <- pSatisfy (matchTagOpen "figure" [])
+ skipMany pBlank
+ let pImg = (\x -> (Just x, Nothing)) <$>
+ (pOptInTag "p" pImage <* skipMany pBlank)
+ pCapt = (\x -> (Nothing, Just x)) <$> do
+ bs <- pInTags "figcaption" block
+ return $ blocksToInlines' $ B.toList bs
+ pSkip = (Nothing, Nothing) <$ pSatisfy (not . matchTagClose "figure")
+ res <- many (pImg <|> pCapt <|> pSkip)
+ let mbimg = msum $ map fst res
+ let mbcap = msum $ map snd res
+ TagClose _ <- pSatisfy (matchTagClose "figure")
+ let caption = fromMaybe mempty mbcap
+ case B.toList <$> mbimg of
+ Just [Image attr _ (url, tit)] ->
+ return $ B.para $ B.imageWith attr url ("fig:" ++ tit) caption
+ _ -> mzero
-pCodeBlock :: TagParser Blocks
+pCodeBlock :: PandocMonad m => TagParser m Blocks
pCodeBlock = try $ do
- TagOpen _ attr <- pSatisfy (~== TagOpen "pre" [])
+ TagOpen _ attr' <- pSatisfy (matchTagOpen "pre" [])
+ let attr = toStringAttr attr'
contents <- manyTill pAnyTag (pCloses "pre" <|> eof)
let rawText = concatMap tagToString contents
-- drop leading newline if any
let result' = case rawText of
- '\n':xs -> xs
- _ -> rawText
+ '\n':xs -> xs
+ _ -> rawText
-- drop trailing newline if any
let result = case reverse result' of
- '\n':_ -> init result'
- _ -> result'
+ '\n':_ -> init result'
+ _ -> result'
return $ B.codeBlockWith (mkAttr attr) result
-tagToString :: Tag String -> String
-tagToString (TagText s) = s
+tagToString :: Tag Text -> String
+tagToString (TagText s) = T.unpack s
tagToString (TagOpen "br" _) = "\n"
-tagToString _ = ""
+tagToString _ = ""
-inline :: TagParser Inlines
+inline :: PandocMonad m => TagParser m Inlines
inline = choice
[ eNoteref
, eSwitch id inline
@@ -540,6 +648,7 @@ inline = choice
, pSuperscript
, pSubscript
, pStrikeout
+ , pUnderline
, pLineBreak
, pLink
, pImage
@@ -549,30 +658,31 @@ inline = choice
, pRawHtmlInline
]
-pLocation :: TagParser ()
+pLocation :: PandocMonad m => TagParser m ()
pLocation = do
(TagPosition r c) <- pSat isTagPosition
setPosition $ newPos "input" r c
-pSat :: (Tag String -> Bool) -> TagParser (Tag String)
+pSat :: PandocMonad m => (Tag Text -> Bool) -> TagParser m (Tag Text)
pSat f = do
pos <- getPosition
token show (const pos) (\x -> if f x then Just x else Nothing)
-pSatisfy :: (Tag String -> Bool) -> TagParser (Tag String)
+pSatisfy :: PandocMonad m => (Tag Text -> Bool) -> TagParser m (Tag Text)
pSatisfy f = try $ optional pLocation >> pSat f
-pAnyTag :: TagParser (Tag String)
+pAnyTag :: PandocMonad m => TagParser m (Tag Text)
pAnyTag = pSatisfy (const True)
-pSelfClosing :: (String -> Bool) -> ([Attribute String] -> Bool)
- -> TagParser (Tag String)
+pSelfClosing :: PandocMonad m
+ => (Text -> Bool) -> ([Attribute Text] -> Bool)
+ -> TagParser m (Tag Text)
pSelfClosing f g = do
open <- pSatisfy (tagOpen f g)
optional $ pSatisfy (tagClose f)
return open
-pQ :: TagParser Inlines
+pQ :: PandocMonad m => TagParser m Inlines
pQ = do
context <- asks quoteContext
let quoteType = case context of
@@ -587,45 +697,50 @@ pQ = do
withQuoteContext innerQuoteContext $
pInlinesInTags "q" constructor
-pEmph :: TagParser Inlines
+pEmph :: PandocMonad m => TagParser m Inlines
pEmph = pInlinesInTags "em" B.emph <|> pInlinesInTags "i" B.emph
-pStrong :: TagParser Inlines
+pStrong :: PandocMonad m => TagParser m Inlines
pStrong = pInlinesInTags "strong" B.strong <|> pInlinesInTags "b" B.strong
-pSuperscript :: TagParser Inlines
+pSuperscript :: PandocMonad m => TagParser m Inlines
pSuperscript = pInlinesInTags "sup" B.superscript
-pSubscript :: TagParser Inlines
+pSubscript :: PandocMonad m => TagParser m Inlines
pSubscript = pInlinesInTags "sub" B.subscript
-pStrikeout :: TagParser Inlines
-pStrikeout = do
+pStrikeout :: PandocMonad m => TagParser m Inlines
+pStrikeout =
pInlinesInTags "s" B.strikeout <|>
pInlinesInTags "strike" B.strikeout <|>
pInlinesInTags "del" B.strikeout <|>
- try (do pSatisfy (~== TagOpen "span" [("class","strikeout")])
+ try (do pSatisfy (matchTagOpen "span" [("class","strikeout")])
contents <- mconcat <$> manyTill inline (pCloses "span")
return $ B.strikeout contents)
-pLineBreak :: TagParser Inlines
+pUnderline :: PandocMonad m => TagParser m Inlines
+pUnderline = pInlinesInTags "u" underlineSpan <|> pInlinesInTags "ins" underlineSpan
+
+pLineBreak :: PandocMonad m => TagParser m Inlines
pLineBreak = do
pSelfClosing (=="br") (const True)
return B.linebreak
-- Unlike fromAttrib from tagsoup, this distinguishes
-- between a missing attribute and an attribute with empty content.
-maybeFromAttrib :: String -> Tag String -> Maybe String
-maybeFromAttrib name (TagOpen _ attrs) = lookup name attrs
+maybeFromAttrib :: String -> Tag Text -> Maybe String
+maybeFromAttrib name (TagOpen _ attrs) =
+ T.unpack <$> lookup (T.pack name) attrs
maybeFromAttrib _ _ = Nothing
-pLink :: TagParser Inlines
+pLink :: PandocMonad m => TagParser m Inlines
pLink = try $ do
tag <- pSatisfy $ tagOpenLit "a" (const True)
- let title = fromAttrib "title" tag
+ let title = T.unpack $ fromAttrib "title" tag
-- take id from id attribute if present, otherwise name
- let uid = maybe (fromAttrib "name" tag) id $ maybeFromAttrib "id" tag
- let cls = words $ fromAttrib "class" tag
+ let uid = fromMaybe (T.unpack $ fromAttrib "name" tag) $
+ maybeFromAttrib "id" tag
+ let cls = words $ T.unpack $ fromAttrib "class" tag
lab <- trimInlines . mconcat <$> manyTill inline (pCloses "a")
-- check for href; if href, then a link, otherwise a span
case maybeFromAttrib "href" tag of
@@ -639,128 +754,149 @@ pLink = try $ do
_ -> url'
return $ B.linkWith (uid, cls, []) (escapeURI url) title lab
-pImage :: TagParser Inlines
+pImage :: PandocMonad m => TagParser m Inlines
pImage = do
tag <- pSelfClosing (=="img") (isJust . lookup "src")
mbBaseHref <- baseHref <$> getState
- let url' = fromAttrib "src" tag
+ let url' = T.unpack $ fromAttrib "src" tag
let url = case (parseURIReference url', mbBaseHref) of
(Just rel, Just bs) -> show (rel `nonStrictRelativeTo` bs)
_ -> url'
- let title = fromAttrib "title" tag
- let alt = fromAttrib "alt" tag
- let uid = fromAttrib "id" tag
- let cls = words $ fromAttrib "class" tag
+ let title = T.unpack $ fromAttrib "title" tag
+ let alt = T.unpack $ fromAttrib "alt" tag
+ let uid = T.unpack $ fromAttrib "id" tag
+ let cls = words $ T.unpack $ fromAttrib "class" tag
let getAtt k = case fromAttrib k tag of
"" -> []
- v -> [(k, v)]
- let kvs = concat $ map getAtt ["width", "height", "sizes", "srcset"]
+ v -> [(T.unpack k, T.unpack v)]
+ let kvs = concatMap getAtt ["width", "height", "sizes", "srcset"]
return $ B.imageWith (uid, cls, kvs) (escapeURI url) title (B.text alt)
-pCode :: TagParser Inlines
+pCode :: PandocMonad m => TagParser m Inlines
pCode = try $ do
- (TagOpen open attr) <- pSatisfy $ tagOpen (`elem` ["code","tt"]) (const True)
+ (TagOpen open attr') <- pSatisfy $ tagOpen (`elem` ["code","tt"]) (const True)
+ let attr = toStringAttr attr'
result <- manyTill pAnyTag (pCloses open)
- return $ B.codeWith (mkAttr attr) $ intercalate " " $ lines $ innerText result
+ return $ B.codeWith (mkAttr attr) $ unwords $ lines $ T.unpack $
+ innerText result
-pSpan :: TagParser Inlines
+pSpan :: PandocMonad m => TagParser m Inlines
pSpan = try $ do
guardEnabled Ext_native_spans
- TagOpen _ attr <- lookAhead $ pSatisfy $ tagOpen (=="span") (const True)
+ TagOpen _ attr' <- lookAhead $ pSatisfy $ tagOpen (=="span") (const True)
+ let attr = toStringAttr attr'
contents <- pInTags "span" inline
- let isSmallCaps = fontVariant == "small-caps"
+ let isSmallCaps = fontVariant == "small-caps" || "smallcaps" `elem` classes
where styleAttr = fromMaybe "" $ lookup "style" attr
fontVariant = fromMaybe "" $ pickStyleAttrProps ["font-variant"] styleAttr
+ classes = fromMaybe [] $
+ words <$> lookup "class" attr
let tag = if isSmallCaps then B.smallcaps else B.spanWith (mkAttr attr)
return $ tag contents
-pRawHtmlInline :: TagParser Inlines
+pRawHtmlInline :: PandocMonad m => TagParser m Inlines
pRawHtmlInline = do
inplain <- asks inPlain
result <- pSatisfy (tagComment (const True))
<|> if inplain
then pSatisfy (not . isBlockTag)
else pSatisfy isInlineTag
- parseRaw <- getOption readerParseRaw
- if parseRaw
- then return $ B.rawInline "html" $ renderTags' [result]
- else return mempty
+ exts <- getOption readerExtensions
+ let raw = T.unpack $ renderTags' [result]
+ if extensionEnabled Ext_raw_html exts
+ then return $ B.rawInline "html" raw
+ else ignore raw
mathMLToTeXMath :: String -> Either String String
mathMLToTeXMath s = writeTeX <$> readMathML s
-pMath :: Bool -> TagParser Inlines
+toStringAttr :: [(Text, Text)] -> [(String, String)]
+toStringAttr = map go
+ where go (x,y) = (T.unpack x, T.unpack y)
+
+pMath :: PandocMonad m => Bool -> TagParser m Inlines
pMath inCase = try $ do
- open@(TagOpen _ attr) <- pSatisfy $ tagOpen (=="math") (const True)
+ open@(TagOpen _ attr') <- pSatisfy $ tagOpen (=="math") (const True)
-- we'll assume math tags are MathML unless specially marked
-- otherwise...
+ let attr = toStringAttr attr'
unless inCase $
guard (maybe True (== mathMLNamespace) (lookup "xmlns" attr))
- contents <- manyTill pAnyTag (pSatisfy (~== TagClose "math"))
- case mathMLToTeXMath (renderTags $ [open] ++ contents ++ [TagClose "math"]) of
+ contents <- manyTill pAnyTag (pSatisfy (matchTagClose "math"))
+ case mathMLToTeXMath (T.unpack $ renderTags $
+ [open] <> contents <> [TagClose "math"]) of
Left _ -> return $ B.spanWith ("",["math"],attr) $ B.text $
- innerText contents
+ T.unpack $ innerText contents
Right [] -> return mempty
Right x -> return $ case lookup "display" attr of
Just "block" -> B.displayMath x
_ -> B.math x
-pInlinesInTags :: String -> (Inlines -> Inlines)
- -> TagParser Inlines
+pInlinesInTags :: PandocMonad m => Text -> (Inlines -> Inlines)
+ -> TagParser m Inlines
pInlinesInTags tagtype f = extractSpaces f <$> pInTags tagtype inline
-pInTags :: (Monoid a) => String -> TagParser a -> TagParser a
+pInTags :: (PandocMonad m, Monoid a) => Text -> TagParser m a -> TagParser m a
pInTags tagtype parser = pInTags' tagtype (const True) parser
-pInTags' :: (Monoid a) => String -> (Tag String -> Bool) -> TagParser a
- -> TagParser a
+pInTags' :: (PandocMonad m, Monoid a)
+ => Text
+ -> (Tag Text -> Bool)
+ -> TagParser m a
+ -> TagParser m a
pInTags' tagtype tagtest parser = try $ do
pSatisfy (\t -> t ~== TagOpen tagtype [] && tagtest t)
mconcat <$> manyTill parser (pCloses tagtype <|> eof)
-- parses p, preceeded by an optional opening tag
-- and followed by an optional closing tags
-pOptInTag :: String -> TagParser a -> TagParser a
+pOptInTag :: PandocMonad m => Text -> TagParser m a -> TagParser m a
pOptInTag tagtype p = try $ do
skipMany pBlank
- optional $ pSatisfy (~== TagOpen tagtype [])
+ optional $ pSatisfy (matchTagOpen tagtype [])
skipMany pBlank
x <- p
skipMany pBlank
- optional $ pSatisfy (~== TagClose tagtype)
+ optional $ pSatisfy (matchTagClose tagtype)
skipMany pBlank
return x
-pCloses :: String -> TagParser ()
+pCloses :: PandocMonad m => Text -> TagParser m ()
pCloses tagtype = try $ do
t <- lookAhead $ pSatisfy $ \tag -> isTagClose tag || isTagOpen tag
case t of
- (TagClose t') | t' == tagtype -> pAnyTag >> return ()
+ (TagClose t') | t' == tagtype -> void pAnyTag
(TagOpen t' _) | t' `closes` tagtype -> return ()
(TagClose "ul") | tagtype == "li" -> return ()
(TagClose "ol") | tagtype == "li" -> return ()
(TagClose "dl") | tagtype == "dd" -> return ()
(TagClose "table") | tagtype == "td" -> return ()
(TagClose "table") | tagtype == "tr" -> return ()
+ (TagClose "td") | tagtype `Set.member` blockHtmlTags -> return ()
+ (TagClose "th") | tagtype `Set.member` blockHtmlTags -> return ()
+ (TagClose t') | tagtype == "p" && t' `Set.member` blockHtmlTags
+ -> return () -- see #3794
_ -> mzero
-pTagText :: TagParser Inlines
+pTagText :: PandocMonad m => TagParser m Inlines
pTagText = try $ do
(TagText str) <- pSatisfy isTagText
st <- getState
qu <- ask
- case flip runReader qu $ runParserT (many pTagContents) st "text" str of
- Left _ -> fail $ "Could not parse `" ++ str ++ "'"
+ parsed <- lift $ lift $
+ flip runReaderT qu $ runParserT (many pTagContents) st "text" str
+ case parsed of
+ Left _ -> throwError $ PandocParseError $ "Could not parse `" <> T.unpack str <> "'"
Right result -> return $ mconcat result
-pBlank :: TagParser ()
+pBlank :: PandocMonad m => TagParser m ()
pBlank = try $ do
(TagText str) <- pSatisfy isTagText
- guard $ all isSpace str
+ guard $ T.all isSpace str
-type InlinesParser = HTMLParser String
+type InlinesParser m = HTMLParser m Text
-pTagContents :: InlinesParser Inlines
+pTagContents :: PandocMonad m => InlinesParser m Inlines
pTagContents =
B.displayMath <$> mathDisplay
<|> B.math <$> mathInline
@@ -770,7 +906,7 @@ pTagContents =
<|> pSymbol
<|> pBad
-pStr :: InlinesParser Inlines
+pStr :: PandocMonad m => InlinesParser m Inlines
pStr = do
result <- many1 $ satisfy $ \c ->
not (isSpace c) && not (isSpecial c) && not (isBad c)
@@ -778,24 +914,24 @@ pStr = do
return $ B.str result
isSpecial :: Char -> Bool
-isSpecial '"' = True
-isSpecial '\'' = True
-isSpecial '.' = True
-isSpecial '-' = True
-isSpecial '$' = True
+isSpecial '"' = True
+isSpecial '\'' = True
+isSpecial '.' = True
+isSpecial '-' = True
+isSpecial '$' = True
isSpecial '\8216' = True
isSpecial '\8217' = True
isSpecial '\8220' = True
isSpecial '\8221' = True
-isSpecial _ = False
+isSpecial _ = False
-pSymbol :: InlinesParser Inlines
+pSymbol :: PandocMonad m => InlinesParser m Inlines
pSymbol = satisfy isSpecial >>= return . B.str . (:[])
isBad :: Char -> Bool
isBad c = c >= '\128' && c <= '\159' -- not allowed in HTML
-pBad :: InlinesParser Inlines
+pBad :: PandocMonad m => InlinesParser m Inlines
pBad = do
c <- satisfy isBad
let c' = case c of
@@ -829,7 +965,7 @@ pBad = do
_ -> '?'
return $ B.str [c']
-pSpace :: InlinesParser Inlines
+pSpace :: PandocMonad m => InlinesParser m Inlines
pSpace = many1 (satisfy isSpace) >>= \xs ->
if '\n' `elem` xs
then return B.softbreak
@@ -839,86 +975,96 @@ pSpace = many1 (satisfy isSpace) >>= \xs ->
-- Constants
--
-eitherBlockOrInline :: [String]
-eitherBlockOrInline = ["audio", "applet", "button", "iframe", "embed",
- "del", "ins",
- "progress", "map", "area", "noscript", "script",
- "object", "svg", "video", "source"]
-
-{-
-inlineHtmlTags :: [[Char]]
-inlineHtmlTags = ["a", "abbr", "acronym", "b", "basefont", "bdo", "big",
- "br", "cite", "code", "dfn", "em", "font", "i", "img",
- "input", "kbd", "label", "q", "s", "samp", "select",
- "small", "span", "strike", "strong", "sub", "sup",
- "textarea", "tt", "u", "var"]
--}
-
-blockHtmlTags :: [String]
-blockHtmlTags = ["?xml", "!DOCTYPE", "address", "article", "aside",
- "blockquote", "body", "button", "canvas",
- "caption", "center", "col", "colgroup", "dd", "dir", "div",
- "dl", "dt", "fieldset", "figcaption", "figure",
- "footer", "form", "h1", "h2", "h3", "h4",
- "h5", "h6", "head", "header", "hgroup", "hr", "html",
- "isindex", "menu", "noframes", "ol", "output", "p", "pre",
- "section", "table", "tbody", "textarea",
- "thead", "tfoot", "ul", "dd",
- "dt", "frameset", "li", "tbody", "td", "tfoot",
- "th", "thead", "tr", "script", "style"]
+eitherBlockOrInline :: Set.Set Text
+eitherBlockOrInline = Set.fromList
+ ["audio", "applet", "button", "iframe", "embed",
+ "del", "ins", "progress", "map", "area", "noscript", "script",
+ "object", "svg", "video", "source"]
+
+blockHtmlTags :: Set.Set Text
+blockHtmlTags = Set.fromList
+ ["?xml", "!DOCTYPE", "address", "article", "aside",
+ "blockquote", "body", "canvas",
+ "caption", "center", "col", "colgroup", "dd", "details",
+ "dir", "div", "dl", "dt", "fieldset", "figcaption", "figure",
+ "footer", "form", "h1", "h2", "h3", "h4",
+ "h5", "h6", "head", "header", "hgroup", "hr", "html",
+ "isindex", "main", "menu", "meta", "noframes", "ol", "output", "p", "pre",
+ "section", "table", "tbody", "textarea",
+ "thead", "tfoot", "ul", "dd",
+ "dt", "frameset", "li", "tbody", "td", "tfoot",
+ "th", "thead", "tr", "script", "style"]
-- We want to allow raw docbook in markdown documents, so we
-- include docbook block tags here too.
-blockDocBookTags :: [String]
-blockDocBookTags = ["calloutlist", "bibliolist", "glosslist", "itemizedlist",
- "orderedlist", "segmentedlist", "simplelist",
- "variablelist", "caution", "important", "note", "tip",
- "warning", "address", "literallayout", "programlisting",
- "programlistingco", "screen", "screenco", "screenshot",
- "synopsis", "example", "informalexample", "figure",
- "informalfigure", "table", "informaltable", "para",
- "simpara", "formalpara", "equation", "informalequation",
- "figure", "screenshot", "mediaobject", "qandaset",
- "procedure", "task", "cmdsynopsis", "funcsynopsis",
- "classsynopsis", "blockquote", "epigraph", "msgset",
- "sidebar", "title"]
-
-epubTags :: [String]
-epubTags = ["case", "switch", "default"]
-
-blockTags :: [String]
-blockTags = blockHtmlTags ++ blockDocBookTags ++ epubTags
-
-isInlineTag :: Tag String -> Bool
-isInlineTag t = tagOpen isInlineTagName (const True) t ||
- tagClose isInlineTagName t ||
- tagComment (const True) t
- where isInlineTagName x = x `notElem` blockTags
-
-isBlockTag :: Tag String -> Bool
-isBlockTag t = tagOpen isBlockTagName (const True) t ||
- tagClose isBlockTagName t ||
- tagComment (const True) t
- where isBlockTagName ('?':_) = True
- isBlockTagName ('!':_) = True
- isBlockTagName x = x `elem` blockTags
- || x `elem` eitherBlockOrInline
-
-isTextTag :: Tag String -> Bool
+blockDocBookTags :: Set.Set Text
+blockDocBookTags = Set.fromList
+ ["calloutlist", "bibliolist", "glosslist", "itemizedlist",
+ "orderedlist", "segmentedlist", "simplelist",
+ "variablelist", "caution", "important", "note", "tip",
+ "warning", "address", "literallayout", "programlisting",
+ "programlistingco", "screen", "screenco", "screenshot",
+ "synopsis", "example", "informalexample", "figure",
+ "informalfigure", "table", "informaltable", "para",
+ "simpara", "formalpara", "equation", "informalequation",
+ "figure", "screenshot", "mediaobject", "qandaset",
+ "procedure", "task", "cmdsynopsis", "funcsynopsis",
+ "classsynopsis", "blockquote", "epigraph", "msgset",
+ "sidebar", "title"]
+
+epubTags :: Set.Set Text
+epubTags = Set.fromList ["case", "switch", "default"]
+
+blockTags :: Set.Set Text
+blockTags = Set.unions [blockHtmlTags, blockDocBookTags, epubTags]
+
+class NamedTag a where
+ getTagName :: a -> Maybe Text
+
+instance NamedTag (Tag Text) where
+ getTagName (TagOpen t _) = Just t
+ getTagName (TagClose t) = Just t
+ getTagName _ = Nothing
+
+instance NamedTag (Tag String) where
+ getTagName (TagOpen t _) = Just (T.pack t)
+ getTagName (TagClose t) = Just (T.pack t)
+ getTagName _ = Nothing
+
+isInlineTag :: NamedTag (Tag a) => Tag a -> Bool
+isInlineTag t = isInlineTagName || isCommentTag t
+ where isInlineTagName = case getTagName t of
+ Just x -> x
+ `Set.notMember` blockTags
+ Nothing -> False
+
+isBlockTag :: NamedTag (Tag a) => Tag a -> Bool
+isBlockTag t = isBlockTagName || isTagComment t
+ where isBlockTagName =
+ case getTagName t of
+ Just x
+ | "?" `T.isPrefixOf` x -> True
+ | "!" `T.isPrefixOf` x -> True
+ | otherwise -> x `Set.member` blockTags
+ || x `Set.member` eitherBlockOrInline
+ Nothing -> False
+
+isTextTag :: Tag a -> Bool
isTextTag = tagText (const True)
-isCommentTag :: Tag String -> Bool
+isCommentTag :: Tag a -> Bool
isCommentTag = tagComment (const True)
-- taken from HXT and extended
-- See http://www.w3.org/TR/html5/syntax.html sec 8.1.2.4 optional tags
-closes :: String -> String -> Bool
+closes :: Text -> Text -> Bool
_ `closes` "body" = False
_ `closes` "html" = False
"body" `closes` "head" = True
"a" `closes` "a" = True
"li" `closes` "li" = True
"th" `closes` t | t `elem` ["th","td"] = True
+"td" `closes` t | t `elem` ["th","td"] = True
"tr" `closes` t | t `elem` ["th","td","tr"] = True
"dd" `closes` t | t `elem` ["dt", "dd"] = True
"dt" `closes` t | t `elem` ["dt","dd"] = True
@@ -926,12 +1072,12 @@ _ `closes` "html" = False
"optgroup" `closes` "optgroup" = True
"optgroup" `closes` "option" = True
"option" `closes` "option" = True
--- http://www.w3.org/TR/html-markup/p.html
+-- https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
x `closes` "p" | x `elem` ["address", "article", "aside", "blockquote",
"dir", "div", "dl", "fieldset", "footer", "form", "h1", "h2", "h3", "h4",
- "h5", "h6", "header", "hr", "menu", "nav", "ol", "p", "pre", "section",
+ "h5", "h6", "header", "hr", "main", "menu", "nav", "ol", "p", "pre", "section",
"table", "ul"] = True
-"meta" `closes` "meta" = True
+_ `closes` "meta" = True
"form" `closes` "form" = True
"label" `closes` "label" = True
"map" `closes` "map" = True
@@ -942,17 +1088,18 @@ t `closes` "select" | t /= "option" = True
"tfoot" `closes` t | t `elem` ["thead","colgroup"] = True
"tbody" `closes` t | t `elem` ["tbody","tfoot","thead","colgroup"] = True
t `closes` t2 |
- t `elem` ["h1","h2","h3","h4","h5","h6","dl","ol","ul","table","div","p"] &&
- t2 `elem` ["h1","h2","h3","h4","h5","h6","p" ] = True -- not "div"
+ t `elem` ["h1","h2","h3","h4","h5","h6","dl","ol","ul","table","div","main","p"] &&
+ t2 `elem` ["h1","h2","h3","h4","h5","h6","p" ] = True -- not "div" or "main"
t1 `closes` t2 |
- t1 `elem` blockTags &&
- t2 `notElem` (blockTags ++ eitherBlockOrInline) = True
+ t1 `Set.member` blockTags &&
+ t2 `Set.notMember` blockTags &&
+ t2 `Set.notMember` eitherBlockOrInline = True
_ `closes` _ = False
--- parsers for use in markdown, textile readers
-- | Matches a stretch of HTML in balanced tags.
-htmlInBalanced :: (Monad m)
+htmlInBalanced :: (HasReaderOptions st, Monad m)
=> (Tag String -> Bool)
-> ParserT String st m String
htmlInBalanced f = try $ do
@@ -973,8 +1120,11 @@ htmlInBalanced f = try $ do
let cs = ec - sc
lscontents <- unlines <$> count ls anyLine
cscontents <- count cs anyChar
- (_,closetag) <- htmlTag (~== TagClose tn)
- return (lscontents ++ cscontents ++ closetag)
+ closetag <- do
+ x <- many (satisfy (/='>'))
+ char '>'
+ return (x <> ">")
+ return (lscontents <> cscontents <> closetag)
_ -> mzero
_ -> mzero
@@ -992,64 +1142,99 @@ htmlInBalanced' tagname ts = fromMaybe [] $ go 0 ts
go n (t:ts') = (t :) <$> go n ts'
go _ [] = mzero
-hasTagWarning :: [Tag String] -> Bool
+hasTagWarning :: [Tag a] -> Bool
hasTagWarning (TagWarning _:_) = True
-hasTagWarning _ = False
+hasTagWarning _ = False
-- | Matches a tag meeting a certain condition.
-htmlTag :: Monad m
+htmlTag :: (HasReaderOptions st, Monad m)
=> (Tag String -> Bool)
-> ParserT [Char] st m (Tag String, String)
htmlTag f = try $ do
lookAhead (char '<')
+ startpos <- getPosition
inp <- getInput
- let (next : _) = canonicalizeTags $ parseTagsOptions
- parseOptions{ optTagWarning = False } inp
- guard $ f next
+ let ts = canonicalizeTags $ parseTagsOptions
+ parseOptions{ optTagWarning = False
+ , optTagPosition = True }
+ (inp ++ " ") -- add space to ensure that
+ -- we get a TagPosition after the tag
+ (next, ln, col) <- case ts of
+ (TagPosition{} : next : TagPosition ln col : _)
+ | f next -> return (next, ln, col)
+ _ -> mzero
+
+ -- <www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>
+ -- should NOT be parsed as an HTML tag, see #2277,
+ -- so we exclude . even though it's a valid character
+ -- in XML element names
+ let isNameChar c = isAlphaNum c || c == ':' || c == '-' || c == '_'
+ let isName s = case s of
+ [] -> False
+ ('?':_) -> True -- processing instruction
+ (c:cs) -> isLetter c && all isNameChar cs
+
+ let endpos = if ln == 1
+ then setSourceColumn startpos
+ (sourceColumn startpos + (col - 1))
+ else setSourceColumn (setSourceLine startpos
+ (sourceLine startpos + (ln - 1)))
+ col
+ let endAngle = try $
+ do char '>'
+ pos <- getPosition
+ guard $ pos >= endpos
+
let handleTag tagname = do
- -- <www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>
- -- should NOT be parsed as an HTML tag, see #2277
- guard $ not ('.' `elem` tagname)
+ -- basic sanity check, since the parser is very forgiving
+ -- and finds tags in stuff like x<y)
+ guard $ isName tagname
+ guard $ not $ null tagname
-- <https://example.org> should NOT be a tag either.
-- tagsoup will parse it as TagOpen "https:" [("example.org","")]
- guard $ not (null tagname)
guard $ last tagname /= ':'
- rendered <- manyTill anyChar (char '>')
- return (next, rendered ++ ">")
+ char '<'
+ rendered <- manyTill anyChar endAngle
+ return (next, "<" ++ rendered ++ ">")
case next of
TagComment s
| "<!--" `isPrefixOf` inp -> do
- count (length s + 4) anyChar
- skipMany (satisfy (/='>'))
- char '>'
- return (next, "<!--" ++ s ++ "-->")
+ string "<!--"
+ count (length s) anyChar
+ string "-->"
+ stripComments <- getOption readerStripComments
+ if stripComments
+ then return (next, "")
+ else return (next, "<!--" <> s <> "-->")
| otherwise -> fail "bogus comment mode, HTML5 parse error"
- TagOpen tagname _attr -> handleTag tagname
- TagClose tagname -> handleTag tagname
+ TagOpen tagname attr -> do
+ guard $ all (isName . fst) attr
+ handleTag tagname
+ TagClose tagname ->
+ handleTag tagname
_ -> mzero
mkAttr :: [(String, String)] -> Attr
mkAttr attr = (attribsId, attribsClasses, attribsKV)
where attribsId = fromMaybe "" $ lookup "id" attr
- attribsClasses = (words $ fromMaybe "" $ lookup "class" attr) ++ epubTypes
+ attribsClasses = words (fromMaybe "" $ lookup "class" attr) <> epubTypes
attribsKV = filter (\(k,_) -> k /= "class" && k /= "id") attr
epubTypes = words $ fromMaybe "" $ lookup "epub:type" attr
-- Strip namespace prefixes
-stripPrefixes :: [Tag String] -> [Tag String]
+stripPrefixes :: [Tag Text] -> [Tag Text]
stripPrefixes = map stripPrefix
-stripPrefix :: Tag String -> Tag String
+stripPrefix :: Tag Text -> Tag Text
stripPrefix (TagOpen s as) =
- TagOpen (stripPrefix' s) (map (stripPrefix' *** id) as)
+ TagOpen (stripPrefix' s) (map (first stripPrefix') as)
stripPrefix (TagClose s) = TagClose (stripPrefix' s)
stripPrefix x = x
-stripPrefix' :: String -> String
+stripPrefix' :: Text -> Text
stripPrefix' s =
- case span (/= ':') s of
- (_, "") -> s
- (_, (_:ts)) -> ts
+ if T.null t then s else T.drop 1 t
+ where (_, t) = T.span (/= ':') s
isSpace :: Char -> Bool
isSpace ' ' = True
@@ -1068,9 +1253,13 @@ instance HasHeaderMap HTMLState where
extractHeaderMap = headerMap
updateHeaderMap f s = s{ headerMap = f (headerMap s) }
+instance HasLogMessages HTMLState where
+ addLogMessage m s = s{ logMessages = m : logMessages s }
+ getLogMessages = reverse . logMessages
+
-- This signature should be more general
-- MonadReader HTMLLocal m => HasQuoteContext st m
-instance HasQuoteContext st (Reader HTMLLocal) where
+instance PandocMonad m => HasQuoteContext HTMLState (ReaderT HTMLLocal m) where
getQuoteContext = asks quoteContext
withQuoteContext q = local (\s -> s{quoteContext = q})
@@ -1088,19 +1277,32 @@ instance HasLastStrPosition HTMLState where
setLastStrPos s st = st {parserState = setLastStrPos s (parserState st)}
getLastStrPos = getLastStrPos . parserState
+-- For now we need a special verison here; the one in Shared has String type
+renderTags' :: [Tag Text] -> Text
+renderTags' = renderTagsOptions
+ renderOptions{ optMinimize = matchTags ["hr", "br", "img",
+ "meta", "link"]
+ , optRawTag = matchTags ["script", "style"] }
+ where matchTags tags = flip elem tags . T.toLower
+
-- EPUB Specific
--
--
-sectioningContent :: [String]
+sectioningContent :: [Text]
sectioningContent = ["article", "aside", "nav", "section"]
-groupingContent :: [String]
+groupingContent :: [Text]
groupingContent = ["p", "hr", "pre", "blockquote", "ol"
, "ul", "li", "dl", "dt", "dt", "dd"
, "figure", "figcaption", "div", "main"]
+matchTagClose :: Text -> (Tag Text -> Bool)
+matchTagClose t = (~== TagClose t)
+
+matchTagOpen :: Text -> [(Text, Text)] -> (Tag Text -> Bool)
+matchTagOpen t as = (~== TagOpen t as)
{-
@@ -1108,7 +1310,7 @@ types :: [(String, ([String], Int))]
types = -- Document divisions
map (\s -> (s, (["section", "body"], 0)))
["volume", "part", "chapter", "division"]
- ++ -- Document section and components
+ <> -- Document section and components
[
("abstract", ([], 0))]
-}
diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs
index 12953bb72..e98c79ed8 100644
--- a/src/Text/Pandoc/Readers/Haddock.hs
+++ b/src/Text/Pandoc/Readers/Haddock.hs
@@ -14,33 +14,40 @@ module Text.Pandoc.Readers.Haddock
( readHaddock
) where
-import Text.Pandoc.Builder (Blocks, Inlines)
-import qualified Text.Pandoc.Builder as B
-import Data.Monoid ((<>))
-import Text.Pandoc.Shared (trim, splitBy)
+import Control.Monad.Except (throwError)
import Data.List (intersperse, stripPrefix)
import Data.Maybe (fromMaybe)
-import Text.Pandoc.Definition
-import Text.Pandoc.Options
+import Data.Monoid ((<>))
+import Data.Text (Text, unpack)
import Documentation.Haddock.Parser
import Documentation.Haddock.Types
-import Debug.Trace (trace)
-
+import Text.Pandoc.Builder (Blocks, Inlines)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Definition
import Text.Pandoc.Error
+import Text.Pandoc.Options
+import Text.Pandoc.Shared (crFilter, splitBy, trim)
+
-- | Parse Haddock markup and return a 'Pandoc' document.
-readHaddock :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse
- -> Either PandocError Pandoc
-readHaddock opts =
+readHaddock :: PandocMonad m
+ => ReaderOptions
+ -> Text
+ -> m Pandoc
+readHaddock opts s = case readHaddockEither opts (unpack (crFilter s)) of
+ Right result -> return result
+ Left e -> throwError e
+
+readHaddockEither :: ReaderOptions -- ^ Reader options
+ -> String -- ^ String to parse
+ -> Either PandocError Pandoc
+readHaddockEither _opts =
#if MIN_VERSION_haddock_library(1,2,0)
- Right . B.doc . docHToBlocks . trace' . _doc . parseParas
+ Right . B.doc . docHToBlocks . _doc . parseParas
#else
- Right . B.doc . docHToBlocks . trace' . parseParas
+ Right . B.doc . docHToBlocks . parseParas
#endif
- where trace' x = if readerTrace opts
- then trace (show x) x
- else x
docHToBlocks :: DocH String Identifier -> Blocks
docHToBlocks d' =
@@ -90,7 +97,7 @@ docHToBlocks d' =
isPlain (Plain _) = True
isPlain _ = False
extractContents (Plain xs) = xs
- extractContents _ = []
+ extractContents _ = []
docHToInlines :: Bool -> DocH String Identifier -> Inlines
docHToInlines isCode d' =
@@ -135,7 +142,7 @@ makeExample prompt expression result =
<> B.space
<> B.codeWith ([], ["haskell","expr"], []) (trim expression)
<> B.linebreak
- <> (mconcat $ intersperse B.linebreak $ map coder result')
+ <> mconcat (intersperse B.linebreak $ map coder result')
where
-- 1. drop trailing whitespace from the prompt, remember the prefix
prefix = takeWhile (`elem` " \t") prompt
diff --git a/src/Text/Pandoc/Readers/JATS.hs b/src/Text/Pandoc/Readers/JATS.hs
new file mode 100644
index 000000000..8158a4511
--- /dev/null
+++ b/src/Text/Pandoc/Readers/JATS.hs
@@ -0,0 +1,496 @@
+{-# LANGUAGE ExplicitForAll, TupleSections #-}
+module Text.Pandoc.Readers.JATS ( readJATS ) where
+import Control.Monad.State.Strict
+import Data.Char (isDigit, isSpace, toUpper)
+import Data.Default
+import Data.Generics
+import Data.List (intersperse)
+import qualified Data.Map as Map
+import Data.Maybe (maybeToList, fromMaybe)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.HTML.TagSoup.Entity (lookupEntity)
+import Text.Pandoc.Builder
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Options
+import Text.Pandoc.Shared (underlineSpan, crFilter, safeRead)
+import Text.TeXMath (readMathML, writeTeX)
+import Text.XML.Light
+import qualified Data.Set as S (fromList, member)
+import Data.Set ((\\))
+
+type JATS m = StateT JATSState m
+
+data JATSState = JATSState{ jatsSectionLevel :: Int
+ , jatsQuoteType :: QuoteType
+ , jatsMeta :: Meta
+ , jatsBook :: Bool
+ , jatsFigureTitle :: Inlines
+ , jatsContent :: [Content]
+ } deriving Show
+
+instance Default JATSState where
+ def = JATSState{ jatsSectionLevel = 0
+ , jatsQuoteType = DoubleQuote
+ , jatsMeta = mempty
+ , jatsBook = False
+ , jatsFigureTitle = mempty
+ , jatsContent = [] }
+
+
+readJATS :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
+readJATS _ inp = do
+ let tree = normalizeTree . parseXML
+ $ T.unpack $ crFilter inp
+ (bs, st') <- flip runStateT (def{ jatsContent = tree }) $ mapM parseBlock tree
+ return $ Pandoc (jatsMeta st') (toList . mconcat $ bs)
+
+-- normalize input, consolidating adjacent Text and CRef elements
+normalizeTree :: [Content] -> [Content]
+normalizeTree = everywhere (mkT go)
+ where go :: [Content] -> [Content]
+ go (Text (CData CDataRaw _ _):xs) = xs
+ go (Text (CData CDataText s1 z):Text (CData CDataText s2 _):xs) =
+ Text (CData CDataText (s1 ++ s2) z):xs
+ go (Text (CData CDataText s1 z):CRef r:xs) =
+ Text (CData CDataText (s1 ++ convertEntity r) z):xs
+ go (CRef r:Text (CData CDataText s1 z):xs) =
+ Text (CData CDataText (convertEntity r ++ s1) z):xs
+ go (CRef r1:CRef r2:xs) =
+ Text (CData CDataText (convertEntity r1 ++ convertEntity r2) Nothing):xs
+ go xs = xs
+
+convertEntity :: String -> String
+convertEntity e = Data.Maybe.fromMaybe (map toUpper e) (lookupEntity e)
+
+-- convenience function to get an attribute value, defaulting to ""
+attrValue :: String -> Element -> String
+attrValue attr =
+ fromMaybe "" . maybeAttrValue attr
+
+maybeAttrValue :: String -> Element -> Maybe String
+maybeAttrValue attr elt =
+ lookupAttrBy (\x -> qName x == attr) (elAttribs elt)
+
+-- convenience function
+named :: String -> Element -> Bool
+named s e = qName (elName e) == s
+
+--
+
+addMeta :: PandocMonad m => ToMetaValue a => String -> a -> JATS m ()
+addMeta field val = modify (setMeta field val)
+
+instance HasMeta JATSState where
+ setMeta field v s = s {jatsMeta = setMeta field v (jatsMeta s)}
+ deleteMeta field s = s {jatsMeta = deleteMeta field (jatsMeta s)}
+
+isBlockElement :: Content -> Bool
+isBlockElement (Elem e) = qName (elName e) `S.member` blocktags
+ where blocktags = S.fromList (paragraphLevel ++ lists ++ mathML ++ other) \\ S.fromList inlinetags
+ paragraphLevel = ["address", "array", "boxed-text", "chem-struct-wrap",
+ "code", "fig", "fig-group", "graphic", "media", "preformat",
+ "supplementary-material", "table-wrap", "table-wrap-group",
+ "alternatives", "disp-formula", "disp-formula-group"]
+ lists = ["def-list", "list"]
+ mathML = ["tex-math", "mml:math"]
+ other = ["p", "related-article", "related-object", "ack", "disp-quote",
+ "speech", "statement", "verse-group", "x"]
+ inlinetags = ["email", "ext-link", "uri", "inline-supplementary-material",
+ "related-article", "related-object", "hr", "bold", "fixed-case",
+ "italic", "monospace", "overline", "overline-start", "overline-end",
+ "roman", "sans-serif", "sc", "strike", "underline", "underline-start",
+ "underline-end", "ruby", "alternatives", "inline-graphic", "private-char",
+ "chem-struct", "inline-formula", "tex-math", "mml:math", "abbrev",
+ "milestone-end", "milestone-start", "named-content", "styled-content",
+ "fn", "target", "xref", "sub", "sup", "x", "address", "array",
+ "boxed-text", "chem-struct-wrap", "code", "fig", "fig-group", "graphic",
+ "media", "preformat", "supplementary-material", "table-wrap",
+ "table-wrap-group", "disp-formula", "disp-formula-group",
+ "citation-alternatives", "element-citation", "mixed-citation",
+ "nlm-citation", "award-id", "funding-source", "open-access",
+ "def-list", "list", "ack", "disp-quote", "speech", "statement",
+ "verse-group"]
+isBlockElement _ = False
+
+-- Trim leading and trailing newline characters
+trimNl :: String -> String
+trimNl = reverse . go . reverse . go
+ where go ('\n':xs) = xs
+ go xs = xs
+
+-- function that is used by both graphic (in parseBlock)
+-- and inline-graphic (in parseInline)
+getGraphic :: PandocMonad m => Element -> JATS m Inlines
+getGraphic e = do
+ let atVal a = attrValue a e
+ attr = (atVal "id", words $ atVal "role", [])
+ imageUrl = atVal "href"
+ captionOrLabel = case filterChild (\x -> named "caption" x
+ || named "label" x) e of
+ Nothing -> return mempty
+ Just z -> mconcat <$>
+ mapM parseInline (elContent z)
+ figTitle <- gets jatsFigureTitle
+ let (caption, title) = if isNull figTitle
+ then (captionOrLabel, atVal "title")
+ else (return figTitle, "fig:")
+ fmap (imageWith attr imageUrl title) caption
+
+getBlocks :: PandocMonad m => Element -> JATS m Blocks
+getBlocks e = mconcat <$>
+ mapM parseBlock (elContent e)
+
+
+parseBlock :: PandocMonad m => Content -> JATS m Blocks
+parseBlock (Text (CData CDataRaw _ _)) = return mempty -- DOCTYPE
+parseBlock (Text (CData _ s _)) = if all isSpace s
+ then return mempty
+ else return $ plain $ trimInlines $ text s
+parseBlock (CRef x) = return $ plain $ str $ map toUpper x
+parseBlock (Elem e) =
+ case qName (elName e) of
+ "p" -> parseMixed para (elContent e)
+ "code" -> codeBlockWithLang
+ "preformat" -> codeBlockWithLang
+ "disp-quote" -> parseBlockquote
+ "list" -> case attrValue "list-type" e of
+ "bullet" -> bulletList <$> listitems
+ listType -> do
+ let start = fromMaybe 1 $
+ (strContent <$> (filterElement (named "list-item") e
+ >>= filterElement (named "lable")))
+ >>= safeRead
+ orderedListWith (start, parseListStyleType listType, DefaultDelim)
+ <$> listitems
+ "def-list" -> definitionList <$> deflistitems
+ "sec" -> gets jatsSectionLevel >>= sect . (+1)
+ "graphic" -> para <$> getGraphic e
+ "journal-meta" -> parseMetadata e
+ "article-meta" -> parseMetadata e
+ "custom-meta" -> parseMetadata e
+ "title" -> return mempty -- processed by header
+ "table" -> parseTable
+ "fig" -> divWith (attrValue "id" e, ["fig"], []) <$> getBlocks e
+ "table-wrap" -> divWith (attrValue "id" e, ["table-wrap"], []) <$> getBlocks e
+ "caption" -> divWith (attrValue "id" e, ["caption"], []) <$> sect 6
+ "ref-list" -> parseRefList e
+ "?xml" -> return mempty
+ _ -> getBlocks e
+ where parseMixed container conts = do
+ let (ils,rest) = break isBlockElement conts
+ ils' <- (trimInlines . mconcat) <$> mapM parseInline ils
+ let p = if ils' == mempty then mempty else container ils'
+ case rest of
+ [] -> return p
+ (r:rs) -> do
+ b <- parseBlock r
+ x <- parseMixed container rs
+ return $ p <> b <> x
+ codeBlockWithLang = do
+ let classes' = case attrValue "language" e of
+ "" -> []
+ x -> [x]
+ return $ codeBlockWith (attrValue "id" e, classes', [])
+ $ trimNl $ strContentRecursive e
+ parseBlockquote = do
+ attrib <- case filterChild (named "attribution") e of
+ Nothing -> return mempty
+ Just z -> (para . (str "— " <>) . mconcat)
+ <$>
+ mapM parseInline (elContent z)
+ contents <- getBlocks e
+ return $ blockQuote (contents <> attrib)
+ parseListStyleType "roman-lower" = LowerRoman
+ parseListStyleType "roman-upper" = UpperRoman
+ parseListStyleType "alpha-lower" = LowerAlpha
+ parseListStyleType "alpha-upper" = UpperAlpha
+ parseListStyleType _ = DefaultStyle
+ listitems = mapM getBlocks $ filterChildren (named "list-item") e
+ deflistitems = mapM parseVarListEntry $ filterChildren
+ (named "def-item") e
+ parseVarListEntry e' = do
+ let terms = filterChildren (named "term") e'
+ let items = filterChildren (named "def") e'
+ terms' <- mapM getInlines terms
+ items' <- mapM getBlocks items
+ return (mconcat $ intersperse (str "; ") terms', items')
+ parseTable = do
+ let isCaption x = named "title" x || named "caption" x
+ caption <- case filterChild isCaption e of
+ Just t -> getInlines t
+ Nothing -> return mempty
+ let e' = fromMaybe e $ filterChild (named "tgroup") e
+ let isColspec x = named "colspec" x || named "col" x
+ let colspecs = case filterChild (named "colgroup") e' of
+ Just c -> filterChildren isColspec c
+ _ -> filterChildren isColspec e'
+ let isRow x = named "row" x || named "tr" x
+ headrows <- case filterChild (named "thead") e' of
+ Just h -> case filterChild isRow h of
+ Just x -> parseRow x
+ Nothing -> return []
+ Nothing -> return []
+ bodyrows <- case filterChild (named "tbody") e' of
+ Just b -> mapM parseRow
+ $ filterChildren isRow b
+ Nothing -> mapM parseRow
+ $ filterChildren isRow e'
+ let toAlignment c = case findAttr (unqual "align") c of
+ Just "left" -> AlignLeft
+ Just "right" -> AlignRight
+ Just "center" -> AlignCenter
+ _ -> AlignDefault
+ let toWidth c = case findAttr (unqual "colwidth") c of
+ Just w -> fromMaybe 0
+ $ safeRead $ '0': filter (\x ->
+ isDigit x || x == '.') w
+ Nothing -> 0 :: Double
+ let numrows = case bodyrows of
+ [] -> 0
+ xs -> maximum $ map length xs
+ let aligns = case colspecs of
+ [] -> replicate numrows AlignDefault
+ cs -> map toAlignment cs
+ let widths = case colspecs of
+ [] -> replicate numrows 0
+ cs -> let ws = map toWidth cs
+ tot = sum ws
+ in if all (> 0) ws
+ then map (/ tot) ws
+ else replicate numrows 0
+ let headrows' = if null headrows
+ then replicate numrows mempty
+ else headrows
+ return $ table caption (zip aligns widths)
+ headrows' bodyrows
+ isEntry x = named "entry" x || named "td" x || named "th" x
+ parseRow = mapM (parseMixed plain . elContent) . filterChildren isEntry
+ sect n = do isbook <- gets jatsBook
+ let n' = if isbook || n == 0 then n + 1 else n
+ headerText <- case filterChild (named "title") e `mplus`
+ (filterChild (named "info") e >>=
+ filterChild (named "title")) of
+ Just t -> getInlines t
+ Nothing -> return mempty
+ oldN <- gets jatsSectionLevel
+ modify $ \st -> st{ jatsSectionLevel = n }
+ b <- getBlocks e
+ let ident = attrValue "id" e
+ modify $ \st -> st{ jatsSectionLevel = oldN }
+ return $ headerWith (ident,[],[]) n' headerText <> b
+
+getInlines :: PandocMonad m => Element -> JATS m Inlines
+getInlines e' = (trimInlines . mconcat) <$>
+ mapM parseInline (elContent e')
+
+parseMetadata :: PandocMonad m => Element -> JATS m Blocks
+parseMetadata e = do
+ getTitle e
+ getAuthors e
+ getAffiliations e
+ return mempty
+
+getTitle :: PandocMonad m => Element -> JATS m ()
+getTitle e = do
+ tit <- case filterElement (named "article-title") e of
+ Just s -> getInlines s
+ Nothing -> return mempty
+ subtit <- case filterElement (named "subtitle") e of
+ Just s -> (text ": " <>) <$>
+ getInlines s
+ Nothing -> return mempty
+ when (tit /= mempty) $ addMeta "title" tit
+ when (subtit /= mempty) $ addMeta "subtitle" subtit
+
+getAuthors :: PandocMonad m => Element -> JATS m ()
+getAuthors e = do
+ authors <- mapM getContrib $ filterElements
+ (\x -> named "contrib" x &&
+ attrValue "contrib-type" x == "author") e
+ authorNotes <- mapM getInlines $ filterElements (named "author-notes") e
+ let authors' = case (reverse authors, authorNotes) of
+ ([], _) -> []
+ (_, []) -> authors
+ (a:as, ns) -> reverse as ++ [a <> mconcat ns]
+ unless (null authors) $ addMeta "author" authors'
+
+getAffiliations :: PandocMonad m => Element -> JATS m ()
+getAffiliations x = do
+ affs <- mapM getInlines $ filterChildren (named "aff") x
+ unless (null affs) $ addMeta "institute" affs
+
+getContrib :: PandocMonad m => Element -> JATS m Inlines
+getContrib x = do
+ given <- maybe (return mempty) getInlines
+ $ filterElement (named "given-names") x
+ family <- maybe (return mempty) getInlines
+ $ filterElement (named "surname") x
+ if given == mempty && family == mempty
+ then return mempty
+ else if given == mempty || family == mempty
+ then return $ given <> family
+ else return $ given <> space <> family
+
+parseRefList :: PandocMonad m => Element -> JATS m Blocks
+parseRefList e = do
+ refs <- mapM parseRef $ filterChildren (named "ref") e
+ addMeta "references" refs
+ return mempty
+
+parseRef :: PandocMonad m
+ => Element -> JATS m (Map.Map String MetaValue)
+parseRef e = do
+ let refId = text $ attrValue "id" e
+ let getInlineText n = maybe (return mempty) getInlines . filterChild (named n)
+ case filterChild (named "element-citation") e of
+ Just c -> do
+ let refType = text $
+ case attrValue "publication-type" c of
+ "journal" -> "article-journal"
+ x -> x
+ (refTitle, refContainerTitle) <- do
+ t <- getInlineText "article-title" c
+ ct <- getInlineText "source" c
+ if t == mempty
+ then return (ct, mempty)
+ else return (t, ct)
+ refLabel <- getInlineText "label" c
+ refYear <- getInlineText "year" c
+ refVolume <- getInlineText "volume" c
+ refFirstPage <- getInlineText "fpage" c
+ refLastPage <- getInlineText "lpage" c
+ refPublisher <- getInlineText "publisher-name" c
+ refPublisherPlace <- getInlineText "publisher-loc" c
+ let refPages = refFirstPage <> (if refLastPage == mempty
+ then mempty
+ else text "\x2013" <> refLastPage)
+ let personGroups' = filterChildren (named "person-group") c
+ let getName nm = do
+ given <- maybe (return mempty) getInlines
+ $ filterChild (named "given-names") nm
+ family <- maybe (return mempty) getInlines
+ $ filterChild (named "surname") nm
+ return $ toMetaValue $ Map.fromList [
+ ("given", given)
+ , ("family", family)
+ ]
+ personGroups <- mapM (\pg ->
+ do names <- mapM getName
+ (filterChildren (named "name") pg)
+ return (attrValue "person-group-type" pg,
+ toMetaValue names))
+ personGroups'
+ return $ Map.fromList $
+ [ ("id", toMetaValue refId)
+ , ("type", toMetaValue refType)
+ , ("title", toMetaValue refTitle)
+ , ("container-title", toMetaValue refContainerTitle)
+ , ("publisher", toMetaValue refPublisher)
+ , ("publisher-place", toMetaValue refPublisherPlace)
+ , ("title", toMetaValue refTitle)
+ , ("issued", toMetaValue
+ $ Map.fromList [
+ ("year", refYear)
+ ])
+ , ("volume", toMetaValue refVolume)
+ , ("page", toMetaValue refPages)
+ , ("citation-label", toMetaValue refLabel)
+ ] ++ personGroups
+ Nothing -> return $ Map.insert "id" (toMetaValue refId) mempty
+ -- TODO handle mixed-citation
+
+strContentRecursive :: Element -> String
+strContentRecursive = strContent .
+ (\e' -> e'{ elContent = map elementToStr $ elContent e' })
+
+elementToStr :: Content -> Content
+elementToStr (Elem e') = Text $ CData CDataText (strContentRecursive e') Nothing
+elementToStr x = x
+
+parseInline :: PandocMonad m => Content -> JATS m Inlines
+parseInline (Text (CData _ s _)) = return $ text s
+parseInline (CRef ref) =
+ return $ maybe (text $ map toUpper ref) text $ lookupEntity ref
+parseInline (Elem e) =
+ case qName (elName e) of
+ "italic" -> emph <$> innerInlines
+ "bold" -> strong <$> innerInlines
+ "strike" -> strikeout <$> innerInlines
+ "sub" -> subscript <$> innerInlines
+ "sup" -> superscript <$> innerInlines
+ "underline" -> underlineSpan <$> innerInlines
+ "break" -> return linebreak
+ "sc" -> smallcaps <$> innerInlines
+
+ "code" -> codeWithLang
+ "monospace" -> codeWithLang
+
+ "inline-graphic" -> getGraphic e
+ "disp-quote" -> do
+ qt <- gets jatsQuoteType
+ let qt' = if qt == SingleQuote then DoubleQuote else SingleQuote
+ modify $ \st -> st{ jatsQuoteType = qt' }
+ contents <- innerInlines
+ modify $ \st -> st{ jatsQuoteType = qt }
+ return $ if qt == SingleQuote
+ then singleQuoted contents
+ else doubleQuoted contents
+
+ "xref" -> do
+ ils <- innerInlines
+ let rid = attrValue "rid" e
+ let refType = ("ref-type",) <$> maybeAttrValue "ref-type" e
+ let attr = (attrValue "id" e, [], maybeToList refType)
+ return $ if refType == Just ("ref-type","bibr")
+ then cite [Citation{
+ citationId = rid
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0}] ils
+ else linkWith attr ('#' : rid) "" ils
+ "ext-link" -> do
+ ils <- innerInlines
+ let title = fromMaybe "" $ findAttr (QName "title" (Just "http://www.w3.org/1999/xlink") Nothing) e
+ let href = case findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e of
+ Just h -> h
+ _ -> '#' : attrValue "rid" e
+ let ils' = if ils == mempty then str href else ils
+ let attr = (attrValue "id" e, [], [])
+ return $ linkWith attr href title ils'
+
+ "disp-formula" -> formula displayMath
+ "inline-formula" -> formula math
+ "math" | qPrefix (elName e) == Just "mml" -> return . math $ mathML e
+ "tex-math" -> return . math $ strContent e
+
+ "email" -> return $ link ("mailto:" ++ strContent e) ""
+ $ str $ strContent e
+ "uri" -> return $ link (strContent e) "" $ str $ strContent e
+ "fn" -> (note . mconcat) <$>
+ mapM parseBlock (elContent e)
+ _ -> innerInlines
+ where innerInlines = (trimInlines . mconcat) <$>
+ mapM parseInline (elContent e)
+ mathML x =
+ case readMathML . showElement $ everywhere (mkT removePrefix) x of
+ Left _ -> mempty
+ Right m -> writeTeX m
+ formula constructor = do
+ let whereToLook = fromMaybe e $ filterElement (named "alternatives") e
+ texMaths = map strContent $
+ filterChildren (named "tex-math") whereToLook
+ mathMLs = map mathML $
+ filterChildren isMathML whereToLook
+ return . mconcat . take 1 . map constructor $ texMaths ++ mathMLs
+
+ isMathML x = qName (elName x) == "math" &&
+ qPrefix (elName x) == Just "mml"
+ removePrefix elname = elname { qPrefix = Nothing }
+ codeWithLang = do
+ let classes' = case attrValue "language" e of
+ "" -> []
+ l -> [l]
+ return $ codeWith (attrValue "id" e,classes',[]) $ strContentRecursive e
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
index edcf35e51..57d2803ba 100644
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -1,6 +1,10 @@
-{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.LaTeX
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -27,218 +31,596 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Portability : portable
Conversion of LaTeX to 'Pandoc' document.
+
-}
module Text.Pandoc.Readers.LaTeX ( readLaTeX,
+ applyMacros,
rawLaTeXInline,
rawLaTeXBlock,
inlineCommand,
- handleIncludes
+ tokenize,
+ untokenize
) where
-import Text.Pandoc.Definition
-import Text.Pandoc.Walk
-import Text.Pandoc.Shared
-import Text.Pandoc.Options
-import Text.Pandoc.Parsing hiding ((<|>), many, optional, space,
- mathDisplay, mathInline)
-import qualified Text.Pandoc.UTF8 as UTF8
-import Data.Char ( chr, ord, isLetter, isAlphaNum )
-import Control.Monad.Trans (lift)
+import Control.Applicative (many, optional, (<|>))
import Control.Monad
-import Text.Pandoc.Builder
-import Control.Applicative ((<|>), many, optional)
-import Data.Maybe (fromMaybe, maybeToList)
-import System.Environment (getEnv)
-import System.FilePath (replaceExtension, (</>), takeExtension, addExtension)
-import Data.List (intercalate)
+import Control.Monad.Except (throwError)
+import Control.Monad.Trans (lift)
+import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord, toLower)
+import Data.Default
+import Data.List (intercalate, isPrefixOf)
import qualified Data.Map as M
-import qualified Control.Exception as E
-import Text.Pandoc.Highlighting (fromListingsLanguage)
+import Data.Maybe (fromMaybe, maybeToList)
+import qualified Data.Set as Set
+import Data.Text (Text)
+import qualified Data.Text as T
+import Safe (minimumDef)
+import System.FilePath (addExtension, replaceExtension, takeExtension)
+import Text.Pandoc.BCP47 (Lang (..), renderLang)
+import Text.Pandoc.Builder
+import Text.Pandoc.Class (PandocMonad, PandocPure, getResourcePath, lookupEnv,
+ readFileFromDirs, report, setResourcePath,
+ setTranslations, translateTerm, trace)
+import Text.Pandoc.Error (PandocError (PandocMacroLoop, PandocParseError, PandocParsecError))
+import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
import Text.Pandoc.ImageSize (numUnit, showFl)
-import Text.Pandoc.Error
+import Text.Pandoc.Logging
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline,
+ optional, space, spaces, withRaw, (<|>))
+import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..),
+ Tok (..), TokType (..))
+import Text.Pandoc.Shared
+import qualified Text.Pandoc.Translations as Translations
+import Text.Pandoc.Walk
+import Text.Parsec.Pos
+import qualified Text.Pandoc.Builder as B
--- | Parse LaTeX from string and return 'Pandoc' document.
-readLaTeX :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assumes @'\n'@ line endings)
- -> Either PandocError Pandoc
-readLaTeX opts = readWith parseLaTeX def{ stateOptions = opts }
+-- for debugging:
+-- import Text.Pandoc.Extensions (getDefaultExtensions)
+-- import Text.Pandoc.Class (runIOorExplode, PandocIO)
+-- import Debug.Trace (traceShowId)
-parseLaTeX :: LP Pandoc
+-- | Parse LaTeX from string and return 'Pandoc' document.
+readLaTeX :: PandocMonad m
+ => ReaderOptions -- ^ Reader options
+ -> Text -- ^ String to parse (assumes @'\n'@ line endings)
+ -> m Pandoc
+readLaTeX opts ltx = do
+ parsed <- runParserT parseLaTeX def{ sOptions = opts } "source"
+ (tokenize "source" (crFilter ltx))
+ case parsed of
+ Right result -> return result
+ Left e -> throwError $ PandocParsecError (T.unpack ltx) e
+
+parseLaTeX :: PandocMonad m => LP m Pandoc
parseLaTeX = do
bs <- blocks
eof
st <- getState
- let meta = stateMeta st
- let (Pandoc _ bs') = doc bs
+ let meta = sMeta st
+ let doc' = doc bs
+ let headerLevel (Header n _ _) = [n]
+ headerLevel _ = []
+ let bottomLevel = minimumDef 1 $ query headerLevel doc'
+ let adjustHeaders m (Header n attr ils) = Header (n+m) attr ils
+ adjustHeaders _ x = x
+ let (Pandoc _ bs') =
+ -- handle the case where you have \part or \chapter
+ (if bottomLevel < 1
+ then walk (adjustHeaders (1 - bottomLevel))
+ else id) $
+ walk (resolveRefs (sLabels st)) doc'
return $ Pandoc meta bs'
-type LP = Parser String ParserState
-
-anyControlSeq :: LP String
-anyControlSeq = do
- char '\\'
- next <- option '\n' anyChar
- case next of
- '\n' -> return ""
- c | isLetter c -> (c:) <$> (many letter <* optional sp)
- | otherwise -> return [c]
-
-controlSeq :: String -> LP String
-controlSeq name = try $ do
- char '\\'
- case name of
- "" -> mzero
- [c] | not (isLetter c) -> string [c]
- cs -> string cs <* notFollowedBy letter <* optional sp
- return name
-
-dimenarg :: LP String
-dimenarg = try $ do
- ch <- option "" $ string "="
- num <- many1 digit
- dim <- oneOfStrings ["pt","pc","in","bp","cm","mm","dd","cc","sp"]
- return $ ch ++ num ++ dim
-
-sp :: LP ()
-sp = whitespace <|> endline
-
-whitespace :: LP ()
-whitespace = skipMany1 $ satisfy (\c -> c == ' ' || c == '\t')
-
-endline :: LP ()
-endline = try (newline >> lookAhead anyChar >> notFollowedBy blankline)
+resolveRefs :: M.Map String [Inline] -> Inline -> Inline
+resolveRefs labels x@(Link (ident,classes,kvs) _ _) =
+ case (lookup "reference-type" kvs,
+ lookup "reference" kvs) of
+ (Just "ref", Just lab) ->
+ case M.lookup lab labels of
+ Just txt -> Link (ident,classes,kvs) txt ('#':lab, "")
+ Nothing -> x
+ _ -> x
+resolveRefs _ x = x
+
+
+-- testParser :: LP PandocIO a -> Text -> IO a
+-- testParser p t = do
+-- res <- runIOorExplode (runParserT p defaultLaTeXState{
+-- sOptions = def{ readerExtensions =
+-- enableExtension Ext_raw_tex $
+-- getDefaultExtensions "latex" }} "source" (tokenize "source" t))
+-- case res of
+-- Left e -> error (show e)
+-- Right r -> return r
+
+newtype HeaderNum = HeaderNum [Int]
+ deriving (Show)
+
+renderHeaderNum :: HeaderNum -> String
+renderHeaderNum (HeaderNum xs) =
+ intercalate "." (map show xs)
+
+incrementHeaderNum :: Int -> HeaderNum -> HeaderNum
+incrementHeaderNum level (HeaderNum ns) = HeaderNum $
+ case reverse (take level (ns ++ repeat 0)) of
+ (x:xs) -> reverse (x+1 : xs)
+ [] -> [] -- shouldn't happen
+
+data LaTeXState = LaTeXState{ sOptions :: ReaderOptions
+ , sMeta :: Meta
+ , sQuoteContext :: QuoteContext
+ , sMacros :: M.Map Text Macro
+ , sContainers :: [String]
+ , sHeaders :: M.Map Inlines String
+ , sLogMessages :: [LogMessage]
+ , sIdentifiers :: Set.Set String
+ , sVerbatimMode :: Bool
+ , sCaption :: Maybe Inlines
+ , sInListItem :: Bool
+ , sInTableCell :: Bool
+ , sLastHeaderNum :: HeaderNum
+ , sLabels :: M.Map String [Inline]
+ , sToggles :: M.Map String Bool
+ }
+ deriving Show
+
+defaultLaTeXState :: LaTeXState
+defaultLaTeXState = LaTeXState{ sOptions = def
+ , sMeta = nullMeta
+ , sQuoteContext = NoQuote
+ , sMacros = M.empty
+ , sContainers = []
+ , sHeaders = M.empty
+ , sLogMessages = []
+ , sIdentifiers = Set.empty
+ , sVerbatimMode = False
+ , sCaption = Nothing
+ , sInListItem = False
+ , sInTableCell = False
+ , sLastHeaderNum = HeaderNum []
+ , sLabels = M.empty
+ , sToggles = M.empty
+ }
+
+instance PandocMonad m => HasQuoteContext LaTeXState m where
+ getQuoteContext = sQuoteContext <$> getState
+ withQuoteContext context parser = do
+ oldState <- getState
+ let oldQuoteContext = sQuoteContext oldState
+ setState oldState { sQuoteContext = context }
+ result <- parser
+ newState <- getState
+ setState newState { sQuoteContext = oldQuoteContext }
+ return result
+
+instance HasLogMessages LaTeXState where
+ addLogMessage msg st = st{ sLogMessages = msg : sLogMessages st }
+ getLogMessages st = reverse $ sLogMessages st
+
+instance HasIdentifierList LaTeXState where
+ extractIdentifierList = sIdentifiers
+ updateIdentifierList f st = st{ sIdentifiers = f $ sIdentifiers st }
+
+instance HasIncludeFiles LaTeXState where
+ getIncludeFiles = sContainers
+ addIncludeFile f s = s{ sContainers = f : sContainers s }
+ dropLatestIncludeFile s = s { sContainers = drop 1 $ sContainers s }
+
+instance HasHeaderMap LaTeXState where
+ extractHeaderMap = sHeaders
+ updateHeaderMap f st = st{ sHeaders = f $ sHeaders st }
+
+instance HasMacros LaTeXState where
+ extractMacros st = sMacros st
+ updateMacros f st = st{ sMacros = f (sMacros st) }
+
+instance HasReaderOptions LaTeXState where
+ extractReaderOptions = sOptions
+
+instance HasMeta LaTeXState where
+ setMeta field val st =
+ st{ sMeta = setMeta field val $ sMeta st }
+ deleteMeta field st =
+ st{ sMeta = deleteMeta field $ sMeta st }
+
+instance Default LaTeXState where
+ def = defaultLaTeXState
+
+type LP m = ParserT [Tok] LaTeXState m
+
+withVerbatimMode :: PandocMonad m => LP m a -> LP m a
+withVerbatimMode parser = do
+ updateState $ \st -> st{ sVerbatimMode = True }
+ result <- parser
+ updateState $ \st -> st{ sVerbatimMode = False }
+ return result
+
+rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s)
+ => LP m a -> ParserT String s m (a, String)
+rawLaTeXParser parser = do
+ inp <- getInput
+ let toks = tokenize "source" $ T.pack inp
+ pstate <- getState
+ let lstate = def{ sOptions = extractReaderOptions pstate
+ , sMacros = extractMacros pstate }
+ let rawparser = (,) <$> withRaw parser <*> getState
+ res <- lift $ runParserT rawparser lstate "chunk" toks
+ case res of
+ Left _ -> mzero
+ Right ((val, raw), st) -> do
+ updateState (updateMacros (sMacros st <>))
+ rawstring <- takeP (T.length (untokenize raw))
+ return (val, rawstring)
+
+applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s)
+ => String -> ParserT String s m String
+applyMacros s = (guardDisabled Ext_latex_macros >> return s) <|>
+ do let retokenize = doMacros 0 *>
+ (toksToString <$> many (satisfyTok (const True)))
+ pstate <- getState
+ let lstate = def{ sOptions = extractReaderOptions pstate
+ , sMacros = extractMacros pstate }
+ res <- runParserT retokenize lstate "math" (tokenize "math" (T.pack s))
+ case res of
+ Left e -> fail (show e)
+ Right s' -> return s'
+
+rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s)
+ => ParserT String s m String
+rawLaTeXBlock = do
+ lookAhead (try (char '\\' >> letter))
+ -- we don't want to apply newly defined latex macros to their own
+ -- definitions:
+ snd <$> rawLaTeXParser macroDef
+ <|> ((snd <$> rawLaTeXParser (environment <|> blockCommand)) >>= applyMacros)
+
+rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
+ => ParserT String s m String
+rawLaTeXInline = do
+ lookAhead (try (char '\\' >> letter))
+ rawLaTeXParser (inlineEnvironment <|> inlineCommand') >>= applyMacros . snd
+
+inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines
+inlineCommand = do
+ lookAhead (try (char '\\' >> letter))
+ fst <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand')
+
+tokenize :: SourceName -> Text -> [Tok]
+tokenize sourcename = totoks (initialPos sourcename)
+
+totoks :: SourcePos -> Text -> [Tok]
+totoks pos t =
+ case T.uncons t of
+ Nothing -> []
+ Just (c, rest)
+ | c == '\n' ->
+ Tok pos Newline "\n"
+ : totoks (setSourceColumn (incSourceLine pos 1) 1) rest
+ | isSpaceOrTab c ->
+ let (sps, rest') = T.span isSpaceOrTab t
+ in Tok pos Spaces sps
+ : totoks (incSourceColumn pos (T.length sps))
+ rest'
+ | isAlphaNum c ->
+ let (ws, rest') = T.span isAlphaNum t
+ in Tok pos Word ws
+ : totoks (incSourceColumn pos (T.length ws)) rest'
+ | c == '%' ->
+ let (cs, rest') = T.break (== '\n') rest
+ in Tok pos Comment ("%" <> cs)
+ : totoks (incSourceColumn pos (1 + T.length cs)) rest'
+ | c == '\\' ->
+ case T.uncons rest of
+ Nothing -> [Tok pos (CtrlSeq " ") "\\"]
+ Just (d, rest')
+ | isLetterOrAt d ->
+ -- \makeatletter is common in macro defs;
+ -- ideally we should make tokenization sensitive
+ -- to \makeatletter and \makeatother, but this is
+ -- probably best for now
+ let (ws, rest'') = T.span isLetterOrAt rest
+ (ss, rest''') = T.span isSpaceOrTab rest''
+ in Tok pos (CtrlSeq ws) ("\\" <> ws <> ss)
+ : totoks (incSourceColumn pos
+ (1 + T.length ws + T.length ss)) rest'''
+ | isSpaceOrTab d || d == '\n' ->
+ let (w1, r1) = T.span isSpaceOrTab rest
+ (w2, (w3, r3)) = case T.uncons r1 of
+ Just ('\n', r2)
+ -> (T.pack "\n",
+ T.span isSpaceOrTab r2)
+ _ -> (mempty, (mempty, r1))
+ ws = "\\" <> w1 <> w2 <> w3
+ in case T.uncons r3 of
+ Just ('\n', _) ->
+ Tok pos (CtrlSeq " ") ("\\" <> w1)
+ : totoks (incSourceColumn pos (T.length ws))
+ r1
+ _ ->
+ Tok pos (CtrlSeq " ") ws
+ : totoks (incSourceColumn pos (T.length ws))
+ r3
+ | otherwise ->
+ Tok pos (CtrlSeq (T.singleton d)) (T.pack [c,d])
+ : totoks (incSourceColumn pos 2) rest'
+ | c == '#' ->
+ let (t1, t2) = T.span (\d -> d >= '0' && d <= '9') rest
+ in case safeRead (T.unpack t1) of
+ Just i ->
+ Tok pos (Arg i) ("#" <> t1)
+ : totoks (incSourceColumn pos (1 + T.length t1)) t2
+ Nothing ->
+ Tok pos Symbol "#"
+ : totoks (incSourceColumn pos 1) t2
+ | c == '^' ->
+ case T.uncons rest of
+ Just ('^', rest') ->
+ case T.uncons rest' of
+ Just (d, rest'')
+ | isLowerHex d ->
+ case T.uncons rest'' of
+ Just (e, rest''') | isLowerHex e ->
+ Tok pos Esc2 (T.pack ['^','^',d,e])
+ : totoks (incSourceColumn pos 4) rest'''
+ _ ->
+ Tok pos Esc1 (T.pack ['^','^',d])
+ : totoks (incSourceColumn pos 3) rest''
+ | d < '\128' ->
+ Tok pos Esc1 (T.pack ['^','^',d])
+ : totoks (incSourceColumn pos 3) rest''
+ _ -> Tok pos Symbol "^" :
+ Tok (incSourceColumn pos 1) Symbol "^" :
+ totoks (incSourceColumn pos 2) rest'
+ _ -> Tok pos Symbol "^"
+ : totoks (incSourceColumn pos 1) rest
+ | otherwise ->
+ Tok pos Symbol (T.singleton c) : totoks (incSourceColumn pos 1) rest
+
+isSpaceOrTab :: Char -> Bool
+isSpaceOrTab ' ' = True
+isSpaceOrTab '\t' = True
+isSpaceOrTab _ = False
+
+isLetterOrAt :: Char -> Bool
+isLetterOrAt '@' = True
+isLetterOrAt c = isLetter c
isLowerHex :: Char -> Bool
isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f'
-tildeEscape :: LP Char
-tildeEscape = try $ do
- string "^^"
- c <- satisfy (\x -> x >= '\0' && x <= '\128')
- d <- if isLowerHex c
- then option "" $ count 1 (satisfy isLowerHex)
- else return ""
- if null d
- then case ord c of
- x | x >= 64 && x <= 127 -> return $ chr (x - 64)
- | otherwise -> return $ chr (x + 64)
- else return $ chr $ read ('0':'x':c:d)
-
-comment :: LP ()
-comment = do
- char '%'
- skipMany (satisfy (/='\n'))
- optional newline
- return ()
+untokenize :: [Tok] -> Text
+untokenize = mconcat . map untoken
+
+untoken :: Tok -> Text
+untoken (Tok _ _ t) = t
+
+satisfyTok :: PandocMonad m => (Tok -> Bool) -> LP m Tok
+satisfyTok f =
+ try $ do
+ res <- tokenPrim (T.unpack . untoken) updatePos matcher
+ doMacros 0 -- apply macros on remaining input stream
+ return res
+ where matcher t | f t = Just t
+ | otherwise = Nothing
+ updatePos :: SourcePos -> Tok -> [Tok] -> SourcePos
+ updatePos _spos _ (Tok pos _ _ : _) = pos
+ updatePos spos _ [] = incSourceColumn spos 1
+
+doMacros :: PandocMonad m => Int -> LP m ()
+doMacros n = do
+ verbatimMode <- sVerbatimMode <$> getState
+ unless verbatimMode $ do
+ inp <- getInput
+ case inp of
+ Tok spos (CtrlSeq "begin") _ : Tok _ Symbol "{" :
+ Tok _ Word name : Tok _ Symbol "}" : ts
+ -> handleMacros spos name ts
+ Tok spos (CtrlSeq "end") _ : Tok _ Symbol "{" :
+ Tok _ Word name : Tok _ Symbol "}" : ts
+ -> handleMacros spos ("end" <> name) ts
+ Tok _ (CtrlSeq "expandafter") _ : t : ts
+ -> do setInput ts
+ doMacros n
+ getInput >>= setInput . combineTok t
+ Tok spos (CtrlSeq name) _ : ts
+ -> handleMacros spos name ts
+ _ -> return ()
+ where combineTok (Tok spos (CtrlSeq name) x) (Tok _ Word w : ts)
+ | T.all isLetterOrAt w =
+ Tok spos (CtrlSeq (name <> w)) (x1 <> w <> x2) : ts
+ where (x1, x2) = T.break isSpaceOrTab x
+ combineTok t ts = t:ts
+ handleMacros spos name ts = do
+ macros <- sMacros <$> getState
+ case M.lookup name macros of
+ Nothing -> return ()
+ Just (Macro expansionPoint numargs optarg newtoks) -> do
+ setInput ts
+ let getarg = try $ spaces >> bracedOrToken
+ args <- case optarg of
+ Nothing -> count numargs getarg
+ Just o ->
+ (:) <$> option o bracketedToks
+ <*> count (numargs - 1) getarg
+ -- first boolean param is true if we're tokenizing
+ -- an argument (in which case we don't want to
+ -- expand #1 etc.)
+ let addTok False (Tok _ (Arg i) _) acc | i > 0
+ , i <= numargs =
+ foldr (addTok True) acc (args !! (i - 1))
+ -- add space if needed after control sequence
+ -- see #4007
+ addTok _ (Tok _ (CtrlSeq x) txt)
+ acc@(Tok _ Word _ : _)
+ | not (T.null txt) &&
+ isLetter (T.last txt) =
+ Tok spos (CtrlSeq x) (txt <> " ") : acc
+ addTok _ t acc = setpos spos t : acc
+ ts' <- getInput
+ setInput $ foldr (addTok False) ts' newtoks
+ case expansionPoint of
+ ExpandWhenUsed ->
+ if n > 20 -- detect macro expansion loops
+ then throwError $ PandocMacroLoop (T.unpack name)
+ else doMacros (n + 1)
+ ExpandWhenDefined -> return ()
+
+
+setpos :: SourcePos -> Tok -> Tok
+setpos spos (Tok _ tt txt) = Tok spos tt txt
+
+anyControlSeq :: PandocMonad m => LP m Tok
+anyControlSeq = satisfyTok isCtrlSeq
+ where isCtrlSeq (Tok _ (CtrlSeq _) _) = True
+ isCtrlSeq _ = False
+
+anySymbol :: PandocMonad m => LP m Tok
+anySymbol = satisfyTok isSym
+ where isSym (Tok _ Symbol _) = True
+ isSym _ = False
+
+spaces :: PandocMonad m => LP m ()
+spaces = skipMany (satisfyTok (tokTypeIn [Comment, Spaces, Newline]))
+
+spaces1 :: PandocMonad m => LP m ()
+spaces1 = skipMany1 (satisfyTok (tokTypeIn [Comment, Spaces, Newline]))
+
+tokTypeIn :: [TokType] -> Tok -> Bool
+tokTypeIn toktypes (Tok _ tt _) = tt `elem` toktypes
+
+controlSeq :: PandocMonad m => Text -> LP m Tok
+controlSeq name = satisfyTok isNamed
+ where isNamed (Tok _ (CtrlSeq n) _) = n == name
+ isNamed _ = False
+
+symbol :: PandocMonad m => Char -> LP m Tok
+symbol c = satisfyTok isc
+ where isc (Tok _ Symbol d) = case T.uncons d of
+ Just (c',_) -> c == c'
+ _ -> False
+ isc _ = False
+
+symbolIn :: PandocMonad m => [Char] -> LP m Tok
+symbolIn cs = satisfyTok isInCs
+ where isInCs (Tok _ Symbol d) = case T.uncons d of
+ Just (c,_) -> c `elem` cs
+ _ -> False
+ isInCs _ = False
+
+sp :: PandocMonad m => LP m ()
+sp = whitespace <|> endline
-bgroup :: LP ()
+whitespace :: PandocMonad m => LP m ()
+whitespace = () <$ satisfyTok isSpaceTok
+ where isSpaceTok (Tok _ Spaces _) = True
+ isSpaceTok _ = False
+
+newlineTok :: PandocMonad m => LP m ()
+newlineTok = () <$ satisfyTok isNewlineTok
+
+isNewlineTok :: Tok -> Bool
+isNewlineTok (Tok _ Newline _) = True
+isNewlineTok _ = False
+
+comment :: PandocMonad m => LP m ()
+comment = () <$ satisfyTok isCommentTok
+ where isCommentTok (Tok _ Comment _) = True
+ isCommentTok _ = False
+
+anyTok :: PandocMonad m => LP m Tok
+anyTok = satisfyTok (const True)
+
+endline :: PandocMonad m => LP m ()
+endline = try $ do
+ newlineTok
+ lookAhead anyTok
+ notFollowedBy blankline
+
+blankline :: PandocMonad m => LP m ()
+blankline = try $ skipMany whitespace *> newlineTok
+
+primEscape :: PandocMonad m => LP m Char
+primEscape = do
+ Tok _ toktype t <- satisfyTok (tokTypeIn [Esc1, Esc2])
+ case toktype of
+ Esc1 -> case T.uncons (T.drop 2 t) of
+ Just (c, _)
+ | c >= '\64' && c <= '\127' -> return (chr (ord c - 64))
+ | otherwise -> return (chr (ord c + 64))
+ Nothing -> fail "Empty content of Esc1"
+ Esc2 -> case safeRead ('0':'x':T.unpack (T.drop 2 t)) of
+ Just x -> return (chr x)
+ Nothing -> fail $ "Could not read: " ++ T.unpack t
+ _ -> fail "Expected an Esc1 or Esc2 token" -- should not happen
+
+bgroup :: PandocMonad m => LP m Tok
bgroup = try $ do
- skipMany (spaceChar <|> try (newline <* notFollowedBy blankline))
- () <$ char '{'
- <|> () <$ controlSeq "bgroup"
- <|> () <$ controlSeq "begingroup"
-
-egroup :: LP ()
-egroup = () <$ char '}'
- <|> () <$ controlSeq "egroup"
- <|> () <$ controlSeq "endgroup"
-
-grouped :: Monoid a => LP a -> LP a
-grouped parser = try $ bgroup *> (mconcat <$> manyTill parser egroup)
-
-braced :: LP String
-braced = bgroup *> (concat <$> manyTill
- ( many1 (satisfy (\c -> c /= '\\' && c /= '}' && c /= '{'))
- <|> try (string "\\}")
- <|> try (string "\\{")
- <|> try (string "\\\\")
- <|> ((\x -> "{" ++ x ++ "}") <$> braced)
- <|> count 1 anyChar
- ) egroup)
-
-bracketed :: Monoid a => LP a -> LP a
-bracketed parser = try $ char '[' *> (mconcat <$> manyTill parser (char ']'))
-
-mathDisplay :: LP String -> LP Inlines
-mathDisplay p = displayMath <$> (try p >>= applyMacros' . trim)
-
-mathInline :: LP String -> LP Inlines
-mathInline p = math <$> (try p >>= applyMacros')
-
-mathChars :: LP String
-mathChars =
- concat <$> many (escapedChar
- <|> (snd <$> withRaw braced)
- <|> many1 (satisfy isOrdChar))
- where escapedChar = try $ do char '\\'
- c <- anyChar
- return ['\\',c]
- isOrdChar '$' = False
- isOrdChar '{' = False
- isOrdChar '}' = False
- isOrdChar '\\' = False
- isOrdChar _ = True
-
-quoted' :: (Inlines -> Inlines) -> LP String -> LP () -> LP Inlines
-quoted' f starter ender = do
- startchs <- starter
- smart <- getOption readerSmart
- if smart
- then do
- ils <- many (notFollowedBy ender >> inline)
- (ender >> return (f (mconcat ils))) <|>
- (<> mconcat ils) <$>
- lit (case startchs of
- "``" -> "“"
- "`" -> "‘"
- _ -> startchs)
- else lit startchs
-
-doubleQuote :: LP Inlines
-doubleQuote = do
- quoted' doubleQuoted (try $ string "``") (void $ try $ string "''")
- <|> quoted' doubleQuoted (string "“") (void $ char '”')
- -- the following is used by babel for localized quotes:
- <|> quoted' doubleQuoted (try $ string "\"`") (void $ try $ string "\"'")
- <|> quoted' doubleQuoted (string "\"") (void $ char '"')
-
-singleQuote :: LP Inlines
-singleQuote = do
- smart <- getOption readerSmart
- if smart
- then quoted' singleQuoted (string "`") (try $ char '\'' >> notFollowedBy letter)
- <|> quoted' singleQuoted (string "‘") (try $ char '’' >> notFollowedBy letter)
- else str <$> many1 (oneOf "`\'‘’")
-
-inline :: LP Inlines
-inline = (mempty <$ comment)
- <|> (space <$ whitespace)
- <|> (softbreak <$ endline)
- <|> inlineText
- <|> inlineCommand
- <|> inlineEnvironment
- <|> inlineGroup
- <|> (char '-' *> option (str "-")
- (char '-' *> option (str "–") (str "—" <$ char '-')))
- <|> doubleQuote
- <|> singleQuote
- <|> (str "”" <$ try (string "''"))
- <|> (str "”" <$ char '”')
- <|> (str "’" <$ char '\'')
- <|> (str "’" <$ char '’')
- <|> (str "\160" <$ char '~')
- <|> mathDisplay (string "$$" *> mathChars <* string "$$")
- <|> mathInline (char '$' *> mathChars <* char '$')
- <|> (guardEnabled Ext_literate_haskell *> char '|' *> doLHSverb)
- <|> (str . (:[]) <$> tildeEscape)
- <|> (str . (:[]) <$> oneOf "[]")
- <|> (str . (:[]) <$> oneOf "#&~^'`\"[]") -- TODO print warning?
- -- <|> (str <$> count 1 (satisfy (\c -> c /= '\\' && c /='\n' && c /='}' && c /='{'))) -- eat random leftover characters
-
-inlines :: LP Inlines
-inlines = mconcat <$> many (notFollowedBy (char '}') *> inline)
-
-inlineGroup :: LP Inlines
+ skipMany sp
+ symbol '{' <|> controlSeq "bgroup" <|> controlSeq "begingroup"
+
+egroup :: PandocMonad m => LP m Tok
+egroup = symbol '}' <|> controlSeq "egroup" <|> controlSeq "endgroup"
+
+grouped :: (PandocMonad m, Monoid a) => LP m a -> LP m a
+grouped parser = try $ do
+ bgroup
+ -- first we check for an inner 'grouped', because
+ -- {{a,b}} should be parsed the same as {a,b}
+ try (grouped parser <* egroup) <|> (mconcat <$> manyTill parser egroup)
+
+braced :: PandocMonad m => LP m [Tok]
+braced = bgroup *> braced' 1
+ where braced' (n :: Int) =
+ handleEgroup n <|> handleBgroup n <|> handleOther n
+ handleEgroup n = do
+ t <- egroup
+ if n == 1
+ then return []
+ else (t:) <$> braced' (n - 1)
+ handleBgroup n = do
+ t <- bgroup
+ (t:) <$> braced' (n + 1)
+ handleOther n = do
+ t <- anyTok
+ (t:) <$> braced' n
+
+bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a
+bracketed parser = try $ do
+ symbol '['
+ mconcat <$> manyTill parser (symbol ']')
+
+dimenarg :: PandocMonad m => LP m Text
+dimenarg = try $ do
+ ch <- option False $ True <$ symbol '='
+ Tok _ _ s <- satisfyTok isWordTok
+ guard $ T.take 2 (T.reverse s) `elem`
+ ["pt","pc","in","bp","cm","mm","dd","cc","sp"]
+ let num = T.take (T.length s - 2) s
+ guard $ T.length num > 0
+ guard $ T.all isDigit num
+ return $ T.pack ['=' | ch] <> s
+
+-- inline elements:
+
+word :: PandocMonad m => LP m Inlines
+word = (str . T.unpack . untoken) <$> satisfyTok isWordTok
+
+regularSymbol :: PandocMonad m => LP m Inlines
+regularSymbol = (str . T.unpack . untoken) <$> satisfyTok isRegularSymbol
+ where isRegularSymbol (Tok _ Symbol t) = not $ T.any isSpecial t
+ isRegularSymbol _ = False
+ isSpecial c = c `Set.member` specialChars
+
+specialChars :: Set.Set Char
+specialChars = Set.fromList "#$%&~_^\\{}"
+
+isWordTok :: Tok -> Bool
+isWordTok (Tok _ Word _) = True
+isWordTok _ = False
+
+inlineGroup :: PandocMonad m => LP m Inlines
inlineGroup = do
ils <- grouped inline
if isNull ils
@@ -247,386 +629,19 @@ inlineGroup = do
-- we need the span so we can detitlecase bibtex entries;
-- we need to know when something is {C}apitalized
-block :: LP Blocks
-block = (mempty <$ comment)
- <|> (mempty <$ ((spaceChar <|> newline) *> spaces))
- <|> environment
- <|> macro
- <|> blockCommand
- <|> paragraph
- <|> grouped block
- <|> (mempty <$ char '&') -- loose & in table environment
-
-
-blocks :: LP Blocks
-blocks = mconcat <$> many block
-
-getRawCommand :: String -> LP String
-getRawCommand name' = do
- rawargs <- withRaw (many (try (optional sp *> opt)) *>
- option "" (try (optional sp *> dimenarg)) *>
- many braced)
- return $ '\\' : name' ++ snd rawargs
-
-lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
-lookupListDefault d = (fromMaybe d .) . lookupList
- where
- lookupList l m = msum $ map (`M.lookup` m) l
-
-blockCommand :: LP Blocks
-blockCommand = try $ do
- name <- anyControlSeq
- guard $ name /= "begin" && name /= "end"
- star <- option "" (string "*" <* optional sp)
- let name' = name ++ star
- let raw = do
- rawcommand <- getRawCommand name'
- transformed <- applyMacros' rawcommand
- guard $ transformed /= rawcommand
- notFollowedBy $ parseFromString inlines transformed
- parseFromString blocks transformed
- lookupListDefault raw [name',name] blockCommands
-
-inBrackets :: Inlines -> Inlines
-inBrackets x = str "[" <> x <> str "]"
-
--- eat an optional argument and one or more arguments in braces
-ignoreInlines :: String -> (String, LP Inlines)
-ignoreInlines name = (name, doraw <|> (mempty <$ optargs))
- where optargs = skipopts *> skipMany (try $ optional sp *> braced)
- contseq = '\\':name
- doraw = (rawInline "latex" . (contseq ++) . snd) <$>
- (getOption readerParseRaw >>= guard >> withRaw optargs)
-
-ignoreBlocks :: String -> (String, LP Blocks)
-ignoreBlocks name = (name, doraw <|> (mempty <$ optargs))
- where optargs = skipopts *> skipMany (try $ optional sp *> braced)
- contseq = '\\':name
- doraw = (rawBlock "latex" . (contseq ++) . snd) <$>
- (getOption readerParseRaw >>= guard >> withRaw optargs)
-
-blockCommands :: M.Map String (LP Blocks)
-blockCommands = M.fromList $
- [ ("par", mempty <$ skipopts)
- , ("title", mempty <$ (skipopts *>
- (grouped inline >>= addMeta "title")
- <|> (grouped block >>= addMeta "title")))
- , ("subtitle", mempty <$ (skipopts *> tok >>= addMeta "subtitle"))
- , ("author", mempty <$ (skipopts *> authors))
- -- -- in letter class, temp. store address & sig as title, author
- , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
- , ("signature", mempty <$ (skipopts *> authors))
- , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
- -- sectioning
- , ("chapter", updateState (\s -> s{ stateHasChapters = True })
- *> section nullAttr 0)
- , ("chapter*", updateState (\s -> s{ stateHasChapters = True })
- *> section ("",["unnumbered"],[]) 0)
- , ("section", section nullAttr 1)
- , ("section*", section ("",["unnumbered"],[]) 1)
- , ("subsection", section nullAttr 2)
- , ("subsection*", section ("",["unnumbered"],[]) 2)
- , ("subsubsection", section nullAttr 3)
- , ("subsubsection*", section ("",["unnumbered"],[]) 3)
- , ("paragraph", section nullAttr 4)
- , ("paragraph*", section ("",["unnumbered"],[]) 4)
- , ("subparagraph", section nullAttr 5)
- , ("subparagraph*", section ("",["unnumbered"],[]) 5)
- -- beamer slides
- , ("frametitle", section nullAttr 3)
- , ("framesubtitle", section nullAttr 4)
- -- letters
- , ("opening", (para . trimInlines) <$> (skipopts *> tok))
- , ("closing", skipopts *> closing)
- --
- , ("hrule", pure horizontalRule)
- , ("strut", pure mempty)
- , ("rule", skipopts *> tok *> tok *> pure horizontalRule)
- , ("item", skipopts *> looseItem)
- , ("documentclass", skipopts *> braced *> preamble)
- , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
- , ("caption", skipopts *> setCaption)
- , ("PandocStartInclude", startInclude)
- , ("PandocEndInclude", endInclude)
- , ("bibliography", mempty <$ (skipopts *> braced >>=
- addMeta "bibliography" . splitBibs))
- , ("addbibresource", mempty <$ (skipopts *> braced >>=
- addMeta "bibliography" . splitBibs))
- ] ++ map ignoreBlocks
- -- these commands will be ignored unless --parse-raw is specified,
- -- in which case they will appear as raw latex blocks
- [ "newcommand", "renewcommand", "newenvironment", "renewenvironment"
- -- newcommand, etc. should be parsed by macro, but we need this
- -- here so these aren't parsed as inline commands to ignore
- , "special", "pdfannot", "pdfstringdef"
- , "bibliographystyle"
- , "maketitle", "makeindex", "makeglossary"
- , "addcontentsline", "addtocontents", "addtocounter"
- -- \ignore{} is used conventionally in literate haskell for definitions
- -- that are to be processed by the compiler but not printed.
- , "ignore"
- , "hyperdef"
- , "markboth", "markright", "markleft"
- , "newpage"
- ]
-
-addMeta :: ToMetaValue a => String -> a -> LP ()
-addMeta field val = updateState $ \st ->
- st{ stateMeta = addMetaField field val $ stateMeta st }
-
-splitBibs :: String -> [Inlines]
-splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
-
-setCaption :: LP Blocks
-setCaption = do
- ils <- tok
- mblabel <- option Nothing $
- try $ spaces' >> controlSeq "label" >> (Just <$> tok)
- let ils' = case mblabel of
- Just lab -> ils <> spanWith
- ("",[],[("data-label", stringify lab)]) mempty
- Nothing -> ils
- updateState $ \st -> st{ stateCaption = Just ils' }
- return mempty
-
-resetCaption :: LP ()
-resetCaption = updateState $ \st -> st{ stateCaption = Nothing }
-
-authors :: LP ()
-authors = try $ do
- char '{'
- let oneAuthor = mconcat <$>
- many1 (notFollowedBy' (controlSeq "and") >>
- (inline <|> mempty <$ blockCommand))
- -- skip e.g. \vspace{10pt}
- auths <- sepBy oneAuthor (controlSeq "and")
- char '}'
- addMeta "author" (map trimInlines auths)
-
-section :: Attr -> Int -> LP Blocks
-section (ident, classes, kvs) lvl = do
- hasChapters <- stateHasChapters `fmap` getState
- let lvl' = if hasChapters then lvl + 1 else lvl
- skipopts
- contents <- grouped inline
- lab <- option ident $ try (spaces' >> controlSeq "label" >> spaces' >> braced)
- attr' <- registerHeader (lab, classes, kvs) contents
- return $ headerWith attr' lvl' contents
-
-inlineCommand :: LP Inlines
-inlineCommand = try $ do
- name <- anyControlSeq
- guard $ name /= "begin" && name /= "end"
- guard $ not $ isBlockCommand name
- parseRaw <- getOption readerParseRaw
- star <- option "" (string "*")
- let name' = name ++ star
- let raw = do
- rawargs <- withRaw
- (skipangles *> skipopts *> option "" dimenarg *> many braced)
- let rawcommand = '\\' : name ++ star ++ snd rawargs
- transformed <- applyMacros' rawcommand
- if transformed /= rawcommand
- then parseFromString inlines transformed
- else if parseRaw
- then return $ rawInline "latex" rawcommand
- else return mempty
- (lookupListDefault mzero [name',name] inlineCommands <*
- optional (try (string "{}")))
- <|> raw
-
-unlessParseRaw :: LP ()
-unlessParseRaw = getOption readerParseRaw >>= guard . not
-
-isBlockCommand :: String -> Bool
-isBlockCommand s = s `M.member` blockCommands
-
-
-inlineEnvironments :: M.Map String (LP Inlines)
-inlineEnvironments = M.fromList
- [ ("displaymath", mathEnv id Nothing "displaymath")
- , ("math", math <$> verbEnv "math")
- , ("equation", mathEnv id Nothing "equation")
- , ("equation*", mathEnv id Nothing "equation*")
- , ("gather", mathEnv id (Just "gathered") "gather")
- , ("gather*", mathEnv id (Just "gathered") "gather*")
- , ("multline", mathEnv id (Just "gathered") "multline")
- , ("multline*", mathEnv id (Just "gathered") "multline*")
- , ("eqnarray", mathEnv id (Just "aligned") "eqnarray")
- , ("eqnarray*", mathEnv id (Just "aligned") "eqnarray*")
- , ("align", mathEnv id (Just "aligned") "align")
- , ("align*", mathEnv id (Just "aligned") "align*")
- , ("alignat", mathEnv id (Just "aligned") "alignat")
- , ("alignat*", mathEnv id (Just "aligned") "alignat*")
- ]
-
-inlineCommands :: M.Map String (LP Inlines)
-inlineCommands = M.fromList $
- [ ("emph", extractSpaces emph <$> tok)
- , ("textit", extractSpaces emph <$> tok)
- , ("textsl", extractSpaces emph <$> tok)
- , ("textsc", extractSpaces smallcaps <$> tok)
- , ("sout", extractSpaces strikeout <$> tok)
- , ("textsuperscript", extractSpaces superscript <$> tok)
- , ("textsubscript", extractSpaces subscript <$> tok)
- , ("textbackslash", lit "\\")
- , ("backslash", lit "\\")
- , ("slash", lit "/")
- , ("textbf", extractSpaces strong <$> tok)
- , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
- , ("ldots", lit "…")
- , ("dots", lit "…")
- , ("mdots", lit "…")
- , ("sim", lit "~")
- , ("label", unlessParseRaw >> (inBrackets <$> tok))
- , ("ref", unlessParseRaw >> (inBrackets <$> tok))
- , ("noindent", unlessParseRaw >> return mempty)
- , ("textgreek", tok)
- , ("sep", lit ",")
- , ("cref", unlessParseRaw >> (inBrackets <$> tok)) -- from cleveref.sty
- , ("(", mathInline $ manyTill anyChar (try $ string "\\)"))
- , ("[", mathDisplay $ manyTill anyChar (try $ string "\\]"))
- , ("ensuremath", mathInline braced)
- , ("texorpdfstring", (\_ x -> x) <$> tok <*> tok)
- , ("P", lit "¶")
- , ("S", lit "§")
- , ("$", lit "$")
- , ("%", lit "%")
- , ("&", lit "&")
- , ("#", lit "#")
- , ("_", lit "_")
- , ("{", lit "{")
- , ("}", lit "}")
- -- old TeX commands
- , ("em", extractSpaces emph <$> inlines)
- , ("it", extractSpaces emph <$> inlines)
- , ("sl", extractSpaces emph <$> inlines)
- , ("bf", extractSpaces strong <$> inlines)
- , ("rm", inlines)
- , ("itshape", extractSpaces emph <$> inlines)
- , ("slshape", extractSpaces emph <$> inlines)
- , ("scshape", extractSpaces smallcaps <$> inlines)
- , ("bfseries", extractSpaces strong <$> inlines)
- , ("/", pure mempty) -- italic correction
- , ("aa", lit "å")
- , ("AA", lit "Å")
- , ("ss", lit "ß")
- , ("o", lit "ø")
- , ("O", lit "Ø")
- , ("L", lit "Ł")
- , ("l", lit "ł")
- , ("ae", lit "æ")
- , ("AE", lit "Æ")
- , ("oe", lit "œ")
- , ("OE", lit "Œ")
- , ("pounds", lit "£")
- , ("euro", lit "€")
- , ("copyright", lit "©")
- , ("textasciicircum", lit "^")
- , ("textasciitilde", lit "~")
- , ("H", try $ tok >>= accent hungarumlaut)
- , ("`", option (str "`") $ try $ tok >>= accent grave)
- , ("'", option (str "'") $ try $ tok >>= accent acute)
- , ("^", option (str "^") $ try $ tok >>= accent circ)
- , ("~", option (str "~") $ try $ tok >>= accent tilde)
- , ("\"", option (str "\"") $ try $ tok >>= accent umlaut)
- , (".", option (str ".") $ try $ tok >>= accent dot)
- , ("=", option (str "=") $ try $ tok >>= accent macron)
- , ("c", option (str "c") $ try $ tok >>= accent cedilla)
- , ("v", option (str "v") $ try $ tok >>= accent hacek)
- , ("u", option (str "u") $ try $ tok >>= accent breve)
- , ("i", lit "i")
- , ("\\", linebreak <$ (optional (bracketed inline) *> spaces'))
- , (",", pure mempty)
- , ("@", pure mempty)
- , (" ", lit "\160")
- , ("ps", pure $ str "PS." <> space)
- , ("TeX", lit "TeX")
- , ("LaTeX", lit "LaTeX")
- , ("bar", lit "|")
- , ("textless", lit "<")
- , ("textgreater", lit ">")
- , ("thanks", (note . mconcat) <$> (char '{' *> manyTill block (char '}')))
- , ("footnote", (note . mconcat) <$> (char '{' *> manyTill block (char '}')))
- , ("verb", doverb)
- , ("lstinline", skipopts *> doverb)
- , ("Verb", doverb)
- , ("texttt", (code . stringify . toList) <$> tok)
- , ("url", (unescapeURL <$> braced) >>= \url ->
- pure (link url "" (str url)))
- , ("href", (unescapeURL <$> braced <* optional sp) >>= \url ->
- tok >>= \lab ->
- pure (link url "" lab))
- , ("includegraphics", do options <- option [] keyvals
- src <- unescapeURL . removeDoubleQuotes <$> braced
- mkImage options src)
- , ("enquote", enquote)
- , ("cite", citation "cite" NormalCitation False)
- , ("Cite", citation "Cite" NormalCitation False)
- , ("citep", citation "citep" NormalCitation False)
- , ("citep*", citation "citep*" NormalCitation False)
- , ("citeal", citation "citeal" NormalCitation False)
- , ("citealp", citation "citealp" NormalCitation False)
- , ("citealp*", citation "citealp*" NormalCitation False)
- , ("autocite", citation "autocite" NormalCitation False)
- , ("smartcite", citation "smartcite" NormalCitation False)
- , ("footcite", inNote <$> citation "footcite" NormalCitation False)
- , ("parencite", citation "parencite" NormalCitation False)
- , ("supercite", citation "supercite" NormalCitation False)
- , ("footcitetext", inNote <$> citation "footcitetext" NormalCitation False)
- , ("citeyearpar", citation "citeyearpar" SuppressAuthor False)
- , ("citeyear", citation "citeyear" SuppressAuthor False)
- , ("autocite*", citation "autocite*" SuppressAuthor False)
- , ("cite*", citation "cite*" SuppressAuthor False)
- , ("parencite*", citation "parencite*" SuppressAuthor False)
- , ("textcite", citation "textcite" AuthorInText False)
- , ("citet", citation "citet" AuthorInText False)
- , ("citet*", citation "citet*" AuthorInText False)
- , ("citealt", citation "citealt" AuthorInText False)
- , ("citealt*", citation "citealt*" AuthorInText False)
- , ("textcites", citation "textcites" AuthorInText True)
- , ("cites", citation "cites" NormalCitation True)
- , ("autocites", citation "autocites" NormalCitation True)
- , ("footcites", inNote <$> citation "footcites" NormalCitation True)
- , ("parencites", citation "parencites" NormalCitation True)
- , ("supercites", citation "supercites" NormalCitation True)
- , ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
- , ("Autocite", citation "Autocite" NormalCitation False)
- , ("Smartcite", citation "Smartcite" NormalCitation False)
- , ("Footcite", citation "Footcite" NormalCitation False)
- , ("Parencite", citation "Parencite" NormalCitation False)
- , ("Supercite", citation "Supercite" NormalCitation False)
- , ("Footcitetext", inNote <$> citation "Footcitetext" NormalCitation False)
- , ("Citeyearpar", citation "Citeyearpar" SuppressAuthor False)
- , ("Citeyear", citation "Citeyear" SuppressAuthor False)
- , ("Autocite*", citation "Autocite*" SuppressAuthor False)
- , ("Cite*", citation "Cite*" SuppressAuthor False)
- , ("Parencite*", citation "Parencite*" SuppressAuthor False)
- , ("Textcite", citation "Textcite" AuthorInText False)
- , ("Textcites", citation "Textcites" AuthorInText True)
- , ("Cites", citation "Cites" NormalCitation True)
- , ("Autocites", citation "Autocites" NormalCitation True)
- , ("Footcites", citation "Footcites" NormalCitation True)
- , ("Parencites", citation "Parencites" NormalCitation True)
- , ("Supercites", citation "Supercites" NormalCitation True)
- , ("Footcitetexts", inNote <$> citation "Footcitetexts" NormalCitation True)
- , ("citetext", complexNatbibCitation NormalCitation)
- , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
- complexNatbibCitation AuthorInText)
- <|> citation "citeauthor" AuthorInText False)
- , ("nocite", mempty <$ (citation "nocite" NormalCitation False >>=
- addMeta "nocite"))
- ] ++ map ignoreInlines
- -- these commands will be ignored unless --parse-raw is specified,
- -- in which case they will appear as raw latex blocks:
- [ "index" ]
+doLHSverb :: PandocMonad m => LP m Inlines
+doLHSverb =
+ (codeWith ("",["haskell"],[]) . T.unpack . untokenize)
+ <$> manyTill (satisfyTok (not . isNewlineTok)) (symbol '|')
-mkImage :: [(String, String)] -> String -> LP Inlines
+mkImage :: PandocMonad m => [(String, String)] -> String -> LP m Inlines
mkImage options src = do
- let replaceTextwidth (k,v) = case numUnit v of
- Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
- _ -> (k, v)
- let kvs = map replaceTextwidth $ filter (\(k,_) -> k `elem` ["width", "height"]) options
+ let replaceTextwidth (k,v) =
+ case numUnit v of
+ Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
+ _ -> (k, v)
+ let kvs = map replaceTextwidth
+ $ filter (\(k,_) -> k `elem` ["width", "height"]) options
let attr = ("",[], kvs)
let alt = str "image"
case takeExtension src of
@@ -635,40 +650,164 @@ mkImage options src = do
return $ imageWith attr (addExtension src defaultExt) "" alt
_ -> return $ imageWith attr src "" alt
-inNote :: Inlines -> Inlines
-inNote ils =
- note $ para $ ils <> str "."
+doxspace :: PandocMonad m => LP m Inlines
+doxspace =
+ (space <$ lookAhead (satisfyTok startsWithLetter)) <|> return mempty
+ where startsWithLetter (Tok _ Word t) =
+ case T.uncons t of
+ Just (c, _) | isLetter c -> True
+ _ -> False
+ startsWithLetter _ = False
-unescapeURL :: String -> String
-unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
- where isEscapable c = c `elem` ("#$%&~_^\\{}" :: String)
-unescapeURL (x:xs) = x:unescapeURL xs
-unescapeURL [] = ""
-enquote :: LP Inlines
+-- converts e.g. \SI{1}[\$]{} to "$ 1" or \SI{1}{\euro} to "1 €"
+dosiunitx :: PandocMonad m => LP m Inlines
+dosiunitx = do
+ skipopts
+ value <- tok
+ valueprefix <- option "" $ bracketed tok
+ unit <- tok
+ let emptyOr160 "" = ""
+ emptyOr160 _ = "\160"
+ return . mconcat $ [valueprefix,
+ emptyOr160 valueprefix,
+ value,
+ emptyOr160 unit,
+ unit]
+
+lit :: String -> LP m Inlines
+lit = pure . str
+
+removeDoubleQuotes :: Text -> Text
+removeDoubleQuotes t =
+ Data.Maybe.fromMaybe t $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
+
+doubleQuote :: PandocMonad m => LP m Inlines
+doubleQuote =
+ quoted' doubleQuoted (try $ count 2 $ symbol '`')
+ (void $ try $ count 2 $ symbol '\'')
+ <|> quoted' doubleQuoted ((:[]) <$> symbol '“') (void $ symbol '”')
+ -- the following is used by babel for localized quotes:
+ <|> quoted' doubleQuoted (try $ sequence [symbol '"', symbol '`'])
+ (void $ try $ sequence [symbol '"', symbol '\''])
+
+singleQuote :: PandocMonad m => LP m Inlines
+singleQuote =
+ quoted' singleQuoted ((:[]) <$> symbol '`')
+ (try $ symbol '\'' >>
+ notFollowedBy (satisfyTok startsWithLetter))
+ <|> quoted' singleQuoted ((:[]) <$> symbol '‘')
+ (try $ symbol '’' >>
+ notFollowedBy (satisfyTok startsWithLetter))
+ where startsWithLetter (Tok _ Word t) =
+ case T.uncons t of
+ Just (c, _) | isLetter c -> True
+ _ -> False
+ startsWithLetter _ = False
+
+quoted' :: PandocMonad m
+ => (Inlines -> Inlines)
+ -> LP m [Tok]
+ -> LP m ()
+ -> LP m Inlines
+quoted' f starter ender = do
+ startchs <- (T.unpack . untokenize) <$> starter
+ smart <- extensionEnabled Ext_smart <$> getOption readerExtensions
+ if smart
+ then do
+ ils <- many (notFollowedBy ender >> inline)
+ (ender >> return (f (mconcat ils))) <|>
+ (<> mconcat ils) <$>
+ lit (case startchs of
+ "``" -> "“"
+ "`" -> "‘"
+ cs -> cs)
+ else lit startchs
+
+enquote :: PandocMonad m => LP m Inlines
enquote = do
skipopts
- context <- stateQuoteContext <$> getState
- if context == InDoubleQuote
+ quoteContext <- sQuoteContext <$> getState
+ if quoteContext == InDoubleQuote
then singleQuoted <$> withQuoteContext InSingleQuote tok
else doubleQuoted <$> withQuoteContext InDoubleQuote tok
-doverb :: LP Inlines
+doAcronym :: PandocMonad m => String -> LP m Inlines
+doAcronym form = do
+ acro <- braced
+ return . mconcat $ [spanWith ("",[],[("acronym-label", toksToString acro),
+ ("acronym-form", "singular+" ++ form)])
+ $ str $ toksToString acro]
+
+doAcronymPlural :: PandocMonad m => String -> LP m Inlines
+doAcronymPlural form = do
+ acro <- braced
+ plural <- lit "s"
+ return . mconcat $ [spanWith ("",[],[("acronym-label", toksToString acro),
+ ("acronym-form", "plural+" ++ form)]) $
+ mconcat [str $ toksToString acro, plural]]
+
+doverb :: PandocMonad m => LP m Inlines
doverb = do
- marker <- anyChar
- code <$> manyTill (satisfy (/='\n')) (char marker)
-
-doLHSverb :: LP Inlines
-doLHSverb = codeWith ("",["haskell"],[]) <$> manyTill (satisfy (/='\n')) (char '|')
+ Tok _ Symbol t <- anySymbol
+ marker <- case T.uncons t of
+ Just (c, ts) | T.null ts -> return c
+ _ -> mzero
+ withVerbatimMode $
+ (code . T.unpack . untokenize) <$>
+ manyTill (verbTok marker) (symbol marker)
+
+verbTok :: PandocMonad m => Char -> LP m Tok
+verbTok stopchar = do
+ t@(Tok pos toktype txt) <- satisfyTok (not . isNewlineTok)
+ case T.findIndex (== stopchar) txt of
+ Nothing -> return t
+ Just i -> do
+ let (t1, t2) = T.splitAt i txt
+ inp <- getInput
+ setInput $ Tok (incSourceColumn pos i) Symbol (T.singleton stopchar)
+ : totoks (incSourceColumn pos (i + 1)) (T.drop 1 t2) ++ inp
+ return $ Tok pos toktype t1
+
+dolstinline :: PandocMonad m => LP m Inlines
+dolstinline = do
+ options <- option [] keyvals
+ let classes = maybeToList $ lookup "language" options >>= fromListingsLanguage
+ Tok _ Symbol t <- anySymbol
+ marker <- case T.uncons t of
+ Just (c, ts) | T.null ts -> return c
+ _ -> mzero
+ let stopchar = if marker == '{' then '}' else marker
+ withVerbatimMode $
+ (codeWith ("",classes,[]) . T.unpack . untokenize) <$>
+ manyTill (verbTok stopchar) (symbol stopchar)
+
+keyval :: PandocMonad m => LP m (String, String)
+keyval = try $ do
+ Tok _ Word key <- satisfyTok isWordTok
+ let isSpecSym (Tok _ Symbol t) = t /= "]" && t /= ","
+ isSpecSym _ = False
+ optional sp
+ val <- option [] $ do
+ symbol '='
+ optional sp
+ braced <|> many1 (satisfyTok isWordTok <|> satisfyTok isSpecSym
+ <|> anyControlSeq)
+ optional sp
+ optional (symbol ',')
+ optional sp
+ return (T.unpack key, T.unpack . untokenize $ val)
-lit :: String -> LP Inlines
-lit = pure . str
+keyvals :: PandocMonad m => LP m [(String, String)]
+keyvals = try $ symbol '[' >> manyTill keyval (symbol ']')
-accent :: (Char -> String) -> Inlines -> LP Inlines
-accent f ils =
+accent :: PandocMonad m => Char -> (Char -> String) -> LP m Inlines
+accent c f = try $ do
+ ils <- tok
case toList ils of
(Str (x:xs) : ys) -> return $ fromList (Str (f x ++ xs) : ys)
- [] -> mzero
+ [Space] -> return $ str [c]
+ [] -> return $ str [c]
_ -> return ils
grave :: Char -> String
@@ -855,6 +994,19 @@ hacek 'Z' = "Ž"
hacek 'z' = "ž"
hacek c = [c]
+ogonek :: Char -> String
+ogonek 'a' = "ą"
+ogonek 'e' = "ę"
+ogonek 'o' = "ǫ"
+ogonek 'i' = "į"
+ogonek 'u' = "ų"
+ogonek 'A' = "Ą"
+ogonek 'E' = "Ę"
+ogonek 'I' = "Į"
+ogonek 'O' = "Ǫ"
+ogonek 'U' = "Ų"
+ogonek c = [c]
+
breve :: Char -> String
breve 'A' = "Ă"
breve 'a' = "ă"
@@ -870,368 +1022,1181 @@ breve 'U' = "Ŭ"
breve 'u' = "ŭ"
breve c = [c]
-tok :: LP Inlines
-tok = try $ grouped inline <|> inlineCommand <|> str <$> count 1 inlineChar
+toksToString :: [Tok] -> String
+toksToString = T.unpack . untokenize
+
+mathDisplay :: String -> Inlines
+mathDisplay = displayMath . trim
-opt :: LP Inlines
-opt = bracketed inline
+mathInline :: String -> Inlines
+mathInline = math . trim
-rawopt :: LP String
+dollarsMath :: PandocMonad m => LP m Inlines
+dollarsMath = do
+ symbol '$'
+ display <- option False (True <$ symbol '$')
+ contents <- trim . toksToString <$>
+ many (notFollowedBy (symbol '$') >> anyTok)
+ if display
+ then
+ mathDisplay contents <$ try (symbol '$' >> symbol '$')
+ <|> (guard (null contents) >> return (mathInline ""))
+ else mathInline contents <$ symbol '$'
+
+-- citations
+
+addPrefix :: [Inline] -> [Citation] -> [Citation]
+addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
+addPrefix _ _ = []
+
+addSuffix :: [Inline] -> [Citation] -> [Citation]
+addSuffix s ks@(_:_) =
+ let k = last ks
+ in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
+addSuffix _ _ = []
+
+simpleCiteArgs :: PandocMonad m => LP m [Citation]
+simpleCiteArgs = try $ do
+ first <- optionMaybe $ toList <$> opt
+ second <- optionMaybe $ toList <$> opt
+ keys <- try $ bgroup *> manyTill citationLabel egroup
+ let (pre, suf) = case (first , second ) of
+ (Just s , Nothing) -> (mempty, s )
+ (Just s , Just t ) -> (s , t )
+ _ -> (mempty, mempty)
+ conv k = Citation { citationId = k
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = NormalCitation
+ , citationHash = 0
+ , citationNoteNum = 0
+ }
+ return $ addPrefix pre $ addSuffix suf $ map conv keys
+
+citationLabel :: PandocMonad m => LP m String
+citationLabel = do
+ optional spaces
+ toksToString <$>
+ (many1 (satisfyTok isWordTok <|> symbolIn bibtexKeyChar)
+ <* optional spaces
+ <* optional (symbol ',')
+ <* optional spaces)
+ where bibtexKeyChar = ".:;?!`'()/*@_+=-[]" :: [Char]
+
+cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation]
+cites mode multi = try $ do
+ cits <- if multi
+ then many1 simpleCiteArgs
+ else count 1 simpleCiteArgs
+ let cs = concat cits
+ return $ case mode of
+ AuthorInText -> case cs of
+ (c:rest) -> c {citationMode = mode} : rest
+ [] -> []
+ _ -> map (\a -> a {citationMode = mode}) cs
+
+citation :: PandocMonad m => String -> CitationMode -> Bool -> LP m Inlines
+citation name mode multi = do
+ (c,raw) <- withRaw $ cites mode multi
+ return $ cite c (rawInline "latex" $ "\\" ++ name ++ toksToString raw)
+
+handleCitationPart :: Inlines -> [Citation]
+handleCitationPart ils =
+ let isCite Cite{} = True
+ isCite _ = False
+ (pref, rest) = break isCite (toList ils)
+ in case rest of
+ (Cite cs _:suff) -> addPrefix pref $ addSuffix suff cs
+ _ -> []
+
+complexNatbibCitation :: PandocMonad m => CitationMode -> LP m Inlines
+complexNatbibCitation mode = try $ do
+ (cs, raw) <-
+ withRaw $ concat <$> do
+ bgroup
+ items <- mconcat <$>
+ many1 (notFollowedBy (symbol ';') >> inline)
+ `sepBy1` (symbol ';')
+ egroup
+ return $ map handleCitationPart items
+ case cs of
+ [] -> mzero
+ (c:cits) -> return $ cite (c{ citationMode = mode }:cits)
+ (rawInline "latex" $ "\\citetext" ++ toksToString raw)
+
+inNote :: Inlines -> Inlines
+inNote ils =
+ note $ para $ ils <> str "."
+
+inlineCommand' :: PandocMonad m => LP m Inlines
+inlineCommand' = try $ do
+ Tok _ (CtrlSeq name) cmd <- anyControlSeq
+ guard $ name /= "begin" && name /= "end"
+ star <- option "" ("*" <$ symbol '*' <* optional sp)
+ let name' = name <> star
+ let names = ordNub [name', name] -- check non-starred as fallback
+ let raw = do
+ guard $ isInlineCommand name || not (isBlockCommand name)
+ rawcommand <- getRawCommand name (cmd <> star)
+ (guardEnabled Ext_raw_tex >> return (rawInline "latex" rawcommand))
+ <|> ignore rawcommand
+ lookupListDefault raw names inlineCommands
+
+tok :: PandocMonad m => LP m Inlines
+tok = try $ spaces >> grouped inline <|> inlineCommand' <|> singleChar'
+ where singleChar' = do
+ Tok _ _ t <- singleChar
+ return (str (T.unpack t))
+
+singleChar :: PandocMonad m => LP m Tok
+singleChar = try $ do
+ Tok pos toktype t <- satisfyTok (tokTypeIn [Word, Symbol])
+ guard $ not $ toktype == Symbol &&
+ T.any (`Set.member` specialChars) t
+ if T.length t > 1
+ then do
+ let (t1, t2) = (T.take 1 t, T.drop 1 t)
+ inp <- getInput
+ setInput $ Tok (incSourceColumn pos 1) toktype t2 : inp
+ return $ Tok pos toktype t1
+ else return $ Tok pos toktype t
+
+opt :: PandocMonad m => LP m Inlines
+opt = bracketed inline <|> (str . T.unpack <$> rawopt)
+
+rawopt :: PandocMonad m => LP m Text
rawopt = do
- contents <- bracketed (many1 (noneOf "[]") <|> try (string "\\]") <|>
- try (string "\\[") <|> rawopt)
+ inner <- untokenize <$> bracketedToks
optional sp
- return $ "[" ++ contents ++ "]"
+ return $ "[" <> inner <> "]"
-skipopts :: LP ()
+skipopts :: PandocMonad m => LP m ()
skipopts = skipMany rawopt
-- opts in angle brackets are used in beamer
-rawangle :: LP ()
+rawangle :: PandocMonad m => LP m ()
rawangle = try $ do
- char '<'
- skipMany (noneOf ">")
- char '>'
- return ()
+ symbol '<'
+ () <$ manyTill anyTok (symbol '>')
-skipangles :: LP ()
+skipangles :: PandocMonad m => LP m ()
skipangles = skipMany rawangle
-inlineText :: LP Inlines
-inlineText = str <$> many1 inlineChar
+ignore :: (Monoid a, PandocMonad m) => String -> ParserT s u m a
+ignore raw = do
+ pos <- getPosition
+ report $ SkippedContent raw pos
+ return mempty
-inlineChar :: LP Char
-inlineChar = noneOf "\\$%&~#{}^'`\"‘’“”-[] \t\n"
+withRaw :: PandocMonad m => LP m a -> LP m (a, [Tok])
+withRaw parser = do
+ inp <- getInput
+ result <- parser
+ nxt <- option (Tok (initialPos "source") Word "") (lookAhead anyTok)
+ let raw = takeWhile (/= nxt) inp
+ return (result, raw)
-environment :: LP Blocks
-environment = do
- controlSeq "begin"
- name <- braced
- M.findWithDefault mzero name environments
- <|> rawEnv name
+inBrackets :: Inlines -> Inlines
+inBrackets x = str "[" <> x <> str "]"
+
+unescapeURL :: String -> String
+unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
+ where isEscapable c = c `elem` ("#$%&~_^\\{}" :: String)
+unescapeURL (x:xs) = x:unescapeURL xs
+unescapeURL [] = ""
-inlineEnvironment :: LP Inlines
+mathEnvWith :: PandocMonad m
+ => (Inlines -> a) -> Maybe Text -> Text -> LP m a
+mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name
+ where inner x = case innerEnv of
+ Nothing -> x
+ Just y -> "\\begin{" ++ T.unpack y ++ "}\n" ++ x ++
+ "\\end{" ++ T.unpack y ++ "}"
+
+mathEnv :: PandocMonad m => Text -> LP m String
+mathEnv name = do
+ skipopts
+ optional blankline
+ res <- manyTill anyTok (end_ name)
+ return $ stripTrailingNewlines $ T.unpack $ untokenize res
+
+inlineEnvironment :: PandocMonad m => LP m Inlines
inlineEnvironment = try $ do
controlSeq "begin"
- name <- braced
+ name <- untokenize <$> braced
M.findWithDefault mzero name inlineEnvironments
-rawEnv :: String -> LP Blocks
-rawEnv name = do
- parseRaw <- getOption readerParseRaw
- rawOptions <- mconcat <$> many rawopt
- let addBegin x = "\\begin{" ++ name ++ "}" ++ rawOptions ++ x
- if parseRaw
- then (rawBlock "latex" . addBegin) <$>
- (withRaw (env name blocks) >>= applyMacros' . snd)
- else env name blocks
-
-----
-
-type IncludeParser = ParserT String [String] IO String
-
--- | Replace "include" commands with file contents.
-handleIncludes :: String -> IO (Either PandocError String)
-handleIncludes s = mapLeft (ParsecError s) <$> runParserT includeParser' [] "input" s
-
-includeParser' :: IncludeParser
-includeParser' =
- concat <$> many (comment' <|> escaped' <|> blob' <|> include'
- <|> startMarker' <|> endMarker'
- <|> verbCmd' <|> verbatimEnv' <|> backslash')
-
-comment' :: IncludeParser
-comment' = do
- char '%'
- xs <- manyTill anyChar newline
- return ('%':xs ++ "\n")
-
-escaped' :: IncludeParser
-escaped' = try $ string "\\%" <|> string "\\\\"
-
-verbCmd' :: IncludeParser
-verbCmd' = fmap snd <$>
- withRaw $ try $ do
- string "\\verb"
- c <- anyChar
- manyTill anyChar (char c)
-
-verbatimEnv' :: IncludeParser
-verbatimEnv' = fmap snd <$>
- withRaw $ try $ do
- string "\\begin"
- name <- braced'
- guard $ name `elem` ["verbatim", "Verbatim", "BVerbatim",
- "lstlisting", "minted", "alltt", "comment"]
- manyTill anyChar (try $ string $ "\\end{" ++ name ++ "}")
-
-blob' :: IncludeParser
-blob' = try $ many1 (noneOf "\\%")
-
-backslash' :: IncludeParser
-backslash' = string "\\"
-
-braced' :: IncludeParser
-braced' = try $ char '{' *> manyTill (satisfy (/='}')) (char '}')
+inlineEnvironments :: PandocMonad m => M.Map Text (LP m Inlines)
+inlineEnvironments = M.fromList [
+ ("displaymath", mathEnvWith id Nothing "displaymath")
+ , ("math", math <$> mathEnv "math")
+ , ("equation", mathEnvWith id Nothing "equation")
+ , ("equation*", mathEnvWith id Nothing "equation*")
+ , ("gather", mathEnvWith id (Just "gathered") "gather")
+ , ("gather*", mathEnvWith id (Just "gathered") "gather*")
+ , ("multline", mathEnvWith id (Just "gathered") "multline")
+ , ("multline*", mathEnvWith id (Just "gathered") "multline*")
+ , ("eqnarray", mathEnvWith id (Just "aligned") "eqnarray")
+ , ("eqnarray*", mathEnvWith id (Just "aligned") "eqnarray*")
+ , ("align", mathEnvWith id (Just "aligned") "align")
+ , ("align*", mathEnvWith id (Just "aligned") "align*")
+ , ("alignat", mathEnvWith id (Just "aligned") "alignat")
+ , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
+ ]
-maybeAddExtension :: String -> FilePath -> FilePath
-maybeAddExtension ext fp =
- if null (takeExtension fp)
- then addExtension fp ext
- else fp
+inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines)
+inlineCommands = M.union inlineLanguageCommands $ M.fromList
+ [ ("emph", extractSpaces emph <$> tok)
+ , ("textit", extractSpaces emph <$> tok)
+ , ("textsl", extractSpaces emph <$> tok)
+ , ("textsc", extractSpaces smallcaps <$> tok)
+ , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
+ , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
+ , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
+ , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
+ , ("texttt", ttfamily)
+ , ("sout", extractSpaces strikeout <$> tok)
+ , ("alert", skipangles >> spanWith ("",["alert"],[]) <$> tok) -- beamer
+ , ("lq", return (str "‘"))
+ , ("rq", return (str "’"))
+ , ("textquoteleft", return (str "‘"))
+ , ("textquoteright", return (str "’"))
+ , ("textquotedblleft", return (str "“"))
+ , ("textquotedblright", return (str "”"))
+ , ("textsuperscript", extractSpaces superscript <$> tok)
+ , ("textsubscript", extractSpaces subscript <$> tok)
+ , ("textbackslash", lit "\\")
+ , ("backslash", lit "\\")
+ , ("slash", lit "/")
+ , ("textbf", extractSpaces strong <$> tok)
+ , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
+ , ("ldots", lit "…")
+ , ("vdots", lit "\8942")
+ , ("dots", lit "…")
+ , ("mdots", lit "…")
+ , ("sim", lit "~")
+ , ("sep", lit ",")
+ , ("label", rawInlineOr "label" dolabel)
+ , ("ref", rawInlineOr "ref" $ doref "ref")
+ , ("cref", rawInlineOr "cref" $ doref "ref") -- from cleveref.sty
+ , ("vref", rawInlineOr "vref" $ doref "ref+page") -- from varioref.sty
+ , ("eqref", rawInlineOr "eqref" $ doref "eqref") -- from amsmath.sty
+ , ("lettrine", optional opt >> extractSpaces (spanWith ("",["lettrine"],[])) <$> tok)
+ , ("(", mathInline . toksToString <$> manyTill anyTok (controlSeq ")"))
+ , ("[", mathDisplay . toksToString <$> manyTill anyTok (controlSeq "]"))
+ , ("ensuremath", mathInline . toksToString <$> braced)
+ , ("texorpdfstring", (\_ x -> x) <$> tok <*> tok)
+ , ("P", lit "¶")
+ , ("S", lit "§")
+ , ("$", lit "$")
+ , ("%", lit "%")
+ , ("&", lit "&")
+ , ("#", lit "#")
+ , ("_", lit "_")
+ , ("{", lit "{")
+ , ("}", lit "}")
+ -- old TeX commands
+ , ("em", extractSpaces emph <$> inlines)
+ , ("it", extractSpaces emph <$> inlines)
+ , ("sl", extractSpaces emph <$> inlines)
+ , ("bf", extractSpaces strong <$> inlines)
+ , ("rm", inlines)
+ , ("itshape", extractSpaces emph <$> inlines)
+ , ("slshape", extractSpaces emph <$> inlines)
+ , ("scshape", extractSpaces smallcaps <$> inlines)
+ , ("bfseries", extractSpaces strong <$> inlines)
+ , ("/", pure mempty) -- italic correction
+ , ("aa", lit "å")
+ , ("AA", lit "Å")
+ , ("ss", lit "ß")
+ , ("o", lit "ø")
+ , ("O", lit "Ø")
+ , ("L", lit "Ł")
+ , ("l", lit "ł")
+ , ("ae", lit "æ")
+ , ("AE", lit "Æ")
+ , ("oe", lit "œ")
+ , ("OE", lit "Œ")
+ , ("pounds", lit "£")
+ , ("euro", lit "€")
+ , ("copyright", lit "©")
+ , ("textasciicircum", lit "^")
+ , ("textasciitilde", lit "~")
+ , ("H", accent '\779' hungarumlaut)
+ , ("`", accent '`' grave)
+ , ("'", accent '\'' acute)
+ , ("^", accent '^' circ)
+ , ("~", accent '~' tilde)
+ , ("\"", accent '\776' umlaut)
+ , (".", accent '\775' dot)
+ , ("=", accent '\772' macron)
+ , ("c", accent '\807' cedilla)
+ , ("v", accent 'ˇ' hacek)
+ , ("u", accent '\774' breve)
+ , ("k", accent '\808' ogonek)
+ , ("textogonekcentered", accent '\808' ogonek)
+ , ("i", lit "i")
+ , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState
+ guard $ not inTableCell
+ optional opt
+ spaces))
+ , (",", lit "\8198")
+ , ("@", pure mempty)
+ , (" ", lit "\160")
+ , ("ps", pure $ str "PS." <> space)
+ , ("TeX", lit "TeX")
+ , ("LaTeX", lit "LaTeX")
+ , ("bar", lit "|")
+ , ("textless", lit "<")
+ , ("textgreater", lit ">")
+ , ("thanks", skipopts >> note <$> grouped block)
+ , ("footnote", skipopts >> note <$> grouped block)
+ , ("verb", doverb)
+ , ("lstinline", dolstinline)
+ , ("Verb", doverb)
+ , ("url", ((unescapeURL . T.unpack . untokenize) <$> braced) >>= \url ->
+ pure (link url "" (str url)))
+ , ("href", (unescapeURL . toksToString <$>
+ braced <* optional sp) >>= \url ->
+ tok >>= \lab -> pure (link url "" lab))
+ , ("includegraphics", do options <- option [] keyvals
+ src <- unescapeURL . T.unpack .
+ removeDoubleQuotes . untokenize <$> braced
+ mkImage options src)
+ , ("enquote", enquote)
+ , ("figurename", doTerm Translations.Figure)
+ , ("prefacename", doTerm Translations.Preface)
+ , ("refname", doTerm Translations.References)
+ , ("bibname", doTerm Translations.Bibliography)
+ , ("chaptername", doTerm Translations.Chapter)
+ , ("partname", doTerm Translations.Part)
+ , ("contentsname", doTerm Translations.Contents)
+ , ("listfigurename", doTerm Translations.ListOfFigures)
+ , ("listtablename", doTerm Translations.ListOfTables)
+ , ("indexname", doTerm Translations.Index)
+ , ("abstractname", doTerm Translations.Abstract)
+ , ("tablename", doTerm Translations.Table)
+ , ("enclname", doTerm Translations.Encl)
+ , ("ccname", doTerm Translations.Cc)
+ , ("headtoname", doTerm Translations.To)
+ , ("pagename", doTerm Translations.Page)
+ , ("seename", doTerm Translations.See)
+ , ("seealsoname", doTerm Translations.SeeAlso)
+ , ("proofname", doTerm Translations.Proof)
+ , ("glossaryname", doTerm Translations.Glossary)
+ , ("lstlistingname", doTerm Translations.Listing)
+ , ("cite", citation "cite" NormalCitation False)
+ , ("Cite", citation "Cite" NormalCitation False)
+ , ("citep", citation "citep" NormalCitation False)
+ , ("citep*", citation "citep*" NormalCitation False)
+ , ("citeal", citation "citeal" NormalCitation False)
+ , ("citealp", citation "citealp" NormalCitation False)
+ , ("citealp*", citation "citealp*" NormalCitation False)
+ , ("autocite", citation "autocite" NormalCitation False)
+ , ("smartcite", citation "smartcite" NormalCitation False)
+ , ("footcite", inNote <$> citation "footcite" NormalCitation False)
+ , ("parencite", citation "parencite" NormalCitation False)
+ , ("supercite", citation "supercite" NormalCitation False)
+ , ("footcitetext", inNote <$> citation "footcitetext" NormalCitation False)
+ , ("citeyearpar", citation "citeyearpar" SuppressAuthor False)
+ , ("citeyear", citation "citeyear" SuppressAuthor False)
+ , ("autocite*", citation "autocite*" SuppressAuthor False)
+ , ("cite*", citation "cite*" SuppressAuthor False)
+ , ("parencite*", citation "parencite*" SuppressAuthor False)
+ , ("textcite", citation "textcite" AuthorInText False)
+ , ("citet", citation "citet" AuthorInText False)
+ , ("citet*", citation "citet*" AuthorInText False)
+ , ("citealt", citation "citealt" AuthorInText False)
+ , ("citealt*", citation "citealt*" AuthorInText False)
+ , ("textcites", citation "textcites" AuthorInText True)
+ , ("cites", citation "cites" NormalCitation True)
+ , ("autocites", citation "autocites" NormalCitation True)
+ , ("footcites", inNote <$> citation "footcites" NormalCitation True)
+ , ("parencites", citation "parencites" NormalCitation True)
+ , ("supercites", citation "supercites" NormalCitation True)
+ , ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
+ , ("Autocite", citation "Autocite" NormalCitation False)
+ , ("Smartcite", citation "Smartcite" NormalCitation False)
+ , ("Footcite", citation "Footcite" NormalCitation False)
+ , ("Parencite", citation "Parencite" NormalCitation False)
+ , ("Supercite", citation "Supercite" NormalCitation False)
+ , ("Footcitetext", inNote <$> citation "Footcitetext" NormalCitation False)
+ , ("Citeyearpar", citation "Citeyearpar" SuppressAuthor False)
+ , ("Citeyear", citation "Citeyear" SuppressAuthor False)
+ , ("Autocite*", citation "Autocite*" SuppressAuthor False)
+ , ("Cite*", citation "Cite*" SuppressAuthor False)
+ , ("Parencite*", citation "Parencite*" SuppressAuthor False)
+ , ("Textcite", citation "Textcite" AuthorInText False)
+ , ("Textcites", citation "Textcites" AuthorInText True)
+ , ("Cites", citation "Cites" NormalCitation True)
+ , ("Autocites", citation "Autocites" NormalCitation True)
+ , ("Footcites", citation "Footcites" NormalCitation True)
+ , ("Parencites", citation "Parencites" NormalCitation True)
+ , ("Supercites", citation "Supercites" NormalCitation True)
+ , ("Footcitetexts", inNote <$> citation "Footcitetexts" NormalCitation True)
+ , ("citetext", complexNatbibCitation NormalCitation)
+ , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
+ complexNatbibCitation AuthorInText)
+ <|> citation "citeauthor" AuthorInText False)
+ , ("nocite", mempty <$ (citation "nocite" NormalCitation False >>=
+ addMeta "nocite"))
+ , ("hyperlink", hyperlink)
+ , ("hypertarget", hypertargetInline)
+ -- glossaries package
+ , ("gls", doAcronym "short")
+ , ("Gls", doAcronym "short")
+ , ("glsdesc", doAcronym "long")
+ , ("Glsdesc", doAcronym "long")
+ , ("GLSdesc", doAcronym "long")
+ , ("acrlong", doAcronym "long")
+ , ("Acrlong", doAcronym "long")
+ , ("acrfull", doAcronym "full")
+ , ("Acrfull", doAcronym "full")
+ , ("acrshort", doAcronym "abbrv")
+ , ("Acrshort", doAcronym "abbrv")
+ , ("glspl", doAcronymPlural "short")
+ , ("Glspl", doAcronymPlural "short")
+ , ("glsdescplural", doAcronymPlural "long")
+ , ("Glsdescplural", doAcronymPlural "long")
+ , ("GLSdescplural", doAcronymPlural "long")
+ -- acronyms package
+ , ("ac", doAcronym "short")
+ , ("acf", doAcronym "full")
+ , ("acs", doAcronym "abbrv")
+ , ("acp", doAcronymPlural "short")
+ , ("acfp", doAcronymPlural "full")
+ , ("acsp", doAcronymPlural "abbrv")
+ -- siuntix
+ , ("SI", dosiunitx)
+ -- hyphenat
+ , ("bshyp", lit "\\\173")
+ , ("fshyp", lit "/\173")
+ , ("dothyp", lit ".\173")
+ , ("colonhyp", lit ":\173")
+ , ("hyp", lit "-")
+ , ("nohyphens", tok)
+ , ("textnhtt", ttfamily)
+ , ("nhttfamily", ttfamily)
+ -- LaTeX colors
+ , ("textcolor", coloredInline "color")
+ , ("colorbox", coloredInline "background-color")
+ -- fontawesome
+ , ("faCheck", lit "\10003")
+ , ("faClose", lit "\10007")
+ -- xspace
+ , ("xspace", doxspace)
+ -- etoolbox
+ , ("ifstrequal", ifstrequal)
+ , ("newtoggle", braced >>= newToggle)
+ , ("toggletrue", braced >>= setToggle True)
+ , ("togglefalse", braced >>= setToggle False)
+ , ("iftoggle", try $ ifToggle >> inline)
+ -- biblatex misc
+ , ("RN", romanNumeralUpper)
+ , ("Rn", romanNumeralLower)
+ -- babel
+ , ("foreignlanguage", foreignlanguage)
+ ]
-include' :: IncludeParser
-include' = do
- fs' <- try $ do
- char '\\'
- name <- try (string "include")
- <|> try (string "input")
- <|> string "usepackage"
- -- skip options
- skipMany $ try $ char '[' *> manyTill anyChar (char ']')
- fs <- (map trim . splitBy (==',')) <$> braced'
- return $ if name == "usepackage"
- then map (maybeAddExtension ".sty") fs
- else map (maybeAddExtension ".tex") fs
- pos <- getPosition
- containers <- getState
- let fn = case containers of
- (f':_) -> f'
- [] -> "input"
- -- now process each include file in order...
- rest <- getInput
- results' <- forM fs' (\f -> do
- when (f `elem` containers) $
- fail "Include file loop!"
- contents <- lift $ readTeXFile f
- return $ "\\PandocStartInclude{" ++ f ++ "}" ++
- contents ++ "\\PandocEndInclude{" ++
- fn ++ "}{" ++ show (sourceLine pos) ++ "}{"
- ++ show (sourceColumn pos) ++ "}")
- setInput $ concat results' ++ rest
- return ""
-
-startMarker' :: IncludeParser
-startMarker' = try $ do
- string "\\PandocStartInclude"
- fn <- braced'
- updateState (fn:)
- setPosition $ newPos fn 1 1
- return $ "\\PandocStartInclude{" ++ fn ++ "}"
-
-endMarker' :: IncludeParser
-endMarker' = try $ do
- string "\\PandocEndInclude"
- fn <- braced'
- ln <- braced'
- co <- braced'
- updateState tail
- setPosition $ newPos fn (fromMaybe 1 $ safeRead ln) (fromMaybe 1 $ safeRead co)
- return $ "\\PandocEndInclude{" ++ fn ++ "}{" ++ ln ++ "}{" ++
- co ++ "}"
-
-readTeXFile :: FilePath -> IO String
-readTeXFile f = do
- texinputs <- E.catch (getEnv "TEXINPUTS") $ \(_ :: E.SomeException) ->
- return "."
- let ds = splitBy (==':') texinputs
- readFileFromDirs ds f
-
-readFileFromDirs :: [FilePath] -> FilePath -> IO String
-readFileFromDirs [] _ = return ""
-readFileFromDirs (d:ds) f =
- E.catch (UTF8.readFile $ d </> f) $ \(_ :: E.SomeException) ->
- readFileFromDirs ds f
-
-----
-
-keyval :: LP (String, String)
-keyval = try $ do
- key <- many1 alphaNum
- val <- option "" $ char '=' >> many1 (alphaNum <|> char '.' <|> char '\\')
- skipMany spaceChar
- optional (char ',')
- skipMany spaceChar
- return (key, val)
+foreignlanguage :: PandocMonad m => LP m Inlines
+foreignlanguage = do
+ babelLang <- T.unpack . untokenize <$> braced
+ case babelLangToBCP47 babelLang of
+ Just lang -> spanWith ("", [], [("lang", renderLang lang)]) <$> tok
+ _ -> tok
+inlineLanguageCommands :: PandocMonad m => M.Map Text (LP m Inlines)
+inlineLanguageCommands = M.fromList $ mk <$> M.toList polyglossiaLangToBCP47
+ where
+ mk (polyglossia, bcp47Func) =
+ ("text" <> T.pack polyglossia, inlineLanguage bcp47Func)
+
+inlineLanguage :: PandocMonad m => (String -> Lang) -> LP m Inlines
+inlineLanguage bcp47Func = do
+ o <- option "" $ (T.unpack . T.filter (\c -> c /= '[' && c /= ']'))
+ <$> rawopt
+ let lang = renderLang $ bcp47Func o
+ extractSpaces (spanWith ("", [], [("lang", lang)])) <$> tok
+
+hyperlink :: PandocMonad m => LP m Inlines
+hyperlink = try $ do
+ src <- toksToString <$> braced
+ lab <- tok
+ return $ link ('#':src) "" lab
+
+hypertargetBlock :: PandocMonad m => LP m Blocks
+hypertargetBlock = try $ do
+ ref <- toksToString <$> braced
+ bs <- grouped block
+ case toList bs of
+ [Header 1 (ident,_,_) _] | ident == ref -> return bs
+ _ -> return $ divWith (ref, [], []) bs
+
+hypertargetInline :: PandocMonad m => LP m Inlines
+hypertargetInline = try $ do
+ ref <- toksToString <$> braced
+ ils <- grouped inline
+ return $ spanWith (ref, [], []) ils
-keyvals :: LP [(String, String)]
-keyvals = try $ char '[' *> manyTill keyval (char ']')
+romanNumeralUpper :: (PandocMonad m) => LP m Inlines
+romanNumeralUpper =
+ str . toRomanNumeral <$> romanNumeralArg
-alltt :: String -> LP Blocks
-alltt t = walk strToCode <$> parseFromString blocks
- (substitute " " "\\ " $ substitute "%" "\\%" $
- intercalate "\\\\\n" $ lines t)
- where strToCode (Str s) = Code nullAttr s
- strToCode x = x
+romanNumeralLower :: (PandocMonad m) => LP m Inlines
+romanNumeralLower =
+ str . map toLower . toRomanNumeral <$> romanNumeralArg
-rawLaTeXBlock :: LP String
-rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
+romanNumeralArg :: (PandocMonad m) => LP m Int
+romanNumeralArg = spaces *> (parser <|> inBraces)
+ where
+ inBraces = do
+ symbol '{'
+ spaces
+ res <- parser
+ spaces
+ symbol '}'
+ return res
+ parser = do
+ Tok _ Word s <- satisfyTok isWordTok
+ let (digits, rest) = T.span isDigit s
+ unless (T.null rest) $
+ fail "Non-digits in argument to \\Rn or \\RN"
+ safeRead $ T.unpack digits
+
+newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
+newToggle name = do
+ updateState $ \st ->
+ st{ sToggles = M.insert (toksToString name) False (sToggles st) }
+ return mempty
-rawLaTeXInline :: LP Inline
-rawLaTeXInline = do
- raw <- (snd <$> withRaw inlineCommand) <|> (snd <$> withRaw blockCommand)
- RawInline "latex" <$> applyMacros' raw
+setToggle :: (Monoid a, PandocMonad m) => Bool -> [Tok] -> LP m a
+setToggle on name = do
+ updateState $ \st ->
+ st{ sToggles = M.adjust (const on) (toksToString name) (sToggles st) }
+ return mempty
-addImageCaption :: Blocks -> LP Blocks
-addImageCaption = walkM go
- where go (Image attr alt (src,tit)) = do
- mbcapt <- stateCaption <$> getState
- return $ case mbcapt of
- Just ils -> Image attr (toList ils) (src, "fig:")
- Nothing -> Image attr alt (src,tit)
- go x = return x
+ifToggle :: PandocMonad m => LP m ()
+ifToggle = do
+ name <- braced
+ spaces
+ yes <- braced
+ spaces
+ no <- braced
+ toggles <- sToggles <$> getState
+ inp <- getInput
+ let name' = toksToString name
+ case M.lookup name' toggles of
+ Just True -> setInput (yes ++ inp)
+ Just False -> setInput (no ++ inp)
+ Nothing -> do
+ pos <- getPosition
+ report $ UndefinedToggle name' pos
+ return ()
-addTableCaption :: Blocks -> LP Blocks
-addTableCaption = walkM go
- where go (Table c als ws hs rs) = do
- mbcapt <- stateCaption <$> getState
- return $ case mbcapt of
- Just ils -> Table (toList ils) als ws hs rs
- Nothing -> Table c als ws hs rs
- go x = return x
+doTerm :: PandocMonad m => Translations.Term -> LP m Inlines
+doTerm term = str <$> translateTerm term
+
+ifstrequal :: (PandocMonad m, Monoid a) => LP m a
+ifstrequal = do
+ str1 <- tok
+ str2 <- tok
+ ifequal <- braced
+ ifnotequal <- braced
+ if str1 == str2
+ then getInput >>= setInput . (ifequal ++)
+ else getInput >>= setInput . (ifnotequal ++)
+ return mempty
-environments :: M.Map String (LP Blocks)
-environments = M.fromList
- [ ("document", env "document" blocks <* skipMany anyChar)
- , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
- , ("letter", env "letter" letterContents)
- , ("minipage", env "minipage" $
- skipopts *> spaces' *> optional braced *> spaces' *> blocks)
- , ("figure", env "figure" $
- resetCaption *> skipopts *> blocks >>= addImageCaption)
- , ("center", env "center" blocks)
- , ("longtable", env "longtable" $
- resetCaption *> simpTable False >>= addTableCaption)
- , ("table", env "table" $
- resetCaption *> skipopts *> blocks >>= addTableCaption)
- , ("tabular*", env "tabular" $ simpTable True)
- , ("tabular", env "tabular" $ simpTable False)
- , ("quote", blockQuote <$> env "quote" blocks)
- , ("quotation", blockQuote <$> env "quotation" blocks)
- , ("verse", blockQuote <$> env "verse" blocks)
- , ("itemize", bulletList <$> listenv "itemize" (many item))
- , ("description", definitionList <$> listenv "description" (many descItem))
- , ("enumerate", orderedList')
- , ("alltt", alltt =<< verbEnv "alltt")
- , ("code", guardEnabled Ext_literate_haskell *>
- (codeBlockWith ("",["sourceCode","literate","haskell"],[]) <$>
- verbEnv "code"))
- , ("comment", mempty <$ verbEnv "comment")
- , ("verbatim", codeBlock <$> verbEnv "verbatim")
- , ("Verbatim", fancyverbEnv "Verbatim")
- , ("BVerbatim", fancyverbEnv "BVerbatim")
- , ("lstlisting", do options <- option [] keyvals
- let kvs = [ (if k == "firstnumber"
- then "startFrom"
- else k, v) | (k,v) <- options ]
- let classes = [ "numberLines" |
- lookup "numbers" options == Just "left" ]
- ++ maybeToList (lookup "language" options
- >>= fromListingsLanguage)
- let attr = (fromMaybe "" (lookup "label" options),classes,kvs)
- codeBlockWith attr <$> verbEnv "lstlisting")
- , ("minted", do options <- option [] keyvals
- lang <- grouped (many1 $ satisfy (/='}'))
- let kvs = [ (if k == "firstnumber"
- then "startFrom"
- else k, v) | (k,v) <- options ]
- let classes = [ lang | not (null lang) ] ++
- [ "numberLines" |
- lookup "linenos" options == Just "true" ]
- let attr = ("",classes,kvs)
- codeBlockWith attr <$> verbEnv "minted")
- , ("obeylines", parseFromString
- (para . trimInlines . mconcat <$> many inline) =<<
- intercalate "\\\\\n" . lines <$> verbEnv "obeylines")
- , ("displaymath", mathEnv para Nothing "displaymath")
- , ("equation", mathEnv para Nothing "equation")
- , ("equation*", mathEnv para Nothing "equation*")
- , ("gather", mathEnv para (Just "gathered") "gather")
- , ("gather*", mathEnv para (Just "gathered") "gather*")
- , ("multline", mathEnv para (Just "gathered") "multline")
- , ("multline*", mathEnv para (Just "gathered") "multline*")
- , ("eqnarray", mathEnv para (Just "aligned") "eqnarray")
- , ("eqnarray*", mathEnv para (Just "aligned") "eqnarray*")
- , ("align", mathEnv para (Just "aligned") "align")
- , ("align*", mathEnv para (Just "aligned") "align*")
- , ("alignat", mathEnv para (Just "aligned") "alignat")
- , ("alignat*", mathEnv para (Just "aligned") "alignat*")
+coloredInline :: PandocMonad m => String -> LP m Inlines
+coloredInline stylename = do
+ skipopts
+ color <- braced
+ spanWith ("",[],[("style",stylename ++ ": " ++ toksToString color)]) <$> tok
+
+ttfamily :: PandocMonad m => LP m Inlines
+ttfamily = (code . stringify . toList) <$> tok
+
+rawInlineOr :: PandocMonad m => Text -> LP m Inlines -> LP m Inlines
+rawInlineOr name' fallback = do
+ parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
+ if parseRaw
+ then rawInline "latex" <$> getRawCommand name' ("\\" <> name')
+ else fallback
+
+getRawCommand :: PandocMonad m => Text -> Text -> LP m String
+getRawCommand name txt = do
+ (_, rawargs) <- withRaw $
+ case name of
+ "write" -> do
+ void $ satisfyTok isWordTok -- digits
+ void braced
+ "titleformat" -> do
+ void braced
+ skipopts
+ void $ count 4 braced
+ "def" ->
+ void $ manyTill anyTok braced
+ _ -> do
+ skipangles
+ skipopts
+ option "" (try (optional sp *> dimenarg))
+ void $ many braced
+ return $ T.unpack (txt <> untokenize rawargs)
+
+isBlockCommand :: Text -> Bool
+isBlockCommand s =
+ s `M.member` (blockCommands :: M.Map Text (LP PandocPure Blocks))
+ || s `Set.member` treatAsBlock
+
+treatAsBlock :: Set.Set Text
+treatAsBlock = Set.fromList
+ [ "let", "def", "DeclareRobustCommand"
+ , "newcommand", "renewcommand"
+ , "newenvironment", "renewenvironment"
+ , "providecommand", "provideenvironment"
+ -- newcommand, etc. should be parsed by macroDef, but we need this
+ -- here so these aren't parsed as inline commands to ignore
+ , "special", "pdfannot", "pdfstringdef"
+ , "bibliographystyle"
+ , "maketitle", "makeindex", "makeglossary"
+ , "addcontentsline", "addtocontents", "addtocounter"
+ -- \ignore{} is used conventionally in literate haskell for definitions
+ -- that are to be processed by the compiler but not printed.
+ , "ignore"
+ , "hyperdef"
+ , "markboth", "markright", "markleft"
+ , "hspace", "vspace"
+ , "newpage"
+ , "clearpage"
+ , "pagebreak"
+ , "titleformat"
+ ]
+
+isInlineCommand :: Text -> Bool
+isInlineCommand s =
+ s `M.member` (inlineCommands :: M.Map Text (LP PandocPure Inlines))
+ || s `Set.member` treatAsInline
+
+treatAsInline :: Set.Set Text
+treatAsInline = Set.fromList
+ [ "index"
+ , "hspace"
+ , "vspace"
+ , "noindent"
+ , "newpage"
+ , "clearpage"
+ , "pagebreak"
]
-letterContents :: LP Blocks
-letterContents = do
- bs <- blocks
- st <- getState
- -- add signature (author) and address (title)
- let addr = case lookupMeta "address" (stateMeta st) of
- Just (MetaBlocks [Plain xs]) ->
- para $ trimInlines $ fromList xs
- _ -> mempty
- return $ addr <> bs -- sig added by \closing
+dolabel :: PandocMonad m => LP m Inlines
+dolabel = do
+ v <- braced
+ let refstr = toksToString v
+ return $ spanWith (refstr,[],[("label", refstr)])
+ $ inBrackets $ str $ toksToString v
+
+doref :: PandocMonad m => String -> LP m Inlines
+doref cls = do
+ v <- braced
+ let refstr = toksToString v
+ return $ linkWith ("",[],[ ("reference-type", cls)
+ , ("reference", refstr)])
+ ('#':refstr)
+ ""
+ (inBrackets $ str refstr)
+
+lookupListDefault :: (Show k, Ord k) => v -> [k] -> M.Map k v -> v
+lookupListDefault d = (fromMaybe d .) . lookupList
+ where lookupList l m = msum $ map (`M.lookup` m) l
+
+inline :: PandocMonad m => LP m Inlines
+inline = (mempty <$ comment)
+ <|> (space <$ whitespace)
+ <|> (softbreak <$ endline)
+ <|> word
+ <|> inlineCommand'
+ <|> inlineEnvironment
+ <|> inlineGroup
+ <|> (symbol '-' *>
+ option (str "-") (symbol '-' *>
+ option (str "–") (str "—" <$ symbol '-')))
+ <|> doubleQuote
+ <|> singleQuote
+ <|> (str "”" <$ try (symbol '\'' >> symbol '\''))
+ <|> (str "”" <$ symbol '”')
+ <|> (str "’" <$ symbol '\'')
+ <|> (str "’" <$ symbol '’')
+ <|> (str "\160" <$ symbol '~')
+ <|> dollarsMath
+ <|> (guardEnabled Ext_literate_haskell *> symbol '|' *> doLHSverb)
+ <|> (str . (:[]) <$> primEscape)
+ <|> regularSymbol
+ <|> (do res <- symbolIn "#^'`\"[]&"
+ pos <- getPosition
+ let s = T.unpack (untoken res)
+ report $ ParsingUnescaped s pos
+ return $ str s)
+
+inlines :: PandocMonad m => LP m Inlines
+inlines = mconcat <$> many inline
+
+-- block elements:
+
+begin_ :: PandocMonad m => Text -> LP m ()
+begin_ t = try (do
+ controlSeq "begin"
+ spaces
+ txt <- untokenize <$> braced
+ guard (t == txt)) <?> ("\\begin{" ++ T.unpack t ++ "}")
+
+end_ :: PandocMonad m => Text -> LP m ()
+end_ t = try (do
+ controlSeq "end"
+ spaces
+ txt <- untokenize <$> braced
+ guard $ t == txt) <?> ("\\end{" ++ T.unpack t ++ "}")
+
+preamble :: PandocMonad m => LP m Blocks
+preamble = mempty <$ many preambleBlock
+ where preambleBlock = spaces1
+ <|> void include
+ <|> void macroDef
+ <|> void blockCommand
+ <|> void braced
+ <|> (notFollowedBy (begin_ "document") >> void anyTok)
+
+paragraph :: PandocMonad m => LP m Blocks
+paragraph = do
+ x <- trimInlines . mconcat <$> many1 inline
+ if x == mempty
+ then return mempty
+ else return $ para x
+
+include :: PandocMonad m => LP m Blocks
+include = do
+ (Tok _ (CtrlSeq name) _) <-
+ controlSeq "include" <|> controlSeq "input" <|>
+ controlSeq "subfile" <|> controlSeq "usepackage"
+ skipMany opt
+ fs <- (map (T.unpack . removeDoubleQuotes . T.strip) . T.splitOn "," .
+ untokenize) <$> braced
+ let fs' = if name == "usepackage"
+ then map (maybeAddExtension ".sty") fs
+ else map (maybeAddExtension ".tex") fs
+ dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
+ mapM_ (insertIncluded dirs) fs'
+ return mempty
+
+insertIncluded :: PandocMonad m
+ => [FilePath]
+ -> FilePath
+ -> LP m ()
+insertIncluded dirs f = do
+ pos <- getPosition
+ containers <- getIncludeFiles <$> getState
+ when (f `elem` containers) $
+ throwError $ PandocParseError $ "Include file loop at " ++ show pos
+ updateState $ addIncludeFile f
+ mbcontents <- readFileFromDirs dirs f
+ contents <- case mbcontents of
+ Just s -> return s
+ Nothing -> do
+ report $ CouldNotLoadIncludeFile f pos
+ return ""
+ getInput >>= setInput . (tokenize f (T.pack contents) ++)
+ updateState dropLatestIncludeFile
+
+maybeAddExtension :: String -> FilePath -> FilePath
+maybeAddExtension ext fp =
+ if null (takeExtension fp)
+ then addExtension fp ext
+ else fp
+
+addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
+addMeta field val = updateState $ \st ->
+ st{ sMeta = addMetaField field val $ sMeta st }
+
+authors :: PandocMonad m => LP m ()
+authors = try $ do
+ bgroup
+ let oneAuthor = mconcat <$>
+ many1 (notFollowedBy' (controlSeq "and") >>
+ (inline <|> mempty <$ blockCommand))
+ -- skip e.g. \vspace{10pt}
+ auths <- sepBy oneAuthor (controlSeq "and")
+ egroup
+ addMeta "author" (map trimInlines auths)
+
+macroDef :: PandocMonad m => LP m Blocks
+macroDef =
+ mempty <$ ((commandDef <|> environmentDef) <* doMacros 0)
+ where commandDef = do
+ (name, macro') <- newcommand <|> letmacro <|> defmacro
+ guardDisabled Ext_latex_macros <|>
+ updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
+ environmentDef = do
+ (name, macro1, macro2) <- newenvironment
+ guardDisabled Ext_latex_macros <|>
+ do updateState $ \s -> s{ sMacros =
+ M.insert name macro1 (sMacros s) }
+ updateState $ \s -> s{ sMacros =
+ M.insert ("end" <> name) macro2 (sMacros s) }
+ -- @\newenvironment{envname}[n-args][default]{begin}{end}@
+ -- is equivalent to
+ -- @\newcommand{\envname}[n-args][default]{begin}@
+ -- @\newcommand{\endenvname}@
+
+letmacro :: PandocMonad m => LP m (Text, Macro)
+letmacro = do
+ controlSeq "let"
+ Tok _ (CtrlSeq name) _ <- anyControlSeq
+ optional $ symbol '='
+ spaces
+ contents <- bracedOrToken
+ return (name, Macro ExpandWhenDefined 0 Nothing contents)
+
+defmacro :: PandocMonad m => LP m (Text, Macro)
+defmacro = try $ do
+ controlSeq "def"
+ Tok _ (CtrlSeq name) _ <- anyControlSeq
+ numargs <- option 0 $ argSeq 1
+ -- we use withVerbatimMode, because macros are to be expanded
+ -- at point of use, not point of definition
+ contents <- withVerbatimMode bracedOrToken
+ return (name, Macro ExpandWhenUsed numargs Nothing contents)
+
+-- Note: we don't yet support fancy things like #1.#2
+argSeq :: PandocMonad m => Int -> LP m Int
+argSeq n = do
+ Tok _ (Arg i) _ <- satisfyTok isArgTok
+ guard $ i == n
+ argSeq (n+1) <|> return n
+
+isArgTok :: Tok -> Bool
+isArgTok (Tok _ (Arg _) _) = True
+isArgTok _ = False
+
+bracedOrToken :: PandocMonad m => LP m [Tok]
+bracedOrToken = braced <|> ((:[]) <$> (anyControlSeq <|> singleChar))
+
+newcommand :: PandocMonad m => LP m (Text, Macro)
+newcommand = do
+ pos <- getPosition
+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
+ controlSeq "renewcommand" <|>
+ controlSeq "providecommand" <|>
+ controlSeq "DeclareRobustCommand"
+ optional $ symbol '*'
+ Tok _ (CtrlSeq name) txt <- withVerbatimMode $ anyControlSeq <|>
+ (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
+ spaces
+ numargs <- option 0 $ try bracketedNum
+ spaces
+ optarg <- option Nothing $ Just <$> try bracketedToks
+ spaces
+ contents <- withVerbatimMode bracedOrToken
+ when (mtype == "newcommand") $ do
+ macros <- sMacros <$> getState
+ case M.lookup name macros of
+ Just _ -> report $ MacroAlreadyDefined (T.unpack txt) pos
+ Nothing -> return ()
+ return (name, Macro ExpandWhenUsed numargs optarg contents)
+
+newenvironment :: PandocMonad m => LP m (Text, Macro, Macro)
+newenvironment = do
+ pos <- getPosition
+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
+ controlSeq "renewenvironment" <|>
+ controlSeq "provideenvironment"
+ optional $ symbol '*'
+ spaces
+ name <- untokenize <$> braced
+ spaces
+ numargs <- option 0 $ try bracketedNum
+ spaces
+ optarg <- option Nothing $ Just <$> try bracketedToks
+ spaces
+ startcontents <- withVerbatimMode bracedOrToken
+ spaces
+ endcontents <- withVerbatimMode bracedOrToken
+ when (mtype == "newenvironment") $ do
+ macros <- sMacros <$> getState
+ case M.lookup name macros of
+ Just _ -> report $ MacroAlreadyDefined (T.unpack name) pos
+ Nothing -> return ()
+ return (name, Macro ExpandWhenUsed numargs optarg startcontents,
+ Macro ExpandWhenUsed 0 Nothing endcontents)
+
+bracketedToks :: PandocMonad m => LP m [Tok]
+bracketedToks = do
+ symbol '['
+ mconcat <$> manyTill (braced <|> (:[]) <$> anyTok) (symbol ']')
+
+bracketedNum :: PandocMonad m => LP m Int
+bracketedNum = do
+ ds <- untokenize <$> bracketedToks
+ case safeRead (T.unpack ds) of
+ Just i -> return i
+ _ -> return 0
+
+setCaption :: PandocMonad m => LP m Blocks
+setCaption = do
+ ils <- tok
+ mblabel <- option Nothing $
+ try $ spaces >> controlSeq "label" >> (Just <$> tok)
+ let ils' = case mblabel of
+ Just lab -> ils <> spanWith
+ ("",[],[("label", stringify lab)]) mempty
+ Nothing -> ils
+ updateState $ \st -> st{ sCaption = Just ils' }
+ return mempty
-closing :: LP Blocks
+looseItem :: PandocMonad m => LP m Blocks
+looseItem = do
+ inListItem <- sInListItem <$> getState
+ guard $ not inListItem
+ skipopts
+ return mempty
+
+resetCaption :: PandocMonad m => LP m ()
+resetCaption = updateState $ \st -> st{ sCaption = Nothing }
+
+section :: PandocMonad m => Bool -> Attr -> Int -> LP m Blocks
+section starred (ident, classes, kvs) lvl = do
+ skipopts
+ contents <- grouped inline
+ lab <- option ident $
+ try (spaces >> controlSeq "label"
+ >> spaces >> toksToString <$> braced)
+ let classes' = if starred then "unnumbered" : classes else classes
+ unless starred $ do
+ hn <- sLastHeaderNum <$> getState
+ let num = incrementHeaderNum lvl hn
+ updateState $ \st -> st{ sLastHeaderNum = num }
+ updateState $ \st -> st{ sLabels = M.insert lab
+ [Str (renderHeaderNum num)]
+ (sLabels st) }
+ attr' <- registerHeader (lab, classes', kvs) contents
+ return $ headerWith attr' lvl contents
+
+blockCommand :: PandocMonad m => LP m Blocks
+blockCommand = try $ do
+ Tok _ (CtrlSeq name) txt <- anyControlSeq
+ guard $ name /= "begin" && name /= "end"
+ star <- option "" ("*" <$ symbol '*' <* optional sp)
+ let name' = name <> star
+ let names = ordNub [name', name]
+ let rawDefiniteBlock = do
+ guard $ isBlockCommand name
+ rawBlock "latex" <$> getRawCommand name (txt <> star)
+ -- heuristic: if it could be either block or inline, we
+ -- treat it if block if we have a sequence of block
+ -- commands followed by a newline. But we stop if we
+ -- hit a \startXXX, since this might start a raw ConTeXt
+ -- environment (this is important because this parser is
+ -- used by the Markdown reader).
+ let startCommand = try $ do
+ Tok _ (CtrlSeq n) _ <- anyControlSeq
+ guard $ "start" `T.isPrefixOf` n
+ let rawMaybeBlock = try $ do
+ guard $ not $ isInlineCommand name
+ curr <- rawBlock "latex" <$> getRawCommand name (txt <> star)
+ rest <- many $ notFollowedBy startCommand *> blockCommand
+ lookAhead $ blankline <|> startCommand
+ return $ curr <> mconcat rest
+ let raw = rawDefiniteBlock <|> rawMaybeBlock
+ lookupListDefault raw names blockCommands
+
+closing :: PandocMonad m => LP m Blocks
closing = do
contents <- tok
st <- getState
let extractInlines (MetaBlocks [Plain ys]) = ys
extractInlines (MetaBlocks [Para ys ]) = ys
- extractInlines _ = []
- let sigs = case lookupMeta "author" (stateMeta st) of
+ extractInlines _ = []
+ let sigs = case lookupMeta "author" (sMeta st) of
Just (MetaList xs) ->
para $ trimInlines $ fromList $
intercalate [LineBreak] $ map extractInlines xs
_ -> mempty
return $ para (trimInlines contents) <> sigs
-item :: LP Blocks
-item = blocks *> controlSeq "item" *> skipopts *> blocks
-
-looseItem :: LP Blocks
-looseItem = do
- ctx <- stateParserContext `fmap` getState
- if ctx == ListItemState
- then mzero
- else return mempty
-
-descItem :: LP (Inlines, [Blocks])
-descItem = do
- blocks -- skip blocks before item
- controlSeq "item"
- optional sp
- ils <- opt
- bs <- blocks
- return (ils, [bs])
-
-env :: String -> LP a -> LP a
-env name p = p <*
- (try (controlSeq "end" *> braced >>= guard . (== name))
- <?> ("\\end{" ++ name ++ "}"))
+blockCommands :: PandocMonad m => M.Map Text (LP m Blocks)
+blockCommands = M.fromList
+ [ ("par", mempty <$ skipopts)
+ , ("parbox", skipopts >> braced >> grouped blocks)
+ , ("title", mempty <$ (skipopts *>
+ (grouped inline >>= addMeta "title")
+ <|> (grouped block >>= addMeta "title")))
+ , ("subtitle", mempty <$ (skipopts *> tok >>= addMeta "subtitle"))
+ , ("author", mempty <$ (skipopts *> authors))
+ -- -- in letter class, temp. store address & sig as title, author
+ , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
+ , ("signature", mempty <$ (skipopts *> authors))
+ , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
+ -- Koma-script metadata commands
+ , ("dedication", mempty <$ (skipopts *> tok >>= addMeta "dedication"))
+ -- sectioning
+ , ("part", section False nullAttr (-1))
+ , ("part*", section True nullAttr (-1))
+ , ("chapter", section False nullAttr 0)
+ , ("chapter*", section True ("",["unnumbered"],[]) 0)
+ , ("section", section False nullAttr 1)
+ , ("section*", section True ("",["unnumbered"],[]) 1)
+ , ("subsection", section False nullAttr 2)
+ , ("subsection*", section True ("",["unnumbered"],[]) 2)
+ , ("subsubsection", section False nullAttr 3)
+ , ("subsubsection*", section True ("",["unnumbered"],[]) 3)
+ , ("paragraph", section False nullAttr 4)
+ , ("paragraph*", section True ("",["unnumbered"],[]) 4)
+ , ("subparagraph", section False nullAttr 5)
+ , ("subparagraph*", section True ("",["unnumbered"],[]) 5)
+ -- beamer slides
+ , ("frametitle", section False nullAttr 3)
+ , ("framesubtitle", section False nullAttr 4)
+ -- letters
+ , ("opening", (para . trimInlines) <$> (skipopts *> tok))
+ , ("closing", skipopts *> closing)
+ -- memoir
+ , ("plainbreak", braced >> pure horizontalRule)
+ , ("plainbreak*", braced >> pure horizontalRule)
+ , ("fancybreak", braced >> pure horizontalRule)
+ , ("fancybreak*", braced >> pure horizontalRule)
+ , ("plainfancybreak", braced >> braced >> braced >> pure horizontalRule)
+ , ("plainfancybreak*", braced >> braced >> braced >> pure horizontalRule)
+ , ("pfbreak", pure horizontalRule)
+ , ("pfbreak*", pure horizontalRule)
+ --
+ , ("hrule", pure horizontalRule)
+ , ("strut", pure mempty)
+ , ("rule", skipopts *> tok *> tok *> pure horizontalRule)
+ , ("item", looseItem)
+ , ("documentclass", skipopts *> braced *> preamble)
+ , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
+ , ("caption", skipopts *> setCaption)
+ , ("bibliography", mempty <$ (skipopts *> braced >>=
+ addMeta "bibliography" . splitBibs . toksToString))
+ , ("addbibresource", mempty <$ (skipopts *> braced >>=
+ addMeta "bibliography" . splitBibs . toksToString))
+ -- includes
+ , ("lstinputlisting", inputListing)
+ , ("graphicspath", graphicsPath)
+ -- polyglossia
+ , ("setdefaultlanguage", setDefaultLanguage)
+ , ("setmainlanguage", setDefaultLanguage)
+ -- hyperlink
+ , ("hypertarget", hypertargetBlock)
+ -- LaTeX colors
+ , ("textcolor", coloredBlock "color")
+ , ("colorbox", coloredBlock "background-color")
+ ]
+
+
+environments :: PandocMonad m => M.Map Text (LP m Blocks)
+environments = M.fromList
+ [ ("document", env "document" blocks)
+ , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
+ , ("letter", env "letter" letterContents)
+ , ("minipage", env "minipage" $
+ skipopts *> spaces *> optional braced *> spaces *> blocks)
+ , ("figure", env "figure" $ skipopts *> figure)
+ , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
+ , ("center", env "center" blocks)
+ , ("longtable", env "longtable" $
+ resetCaption *> simpTable "longtable" False >>= addTableCaption)
+ , ("table", env "table" $
+ resetCaption *> skipopts *> blocks >>= addTableCaption)
+ , ("tabular*", env "tabular*" $ simpTable "tabular*" True)
+ , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
+ , ("tabular", env "tabular" $ simpTable "tabular" False)
+ , ("quote", blockQuote <$> env "quote" blocks)
+ , ("quotation", blockQuote <$> env "quotation" blocks)
+ , ("verse", blockQuote <$> env "verse" blocks)
+ , ("itemize", bulletList <$> listenv "itemize" (many item))
+ , ("description", definitionList <$> listenv "description" (many descItem))
+ , ("enumerate", orderedList')
+ , ("alltt", alltt <$> env "alltt" blocks)
+ , ("code", guardEnabled Ext_literate_haskell *>
+ (codeBlockWith ("",["sourceCode","literate","haskell"],[]) <$>
+ verbEnv "code"))
+ , ("comment", mempty <$ verbEnv "comment")
+ , ("verbatim", codeBlock <$> verbEnv "verbatim")
+ , ("Verbatim", fancyverbEnv "Verbatim")
+ , ("BVerbatim", fancyverbEnv "BVerbatim")
+ , ("lstlisting", do attr <- parseListingsOptions <$> option [] keyvals
+ codeBlockWith attr <$> verbEnv "lstlisting")
+ , ("minted", minted)
+ , ("obeylines", obeylines)
+ , ("displaymath", mathEnvWith para Nothing "displaymath")
+ , ("equation", mathEnvWith para Nothing "equation")
+ , ("equation*", mathEnvWith para Nothing "equation*")
+ , ("gather", mathEnvWith para (Just "gathered") "gather")
+ , ("gather*", mathEnvWith para (Just "gathered") "gather*")
+ , ("multline", mathEnvWith para (Just "gathered") "multline")
+ , ("multline*", mathEnvWith para (Just "gathered") "multline*")
+ , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray")
+ , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*")
+ , ("align", mathEnvWith para (Just "aligned") "align")
+ , ("align*", mathEnvWith para (Just "aligned") "align*")
+ , ("alignat", mathEnvWith para (Just "aligned") "alignat")
+ , ("alignat*", mathEnvWith para (Just "aligned") "alignat*")
+ , ("tikzpicture", rawVerbEnv "tikzpicture")
+ -- etoolbox
+ , ("ifstrequal", ifstrequal)
+ , ("newtoggle", braced >>= newToggle)
+ , ("toggletrue", braced >>= setToggle True)
+ , ("togglefalse", braced >>= setToggle False)
+ , ("iftoggle", try $ ifToggle >> block)
+ ]
+
+environment :: PandocMonad m => LP m Blocks
+environment = do
+ controlSeq "begin"
+ name <- untokenize <$> braced
+ M.findWithDefault mzero name environments
+ <|> rawEnv name
-listenv :: String -> LP a -> LP a
-listenv name p = try $ do
- oldCtx <- stateParserContext `fmap` getState
- updateState $ \st -> st{ stateParserContext = ListItemState }
- res <- env name p
- updateState $ \st -> st{ stateParserContext = oldCtx }
- return res
+env :: PandocMonad m => Text -> LP m a -> LP m a
+env name p = p <* end_ name
-mathEnv :: (Inlines -> a) -> Maybe String -> String -> LP a
-mathEnv f innerEnv name = f <$> mathDisplay (inner <$> verbEnv name)
- where inner x = case innerEnv of
- Nothing -> x
- Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
- "\\end{" ++ y ++ "}"
+rawEnv :: PandocMonad m => Text -> LP m Blocks
+rawEnv name = do
+ exts <- getOption readerExtensions
+ let parseRaw = extensionEnabled Ext_raw_tex exts
+ rawOptions <- mconcat <$> many rawopt
+ let beginCommand = "\\begin{" <> name <> "}" <> rawOptions
+ pos1 <- getPosition
+ (bs, raw) <- withRaw $ env name blocks
+ if parseRaw
+ then return $ rawBlock "latex"
+ $ T.unpack $ beginCommand <> untokenize raw
+ else do
+ report $ SkippedContent (T.unpack beginCommand) pos1
+ pos2 <- getPosition
+ report $ SkippedContent ("\\end{" ++ T.unpack name ++ "}") pos2
+ return bs
+
+rawVerbEnv :: PandocMonad m => Text -> LP m Blocks
+rawVerbEnv name = do
+ pos <- getPosition
+ (_, raw) <- withRaw $ verbEnv name
+ let raw' = "\\begin{tikzpicture}" ++ toksToString raw
+ exts <- getOption readerExtensions
+ let parseRaw = extensionEnabled Ext_raw_tex exts
+ if parseRaw
+ then return $ rawBlock "latex" raw'
+ else do
+ report $ SkippedContent raw' pos
+ return mempty
-verbEnv :: String -> LP String
-verbEnv name = do
+verbEnv :: PandocMonad m => Text -> LP m String
+verbEnv name = withVerbatimMode $ do
skipopts
optional blankline
- let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
- res <- manyTill anyChar endEnv
- return $ stripTrailingNewlines res
+ res <- manyTill anyTok (end_ name)
+ return $ stripTrailingNewlines $ toksToString res
-fancyverbEnv :: String -> LP Blocks
+fancyverbEnv :: PandocMonad m => Text -> LP m Blocks
fancyverbEnv name = do
options <- option [] keyvals
let kvs = [ (if k == "firstnumber"
@@ -1242,142 +2207,176 @@ fancyverbEnv name = do
let attr = ("",classes,kvs)
codeBlockWith attr <$> verbEnv name
-orderedList' :: LP Blocks
-orderedList' = do
- optional sp
- (_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
- try $ char '[' *> anyOrderedListMarker <* char ']'
- spaces
- optional $ try $ controlSeq "setlength" *> grouped (controlSeq "itemindent") *> braced
- spaces
- start <- option 1 $ try $ do controlSeq "setcounter"
- grouped (string "enum" *> many1 (oneOf "iv"))
- optional sp
- num <- grouped (many1 digit)
- spaces
- return (read num + 1 :: Int)
- bs <- listenv "enumerate" (many item)
- return $ orderedListWith (start, style, delim) bs
-
-paragraph :: LP Blocks
-paragraph = do
- x <- trimInlines . mconcat <$> many1 inline
- if x == mempty
- then return mempty
- else return $ para x
-
-preamble :: LP Blocks
-preamble = mempty <$> manyTill preambleBlock beginDoc
- where beginDoc = lookAhead $ try $ controlSeq "begin" *> string "{document}"
- preambleBlock = void comment
- <|> void sp
- <|> void blanklines
- <|> void macro
- <|> void blockCommand
- <|> void anyControlSeq
- <|> void braced
- <|> void anyChar
-
--------
+obeylines :: PandocMonad m => LP m Blocks
+obeylines =
+ para . fromList . removeLeadingTrailingBreaks .
+ walk softBreakToHard . toList <$> env "obeylines" inlines
+ where softBreakToHard SoftBreak = LineBreak
+ softBreakToHard x = x
+ removeLeadingTrailingBreaks = reverse . dropWhile isLineBreak .
+ reverse . dropWhile isLineBreak
+ isLineBreak LineBreak = True
+ isLineBreak _ = False
+
+minted :: PandocMonad m => LP m Blocks
+minted = do
+ options <- option [] keyvals
+ lang <- toksToString <$> braced
+ let kvs = [ (if k == "firstnumber"
+ then "startFrom"
+ else k, v) | (k,v) <- options ]
+ let classes = [ lang | not (null lang) ] ++
+ [ "numberLines" |
+ lookup "linenos" options == Just "true" ]
+ let attr = ("",classes,kvs)
+ codeBlockWith attr <$> verbEnv "minted"
--- citations
+letterContents :: PandocMonad m => LP m Blocks
+letterContents = do
+ bs <- blocks
+ st <- getState
+ -- add signature (author) and address (title)
+ let addr = case lookupMeta "address" (sMeta st) of
+ Just (MetaBlocks [Plain xs]) ->
+ para $ trimInlines $ fromList xs
+ _ -> mempty
+ return $ addr <> bs -- sig added by \closing
-addPrefix :: [Inline] -> [Citation] -> [Citation]
-addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
-addPrefix _ _ = []
+figure :: PandocMonad m => LP m Blocks
+figure = try $ do
+ resetCaption
+ blocks >>= addImageCaption
-addSuffix :: [Inline] -> [Citation] -> [Citation]
-addSuffix s ks@(_:_) =
- let k = last ks
- in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
-addSuffix _ _ = []
+addImageCaption :: PandocMonad m => Blocks -> LP m Blocks
+addImageCaption = walkM go
+ where go (Image attr alt (src,tit))
+ | not ("fig:" `isPrefixOf` tit) = do
+ mbcapt <- sCaption <$> getState
+ return $ case mbcapt of
+ Just ils -> Image attr (toList ils) (src, "fig:" ++ tit)
+ Nothing -> Image attr alt (src,tit)
+ go x = return x
-simpleCiteArgs :: LP [Citation]
-simpleCiteArgs = try $ do
- first <- optionMaybe $ toList <$> opt
- second <- optionMaybe $ toList <$> opt
- char '{'
- optional sp
- keys <- manyTill citationLabel (char '}')
- let (pre, suf) = case (first , second ) of
- (Just s , Nothing) -> (mempty, s )
- (Just s , Just t ) -> (s , t )
- _ -> (mempty, mempty)
- conv k = Citation { citationId = k
- , citationPrefix = []
- , citationSuffix = []
- , citationMode = NormalCitation
- , citationHash = 0
- , citationNoteNum = 0
- }
- return $ addPrefix pre $ addSuffix suf $ map conv keys
+coloredBlock :: PandocMonad m => String -> LP m Blocks
+coloredBlock stylename = try $ do
+ skipopts
+ color <- braced
+ notFollowedBy (grouped inline)
+ let constructor = divWith ("",[],[("style",stylename ++ ": " ++ toksToString color)])
+ constructor <$> grouped block
+
+graphicsPath :: PandocMonad m => LP m Blocks
+graphicsPath = do
+ ps <- map toksToString <$> (bgroup *> manyTill braced egroup)
+ getResourcePath >>= setResourcePath . (++ ps)
+ return mempty
-citationLabel :: LP String
-citationLabel = optional sp *>
- (many1 (satisfy isBibtexKeyChar)
- <* optional sp
- <* optional (char ',')
- <* optional sp)
- where isBibtexKeyChar c = isAlphaNum c || c `elem` (".:;?!`'()/*@_+=-[]" :: String)
+splitBibs :: String -> [Inlines]
+splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
-cites :: CitationMode -> Bool -> LP [Citation]
-cites mode multi = try $ do
- cits <- if multi
- then many1 simpleCiteArgs
- else count 1 simpleCiteArgs
- let cs = concat cits
- return $ case mode of
- AuthorInText -> case cs of
- (c:rest) -> c {citationMode = mode} : rest
- [] -> []
- _ -> map (\a -> a {citationMode = mode}) cs
+alltt :: Blocks -> Blocks
+alltt = walk strToCode
+ where strToCode (Str s) = Code nullAttr s
+ strToCode Space = RawInline (Format "latex") "\\ "
+ strToCode SoftBreak = LineBreak
+ strToCode x = x
-citation :: String -> CitationMode -> Bool -> LP Inlines
-citation name mode multi = do
- (c,raw) <- withRaw $ cites mode multi
- return $ cite c (rawInline "latex" $ "\\" ++ name ++ raw)
+parseListingsOptions :: [(String, String)] -> Attr
+parseListingsOptions options =
+ let kvs = [ (if k == "firstnumber"
+ then "startFrom"
+ else k, v) | (k,v) <- options ]
+ classes = [ "numberLines" |
+ lookup "numbers" options == Just "left" ]
+ ++ maybeToList (lookup "language" options
+ >>= fromListingsLanguage)
+ in (fromMaybe "" (lookup "label" options), classes, kvs)
-complexNatbibCitation :: CitationMode -> LP Inlines
-complexNatbibCitation mode = try $ do
- let ils = (toList . trimInlines . mconcat) <$>
- many (notFollowedBy (oneOf "\\};") >> inline)
- let parseOne = try $ do
- skipSpaces
- pref <- ils
- cit' <- inline -- expect a citation
- let citlist = toList cit'
- cits' <- case citlist of
- [Cite cs _] -> return cs
- _ -> mzero
- suff <- ils
- skipSpaces
- optional $ char ';'
- return $ addPrefix pref $ addSuffix suff cits'
- (c:cits, raw) <- withRaw $ grouped parseOne
- return $ cite (c{ citationMode = mode }:cits)
- (rawInline "latex" $ "\\citetext" ++ raw)
+inputListing :: PandocMonad m => LP m Blocks
+inputListing = do
+ pos <- getPosition
+ options <- option [] keyvals
+ f <- filter (/='"') . toksToString <$> braced
+ dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
+ mbCode <- readFileFromDirs dirs f
+ codeLines <- case mbCode of
+ Just s -> return $ lines s
+ Nothing -> do
+ report $ CouldNotLoadIncludeFile f pos
+ return []
+ let (ident,classes,kvs) = parseListingsOptions options
+ let language = case lookup "language" options >>= fromListingsLanguage of
+ Just l -> [l]
+ Nothing -> take 1 $ languagesByExtension (takeExtension f)
+ let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
+ let lastline = fromMaybe (length codeLines) $
+ lookup "lastline" options >>= safeRead
+ let codeContents = intercalate "\n" $ take (1 + lastline - firstline) $
+ drop (firstline - 1) codeLines
+ return $ codeBlockWith (ident,ordNub (classes ++ language),kvs) codeContents
+
+-- lists
+
+item :: PandocMonad m => LP m Blocks
+item = void blocks *> controlSeq "item" *> skipopts *> blocks
+
+descItem :: PandocMonad m => LP m (Inlines, [Blocks])
+descItem = do
+ blocks -- skip blocks before item
+ controlSeq "item"
+ optional sp
+ ils <- opt
+ bs <- blocks
+ return (ils, [bs])
--- tables
+listenv :: PandocMonad m => Text -> LP m a -> LP m a
+listenv name p = try $ do
+ oldInListItem <- sInListItem `fmap` getState
+ updateState $ \st -> st{ sInListItem = True }
+ res <- env name p
+ updateState $ \st -> st{ sInListItem = oldInListItem }
+ return res
-parseAligns :: LP [Alignment]
-parseAligns = try $ do
- char '{'
- let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
- maybeBar
- let cAlign = AlignCenter <$ char 'c'
- let lAlign = AlignLeft <$ char 'l'
- let rAlign = AlignRight <$ char 'r'
- let parAlign = AlignLeft <$ (char 'p' >> braced)
- let alignChar = cAlign <|> lAlign <|> rAlign <|> parAlign
- aligns' <- sepEndBy alignChar maybeBar
+orderedList' :: PandocMonad m => LP m Blocks
+orderedList' = try $ do
spaces
- char '}'
+ let markerSpec = do
+ symbol '['
+ ts <- toksToString <$> manyTill anyTok (symbol ']')
+ case runParser anyOrderedListMarker def "option" ts of
+ Right r -> return r
+ Left _ -> do
+ pos <- getPosition
+ report $ SkippedContent ("[" ++ ts ++ "]") pos
+ return (1, DefaultStyle, DefaultDelim)
+ (_, style, delim) <- option (1, DefaultStyle, DefaultDelim) markerSpec
spaces
- return aligns'
+ optional $ try $ controlSeq "setlength"
+ *> grouped (count 1 $ controlSeq "itemindent")
+ *> braced
+ spaces
+ start <- option 1 $ try $ do pos <- getPosition
+ controlSeq "setcounter"
+ ctr <- toksToString <$> braced
+ guard $ "enum" `isPrefixOf` ctr
+ guard $ all (`elem` ['i','v']) (drop 4 ctr)
+ optional sp
+ num <- toksToString <$> braced
+ case safeRead num of
+ Just i -> return (i + 1 :: Int)
+ Nothing -> do
+ report $ SkippedContent
+ ("\\setcounter{" ++ ctr ++
+ "}{" ++ num ++ "}") pos
+ return 1
+ bs <- listenv "enumerate" (many item)
+ return $ orderedListWith (start, style, delim) bs
+
+-- tables
-hline :: LP ()
+hline :: PandocMonad m => LP m ()
hline = try $ do
- spaces'
+ spaces
controlSeq "hline" <|>
-- booktabs rules:
controlSeq "toprule" <|>
@@ -1385,80 +2384,312 @@ hline = try $ do
controlSeq "midrule" <|>
controlSeq "endhead" <|>
controlSeq "endfirsthead"
- spaces'
- optional $ bracketed (many1 (satisfy (/=']')))
+ spaces
+ optional opt
return ()
-lbreak :: LP ()
-lbreak = () <$ try (spaces' *>
- (controlSeq "\\" <|> controlSeq "tabularnewline") <*
- spaces')
-
-amp :: LP ()
-amp = () <$ try (spaces' *> char '&' <* spaces')
-
-parseTableRow :: Int -- ^ number of columns
- -> LP [Blocks]
-parseTableRow cols = try $ do
- let tableCellInline = notFollowedBy (amp <|> lbreak) >> inline
- let minipage = try $ controlSeq "begin" *> string "{minipage}" *>
- env "minipage"
- (skipopts *> spaces' *> optional braced *> spaces' *> blocks)
- let tableCell = minipage <|>
- ((plain . trimInlines . mconcat) <$> many tableCellInline)
- cells' <- sepBy1 tableCell amp
- let numcells = length cells'
- guard $ numcells <= cols && numcells >= 1
- guard $ cells' /= [mempty]
- -- note: a & b in a three-column table leaves an empty 3rd cell:
- let cells'' = cells' ++ replicate (cols - numcells) mempty
- spaces'
- return cells''
+lbreak :: PandocMonad m => LP m Tok
+lbreak = (controlSeq "\\" <|> controlSeq "tabularnewline") <* spaces
+
+amp :: PandocMonad m => LP m Tok
+amp = symbol '&'
-spaces' :: LP ()
-spaces' = spaces *> skipMany (comment *> spaces)
+-- Split a Word into individual Symbols (for parseAligns)
+splitWordTok :: PandocMonad m => LP m ()
+splitWordTok = do
+ inp <- getInput
+ case inp of
+ (Tok spos Word t : rest) ->
+ setInput $ map (Tok spos Symbol . T.singleton) (T.unpack t) ++ rest
+ _ -> return ()
-simpTable :: Bool -> LP Blocks
-simpTable hasWidthParameter = try $ do
- when hasWidthParameter $ () <$ (spaces' >> tok)
+parseAligns :: PandocMonad m => LP m [(Alignment, Double, ([Tok], [Tok]))]
+parseAligns = try $ do
+ let maybeBar = skipMany $
+ sp <|> () <$ symbol '|' <|> () <$ (symbol '@' >> braced)
+ let cAlign = AlignCenter <$ symbol 'c'
+ let lAlign = AlignLeft <$ symbol 'l'
+ let rAlign = AlignRight <$ symbol 'r'
+ let parAlign = AlignLeft <$ symbol 'p'
+ -- aligns from tabularx
+ let xAlign = AlignLeft <$ symbol 'X'
+ let mAlign = AlignLeft <$ symbol 'm'
+ let bAlign = AlignLeft <$ symbol 'b'
+ let alignChar = splitWordTok *> ( cAlign <|> lAlign <|> rAlign <|> parAlign
+ <|> xAlign <|> mAlign <|> bAlign )
+ let alignPrefix = symbol '>' >> braced
+ let alignSuffix = symbol '<' >> braced
+ let colWidth = try $ do
+ symbol '{'
+ ds <- trim . toksToString <$> manyTill anyTok (controlSeq "linewidth")
+ spaces
+ symbol '}'
+ case safeRead ds of
+ Just w -> return w
+ Nothing -> return 0.0
+ let alignSpec = do
+ pref <- option [] alignPrefix
+ spaces
+ al <- alignChar
+ width <- colWidth <|> option 0.0 (do s <- toksToString <$> braced
+ pos <- getPosition
+ report $ SkippedContent s pos
+ return 0.0)
+ spaces
+ suff <- option [] alignSuffix
+ return (al, width, (pref, suff))
+ let starAlign = do -- '*{2}{r}' == 'rr', we just expand like a macro
+ symbol '*'
+ spaces
+ ds <- trim . toksToString <$> braced
+ spaces
+ spec <- braced
+ case safeRead ds of
+ Just n ->
+ getInput >>= setInput . (mconcat (replicate n spec) ++)
+ Nothing -> fail $ "Could not parse " ++ ds ++ " as number"
+ bgroup
+ spaces
+ maybeBar
+ aligns' <- many $ try $ spaces >> optional starAlign >>
+ (alignSpec <* maybeBar)
+ spaces
+ egroup
+ spaces
+ return aligns'
+
+parseTableRow :: PandocMonad m
+ => Text -- ^ table environment name
+ -> [([Tok], [Tok])] -- ^ pref/suffixes
+ -> LP m [Blocks]
+parseTableRow envname prefsufs = do
+ notFollowedBy (spaces *> end_ envname)
+ let cols = length prefsufs
+ -- add prefixes and suffixes in token stream:
+ let celltoks (pref, suff) = do
+ prefpos <- getPosition
+ contents <- many (notFollowedBy
+ (() <$ amp <|> () <$ lbreak <|> end_ envname)
+ >> anyTok)
+ suffpos <- getPosition
+ option [] (count 1 amp)
+ return $ map (setpos prefpos) pref ++ contents ++ map (setpos suffpos) suff
+ rawcells <- mapM celltoks prefsufs
+ oldInput <- getInput
+ cells <- mapM (\ts -> setInput ts >> parseTableCell) rawcells
+ setInput oldInput
+ spaces
+ let numcells = length cells
+ guard $ numcells <= cols && numcells >= 1
+ guard $ cells /= [mempty]
+ -- note: a & b in a three-column table leaves an empty 3rd cell:
+ return $ cells ++ replicate (cols - numcells) mempty
+
+parseTableCell :: PandocMonad m => LP m Blocks
+parseTableCell = do
+ let plainify bs = case toList bs of
+ [Para ils] -> plain (fromList ils)
+ _ -> bs
+ updateState $ \st -> st{ sInTableCell = True }
+ cells <- plainify <$> blocks
+ updateState $ \st -> st{ sInTableCell = False }
+ return cells
+
+simpTable :: PandocMonad m => Text -> Bool -> LP m Blocks
+simpTable envname hasWidthParameter = try $ do
+ when hasWidthParameter $ () <$ (spaces >> tok)
skipopts
- aligns <- parseAligns
- let cols = length aligns
+ colspecs <- parseAligns
+ let (aligns, widths, prefsufs) = unzip3 colspecs
+ let cols = length colspecs
optional $ controlSeq "caption" *> skipopts *> setCaption
optional lbreak
- spaces'
+ spaces
skipMany hline
- spaces'
- header' <- option [] $ try (parseTableRow cols <* lbreak <* many1 hline)
- spaces'
- rows <- sepEndBy (parseTableRow cols) (lbreak <* optional (skipMany hline))
- spaces'
+ spaces
+ header' <- option [] $ try (parseTableRow envname prefsufs <*
+ lbreak <* many1 hline)
+ spaces
+ rows <- sepEndBy (parseTableRow envname prefsufs)
+ (lbreak <* optional (skipMany hline))
+ spaces
optional $ controlSeq "caption" *> skipopts *> setCaption
optional lbreak
- spaces'
+ spaces
let header'' = if null header'
then replicate cols mempty
else header'
lookAhead $ controlSeq "end" -- make sure we're at end
- return $ table mempty (zip aligns (repeat 0)) header'' rows
+ return $ table mempty (zip aligns widths) header'' rows
-startInclude :: LP Blocks
-startInclude = do
- fn <- braced
- setPosition $ newPos fn 1 1
- return mempty
+addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
+addTableCaption = walkM go
+ where go (Table c als ws hs rs) = do
+ mbcapt <- sCaption <$> getState
+ return $ case mbcapt of
+ Just ils -> Table (toList ils) als ws hs rs
+ Nothing -> Table c als ws hs rs
+ go x = return x
-endInclude :: LP Blocks
-endInclude = do
- fn <- braced
- ln <- braced
- co <- braced
- setPosition $ newPos fn (fromMaybe 1 $ safeRead ln) (fromMaybe 1 $ safeRead co)
- return mempty
-removeDoubleQuotes :: String -> String
-removeDoubleQuotes ('"':xs) =
- case reverse xs of
- '"':ys -> reverse ys
- _ -> '"':xs
-removeDoubleQuotes xs = xs
+block :: PandocMonad m => LP m Blocks
+block = do
+ res <- (mempty <$ spaces1)
+ <|> environment
+ <|> include
+ <|> macroDef
+ <|> blockCommand
+ <|> paragraph
+ <|> grouped block
+ trace (take 60 $ show $ B.toList res)
+ return res
+
+blocks :: PandocMonad m => LP m Blocks
+blocks = mconcat <$> many block
+
+setDefaultLanguage :: PandocMonad m => LP m Blocks
+setDefaultLanguage = do
+ o <- option "" $ (T.unpack . T.filter (\c -> c /= '[' && c /= ']'))
+ <$> rawopt
+ polylang <- toksToString <$> braced
+ case M.lookup polylang polyglossiaLangToBCP47 of
+ Nothing -> return mempty -- TODO mzero? warning?
+ Just langFunc -> do
+ let l = langFunc o
+ setTranslations l
+ updateState $ setMeta "lang" $ str (renderLang l)
+ return mempty
+
+polyglossiaLangToBCP47 :: M.Map String (String -> Lang)
+polyglossiaLangToBCP47 = M.fromList
+ [ ("arabic", \o -> case filter (/=' ') o of
+ "locale=algeria" -> Lang "ar" "" "DZ" []
+ "locale=mashriq" -> Lang "ar" "" "SY" []
+ "locale=libya" -> Lang "ar" "" "LY" []
+ "locale=morocco" -> Lang "ar" "" "MA" []
+ "locale=mauritania" -> Lang "ar" "" "MR" []
+ "locale=tunisia" -> Lang "ar" "" "TN" []
+ _ -> Lang "ar" "" "" [])
+ , ("german", \o -> case filter (/=' ') o of
+ "spelling=old" -> Lang "de" "" "DE" ["1901"]
+ "variant=austrian,spelling=old"
+ -> Lang "de" "" "AT" ["1901"]
+ "variant=austrian" -> Lang "de" "" "AT" []
+ "variant=swiss,spelling=old"
+ -> Lang "de" "" "CH" ["1901"]
+ "variant=swiss" -> Lang "de" "" "CH" []
+ _ -> Lang "de" "" "" [])
+ , ("lsorbian", \_ -> Lang "dsb" "" "" [])
+ , ("greek", \o -> case filter (/=' ') o of
+ "variant=poly" -> Lang "el" "" "polyton" []
+ "variant=ancient" -> Lang "grc" "" "" []
+ _ -> Lang "el" "" "" [])
+ , ("english", \o -> case filter (/=' ') o of
+ "variant=australian" -> Lang "en" "" "AU" []
+ "variant=canadian" -> Lang "en" "" "CA" []
+ "variant=british" -> Lang "en" "" "GB" []
+ "variant=newzealand" -> Lang "en" "" "NZ" []
+ "variant=american" -> Lang "en" "" "US" []
+ _ -> Lang "en" "" "" [])
+ , ("usorbian", \_ -> Lang "hsb" "" "" [])
+ , ("latin", \o -> case filter (/=' ') o of
+ "variant=classic" -> Lang "la" "" "" ["x-classic"]
+ _ -> Lang "la" "" "" [])
+ , ("slovenian", \_ -> Lang "sl" "" "" [])
+ , ("serbianc", \_ -> Lang "sr" "cyrl" "" [])
+ , ("pinyin", \_ -> Lang "zh" "Latn" "" ["pinyin"])
+ , ("afrikaans", \_ -> Lang "af" "" "" [])
+ , ("amharic", \_ -> Lang "am" "" "" [])
+ , ("assamese", \_ -> Lang "as" "" "" [])
+ , ("asturian", \_ -> Lang "ast" "" "" [])
+ , ("bulgarian", \_ -> Lang "bg" "" "" [])
+ , ("bengali", \_ -> Lang "bn" "" "" [])
+ , ("tibetan", \_ -> Lang "bo" "" "" [])
+ , ("breton", \_ -> Lang "br" "" "" [])
+ , ("catalan", \_ -> Lang "ca" "" "" [])
+ , ("welsh", \_ -> Lang "cy" "" "" [])
+ , ("czech", \_ -> Lang "cs" "" "" [])
+ , ("coptic", \_ -> Lang "cop" "" "" [])
+ , ("danish", \_ -> Lang "da" "" "" [])
+ , ("divehi", \_ -> Lang "dv" "" "" [])
+ , ("esperanto", \_ -> Lang "eo" "" "" [])
+ , ("spanish", \_ -> Lang "es" "" "" [])
+ , ("estonian", \_ -> Lang "et" "" "" [])
+ , ("basque", \_ -> Lang "eu" "" "" [])
+ , ("farsi", \_ -> Lang "fa" "" "" [])
+ , ("finnish", \_ -> Lang "fi" "" "" [])
+ , ("french", \_ -> Lang "fr" "" "" [])
+ , ("friulan", \_ -> Lang "fur" "" "" [])
+ , ("irish", \_ -> Lang "ga" "" "" [])
+ , ("scottish", \_ -> Lang "gd" "" "" [])
+ , ("ethiopic", \_ -> Lang "gez" "" "" [])
+ , ("galician", \_ -> Lang "gl" "" "" [])
+ , ("hebrew", \_ -> Lang "he" "" "" [])
+ , ("hindi", \_ -> Lang "hi" "" "" [])
+ , ("croatian", \_ -> Lang "hr" "" "" [])
+ , ("magyar", \_ -> Lang "hu" "" "" [])
+ , ("armenian", \_ -> Lang "hy" "" "" [])
+ , ("interlingua", \_ -> Lang "ia" "" "" [])
+ , ("indonesian", \_ -> Lang "id" "" "" [])
+ , ("icelandic", \_ -> Lang "is" "" "" [])
+ , ("italian", \_ -> Lang "it" "" "" [])
+ , ("japanese", \_ -> Lang "jp" "" "" [])
+ , ("khmer", \_ -> Lang "km" "" "" [])
+ , ("kurmanji", \_ -> Lang "kmr" "" "" [])
+ , ("kannada", \_ -> Lang "kn" "" "" [])
+ , ("korean", \_ -> Lang "ko" "" "" [])
+ , ("lao", \_ -> Lang "lo" "" "" [])
+ , ("lithuanian", \_ -> Lang "lt" "" "" [])
+ , ("latvian", \_ -> Lang "lv" "" "" [])
+ , ("malayalam", \_ -> Lang "ml" "" "" [])
+ , ("mongolian", \_ -> Lang "mn" "" "" [])
+ , ("marathi", \_ -> Lang "mr" "" "" [])
+ , ("dutch", \_ -> Lang "nl" "" "" [])
+ , ("nynorsk", \_ -> Lang "nn" "" "" [])
+ , ("norsk", \_ -> Lang "no" "" "" [])
+ , ("nko", \_ -> Lang "nqo" "" "" [])
+ , ("occitan", \_ -> Lang "oc" "" "" [])
+ , ("panjabi", \_ -> Lang "pa" "" "" [])
+ , ("polish", \_ -> Lang "pl" "" "" [])
+ , ("piedmontese", \_ -> Lang "pms" "" "" [])
+ , ("portuguese", \_ -> Lang "pt" "" "" [])
+ , ("romansh", \_ -> Lang "rm" "" "" [])
+ , ("romanian", \_ -> Lang "ro" "" "" [])
+ , ("russian", \_ -> Lang "ru" "" "" [])
+ , ("sanskrit", \_ -> Lang "sa" "" "" [])
+ , ("samin", \_ -> Lang "se" "" "" [])
+ , ("slovak", \_ -> Lang "sk" "" "" [])
+ , ("albanian", \_ -> Lang "sq" "" "" [])
+ , ("serbian", \_ -> Lang "sr" "" "" [])
+ , ("swedish", \_ -> Lang "sv" "" "" [])
+ , ("syriac", \_ -> Lang "syr" "" "" [])
+ , ("tamil", \_ -> Lang "ta" "" "" [])
+ , ("telugu", \_ -> Lang "te" "" "" [])
+ , ("thai", \_ -> Lang "th" "" "" [])
+ , ("turkmen", \_ -> Lang "tk" "" "" [])
+ , ("turkish", \_ -> Lang "tr" "" "" [])
+ , ("ukrainian", \_ -> Lang "uk" "" "" [])
+ , ("urdu", \_ -> Lang "ur" "" "" [])
+ , ("vietnamese", \_ -> Lang "vi" "" "" [])
+ ]
+
+babelLangToBCP47 :: String -> Maybe Lang
+babelLangToBCP47 s =
+ case s of
+ "austrian" -> Just $ Lang "de" "" "AT" ["1901"]
+ "naustrian" -> Just $ Lang "de" "" "AT" []
+ "swissgerman" -> Just $ Lang "de" "" "CH" ["1901"]
+ "nswissgerman" -> Just $ Lang "de" "" "CH" []
+ "german" -> Just $ Lang "de" "" "DE" ["1901"]
+ "ngerman" -> Just $ Lang "de" "" "DE" []
+ "lowersorbian" -> Just $ Lang "dsb" "" "" []
+ "uppersorbian" -> Just $ Lang "hsb" "" "" []
+ "polutonikogreek" -> Just $ Lang "el" "" "" ["polyton"]
+ "slovene" -> Just $ Lang "sl" "" "" []
+ "australian" -> Just $ Lang "en" "" "AU" []
+ "canadian" -> Just $ Lang "en" "" "CA" []
+ "british" -> Just $ Lang "en" "" "GB" []
+ "newzealand" -> Just $ Lang "en" "" "NZ" []
+ "american" -> Just $ Lang "en" "" "US" []
+ "classiclatin" -> Just $ Lang "la" "" "" ["x-classic"]
+ _ -> fmap ($ "") $ M.lookup s polyglossiaLangToBCP47
diff --git a/src/Text/Pandoc/Readers/LaTeX/Types.hs b/src/Text/Pandoc/Readers/LaTeX/Types.hs
new file mode 100644
index 000000000..c9cbaa9b9
--- /dev/null
+++ b/src/Text/Pandoc/Readers/LaTeX/Types.hs
@@ -0,0 +1,51 @@
+{-
+Copyright (C) 2017-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.LaTeX.Types
+ Copyright : Copyright (C) 2017-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Types for LaTeX tokens and macros.
+-}
+module Text.Pandoc.Readers.LaTeX.Types ( Tok(..)
+ , TokType(..)
+ , Macro(..)
+ , ExpansionPoint(..)
+ , SourcePos
+ )
+where
+import Data.Text (Text)
+import Text.Parsec.Pos (SourcePos)
+
+data TokType = CtrlSeq Text | Spaces | Newline | Symbol | Word | Comment |
+ Esc1 | Esc2 | Arg Int
+ deriving (Eq, Ord, Show)
+
+data Tok = Tok SourcePos TokType Text
+ deriving (Eq, Ord, Show)
+
+data ExpansionPoint = ExpandWhenDefined | ExpandWhenUsed
+ deriving (Eq, Ord, Show)
+
+data Macro = Macro ExpansionPoint Int (Maybe [Tok]) [Tok]
+ deriving Show
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index cd35a8738..14cf73de4 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE RelaxedPolyRec #-} -- needed for inlinesBetween on GHC < 7
+{-# LANGUAGE RelaxedPolyRec #-}
{-# LANGUAGE ScopedTypeVariables #-}
+
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Markdown
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,63 +30,55 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of markdown-formatted plain text to 'Pandoc' document.
-}
-module Text.Pandoc.Readers.Markdown ( readMarkdown,
- readMarkdownWithWarnings ) where
+module Text.Pandoc.Readers.Markdown ( readMarkdown ) where
-import Data.List ( transpose, sortBy, findIndex, intercalate )
+import Control.Monad
+import Control.Monad.Except (throwError)
+import Data.Char (isAlphaNum, isPunctuation, isSpace, toLower)
+import qualified Data.HashMap.Strict as H
+import Data.List (intercalate, sortBy, transpose, elemIndex)
import qualified Data.Map as M
-import Data.Scientific (coefficient, base10Exponent)
-import Data.Ord ( comparing )
-import Data.Char ( isSpace, isAlphaNum, toLower, isPunctuation )
import Data.Maybe
-import Text.Pandoc.Definition
-import Text.Pandoc.Emoji (emojis)
-import Text.Pandoc.Generic (bottomUp)
-import qualified Data.Text as T
+import Data.Monoid ((<>))
+import Data.Ord (comparing)
+import Data.Scientific (base10Exponent, coefficient)
+import qualified Data.Set as Set
import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Vector as V
+import Data.Yaml (ParseException (..), YamlException (..), YamlMark (..))
import qualified Data.Yaml as Yaml
-import Data.Yaml (ParseException(..), YamlException(..), YamlMark(..))
-import qualified Data.HashMap.Strict as H
+import System.FilePath (addExtension, takeExtension)
+import Text.HTML.TagSoup
+import Text.Pandoc.Builder (Blocks, Inlines)
import qualified Text.Pandoc.Builder as B
-import qualified Text.Pandoc.UTF8 as UTF8
-import qualified Data.Vector as V
-import Text.Pandoc.Builder (Inlines, Blocks, trimInlines)
+import Text.Pandoc.Class (PandocMonad (..), report)
+import Text.Pandoc.Definition
+import Text.Pandoc.Emoji (emojis)
+import Text.Pandoc.Error
+import Text.Pandoc.Logging
import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (tableWith)
+import Text.Pandoc.Readers.HTML (htmlInBalanced, htmlTag, isBlockTag,
+ isCommentTag, isInlineTag, isTextTag)
+import Text.Pandoc.Readers.LaTeX (applyMacros, rawLaTeXBlock, rawLaTeXInline)
import Text.Pandoc.Shared
-import Text.Pandoc.Pretty (charWidth)
+import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.XML (fromEntities)
-import Text.Pandoc.Parsing hiding (tableWith)
-import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXBlock )
-import Text.Pandoc.Readers.HTML ( htmlTag, htmlInBalanced, isInlineTag, isBlockTag,
- isTextTag, isCommentTag )
-import Control.Monad
-import System.FilePath (takeExtension, addExtension)
-import Text.HTML.TagSoup
-import qualified Data.Set as Set
-import Text.Printf (printf)
-import Debug.Trace (trace)
-import Data.Monoid ((<>))
-import Text.Pandoc.Error
-type MarkdownParser = Parser [Char] ParserState
+type MarkdownParser m = ParserT [Char] ParserState m
-- | Read markdown from an input string and return a Pandoc document.
-readMarkdown :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError Pandoc
-readMarkdown opts s =
- (readWith parseMarkdown) def{ stateOptions = opts } (s ++ "\n\n")
-
--- | Read markdown from an input string and return a pair of a Pandoc document
--- and a list of warnings.
-readMarkdownWithWarnings :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError (Pandoc, [String])
-readMarkdownWithWarnings opts s =
- (readWithWarnings parseMarkdown) def{ stateOptions = opts } (s ++ "\n\n")
-
-trimInlinesF :: F Inlines -> F Inlines
-trimInlinesF = liftM trimInlines
+readMarkdown :: PandocMonad m
+ => ReaderOptions -- ^ Reader options
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
+ -> m Pandoc
+readMarkdown opts s = do
+ parsed <- readWithM parseMarkdown def{ stateOptions = opts }
+ (T.unpack (crFilter s) ++ "\n\n")
+ case parsed of
+ Right result -> return result
+ Left e -> throwError e
--
-- Constants and data structure definitions
@@ -117,44 +110,43 @@ isBlank _ = False
--
-- | Succeeds when we're in list context.
-inList :: MarkdownParser ()
+inList :: PandocMonad m => MarkdownParser m ()
inList = do
ctx <- stateParserContext <$> getState
guard (ctx == ListItemState)
-spnl :: Parser [Char] st ()
+spnl :: PandocMonad m => ParserT [Char] st m ()
spnl = try $ do
skipSpaces
optional newline
skipSpaces
notFollowedBy (char '\n')
-indentSpaces :: MarkdownParser String
+spnl' :: PandocMonad m => ParserT [Char] st m String
+spnl' = try $ do
+ xs <- many spaceChar
+ ys <- option "" $ try $ (:) <$> newline
+ <*> (many spaceChar <* notFollowedBy (char '\n'))
+ return (xs ++ ys)
+
+indentSpaces :: PandocMonad m => MarkdownParser m String
indentSpaces = try $ do
tabStop <- getOption readerTabStop
count tabStop (char ' ') <|>
string "\t" <?> "indentation"
-nonindentSpaces :: MarkdownParser String
+nonindentSpaces :: PandocMonad m => MarkdownParser m String
nonindentSpaces = do
- tabStop <- getOption readerTabStop
- sps <- many (char ' ')
- if length sps < tabStop
- then return sps
- else unexpected "indented line"
+ n <- skipNonindentSpaces
+ return $ replicate n ' '
-- returns number of spaces parsed
-skipNonindentSpaces :: MarkdownParser Int
+skipNonindentSpaces :: PandocMonad m => MarkdownParser m Int
skipNonindentSpaces = do
tabStop <- getOption readerTabStop
- atMostSpaces (tabStop - 1) <* notFollowedBy (char ' ')
+ gobbleAtMostSpaces (tabStop - 1) <* notFollowedBy spaceChar
-atMostSpaces :: Int -> MarkdownParser Int
-atMostSpaces n
- | n > 0 = (char ' ' >> (+1) <$> atMostSpaces (n-1)) <|> return 0
- | otherwise = return 0
-
-litChar :: MarkdownParser Char
+litChar :: PandocMonad m => MarkdownParser m Char
litChar = escapedChar'
<|> characterReference
<|> noneOf "\n"
@@ -162,30 +154,32 @@ litChar = escapedChar'
-- | Parse a sequence of inline elements between square brackets,
-- including inlines between balanced pairs of square brackets.
-inlinesInBalancedBrackets :: MarkdownParser (F Inlines)
-inlinesInBalancedBrackets = do
- char '['
- (_, raw) <- withRaw $ charsInBalancedBrackets 1
- guard $ not $ null raw
- parseFromString (trimInlinesF . mconcat <$> many inline) (init raw)
-
-charsInBalancedBrackets :: Int -> MarkdownParser ()
-charsInBalancedBrackets 0 = return ()
-charsInBalancedBrackets openBrackets =
- (char '[' >> charsInBalancedBrackets (openBrackets + 1))
- <|> (char ']' >> charsInBalancedBrackets (openBrackets - 1))
- <|> (( (() <$ code)
- <|> (() <$ (escapedChar'))
- <|> (newline >> notFollowedBy blankline)
- <|> skipMany1 (noneOf "[]`\n\\")
- <|> (() <$ count 1 (oneOf "`\\"))
- ) >> charsInBalancedBrackets openBrackets)
+inlinesInBalancedBrackets :: PandocMonad m => MarkdownParser m (F Inlines)
+inlinesInBalancedBrackets =
+ try $ char '[' >> withRaw (go 1) >>=
+ parseFromString inlines . stripBracket . snd
+ where stripBracket [] = []
+ stripBracket xs = if last xs == ']' then init xs else xs
+ go :: PandocMonad m => Int -> MarkdownParser m ()
+ go 0 = return ()
+ go openBrackets =
+ (() <$ (escapedChar <|>
+ code <|>
+ rawHtmlInline <|>
+ rawLaTeXInline') >> go openBrackets)
+ <|>
+ (do char ']'
+ Control.Monad.when (openBrackets > 1) $ go (openBrackets - 1))
+ <|>
+ (char '[' >> go (openBrackets + 1))
+ <|>
+ (anyChar >> go openBrackets)
--
-- document structure
--
-rawTitleBlockLine :: MarkdownParser String
+rawTitleBlockLine :: PandocMonad m => MarkdownParser m String
rawTitleBlockLine = do
char '%'
skipSpaces
@@ -196,13 +190,13 @@ rawTitleBlockLine = do
anyLine
return $ trim $ unlines (first:rest)
-titleLine :: MarkdownParser (F Inlines)
+titleLine :: PandocMonad m => MarkdownParser m (F Inlines)
titleLine = try $ do
raw <- rawTitleBlockLine
- res <- parseFromString (many inline) raw
- return $ trimInlinesF $ mconcat res
+ res <- parseFromString' inlines raw
+ return $ trimInlinesF res
-authorsLine :: MarkdownParser (F [Inlines])
+authorsLine :: PandocMonad m => MarkdownParser m (F [Inlines])
authorsLine = try $ do
raw <- rawTitleBlockLine
let sep = (char ';' <* spaces) <|> newline
@@ -210,18 +204,18 @@ authorsLine = try $ do
(trimInlinesF . mconcat <$> many
(try $ notFollowedBy sep >> inline))
sep
- sequence <$> parseFromString pAuthors raw
+ sequence <$> parseFromString' pAuthors raw
-dateLine :: MarkdownParser (F Inlines)
+dateLine :: PandocMonad m => MarkdownParser m (F Inlines)
dateLine = try $ do
raw <- rawTitleBlockLine
- res <- parseFromString (many inline) raw
- return $ trimInlinesF $ mconcat res
+ res <- parseFromString' inlines raw
+ return $ trimInlinesF res
-titleBlock :: MarkdownParser ()
+titleBlock :: PandocMonad m => MarkdownParser m ()
titleBlock = pandocTitleBlock <|> mmdTitleBlock
-pandocTitleBlock :: MarkdownParser ()
+pandocTitleBlock :: PandocMonad m => MarkdownParser m ()
pandocTitleBlock = try $ do
guardEnabled Ext_pandoc_title_block
lookAhead (char '%')
@@ -239,7 +233,8 @@ pandocTitleBlock = try $ do
$ nullMeta
updateState $ \st -> st{ stateMeta' = stateMeta' st <> meta' }
-yamlMetaBlock :: MarkdownParser (F Blocks)
+
+yamlMetaBlock :: PandocMonad m => MarkdownParser m (F Blocks)
yamlMetaBlock = try $ do
guardEnabled Ext_yaml_metadata_block
pos <- getPosition
@@ -250,87 +245,105 @@ yamlMetaBlock = try $ do
-- by including --- and ..., we allow yaml blocks with just comments:
let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."]))
optional blanklines
- opts <- stateOptions <$> getState
- meta' <- case Yaml.decodeEither' $ UTF8.fromString rawYaml of
- Right (Yaml.Object hashmap) -> return $ return $
- H.foldrWithKey (\k v m ->
- if ignorable k
- then m
- else case yamlToMeta opts v of
- Left _ -> m
- Right v' -> B.setMeta (T.unpack k) v' m)
- nullMeta hashmap
- Right Yaml.Null -> return $ return nullMeta
- Right _ -> do
- addWarning (Just pos) "YAML header is not an object"
- return $ return nullMeta
- Left err' -> do
- case err' of
- InvalidYaml (Just YamlParseException{
- yamlProblem = problem
- , yamlContext = _ctxt
- , yamlProblemMark = Yaml.YamlMark {
- yamlLine = yline
- , yamlColumn = ycol
- }}) ->
- addWarning (Just $ setSourceLine
- (setSourceColumn pos
- (sourceColumn pos + ycol))
- (sourceLine pos + 1 + yline))
- $ "Could not parse YAML header: " ++
- problem
- _ -> addWarning (Just pos)
- $ "Could not parse YAML header: " ++
- show err'
- return $ return nullMeta
- updateState $ \st -> st{ stateMeta' = stateMeta' st <> meta' }
+ case Yaml.decodeEither' $ UTF8.fromString rawYaml of
+ Right (Yaml.Object hashmap) -> do
+ let alist = H.toList hashmap
+ mapM_ (\(k, v) ->
+ if ignorable k
+ then return ()
+ else do
+ v' <- yamlToMeta v
+ let k' = T.unpack k
+ updateState $ \st -> st{ stateMeta' =
+ do m <- stateMeta' st
+ -- if there's already a value, leave it unchanged
+ case lookupMeta k' m of
+ Just _ -> return m
+ Nothing -> do
+ v'' <- v'
+ return $ B.setMeta (T.unpack k) v'' m}
+ ) alist
+ Right Yaml.Null -> return ()
+ Right _ -> do
+ logMessage $
+ CouldNotParseYamlMetadata "not an object"
+ pos
+ return ()
+ Left err' -> do
+ case err' of
+ InvalidYaml (Just YamlParseException{
+ yamlProblem = problem
+ , yamlContext = _ctxt
+ , yamlProblemMark = Yaml.YamlMark {
+ yamlLine = yline
+ , yamlColumn = ycol
+ }}) ->
+ logMessage $ CouldNotParseYamlMetadata
+ problem (setSourceLine
+ (setSourceColumn pos
+ (sourceColumn pos + ycol))
+ (sourceLine pos + 1 + yline))
+ _ -> logMessage $ CouldNotParseYamlMetadata
+ (show err') pos
+ return ()
return mempty
-- ignore fields ending with _
ignorable :: Text -> Bool
ignorable t = (T.pack "_") `T.isSuffixOf` t
-toMetaValue :: ReaderOptions -> Text -> Either PandocError MetaValue
-toMetaValue opts x = toMeta <$> readMarkdown opts' (T.unpack x)
- where
- toMeta p =
- case p of
- Pandoc _ [Plain xs] -> MetaInlines xs
- Pandoc _ [Para xs]
- | endsWithNewline x -> MetaBlocks [Para xs]
- | otherwise -> MetaInlines xs
- Pandoc _ bs -> MetaBlocks bs
- endsWithNewline t = T.pack "\n" `T.isSuffixOf` t
- opts' = opts{readerExtensions=readerExtensions opts `Set.difference` meta_exts}
- meta_exts = Set.fromList [ Ext_pandoc_title_block
- , Ext_mmd_title_block
- , Ext_yaml_metadata_block
- ]
-
-yamlToMeta :: ReaderOptions -> Yaml.Value -> Either PandocError MetaValue
-yamlToMeta opts (Yaml.String t) = toMetaValue opts t
-yamlToMeta _ (Yaml.Number n)
+toMetaValue :: PandocMonad m
+ => Text -> MarkdownParser m (F MetaValue)
+toMetaValue x =
+ parseFromString' parser' (T.unpack x)
+ where parser' = (asInlines <$> ((trimInlinesF . mconcat)
+ <$> try (guard (not endsWithNewline)
+ *> manyTill inline eof)))
+ <|> (asBlocks <$> parseBlocks)
+ asBlocks p = do
+ p' <- p
+ return $ MetaBlocks (B.toList p')
+ asInlines p = do
+ p' <- p
+ return $ MetaInlines (B.toList p')
+ endsWithNewline = T.pack "\n" `T.isSuffixOf` x
+ -- Note: a standard quoted or unquoted YAML value will
+ -- not end in a newline, but a "block" set off with
+ -- `|` or `>` will.
+
+yamlToMeta :: PandocMonad m
+ => Yaml.Value -> MarkdownParser m (F MetaValue)
+yamlToMeta (Yaml.String t) = toMetaValue t
+yamlToMeta (Yaml.Number n)
-- avoid decimal points for numbers that don't need them:
- | base10Exponent n >= 0 = return $ MetaString $ show
+ | base10Exponent n >= 0 = return $ return $ MetaString $ show
$ coefficient n * (10 ^ base10Exponent n)
- | otherwise = return $ MetaString $ show n
-yamlToMeta _ (Yaml.Bool b) = return $ MetaBool b
-yamlToMeta opts (Yaml.Array xs) = B.toMetaValue <$> mapM (yamlToMeta opts)
- (V.toList xs)
-yamlToMeta opts (Yaml.Object o) = MetaMap <$> H.foldrWithKey (\k v m ->
- if ignorable k
- then m
- else (do
- v' <- yamlToMeta opts v
- m' <- m
- return (M.insert (T.unpack k) v' m')))
- (return M.empty) o
-yamlToMeta _ _ = return $ MetaString ""
-
-stopLine :: MarkdownParser ()
+ | otherwise = return $ return $ MetaString $ show n
+yamlToMeta (Yaml.Bool b) = return $ return $ MetaBool b
+yamlToMeta (Yaml.Array xs) = do
+ xs' <- mapM yamlToMeta (V.toList xs)
+ return $ do
+ xs'' <- sequence xs'
+ return $ B.toMetaValue xs''
+yamlToMeta (Yaml.Object o) = do
+ let alist = H.toList o
+ foldM (\m (k,v) ->
+ if ignorable k
+ then return m
+ else do
+ v' <- yamlToMeta v
+ return $ do
+ MetaMap m' <- m
+ v'' <- v'
+ return (MetaMap $ M.insert (T.unpack k) v'' m'))
+ (return $ MetaMap M.empty)
+ alist
+yamlToMeta _ = return $ return $ MetaString ""
+
+stopLine :: PandocMonad m => MarkdownParser m ()
stopLine = try $ (string "---" <|> string "...") >> blankline >> return ()
-mmdTitleBlock :: MarkdownParser ()
+mmdTitleBlock :: PandocMonad m => MarkdownParser m ()
mmdTitleBlock = try $ do
guardEnabled Ext_mmd_title_block
firstPair <- kvPair False
@@ -340,49 +353,44 @@ mmdTitleBlock = try $ do
updateState $ \st -> st{ stateMeta' = stateMeta' st <>
return (Meta $ M.fromList kvPairs) }
-kvPair :: Bool -> MarkdownParser (String, MetaValue)
+kvPair :: PandocMonad m => Bool -> MarkdownParser m (String, MetaValue)
kvPair allowEmpty = try $ do
key <- many1Till (alphaNum <|> oneOf "_- ") (char ':')
val <- trim <$> manyTill anyChar
(try $ newline >> lookAhead (blankline <|> nonspaceChar))
guard $ allowEmpty || not (null val)
let key' = concat $ words $ map toLower key
- let val' = MetaBlocks $ B.toList $ B.plain $ B.text $ val
+ let val' = MetaBlocks $ B.toList $ B.plain $B.text val
return (key',val')
-parseMarkdown :: MarkdownParser Pandoc
+parseMarkdown :: PandocMonad m => MarkdownParser m Pandoc
parseMarkdown = do
- -- markdown allows raw HTML
- updateState $ \state -> state { stateOptions =
- let oldOpts = stateOptions state in
- oldOpts{ readerParseRaw = True } }
optional titleBlock
blocks <- parseBlocks
st <- getState
- let meta = runF (stateMeta' st) st
- let Pandoc _ bs = B.doc $ runF blocks st
- eastAsianLineBreaks <- option False $
- True <$ guardEnabled Ext_east_asian_line_breaks
- return $ (if eastAsianLineBreaks
- then bottomUp softBreakFilter
- else id) $ Pandoc meta bs
-
-softBreakFilter :: [Inline] -> [Inline]
-softBreakFilter (x:SoftBreak:y:zs) =
- case (stringify x, stringify y) of
- (xs@(_:_), (c:_))
- | charWidth (last xs) == 2 && charWidth c == 2 -> x:y:zs
- _ -> x:SoftBreak:y:zs
-softBreakFilter xs = xs
-
-referenceKey :: MarkdownParser (F Blocks)
+ -- check for notes with no corresponding note references
+ let notesUsed = stateNoteRefs st
+ let notesDefined = M.keys (stateNotes' st)
+ mapM_ (\n -> unless (n `Set.member` notesUsed) $
+ case M.lookup n (stateNotes' st) of
+ Just (pos, _) -> report (NoteDefinedButNotUsed n pos)
+ Nothing -> throwError $
+ PandocShouldNeverHappenError "note not found")
+ notesDefined
+ let doc = runF (do Pandoc _ bs <- B.doc <$> blocks
+ meta <- stateMeta' st
+ return $ Pandoc meta bs) st
+ reportLogMessages
+ return doc
+
+referenceKey :: PandocMonad m => MarkdownParser m (F Blocks)
referenceKey = try $ do
pos <- getPosition
skipNonindentSpaces
(_,raw) <- reference
char ':'
skipSpaces >> optional newline >> skipSpaces >> notFollowedBy (char '[')
- let sourceURL = liftM unwords $ many $ try $ do
+ let sourceURL = fmap unwords $ many $ try $ do
skipMany spaceChar
notFollowedBy' referenceTitle
notFollowedBy' $ guardEnabled Ext_link_attributes >> attributes
@@ -392,7 +400,9 @@ referenceKey = try $ do
src <- try betweenAngles <|> sourceURL
tit <- option "" referenceTitle
attr <- option nullAttr $ try $
- guardEnabled Ext_link_attributes >> skipSpaces >> attributes
+ do guardEnabled Ext_link_attributes
+ skipSpaces >> optional newline >> skipSpaces
+ attributes
addKvs <- option [] $ guardEnabled Ext_mmd_link_attributes
>> many (try $ spnl >> keyValAttr)
blanklines
@@ -402,18 +412,22 @@ referenceKey = try $ do
let oldkeys = stateKeys st
let key = toKey raw
case M.lookup key oldkeys of
- Just _ -> addWarning (Just pos) $ "Duplicate link reference `" ++ raw ++ "'"
- Nothing -> return ()
+ Just (t,a) | not (t == target && a == attr') ->
+ -- We don't warn on two duplicate keys if the targets are also
+ -- the same. This can happen naturally with --reference-location=block
+ -- or section. See #3701.
+ logMessage $ DuplicateLinkReference raw pos
+ _ -> return ()
updateState $ \s -> s { stateKeys = M.insert key (target, attr') oldkeys }
return $ return mempty
-referenceTitle :: MarkdownParser String
+referenceTitle :: PandocMonad m => MarkdownParser m String
referenceTitle = try $ do
skipSpaces >> optional newline >> skipSpaces
quotedTitle '"' <|> quotedTitle '\'' <|> charsInBalanced '(' ')' litChar
-- A link title in quotes
-quotedTitle :: Char -> MarkdownParser String
+quotedTitle :: PandocMonad m => Char -> MarkdownParser m String
quotedTitle c = try $ do
char c
notFollowedBy spaces
@@ -425,7 +439,7 @@ quotedTitle c = try $ do
-- | PHP Markdown Extra style abbreviation key. Currently
-- we just skip them, since Pandoc doesn't have an element for
-- an abbreviation.
-abbrevKey :: MarkdownParser (F Blocks)
+abbrevKey :: PandocMonad m => MarkdownParser m (F Blocks)
abbrevKey = do
guardEnabled Ext_abbreviations
try $ do
@@ -436,23 +450,23 @@ abbrevKey = do
blanklines
return $ return mempty
-noteMarker :: MarkdownParser String
+noteMarker :: PandocMonad m => MarkdownParser m String
noteMarker = string "[^" >> many1Till (satisfy $ not . isBlank) (char ']')
-rawLine :: MarkdownParser String
+rawLine :: PandocMonad m => MarkdownParser m String
rawLine = try $ do
notFollowedBy blankline
notFollowedBy' $ try $ skipNonindentSpaces >> noteMarker
optional indentSpaces
anyLine
-rawLines :: MarkdownParser String
+rawLines :: PandocMonad m => MarkdownParser m String
rawLines = do
first <- anyLine
rest <- many rawLine
return $ unlines (first:rest)
-noteBlock :: MarkdownParser (F Blocks)
+noteBlock :: PandocMonad m => MarkdownParser m (F Blocks)
noteBlock = try $ do
pos <- getPosition
skipNonindentSpaces
@@ -464,26 +478,23 @@ noteBlock = try $ do
rest <- many $ try $ blanklines >> indentSpaces >> rawLines
let raw = unlines (first:rest) ++ "\n"
optional blanklines
- parsed <- parseFromString parseBlocks raw
- let newnote = (ref, parsed)
+ parsed <- parseFromString' parseBlocks raw
oldnotes <- stateNotes' <$> getState
- case lookup ref oldnotes of
- Just _ -> addWarning (Just pos) $ "Duplicate note reference `" ++ ref ++ "'"
+ case M.lookup ref oldnotes of
+ Just _ -> logMessage $ DuplicateNoteReference ref pos
Nothing -> return ()
- updateState $ \s -> s { stateNotes' = newnote : oldnotes }
+ updateState $ \s -> s { stateNotes' = M.insert ref (pos, parsed) oldnotes }
return mempty
--
-- parsing blocks
--
-parseBlocks :: MarkdownParser (F Blocks)
+parseBlocks :: PandocMonad m => MarkdownParser m (F Blocks)
parseBlocks = mconcat <$> manyTill block eof
-block :: MarkdownParser (F Blocks)
+block :: PandocMonad m => MarkdownParser m (F Blocks)
block = do
- tr <- getOption readerTrace
- pos <- getPosition
res <- choice [ mempty <$ blanklines
, codeBlockFenced
, yamlMetaBlock
@@ -493,10 +504,10 @@ block = do
, header
, lhsCodeBlock
, divHtml
+ , divFenced
, htmlBlock
, table
, codeBlockIndented
- , guardEnabled Ext_latex_macros *> (macro >>= return . return)
, rawTeXBlock
, lineBlock
, blockQuote
@@ -509,30 +520,29 @@ block = do
, para
, plain
] <?> "block"
- when tr $ do
- st <- getState
- trace (printf "line %d: %s" (sourceLine pos)
- (take 60 $ show $ B.toList $ runF res st)) (return ())
+ trace (take 60 $ show $ B.toList $ runF res defaultParserState)
return res
--
-- header blocks
--
-header :: MarkdownParser (F Blocks)
+header :: PandocMonad m => MarkdownParser m (F Blocks)
header = setextHeader <|> atxHeader <?> "header"
-atxChar :: MarkdownParser Char
+atxChar :: PandocMonad m => MarkdownParser m Char
atxChar = do
exts <- getOption readerExtensions
- return $ if Set.member Ext_literate_haskell exts
- then '=' else '#'
+ return $ if extensionEnabled Ext_literate_haskell exts
+ then '='
+ else '#'
-atxHeader :: MarkdownParser (F Blocks)
+atxHeader :: PandocMonad m => MarkdownParser m (F Blocks)
atxHeader = try $ do
- level <- atxChar >>= many1 . char >>= return . length
+ level <- fmap length (atxChar >>= many1 . char)
notFollowedBy $ guardEnabled Ext_fancy_lists >>
(char '.' <|> char ')') -- this would be a list
+ guardDisabled Ext_space_in_atx_header <|> notFollowedBy nonspaceChar
skipSpaces
(text, raw) <- withRaw $
trimInlinesF . mconcat <$> many (notFollowedBy atxClosing >> inline)
@@ -542,7 +552,7 @@ atxHeader = try $ do
<|> registerImplicitHeader raw attr'
return $ B.headerWith attr' level <$> text
-atxClosing :: MarkdownParser Attr
+atxClosing :: PandocMonad m => MarkdownParser m Attr
atxClosing = try $ do
attr' <- option nullAttr
(guardEnabled Ext_mmd_header_identifiers >> mmdHeaderIdentifier)
@@ -553,7 +563,7 @@ atxClosing = try $ do
blanklines
return attr
-setextHeaderEnd :: MarkdownParser Attr
+setextHeaderEnd :: PandocMonad m => MarkdownParser m Attr
setextHeaderEnd = try $ do
attr <- option nullAttr
$ (guardEnabled Ext_mmd_header_identifiers >> mmdHeaderIdentifier)
@@ -561,13 +571,18 @@ setextHeaderEnd = try $ do
blanklines
return attr
-mmdHeaderIdentifier :: MarkdownParser Attr
+mmdHeaderIdentifier :: PandocMonad m => MarkdownParser m Attr
mmdHeaderIdentifier = do
- ident <- stripFirstAndLast . snd <$> reference
+ (_, raw) <- reference
+ let raw' = trim $ stripFirstAndLast raw
+ let ident = concat $ words $ map toLower raw'
+ let attr = (ident, [], [])
+ guardDisabled Ext_implicit_header_references
+ <|> registerImplicitHeader raw' attr
skipSpaces
- return (ident,[],[])
+ return attr
-setextHeader :: MarkdownParser (F Blocks)
+setextHeader :: PandocMonad m => MarkdownParser m (F Blocks)
setextHeader = try $ do
-- This lookahead prevents us from wasting time parsing Inlines
-- unless necessary -- it gives a significant performance boost.
@@ -579,13 +594,13 @@ setextHeader = try $ do
underlineChar <- oneOf setextHChars
many (char underlineChar)
blanklines
- let level = (fromMaybe 0 $ findIndex (== underlineChar) setextHChars) + 1
+ let level = fromMaybe 0 (elemIndex underlineChar setextHChars) + 1
attr' <- registerHeader attr (runF text defaultParserState)
guardDisabled Ext_implicit_header_references
<|> registerImplicitHeader raw attr'
return $ B.headerWith attr' level <$> text
-registerImplicitHeader :: String -> Attr -> MarkdownParser ()
+registerImplicitHeader :: PandocMonad m => String -> Attr -> MarkdownParser m ()
registerImplicitHeader raw attr@(ident, _, _) = do
let key = toKey $ "[" ++ raw ++ "]"
updateState (\s -> s { stateHeaderKeys =
@@ -595,7 +610,7 @@ registerImplicitHeader raw attr@(ident, _, _) = do
-- hrule block
--
-hrule :: Parser [Char] st (F Blocks)
+hrule :: PandocMonad m => ParserT [Char] st m (F Blocks)
hrule = try $ do
skipSpaces
start <- satisfy isHruleChar
@@ -609,20 +624,21 @@ hrule = try $ do
-- code blocks
--
-indentedLine :: MarkdownParser String
-indentedLine = indentSpaces >> anyLine >>= return . (++ "\n")
+indentedLine :: PandocMonad m => MarkdownParser m String
+indentedLine = indentSpaces >> anyLineNewline
-blockDelimiter :: (Char -> Bool)
+blockDelimiter :: PandocMonad m
+ => (Char -> Bool)
-> Maybe Int
- -> Parser [Char] st Int
+ -> ParserT [Char] ParserState m Int
blockDelimiter f len = try $ do
+ skipNonindentSpaces
c <- lookAhead (satisfy f)
case len of
Just l -> count l (char c) >> many (char c) >> return l
- Nothing -> count 3 (char c) >> many (char c) >>=
- return . (+ 3) . length
+ Nothing -> fmap ((+ 3) . length) (count 3 (char c) >> many (char c))
-attributes :: MarkdownParser Attr
+attributes :: PandocMonad m => MarkdownParser m Attr
attributes = try $ do
char '{'
spnl
@@ -630,28 +646,28 @@ attributes = try $ do
char '}'
return $ foldl (\x f -> f x) nullAttr attrs
-attribute :: MarkdownParser (Attr -> Attr)
+attribute :: PandocMonad m => MarkdownParser m (Attr -> Attr)
attribute = identifierAttr <|> classAttr <|> keyValAttr <|> specialAttr
-identifier :: MarkdownParser String
+identifier :: PandocMonad m => MarkdownParser m String
identifier = do
first <- letter
rest <- many $ alphaNum <|> oneOf "-_:."
return (first:rest)
-identifierAttr :: MarkdownParser (Attr -> Attr)
+identifierAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
identifierAttr = try $ do
char '#'
result <- identifier
return $ \(_,cs,kvs) -> (result,cs,kvs)
-classAttr :: MarkdownParser (Attr -> Attr)
+classAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
classAttr = try $ do
char '.'
result <- identifier
return $ \(id',cs,kvs) -> (id',cs ++ [result],kvs)
-keyValAttr :: MarkdownParser (Attr -> Attr)
+keyValAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
keyValAttr = try $ do
key <- identifier
char '='
@@ -664,33 +680,53 @@ keyValAttr = try $ do
"class" -> (id',cs ++ words val,kvs)
_ -> (id',cs,kvs ++ [(key,val)])
-specialAttr :: MarkdownParser (Attr -> Attr)
+specialAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
specialAttr = do
char '-'
return $ \(id',cs,kvs) -> (id',cs ++ ["unnumbered"],kvs)
-codeBlockFenced :: MarkdownParser (F Blocks)
+rawAttribute :: PandocMonad m => MarkdownParser m String
+rawAttribute = do
+ char '{'
+ skipMany spaceChar
+ char '='
+ format <- many1 $ satisfy (\c -> isAlphaNum c || c `elem` "-_")
+ skipMany spaceChar
+ char '}'
+ return format
+
+codeBlockFenced :: PandocMonad m => MarkdownParser m (F Blocks)
codeBlockFenced = try $ do
+ indentchars <- nonindentSpaces
+ let indentLevel = length indentchars
c <- try (guardEnabled Ext_fenced_code_blocks >> lookAhead (char '~'))
<|> (guardEnabled Ext_backtick_code_blocks >> lookAhead (char '`'))
size <- blockDelimiter (== c) Nothing
skipMany spaceChar
- attr <- option ([],[],[]) $
- try (guardEnabled Ext_fenced_code_attributes >> attributes)
- <|> ((\x -> ("",[toLanguageId x],[])) <$> many1 nonspaceChar)
+ rawattr <-
+ (Left <$> try (guardEnabled Ext_raw_attribute >> rawAttribute))
+ <|>
+ (Right <$> option ("",[],[])
+ (try (guardEnabled Ext_fenced_code_attributes >> attributes)
+ <|> ((\x -> ("",[toLanguageId x],[])) <$> many1 nonspaceChar)))
blankline
- contents <- manyTill anyLine (blockDelimiter (== c) (Just size))
+ contents <- intercalate "\n" <$>
+ manyTill (gobbleAtMostSpaces indentLevel >> anyLine)
+ (blockDelimiter (== c) (Just size))
blanklines
- return $ return $ B.codeBlockWith attr $ intercalate "\n" contents
+ return $ return $
+ case rawattr of
+ Left syn -> B.rawBlock syn contents
+ Right attr -> B.codeBlockWith attr contents
-- correctly handle github language identifiers
toLanguageId :: String -> String
toLanguageId = map toLower . go
- where go "c++" = "cpp"
+ where go "c++" = "cpp"
go "objective-c" = "objectivec"
- go x = x
+ go x = x
-codeBlockIndented :: MarkdownParser (F Blocks)
+codeBlockIndented :: PandocMonad m => MarkdownParser m (F Blocks)
codeBlockIndented = do
contents <- many1 (indentedLine <|>
try (do b <- blanklines
@@ -701,7 +737,7 @@ codeBlockIndented = do
return $ return $ B.codeBlockWith ("", classes, []) $
stripTrailingNewlines $ concat contents
-lhsCodeBlock :: MarkdownParser (F Blocks)
+lhsCodeBlock :: PandocMonad m => MarkdownParser m (F Blocks)
lhsCodeBlock = do
guardEnabled Ext_literate_haskell
(return . B.codeBlockWith ("",["sourceCode","literate","haskell"],[]) <$>
@@ -709,7 +745,7 @@ lhsCodeBlock = do
<|> (return . B.codeBlockWith ("",["sourceCode","haskell"],[]) <$>
lhsCodeBlockInverseBird)
-lhsCodeBlockLaTeX :: MarkdownParser String
+lhsCodeBlockLaTeX :: PandocMonad m => MarkdownParser m String
lhsCodeBlockLaTeX = try $ do
string "\\begin{code}"
manyTill spaceChar newline
@@ -717,13 +753,13 @@ lhsCodeBlockLaTeX = try $ do
blanklines
return $ stripTrailingNewlines contents
-lhsCodeBlockBird :: MarkdownParser String
+lhsCodeBlockBird :: PandocMonad m => MarkdownParser m String
lhsCodeBlockBird = lhsCodeBlockBirdWith '>'
-lhsCodeBlockInverseBird :: MarkdownParser String
+lhsCodeBlockInverseBird :: PandocMonad m => MarkdownParser m String
lhsCodeBlockInverseBird = lhsCodeBlockBirdWith '<'
-lhsCodeBlockBirdWith :: Char -> MarkdownParser String
+lhsCodeBlockBirdWith :: PandocMonad m => Char -> MarkdownParser m String
lhsCodeBlockBirdWith c = try $ do
pos <- getPosition
when (sourceColumn pos /= 1) $ fail "Not in first column"
@@ -735,7 +771,7 @@ lhsCodeBlockBirdWith c = try $ do
blanklines
return $ intercalate "\n" lns'
-birdTrackLine :: Char -> Parser [Char] st String
+birdTrackLine :: PandocMonad m => Char -> ParserT [Char] st m String
birdTrackLine c = try $ do
char c
-- allow html tags on left margin:
@@ -746,10 +782,10 @@ birdTrackLine c = try $ do
-- block quotes
--
-emailBlockQuoteStart :: MarkdownParser Char
+emailBlockQuoteStart :: PandocMonad m => MarkdownParser m Char
emailBlockQuoteStart = try $ skipNonindentSpaces >> char '>' <* optional (char ' ')
-emailBlockQuote :: MarkdownParser [String]
+emailBlockQuote :: PandocMonad m => MarkdownParser m [String]
emailBlockQuote = try $ do
emailBlockQuoteStart
let emailLine = many $ nonEndline <|> try
@@ -763,113 +799,136 @@ emailBlockQuote = try $ do
optional blanklines
return raw
-blockQuote :: MarkdownParser (F Blocks)
+blockQuote :: PandocMonad m => MarkdownParser m (F Blocks)
blockQuote = do
raw <- emailBlockQuote
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString parseBlocks $ (intercalate "\n" raw) ++ "\n\n"
+ contents <- parseFromString' parseBlocks $ intercalate "\n" raw ++ "\n\n"
return $ B.blockQuote <$> contents
--
-- list blocks
--
-bulletListStart :: MarkdownParser ()
+bulletListStart :: PandocMonad m => MarkdownParser m ()
bulletListStart = try $ do
optional newline -- if preceded by a Plain block in a list context
- startpos <- sourceColumn <$> getPosition
skipNonindentSpaces
notFollowedBy' (() <$ hrule) -- because hrules start out just like lists
satisfy isBulletListMarker
- endpos <- sourceColumn <$> getPosition
- tabStop <- getOption readerTabStop
- lookAhead (newline <|> spaceChar)
- () <$ atMostSpaces (tabStop - (endpos - startpos))
+ gobbleSpaces 1 <|> () <$ lookAhead newline
+ try (gobbleAtMostSpaces 3 >> notFollowedBy spaceChar) <|> return ()
-anyOrderedListStart :: MarkdownParser (Int, ListNumberStyle, ListNumberDelim)
-anyOrderedListStart = try $ do
+orderedListStart :: PandocMonad m
+ => Maybe (ListNumberStyle, ListNumberDelim)
+ -> MarkdownParser m (Int, ListNumberStyle, ListNumberDelim)
+orderedListStart mbstydelim = try $ do
optional newline -- if preceded by a Plain block in a list context
- startpos <- sourceColumn <$> getPosition
skipNonindentSpaces
notFollowedBy $ string "p." >> spaceChar >> digit -- page number
- res <- do guardDisabled Ext_fancy_lists
- start <- many1 digit >>= safeRead
- char '.'
- return (start, DefaultStyle, DefaultDelim)
- <|> do (num, style, delim) <- anyOrderedListMarker
- -- if it could be an abbreviated first name,
- -- insist on more than one space
- when (delim == Period && (style == UpperAlpha ||
- (style == UpperRoman &&
- num `elem` [1, 5, 10, 50, 100, 500, 1000]))) $
- () <$ spaceChar
- return (num, style, delim)
- endpos <- sourceColumn <$> getPosition
- tabStop <- getOption readerTabStop
- lookAhead (newline <|> spaceChar)
- atMostSpaces (tabStop - (endpos - startpos))
- return res
-
-listStart :: MarkdownParser ()
-listStart = bulletListStart <|> (anyOrderedListStart >> return ())
-
-listLine :: MarkdownParser String
-listLine = try $ do
- notFollowedBy' (do indentSpaces
- many spaceChar
+ (do guardDisabled Ext_fancy_lists
+ start <- many1 digit >>= safeRead
+ char '.'
+ gobbleSpaces 1 <|> () <$ lookAhead newline
+ optional $ try (gobbleAtMostSpaces 3 >> notFollowedBy spaceChar)
+ return (start, DefaultStyle, DefaultDelim))
+ <|>
+ (do (num, style, delim) <- maybe
+ anyOrderedListMarker
+ (\(sty,delim) -> (\start -> (start,sty,delim)) <$>
+ orderedListMarker sty delim)
+ mbstydelim
+ gobbleSpaces 1 <|> () <$ lookAhead newline
+ -- if it could be an abbreviated first name,
+ -- insist on more than one space
+ when (delim == Period && (style == UpperAlpha ||
+ (style == UpperRoman &&
+ num `elem` [1, 5, 10, 50, 100, 500, 1000]))) $
+ () <$ lookAhead (newline <|> spaceChar)
+ optional $ try (gobbleAtMostSpaces 3 >> notFollowedBy spaceChar)
+ return (num, style, delim))
+
+listStart :: PandocMonad m => MarkdownParser m ()
+listStart = bulletListStart <|> Control.Monad.void (orderedListStart Nothing)
+
+listLine :: PandocMonad m => Int -> MarkdownParser m String
+listLine continuationIndent = try $ do
+ notFollowedBy' (do gobbleSpaces continuationIndent
+ skipMany spaceChar
listStart)
notFollowedByHtmlCloser
- optional (() <$ indentSpaces)
+ notFollowedByDivCloser
+ optional (() <$ gobbleSpaces continuationIndent)
listLineCommon
-listLineCommon :: MarkdownParser String
+listLineCommon :: PandocMonad m => MarkdownParser m String
listLineCommon = concat <$> manyTill
( many1 (satisfy $ \c -> c /= '\n' && c /= '<')
- <|> liftM snd (htmlTag isCommentTag)
+ <|> fmap snd (htmlTag isCommentTag)
<|> count 1 anyChar
) newline
-- parse raw text for one list item, excluding start marker and continuations
-rawListItem :: MarkdownParser a
- -> MarkdownParser String
-rawListItem start = try $ do
+rawListItem :: PandocMonad m
+ => Bool -- four space rule
+ -> MarkdownParser m a
+ -> MarkdownParser m (String, Int)
+rawListItem fourSpaceRule start = try $ do
+ pos1 <- getPosition
start
+ pos2 <- getPosition
+ let continuationIndent = if fourSpaceRule
+ then 4
+ else sourceColumn pos2 - sourceColumn pos1
first <- listLineCommon
- rest <- many (notFollowedBy listStart >> notFollowedBy blankline >> listLine)
+ rest <- many (do notFollowedBy listStart
+ notFollowedBy (() <$ codeBlockFenced)
+ notFollowedBy blankline
+ listLine continuationIndent)
blanks <- many blankline
- return $ unlines (first:rest) ++ blanks
+ let result = unlines (first:rest) ++ blanks
+ return (result, continuationIndent)
-- continuation of a list item - indented and separated by blankline
-- or (in compact lists) endline.
-- note: nested lists are parsed as continuations
-listContinuation :: MarkdownParser String
-listContinuation = try $ do
- lookAhead indentSpaces
- result <- many1 listContinuationLine
+listContinuation :: PandocMonad m => Int -> MarkdownParser m String
+listContinuation continuationIndent = try $ do
+ x <- try $ do
+ notFollowedBy blankline
+ notFollowedByHtmlCloser
+ notFollowedByDivCloser
+ gobbleSpaces continuationIndent
+ anyLineNewline
+ xs <- many $ try $ do
+ notFollowedBy blankline
+ notFollowedByHtmlCloser
+ notFollowedByDivCloser
+ gobbleSpaces continuationIndent <|> notFollowedBy' listStart
+ anyLineNewline
blanks <- many blankline
- return $ concat result ++ blanks
+ return $ concat (x:xs) ++ blanks
+
+notFollowedByDivCloser :: PandocMonad m => MarkdownParser m ()
+notFollowedByDivCloser =
+ guardDisabled Ext_fenced_divs <|>
+ do divLevel <- stateFencedDivLevel <$> getState
+ guard (divLevel < 1) <|> notFollowedBy divFenceEnd
-notFollowedByHtmlCloser :: MarkdownParser ()
+notFollowedByHtmlCloser :: PandocMonad m => MarkdownParser m ()
notFollowedByHtmlCloser = do
inHtmlBlock <- stateInHtmlBlock <$> getState
case inHtmlBlock of
Just t -> notFollowedBy' $ htmlTag (~== TagClose t)
Nothing -> return ()
-listContinuationLine :: MarkdownParser String
-listContinuationLine = try $ do
- notFollowedBy blankline
- notFollowedBy' listStart
- notFollowedByHtmlCloser
- optional indentSpaces
- result <- anyLine
- return $ result ++ "\n"
-
-listItem :: MarkdownParser a
- -> MarkdownParser (F Blocks)
-listItem start = try $ do
- first <- rawListItem start
- continuations <- many listContinuation
+listItem :: PandocMonad m
+ => Bool -- four-space rule
+ -> MarkdownParser m a
+ -> MarkdownParser m (F Blocks)
+listItem fourSpaceRule start = try $ do
+ (first, continuationIndent) <- rawListItem fourSpaceRule start
+ continuations <- many (listContinuation continuationIndent)
-- parsing with ListItemState forces markers at beginning of lines to
-- count as list item markers, even if not separated by blank space.
-- see definition of "endline"
@@ -878,39 +937,34 @@ listItem start = try $ do
setState $ state {stateParserContext = ListItemState}
-- parse the extracted block, which may contain various block elements:
let raw = concat (first:continuations)
- contents <- parseFromString parseBlocks raw
+ contents <- parseFromString' parseBlocks raw
updateState (\st -> st {stateParserContext = oldContext})
return contents
-orderedList :: MarkdownParser (F Blocks)
+orderedList :: PandocMonad m => MarkdownParser m (F Blocks)
orderedList = try $ do
- (start, style, delim) <- lookAhead anyOrderedListStart
+ (start, style, delim) <- lookAhead (orderedListStart Nothing)
unless (style `elem` [DefaultStyle, Decimal, Example] &&
delim `elem` [DefaultDelim, Period]) $
guardEnabled Ext_fancy_lists
when (style == Example) $ guardEnabled Ext_example_lists
- items <- fmap sequence $ many1 $ listItem
- ( try $ do
- optional newline -- if preceded by Plain block in a list
- startpos <- sourceColumn <$> getPosition
- skipNonindentSpaces
- res <- orderedListMarker style delim
- endpos <- sourceColumn <$> getPosition
- tabStop <- getOption readerTabStop
- lookAhead (newline <|> spaceChar)
- atMostSpaces (tabStop - (endpos - startpos))
- return res )
- start' <- option 1 $ guardEnabled Ext_startnum >> return start
- return $ B.orderedListWith (start', style, delim) <$> fmap compactify' items
-
-bulletList :: MarkdownParser (F Blocks)
+ fourSpaceRule <- (True <$ guardEnabled Ext_four_space_rule)
+ <|> return (style == Example)
+ items <- fmap sequence $ many1 $ listItem fourSpaceRule
+ (orderedListStart (Just (style, delim)))
+ start' <- (start <$ guardEnabled Ext_startnum) <|> return 1
+ return $ B.orderedListWith (start', style, delim) <$> fmap compactify items
+
+bulletList :: PandocMonad m => MarkdownParser m (F Blocks)
bulletList = do
- items <- fmap sequence $ many1 $ listItem bulletListStart
- return $ B.bulletList <$> fmap compactify' items
+ fourSpaceRule <- (True <$ guardEnabled Ext_four_space_rule)
+ <|> return False
+ items <- fmap sequence $ many1 $ listItem fourSpaceRule bulletListStart
+ return $ B.bulletList <$> fmap compactify items
-- definition lists
-defListMarker :: MarkdownParser ()
+defListMarker :: PandocMonad m => MarkdownParser m ()
defListMarker = do
sps <- nonindentSpaces
char ':' <|> char '~'
@@ -921,52 +975,53 @@ defListMarker = do
else mzero
return ()
-definitionListItem :: Bool -> MarkdownParser (F (Inlines, [Blocks]))
+definitionListItem :: PandocMonad m => Bool -> MarkdownParser m (F (Inlines, [Blocks]))
definitionListItem compact = try $ do
rawLine' <- anyLine
raw <- many1 $ defRawBlock compact
- term <- parseFromString (trimInlinesF . mconcat <$> many inline) rawLine'
- contents <- mapM (parseFromString parseBlocks . (++"\n")) raw
+ term <- parseFromString' (trimInlinesF <$> inlines) rawLine'
+ contents <- mapM (parseFromString' parseBlocks . (++"\n")) raw
optional blanklines
return $ liftM2 (,) term (sequence contents)
-defRawBlock :: Bool -> MarkdownParser String
+defRawBlock :: PandocMonad m => Bool -> MarkdownParser m String
defRawBlock compact = try $ do
hasBlank <- option False $ blankline >> return True
defListMarker
- firstline <- anyLine
+ firstline <- anyLineNewline
let dline = try
( do notFollowedBy blankline
notFollowedByHtmlCloser
+ notFollowedByDivCloser
if compact -- laziness not compatible with compact
then () <$ indentSpaces
else (() <$ indentSpaces)
<|> notFollowedBy defListMarker
anyLine )
rawlines <- many dline
- cont <- liftM concat $ many $ try $ do
+ cont <- fmap concat $ many $ try $ do
trailing <- option "" blanklines
ln <- indentSpaces >> notFollowedBy blankline >> anyLine
lns <- many dline
return $ trailing ++ unlines (ln:lns)
- return $ trimr (firstline ++ "\n" ++ unlines rawlines ++ cont) ++
+ return $ trimr (firstline ++ unlines rawlines ++ cont) ++
if hasBlank || not (null cont) then "\n\n" else ""
-definitionList :: MarkdownParser (F Blocks)
+definitionList :: PandocMonad m => MarkdownParser m (F Blocks)
definitionList = try $ do
lookAhead (anyLine >>
- optional (blankline >> notFollowedBy (table >> return ())) >>
+ optional (blankline >> notFollowedBy (Control.Monad.void table)) >>
-- don't capture table caption as def list!
defListMarker)
compactDefinitionList <|> normalDefinitionList
-compactDefinitionList :: MarkdownParser (F Blocks)
+compactDefinitionList :: PandocMonad m => MarkdownParser m (F Blocks)
compactDefinitionList = do
guardEnabled Ext_compact_definition_lists
items <- fmap sequence $ many1 $ definitionListItem True
- return $ B.definitionList <$> fmap compactify'DL items
+ return $ B.definitionList <$> fmap compactifyDL items
-normalDefinitionList :: MarkdownParser (F Blocks)
+normalDefinitionList :: PandocMonad m => MarkdownParser m (F Blocks)
normalDefinitionList = do
guardEnabled Ext_definition_lists
items <- fmap sequence $ many1 $ definitionListItem False
@@ -976,10 +1031,10 @@ normalDefinitionList = do
-- paragraph block
--
-para :: MarkdownParser (F Blocks)
+para :: PandocMonad m => MarkdownParser m (F Blocks)
para = try $ do
exts <- getOption readerExtensions
- result <- trimInlinesF . mconcat <$> many1 inline
+ result <- trimInlinesF <$> inlines1
option (B.plain <$> result)
$ try $ do
newline
@@ -997,29 +1052,35 @@ para = try $ do
Just "div" -> () <$
lookAhead (htmlTag (~== TagClose "div"))
_ -> mzero
+ <|> do guardEnabled Ext_fenced_divs
+ divLevel <- stateFencedDivLevel <$> getState
+ if divLevel > 0
+ then lookAhead divFenceEnd
+ else mzero
return $ do
result' <- result
case B.toList result' of
[Image attr alt (src,tit)]
- | Ext_implicit_figures `Set.member` exts ->
+ | not (null alt) &&
+ Ext_implicit_figures `extensionEnabled` exts ->
-- the fig: at beginning of title indicates a figure
return $ B.para $ B.singleton
$ Image attr alt (src,'f':'i':'g':':':tit)
_ -> return $ B.para result'
-plain :: MarkdownParser (F Blocks)
-plain = fmap B.plain . trimInlinesF . mconcat <$> many1 inline
+plain :: PandocMonad m => MarkdownParser m (F Blocks)
+plain = fmap B.plain . trimInlinesF <$> inlines1
--
-- raw html
--
-htmlElement :: MarkdownParser String
+htmlElement :: PandocMonad m => MarkdownParser m String
htmlElement = rawVerbatimBlock
<|> strictHtmlBlock
- <|> liftM snd (htmlTag isBlockTag)
+ <|> fmap snd (htmlTag isBlockTag)
-htmlBlock :: MarkdownParser (F Blocks)
+htmlBlock :: PandocMonad m => MarkdownParser m (F Blocks)
htmlBlock = do
guardEnabled Ext_raw_html
try (do
@@ -1044,43 +1105,59 @@ htmlBlock = do
<|> (guardEnabled Ext_markdown_in_html_blocks >> rawHtmlBlocks))
<|> htmlBlock'
-htmlBlock' :: MarkdownParser (F Blocks)
+htmlBlock' :: PandocMonad m => MarkdownParser m (F Blocks)
htmlBlock' = try $ do
first <- htmlElement
skipMany spaceChar
optional blanklines
- return $ return $ B.rawBlock "html" first
+ return $ if null first
+ then mempty
+ else return $ B.rawBlock "html" first
-strictHtmlBlock :: MarkdownParser String
+strictHtmlBlock :: PandocMonad m => MarkdownParser m String
strictHtmlBlock = htmlInBalanced (not . isInlineTag)
-rawVerbatimBlock :: MarkdownParser String
+rawVerbatimBlock :: PandocMonad m => MarkdownParser m String
rawVerbatimBlock = htmlInBalanced isVerbTag
where isVerbTag (TagOpen "pre" _) = True
isVerbTag (TagOpen "style" _) = True
isVerbTag (TagOpen "script" _) = True
isVerbTag _ = False
-rawTeXBlock :: MarkdownParser (F Blocks)
+rawTeXBlock :: PandocMonad m => MarkdownParser m (F Blocks)
rawTeXBlock = do
guardEnabled Ext_raw_tex
- result <- (B.rawBlock "latex" . concat <$>
- rawLaTeXBlock `sepEndBy1` blankline)
- <|> (B.rawBlock "context" . concat <$>
- rawConTeXtEnvironment `sepEndBy1` blankline)
- spaces
- return $ return result
-
-rawHtmlBlocks :: MarkdownParser (F Blocks)
+ lookAhead $ try $ char '\\' >> letter
+ result <- (B.rawBlock "context" . trim . concat <$>
+ many1 ((++) <$> (rawConTeXtEnvironment <|> conTeXtCommand)
+ <*> spnl'))
+ <|> (B.rawBlock "latex" . trim . concat <$>
+ many1 ((++) <$> rawLaTeXBlock <*> spnl'))
+ return $ case B.toList result of
+ [RawBlock _ cs]
+ | all (`elem` [' ','\t','\n']) cs -> return mempty
+ -- don't create a raw block for suppressed macro defs
+ _ -> return result
+
+conTeXtCommand :: PandocMonad m => MarkdownParser m String
+conTeXtCommand = oneOfStrings ["\\placeformula"]
+
+rawHtmlBlocks :: PandocMonad m => MarkdownParser m (F Blocks)
rawHtmlBlocks = do
(TagOpen tagtype _, raw) <- htmlTag isBlockTag
+ -- we don't want '<td> text' to be a code block:
+ skipMany spaceChar
+ indentlevel <- (blankline >> length <$> many (char ' ')) <|> return 0
-- try to find closing tag
-- we set stateInHtmlBlock so that closing tags that can be either block or
-- inline will not be parsed as inline tags
oldInHtmlBlock <- stateInHtmlBlock <$> getState
updateState $ \st -> st{ stateInHtmlBlock = Just tagtype }
let closer = htmlTag (\x -> x ~== TagClose tagtype)
- contents <- mconcat <$> many (notFollowedBy' closer >> block)
+ let block' = do notFollowedBy' closer
+ gobbleAtMostSpaces indentlevel
+ block
+ contents <- mconcat <$> many block'
result <-
(closer >>= \(_, rawcloser) -> return (
return (B.rawBlock "html" $ stripMarkdownAttribute raw) <>
@@ -1101,11 +1178,11 @@ stripMarkdownAttribute s = renderTags' $ map filterAttrib $ parseTags s
-- line block
--
-lineBlock :: MarkdownParser (F Blocks)
+lineBlock :: PandocMonad m => MarkdownParser m (F Blocks)
lineBlock = try $ do
guardEnabled Ext_line_blocks
lines' <- lineBlockLines >>=
- mapM (parseFromString (trimInlinesF . mconcat <$> many inline))
+ mapM (parseFromString' (trimInlinesF <$> inlines))
return $ B.lineBlock <$> sequence lines'
--
@@ -1114,8 +1191,9 @@ lineBlock = try $ do
-- Parse a dashed line with optional trailing spaces; return its length
-- and the length including trailing space.
-dashedLine :: Char
- -> Parser [Char] st (Int, Int)
+dashedLine :: PandocMonad m
+ => Char
+ -> ParserT [Char] st m (Int, Int)
dashedLine ch = do
dashes <- many1 (char ch)
sp <- many spaceChar
@@ -1125,8 +1203,9 @@ dashedLine ch = do
-- Parse a table header with dashed lines of '-' preceded by
-- one (or zero) line of text.
-simpleTableHeader :: Bool -- ^ Headerless table
- -> MarkdownParser (F [Blocks], [Alignment], [Int])
+simpleTableHeader :: PandocMonad m
+ => Bool -- ^ Headerless table
+ -> MarkdownParser m (F [Blocks], [Alignment], [Int])
simpleTableHeader headless = try $ do
rawContent <- if headless
then return ""
@@ -1137,17 +1216,17 @@ simpleTableHeader headless = try $ do
let (lengths, lines') = unzip dashes
let indices = scanl (+) (length initSp) lines'
-- If no header, calculate alignment on basis of first row of text
- rawHeads <- liftM (tail . splitStringByIndices (init indices)) $
+ rawHeads <- fmap (tail . splitStringByIndices (init indices)) $
if headless
then lookAhead anyLine
else return rawContent
- let aligns = zipWith alignType (map (\a -> [a]) rawHeads) lengths
+ let aligns = zipWith alignType (map (: []) rawHeads) lengths
let rawHeads' = if headless
then replicate (length dashes) ""
else rawHeads
heads <- fmap sequence
- $ mapM (parseFromString (mconcat <$> many plain))
- $ map trim rawHeads'
+ $
+ mapM ((parseFromString' (mconcat <$> many plain)).trim) rawHeads'
return (heads, aligns, indices)
-- Returns an alignment type for a table, based on a list of strings
@@ -1161,25 +1240,26 @@ alignType strLst len =
let nonempties = filter (not . null) $ map trimr strLst
(leftSpace, rightSpace) =
case sortBy (comparing length) nonempties of
- (x:_) -> (head x `elem` " \t", length x < len)
- [] -> (False, False)
+ (x:_) -> (head x `elem` " \t", length x < len)
+ [] -> (False, False)
in case (leftSpace, rightSpace) of
- (True, False) -> AlignRight
- (False, True) -> AlignLeft
- (True, True) -> AlignCenter
- (False, False) -> AlignDefault
+ (True, False) -> AlignRight
+ (False, True) -> AlignLeft
+ (True, True) -> AlignCenter
+ (False, False) -> AlignDefault
-- Parse a table footer - dashed lines followed by blank line.
-tableFooter :: MarkdownParser String
+tableFooter :: PandocMonad m => MarkdownParser m String
tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines
-- Parse a table separator - dashed line.
-tableSep :: MarkdownParser Char
+tableSep :: PandocMonad m => MarkdownParser m Char
tableSep = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> char '\n'
-- Parse a raw line and split it into chunks by indices.
-rawTableLine :: [Int]
- -> MarkdownParser [String]
+rawTableLine :: PandocMonad m
+ => [Int]
+ -> MarkdownParser m [String]
rawTableLine indices = do
notFollowedBy' (blanklines <|> tableFooter)
line <- many1Till anyChar newline
@@ -1187,31 +1267,34 @@ rawTableLine indices = do
splitStringByIndices (init indices) line
-- Parse a table line and return a list of lists of blocks (columns).
-tableLine :: [Int]
- -> MarkdownParser (F [Blocks])
+tableLine :: PandocMonad m
+ => [Int]
+ -> MarkdownParser m (F [Blocks])
tableLine indices = rawTableLine indices >>=
- fmap sequence . mapM (parseFromString (mconcat <$> many plain))
+ fmap sequence . mapM (parseFromString' (mconcat <$> many plain))
-- Parse a multiline table row and return a list of blocks (columns).
-multilineRow :: [Int]
- -> MarkdownParser (F [Blocks])
+multilineRow :: PandocMonad m
+ => [Int]
+ -> MarkdownParser m (F [Blocks])
multilineRow indices = do
colLines <- many1 (rawTableLine indices)
let cols = map unlines $ transpose colLines
- fmap sequence $ mapM (parseFromString (mconcat <$> many plain)) cols
+ fmap sequence $ mapM (parseFromString' (mconcat <$> many plain)) cols
-- Parses a table caption: inlines beginning with 'Table:'
-- and followed by blank lines.
-tableCaption :: MarkdownParser (F Inlines)
+tableCaption :: PandocMonad m => MarkdownParser m (F Inlines)
tableCaption = try $ do
guardEnabled Ext_table_captions
skipNonindentSpaces
- string ":" <|> string "Table:"
- trimInlinesF . mconcat <$> many1 inline <* blanklines
+ (string ":" <* notFollowedBy (satisfy isPunctuation)) <|> string "Table:"
+ trimInlinesF <$> inlines1 <* blanklines
-- Parse a simple table with '---' header and one line per row.
-simpleTable :: Bool -- ^ Headerless table
- -> MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
+simpleTable :: PandocMonad m
+ => Bool -- ^ Headerless table
+ -> MarkdownParser m ([Alignment], [Double], F [Blocks], F [[Blocks]])
simpleTable headless = do
(aligns, _widths, heads', lines') <-
tableWith (simpleTableHeader headless) tableLine
@@ -1224,13 +1307,15 @@ simpleTable headless = do
-- (which may be multiline), then the rows,
-- which may be multiline, separated by blank lines, and
-- ending with a footer (dashed line followed by blank line).
-multilineTable :: Bool -- ^ Headerless table
- -> MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
+multilineTable :: PandocMonad m
+ => Bool -- ^ Headerless table
+ -> MarkdownParser m ([Alignment], [Double], F [Blocks], F [[Blocks]])
multilineTable headless =
tableWith (multilineTableHeader headless) multilineRow blanklines tableFooter
-multilineTableHeader :: Bool -- ^ Headerless table
- -> MarkdownParser (F [Blocks], [Alignment], [Int])
+multilineTableHeader :: PandocMonad m
+ => Bool -- ^ Headerless table
+ -> MarkdownParser m (F [Blocks], [Alignment], [Int])
multilineTableHeader headless = try $ do
unless headless $
tableSep >> notFollowedBy blankline
@@ -1243,7 +1328,7 @@ multilineTableHeader headless = try $ do
let (lengths, lines') = unzip dashes
let indices = scanl (+) (length initSp) lines'
rawHeadsList <- if headless
- then liftM (map (:[]) . tail .
+ then fmap (map (:[]) . tail .
splitStringByIndices (init indices)) $ lookAhead anyLine
else return $ transpose $ map
(tail . splitStringByIndices (init indices))
@@ -1253,101 +1338,18 @@ multilineTableHeader headless = try $ do
then replicate (length dashes) ""
else map (unlines . map trim) rawHeadsList
heads <- fmap sequence $
- mapM (parseFromString (mconcat <$> many plain)) $
- map trim rawHeads
+ mapM ((parseFromString' (mconcat <$> many plain)).trim) rawHeads
return (heads, aligns, indices)
-- Parse a grid table: starts with row of '-' on top, then header
-- (which may be grid), then the rows,
-- which may be grid, separated by blank lines, and
-- ending with a footer (dashed line followed by blank line).
-gridTable :: Bool -- ^ Headerless table
- -> MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
-gridTable headless =
- tableWith (gridTableHeader headless) gridTableRow
- (gridTableSep '-') gridTableFooter
-
-gridTableSplitLine :: [Int] -> String -> [String]
-gridTableSplitLine indices line = map removeFinalBar $ tail $
- splitStringByIndices (init indices) $ trimr line
-
-gridPart :: Char -> Parser [Char] st ((Int, Int), Alignment)
-gridPart ch = do
- leftColon <- option False (True <$ char ':')
- dashes <- many1 (char ch)
- rightColon <- option False (True <$ char ':')
- char '+'
- let lengthDashes = length dashes + (if leftColon then 1 else 0) +
- (if rightColon then 1 else 0)
- let alignment = case (leftColon, rightColon) of
- (True, True) -> AlignCenter
- (True, False) -> AlignLeft
- (False, True) -> AlignRight
- (False, False) -> AlignDefault
- return ((lengthDashes, lengthDashes + 1), alignment)
-
-gridDashedLines :: Char -> Parser [Char] st [((Int, Int), Alignment)]
-gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
-
-removeFinalBar :: String -> String
-removeFinalBar =
- reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse
-
--- | Separator between rows of grid table.
-gridTableSep :: Char -> MarkdownParser Char
-gridTableSep ch = try $ gridDashedLines ch >> return '\n'
-
--- | Parse header for a grid table.
-gridTableHeader :: Bool -- ^ Headerless table
- -> MarkdownParser (F [Blocks], [Alignment], [Int])
-gridTableHeader headless = try $ do
- optional blanklines
- dashes <- gridDashedLines '-'
- rawContent <- if headless
- then return []
- else many1 (try (char '|' >> anyLine))
- underDashes <- if headless
- then return dashes
- else gridDashedLines '='
- guard $ length dashes == length underDashes
- let lines' = map (snd . fst) underDashes
- let indices = scanl (+) 0 lines'
- let aligns = map snd underDashes
- let rawHeads = if headless
- then replicate (length underDashes) ""
- else map (unlines . map trim) $ transpose
- $ map (gridTableSplitLine indices) rawContent
- heads <- fmap sequence $ mapM (parseFromString parseBlocks . trim) rawHeads
- return (heads, aligns, indices)
+gridTable :: PandocMonad m => Bool -- ^ Headerless table
+ -> MarkdownParser m ([Alignment], [Double], F [Blocks], F [[Blocks]])
+gridTable headless = gridTableWith' parseBlocks headless
-gridTableRawLine :: [Int] -> MarkdownParser [String]
-gridTableRawLine indices = do
- char '|'
- line <- anyLine
- return (gridTableSplitLine indices line)
-
--- | Parse row of grid table.
-gridTableRow :: [Int]
- -> MarkdownParser (F [Blocks])
-gridTableRow indices = do
- colLines <- many1 (gridTableRawLine indices)
- let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $
- transpose colLines
- fmap compactify' <$> fmap sequence (mapM (parseFromString parseBlocks) cols)
-
-removeOneLeadingSpace :: [String] -> [String]
-removeOneLeadingSpace xs =
- if all startsWithSpace xs
- then map (drop 1) xs
- else xs
- where startsWithSpace "" = True
- startsWithSpace (y:_) = y == ' '
-
--- | Parse footer for a grid table.
-gridTableFooter :: MarkdownParser [Char]
-gridTableFooter = blanklines
-
-pipeBreak :: MarkdownParser ([Alignment], [Int])
+pipeBreak :: PandocMonad m => MarkdownParser m ([Alignment], [Int])
pipeBreak = try $ do
nonindentSpaces
openPipe <- (True <$ char '|') <|> return False
@@ -1359,7 +1361,7 @@ pipeBreak = try $ do
blankline
return $ unzip (first:rest)
-pipeTable :: MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
+pipeTable :: PandocMonad m => MarkdownParser m ([Alignment], [Double], F [Blocks], F [[Blocks]])
pipeTable = try $ do
nonindentSpaces
lookAhead nonspaceChar
@@ -1372,41 +1374,40 @@ pipeTable = try $ do
numColumns <- getOption readerColumns
let widths = if maxlength > numColumns
then map (\len ->
- fromIntegral (len + 1) / fromIntegral numColumns)
- seplengths
+ fromIntegral len / fromIntegral (sum seplengths))
+ seplengths
else replicate (length aligns) 0.0
- return $ (aligns, widths, heads', sequence lines'')
+ return (aligns, widths, heads', sequence lines'')
-sepPipe :: MarkdownParser ()
+sepPipe :: PandocMonad m => MarkdownParser m ()
sepPipe = try $ do
char '|' <|> char '+'
notFollowedBy blankline
-- parse a row, also returning probable alignments for org-table cells
-pipeTableRow :: MarkdownParser (F [Blocks])
+pipeTableRow :: PandocMonad m => MarkdownParser m (F [Blocks])
pipeTableRow = try $ do
scanForPipe
skipMany spaceChar
openPipe <- (True <$ char '|') <|> return False
-- split into cells
- let chunk = void (code <|> rawHtmlInline <|> escapedChar <|> rawLaTeXInline')
+ let chunk = void (code <|> math <|> rawHtmlInline <|> escapedChar <|> rawLaTeXInline')
<|> void (noneOf "|\n\r")
let cellContents = ((trim . snd) <$> withRaw (many chunk)) >>=
- parseFromString pipeTableCell
- cells <- cellContents `sepEndBy1` (char '|')
+ parseFromString' pipeTableCell
+ cells <- cellContents `sepEndBy1` char '|'
-- surrounding pipes needed for a one-column table:
guard $ not (length cells == 1 && not openPipe)
blankline
return $ sequence cells
-pipeTableCell :: MarkdownParser (F Blocks)
-pipeTableCell = do
- result <- many inline
- if null result
- then return mempty
- else return $ B.plain . mconcat <$> sequence result
+pipeTableCell :: PandocMonad m => MarkdownParser m (F Blocks)
+pipeTableCell =
+ (do result <- inlines1
+ return $ B.plain <$> result)
+ <|> return mempty
-pipeTableHeaderPart :: Parser [Char] st (Alignment, Int)
+pipeTableHeaderPart :: PandocMonad m => ParserT [Char] st m (Alignment, Int)
pipeTableHeaderPart = try $ do
skipMany spaceChar
left <- optionMaybe (char ':')
@@ -1414,15 +1415,15 @@ pipeTableHeaderPart = try $ do
right <- optionMaybe (char ':')
skipMany spaceChar
let len = length pipe + maybe 0 (const 1) left + maybe 0 (const 1) right
- return $
- ((case (left,right) of
- (Nothing,Nothing) -> AlignDefault
- (Just _,Nothing) -> AlignLeft
- (Nothing,Just _) -> AlignRight
- (Just _,Just _) -> AlignCenter), len)
+ return
+ (case (left,right) of
+ (Nothing,Nothing) -> AlignDefault
+ (Just _,Nothing) -> AlignLeft
+ (Nothing,Just _) -> AlignRight
+ (Just _,Just _) -> AlignCenter, len)
-- Succeed only if current line contains a pipe.
-scanForPipe :: Parser [Char] st ()
+scanForPipe :: PandocMonad m => ParserT [Char] st m ()
scanForPipe = do
inp <- getInput
case break (\c -> c == '\n' || c == '|') inp of
@@ -1432,22 +1433,23 @@ scanForPipe = do
-- | Parse a table using 'headerParser', 'rowParser',
-- 'lineParser', and 'footerParser'. Variant of the version in
-- Text.Pandoc.Parsing.
-tableWith :: MarkdownParser (F [Blocks], [Alignment], [Int])
- -> ([Int] -> MarkdownParser (F [Blocks]))
- -> MarkdownParser sep
- -> MarkdownParser end
- -> MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
+tableWith :: PandocMonad m
+ => MarkdownParser m (F [Blocks], [Alignment], [Int])
+ -> ([Int] -> MarkdownParser m (F [Blocks]))
+ -> MarkdownParser m sep
+ -> MarkdownParser m end
+ -> MarkdownParser m ([Alignment], [Double], F [Blocks], F [[Blocks]])
tableWith headerParser rowParser lineParser footerParser = try $ do
(heads, aligns, indices) <- headerParser
lines' <- fmap sequence $ rowParser indices `sepEndBy1` lineParser
footerParser
numColumns <- getOption readerColumns
- let widths = if (indices == [])
+ let widths = if null indices
then replicate (length aligns) 0.0
else widthsFromIndices numColumns indices
- return $ (aligns, widths, heads, lines')
+ return (aligns, widths, heads, lines')
-table :: MarkdownParser (F Blocks)
+table :: PandocMonad m => MarkdownParser m (F Blocks)
table = try $ do
frontCaption <- option Nothing (Just <$> tableCaption)
(aligns, widths, heads, lns) <-
@@ -1462,8 +1464,8 @@ table = try $ do
(gridTable False <|> gridTable True)) <?> "table"
optional blanklines
caption <- case frontCaption of
- Nothing -> option (return mempty) tableCaption
- Just c -> return c
+ Nothing -> option (return mempty) tableCaption
+ Just c -> return c
-- renormalize widths if greater than 100%:
let totalWidth = sum widths
let widths' = if totalWidth < 1
@@ -1479,7 +1481,13 @@ table = try $ do
-- inline
--
-inline :: MarkdownParser (F Inlines)
+inlines :: PandocMonad m => MarkdownParser m (F Inlines)
+inlines = mconcat <$> many inline
+
+inlines1 :: PandocMonad m => MarkdownParser m (F Inlines)
+inlines1 = mconcat <$> many1 inline
+
+inline :: PandocMonad m => MarkdownParser m (F Inlines)
inline = choice [ whitespace
, bareURL
, str
@@ -1499,6 +1507,7 @@ inline = choice [ whitespace
, autoLink
, spanHtml
, rawHtmlInline
+ , escapedNewline
, escapedChar
, rawLaTeXInline'
, exampleRef
@@ -1509,32 +1518,36 @@ inline = choice [ whitespace
, ltSign
] <?> "inline"
-escapedChar' :: MarkdownParser Char
+escapedChar' :: PandocMonad m => MarkdownParser m Char
escapedChar' = try $ do
char '\\'
(guardEnabled Ext_all_symbols_escapable >> satisfy (not . isAlphaNum))
<|> (guardEnabled Ext_angle_brackets_escapable >>
oneOf "\\`*_{}[]()>#+-.!~\"<>")
- <|> (guardEnabled Ext_escaped_line_breaks >> char '\n')
<|> oneOf "\\`*_{}[]()>#+-.!~\""
-escapedChar :: MarkdownParser (F Inlines)
+escapedNewline :: PandocMonad m => MarkdownParser m (F Inlines)
+escapedNewline = try $ do
+ guardEnabled Ext_escaped_line_breaks
+ char '\\'
+ lookAhead (char '\n') -- don't consume the newline (see #3730)
+ return $ return B.linebreak
+
+escapedChar :: PandocMonad m => MarkdownParser m (F Inlines)
escapedChar = do
result <- escapedChar'
case result of
- ' ' -> return $ return $ B.str "\160" -- "\ " is a nonbreaking space
- '\n' -> guardEnabled Ext_escaped_line_breaks >>
- return (return B.linebreak) -- "\[newline]" is a linebreak
- _ -> return $ return $ B.str [result]
+ ' ' -> return $ return $ B.str "\160" -- "\ " is a nonbreaking space
+ _ -> return $ return $ B.str [result]
-ltSign :: MarkdownParser (F Inlines)
+ltSign :: PandocMonad m => MarkdownParser m (F Inlines)
ltSign = do
guardDisabled Ext_raw_html
<|> (notFollowedByHtmlCloser >> notFollowedBy' (htmlTag isBlockTag))
char '<'
return $ return $ B.str "<"
-exampleRef :: MarkdownParser (F Inlines)
+exampleRef :: PandocMonad m => MarkdownParser m (F Inlines)
exampleRef = try $ do
guardEnabled Ext_example_lists
char '@'
@@ -1542,10 +1555,10 @@ exampleRef = try $ do
return $ do
st <- askF
return $ case M.lookup lab (stateExamples st) of
- Just n -> B.str (show n)
- Nothing -> B.str ('@':lab)
+ Just n -> B.str (show n)
+ Nothing -> B.str ('@':lab)
-symbol :: MarkdownParser (F Inlines)
+symbol :: PandocMonad m => MarkdownParser m (F Inlines)
symbol = do
result <- noneOf "<\\\n\t "
<|> try (do lookAhead $ char '\\'
@@ -1554,28 +1567,36 @@ symbol = do
return $ return $ B.str [result]
-- parses inline code, between n `s and n `s
-code :: MarkdownParser (F Inlines)
+code :: PandocMonad m => MarkdownParser m (F Inlines)
code = try $ do
starts <- many1 (char '`')
skipSpaces
- result <- many1Till (many1 (noneOf "`\n") <|> many1 (char '`') <|>
+ result <- (trim . concat) <$>
+ many1Till (many1 (noneOf "`\n") <|> many1 (char '`') <|>
(char '\n' >> notFollowedBy' blankline >> return " "))
(try (skipSpaces >> count (length starts) (char '`') >>
notFollowedBy (char '`')))
- attr <- option ([],[],[]) (try $ guardEnabled Ext_inline_code_attributes
- >> attributes)
- return $ return $ B.codeWith attr $ trim $ concat result
-
-math :: MarkdownParser (F Inlines)
-math = (return . B.displayMath <$> (mathDisplay >>= applyMacros'))
- <|> (return . B.math <$> (mathInline >>= applyMacros')) <+?>
- ((getOption readerSmart >>= guard) *> (return <$> apostrophe)
+ rawattr <-
+ (Left <$> try (guardEnabled Ext_raw_attribute >> rawAttribute))
+ <|>
+ (Right <$> option ("",[],[])
+ (try (guardEnabled Ext_inline_code_attributes >> attributes)))
+ return $ return $
+ case rawattr of
+ Left syn -> B.rawInline syn result
+ Right attr -> B.codeWith attr result
+
+math :: PandocMonad m => MarkdownParser m (F Inlines)
+math = (return . B.displayMath <$> (mathDisplay >>= applyMacros))
+ <|> (return . B.math <$> (mathInline >>= applyMacros)) <+?>
+ (guardEnabled Ext_smart *> (return <$> apostrophe)
<* notFollowedBy (space <|> satisfy isPunctuation))
-- Parses material enclosed in *s, **s, _s, or __s.
-- Designed to avoid backtracking.
-enclosure :: Char
- -> MarkdownParser (F Inlines)
+enclosure :: PandocMonad m
+ => Char
+ -> MarkdownParser m (F Inlines)
enclosure c = do
-- we can't start an enclosure with _ if after a string and
-- the intraword_underscores extension is enabled:
@@ -1584,14 +1605,14 @@ enclosure c = do
<|> (guard =<< notAfterString)
cs <- many1 (char c)
(return (B.str cs) <>) <$> whitespace
- <|> do
+ <|>
case length cs of
- 3 -> three c
- 2 -> two c mempty
- 1 -> one c mempty
- _ -> return (return $ B.str cs)
+ 3 -> three c
+ 2 -> two c mempty
+ 1 -> one c mempty
+ _ -> return (return $ B.str cs)
-ender :: Char -> Int -> MarkdownParser ()
+ender :: PandocMonad m => Char -> Int -> MarkdownParser m ()
ender c n = try $ do
count n (char c)
guard (c == '*')
@@ -1602,104 +1623,96 @@ ender c n = try $ do
-- If one c, emit emph and then parse two.
-- If two cs, emit strong and then parse one.
-- Otherwise, emit ccc then the results.
-three :: Char -> MarkdownParser (F Inlines)
+three :: PandocMonad m => Char -> MarkdownParser m (F Inlines)
three c = do
contents <- mconcat <$> many (notFollowedBy (ender c 1) >> inline)
- (ender c 3 >> return ((B.strong . B.emph) <$> contents))
- <|> (ender c 2 >> one c (B.strong <$> contents))
- <|> (ender c 1 >> two c (B.emph <$> contents))
+ (ender c 3 >> updateLastStrPos >> return ((B.strong . B.emph) <$> contents))
+ <|> (ender c 2 >> updateLastStrPos >> one c (B.strong <$> contents))
+ <|> (ender c 1 >> updateLastStrPos >> two c (B.emph <$> contents))
<|> return (return (B.str [c,c,c]) <> contents)
-- Parse inlines til you hit two c's, and emit strong.
-- If you never do hit two cs, emit ** plus inlines parsed.
-two :: Char -> F Inlines -> MarkdownParser (F Inlines)
+two :: PandocMonad m => Char -> F Inlines -> MarkdownParser m (F Inlines)
two c prefix' = do
contents <- mconcat <$> many (try $ notFollowedBy (ender c 2) >> inline)
- (ender c 2 >> return (B.strong <$> (prefix' <> contents)))
+ (ender c 2 >> updateLastStrPos >>
+ return (B.strong <$> (prefix' <> contents)))
<|> return (return (B.str [c,c]) <> (prefix' <> contents))
-- Parse inlines til you hit a c, and emit emph.
-- If you never hit a c, emit * plus inlines parsed.
-one :: Char -> F Inlines -> MarkdownParser (F Inlines)
+one :: PandocMonad m => Char -> F Inlines -> MarkdownParser m (F Inlines)
one c prefix' = do
contents <- mconcat <$> many ( (notFollowedBy (ender c 1) >> inline)
<|> try (string [c,c] >>
notFollowedBy (ender c 1) >>
two c mempty) )
- (ender c 1 >> return (B.emph <$> (prefix' <> contents)))
+ (ender c 1 >> updateLastStrPos >> return (B.emph <$> (prefix' <> contents)))
<|> return (return (B.str [c]) <> (prefix' <> contents))
-strongOrEmph :: MarkdownParser (F Inlines)
+strongOrEmph :: PandocMonad m => MarkdownParser m (F Inlines)
strongOrEmph = enclosure '*' <|> enclosure '_'
-- | Parses a list of inlines between start and end delimiters.
-inlinesBetween :: (Show b)
- => MarkdownParser a
- -> MarkdownParser b
- -> MarkdownParser (F Inlines)
+inlinesBetween :: PandocMonad m
+ => (Show b)
+ => MarkdownParser m a
+ -> MarkdownParser m b
+ -> MarkdownParser m (F Inlines)
inlinesBetween start end =
(trimInlinesF . mconcat) <$> try (start >> many1Till inner end)
where inner = innerSpace <|> (notFollowedBy' (() <$ whitespace) >> inline)
innerSpace = try $ whitespace <* notFollowedBy' end
-strikeout :: MarkdownParser (F Inlines)
+strikeout :: PandocMonad m => MarkdownParser m (F Inlines)
strikeout = fmap B.strikeout <$>
(guardEnabled Ext_strikeout >> inlinesBetween strikeStart strikeEnd)
where strikeStart = string "~~" >> lookAhead nonspaceChar
>> notFollowedBy (char '~')
strikeEnd = try $ string "~~"
-superscript :: MarkdownParser (F Inlines)
+superscript :: PandocMonad m => MarkdownParser m (F Inlines)
superscript = fmap B.superscript <$> try (do
guardEnabled Ext_superscript
char '^'
mconcat <$> many1Till (notFollowedBy spaceChar >> inline) (char '^'))
-subscript :: MarkdownParser (F Inlines)
+subscript :: PandocMonad m => MarkdownParser m (F Inlines)
subscript = fmap B.subscript <$> try (do
guardEnabled Ext_subscript
char '~'
mconcat <$> many1Till (notFollowedBy spaceChar >> inline) (char '~'))
-whitespace :: MarkdownParser (F Inlines)
+whitespace :: PandocMonad m => MarkdownParser m (F Inlines)
whitespace = spaceChar >> return <$> (lb <|> regsp) <?> "whitespace"
where lb = spaceChar >> skipMany spaceChar >> option B.space (endline >> return B.linebreak)
regsp = skipMany spaceChar >> return B.space
-nonEndline :: Parser [Char] st Char
+nonEndline :: PandocMonad m => ParserT [Char] st m Char
nonEndline = satisfy (/='\n')
-str :: MarkdownParser (F Inlines)
+str :: PandocMonad m => MarkdownParser m (F Inlines)
str = do
- result <- many1 alphaNum
+ result <- many1 (alphaNum <|> try (char '.' <* notFollowedBy (char '.')))
updateLastStrPos
- let spacesToNbr = map (\c -> if c == ' ' then '\160' else c)
- isSmart <- getOption readerSmart
- if isSmart
- then case likelyAbbrev result of
- [] -> return $ return $ B.str result
- xs -> choice (map (\x ->
- try (string x >> oneOf " \n" >>
- lookAhead alphaNum >>
- return (return $ B.str
- $ result ++ spacesToNbr x ++ "\160"))) xs)
- <|> (return $ return $ B.str result)
- else return $ return $ B.str result
-
--- | if the string matches the beginning of an abbreviation (before
--- the first period, return strings that would finish the abbreviation.
-likelyAbbrev :: String -> [String]
-likelyAbbrev x =
- let abbrevs = [ "Mr.", "Mrs.", "Ms.", "Capt.", "Dr.", "Prof.",
- "Gen.", "Gov.", "e.g.", "i.e.", "Sgt.", "St.",
- "vol.", "vs.", "Sen.", "Rep.", "Pres.", "Hon.",
- "Rev.", "Ph.D.", "M.D.", "M.A.", "p.", "pp.",
- "ch.", "sec.", "cf.", "cp."]
- abbrPairs = map (break (=='.')) abbrevs
- in map snd $ filter (\(y,_) -> y == x) abbrPairs
+ (do guardEnabled Ext_smart
+ abbrevs <- getOption readerAbbreviations
+ if not (null result) && last result == '.' && result `Set.member` abbrevs
+ then try (do ils <- whitespace <|> endline
+ lookAhead alphaNum
+ return $ do
+ ils' <- ils
+ if ils' == B.space
+ then return (B.str result <> B.str "\160")
+ else -- linebreak or softbreak
+ return (ils' <> B.str result <> B.str "\160"))
+ <|> return (return (B.str result))
+ else return (return (B.str result)))
+ <|> return (return (B.str result))
-- an endline character that can be treated as a space, not a structural break
-endline :: MarkdownParser (F Inlines)
+endline :: PandocMonad m => MarkdownParser m (F Inlines)
endline = try $ do
newline
notFollowedBy blankline
@@ -1711,6 +1724,7 @@ endline = try $ do
guardDisabled Ext_backtick_code_blocks <|>
notFollowedBy (() <$ (lookAhead (char '`') >> codeBlockFenced))
notFollowedByHtmlCloser
+ notFollowedByDivCloser
(eof >> return mempty)
<|> (guardEnabled Ext_hard_line_breaks >> return (return B.linebreak))
<|> (guardEnabled Ext_ignore_line_breaks >> return mempty)
@@ -1721,23 +1735,25 @@ endline = try $ do
--
-- a reference label for a link
-reference :: MarkdownParser (F Inlines, String)
-reference = do notFollowedBy' (string "[^") -- footnote reference
- withRaw $ trimInlinesF <$> inlinesInBalancedBrackets
+reference :: PandocMonad m => MarkdownParser m (F Inlines, String)
+reference = do
+ guardDisabled Ext_footnotes <|> notFollowedBy' (string "[^")
+ guardDisabled Ext_citations <|> notFollowedBy' (string "[@")
+ withRaw $ trimInlinesF <$> inlinesInBalancedBrackets
-parenthesizedChars :: MarkdownParser [Char]
+parenthesizedChars :: PandocMonad m => MarkdownParser m [Char]
parenthesizedChars = do
result <- charsInBalanced '(' ')' litChar
return $ '(' : result ++ ")"
-- source for a link, with optional title
-source :: MarkdownParser (String, String)
+source :: PandocMonad m => MarkdownParser m (String, String)
source = do
char '('
skipSpaces
let urlChunk =
try parenthesizedChars
- <|> (notFollowedBy (oneOf " )") >> (count 1 litChar))
+ <|> (notFollowedBy (oneOf " )") >> count 1 litChar)
<|> try (many1 spaceChar <* notFollowedBy (oneOf "\"')"))
let sourceURL = (unwords . words . concat) <$> many urlChunk
let betweenAngles = try $
@@ -1748,10 +1764,10 @@ source = do
char ')'
return (escapeURI $ trimr src, tit)
-linkTitle :: MarkdownParser String
+linkTitle :: PandocMonad m => MarkdownParser m String
linkTitle = quotedTitle '"' <|> quotedTitle '\''
-link :: MarkdownParser (F Inlines)
+link :: PandocMonad m => MarkdownParser m (F Inlines)
link = try $ do
st <- getState
guard $ stateAllowLinks st
@@ -1760,21 +1776,31 @@ link = try $ do
setState $ st{ stateAllowLinks = True }
regLink B.linkWith lab <|> referenceLink B.linkWith (lab,raw)
-bracketedSpan :: MarkdownParser (F Inlines)
+bracketedSpan :: PandocMonad m => MarkdownParser m (F Inlines)
bracketedSpan = try $ do
guardEnabled Ext_bracketed_spans
(lab,_) <- reference
attr <- attributes
- let (ident,classes,keyvals) = attr
- case lookup "style" keyvals of
- Just s | null ident && null classes &&
- map toLower (filter (`notElem` " \t;") s) ==
- "font-variant:small-caps"
- -> return $ B.smallcaps <$> lab
- _ -> return $ B.spanWith attr <$> lab
-
-regLink :: (Attr -> String -> String -> Inlines -> Inlines)
- -> F Inlines -> MarkdownParser (F Inlines)
+ return $ if isSmallCaps attr
+ then B.smallcaps <$> lab
+ else B.spanWith attr <$> lab
+
+-- | We treat a span as SmallCaps if class is "smallcaps" (and
+-- no other attributes are set or if style is "font-variant:small-caps"
+-- (and no other attributes are set).
+isSmallCaps :: Attr -> Bool
+isSmallCaps ("",["smallcaps"],[]) = True
+isSmallCaps ("",[],kvs) =
+ case lookup "style" kvs of
+ Just s -> map toLower (filter (`notElem` " \t;") s) ==
+ "font-variant:small-caps"
+ Nothing -> False
+isSmallCaps _ = False
+
+regLink :: PandocMonad m
+ => (Attr -> String -> String -> Inlines -> Inlines)
+ -> F Inlines
+ -> MarkdownParser m (F Inlines)
regLink constructor lab = try $ do
(src, tit) <- source
attr <- option nullAttr $
@@ -1782,20 +1808,24 @@ regLink constructor lab = try $ do
return $ constructor attr src tit <$> lab
-- a link like [this][ref] or [this][] or [this]
-referenceLink :: (Attr -> String -> String -> Inlines -> Inlines)
- -> (F Inlines, String) -> MarkdownParser (F Inlines)
+referenceLink :: PandocMonad m
+ => (Attr -> String -> String -> Inlines -> Inlines)
+ -> (F Inlines, String)
+ -> MarkdownParser m (F Inlines)
referenceLink constructor (lab, raw) = do
sp <- (True <$ lookAhead (char ' ')) <|> return False
(_,raw') <- option (mempty, "") $
- lookAhead (try (guardEnabled Ext_citations >>
- spnl >> normalCite >> return (mempty, "")))
+ lookAhead (try (do guardEnabled Ext_citations
+ guardDisabled Ext_spaced_reference_links <|> spnl
+ normalCite
+ return (mempty, "")))
<|>
- try (spnl >> reference)
+ try ((guardDisabled Ext_spaced_reference_links <|> spnl) >> reference)
when (raw' == "") $ guardEnabled Ext_shortcut_reference_links
let labIsRef = raw' == "" || raw' == "[]"
let key = toKey $ if labIsRef then raw else raw'
- parsedRaw <- parseFromString (mconcat <$> many inline) raw'
- fallback <- parseFromString (mconcat <$> many inline) $ dropBrackets raw
+ parsedRaw <- parseFromString' inlines raw'
+ fallback <- parseFromString' inlines $ dropBrackets raw
implicitHeaderRefs <- option False $
True <$ guardEnabled Ext_implicit_header_references
let makeFallback = do
@@ -1820,11 +1850,11 @@ referenceLink constructor (lab, raw) = do
dropBrackets :: String -> String
dropBrackets = reverse . dropRB . reverse . dropLB
where dropRB (']':xs) = xs
- dropRB xs = xs
+ dropRB xs = xs
dropLB ('[':xs) = xs
- dropLB xs = xs
+ dropLB xs = xs
-bareURL :: MarkdownParser (F Inlines)
+bareURL :: PandocMonad m => MarkdownParser m (F Inlines)
bareURL = try $ do
guardEnabled Ext_autolink_bare_uris
getState >>= guard . stateAllowLinks
@@ -1832,7 +1862,7 @@ bareURL = try $ do
notFollowedBy $ try $ spaces >> htmlTag (~== TagClose "a")
return $ return $ B.link src "" (B.str orig)
-autoLink :: MarkdownParser (F Inlines)
+autoLink :: PandocMonad m => MarkdownParser m (F Inlines)
autoLink = try $ do
getState >>= guard . stateAllowLinks
char '<'
@@ -1846,7 +1876,7 @@ autoLink = try $ do
guardEnabled Ext_link_attributes >> attributes
return $ return $ B.linkWith attr (src ++ escapeURI extra) "" (B.str $ orig ++ extra)
-image :: MarkdownParser (F Inlines)
+image :: PandocMonad m => MarkdownParser m (F Inlines)
image = try $ do
char '!'
(lab,raw) <- reference
@@ -1856,54 +1886,55 @@ image = try $ do
_ -> B.imageWith attr' src
regLink constructor lab <|> referenceLink constructor (lab,raw)
-note :: MarkdownParser (F Inlines)
+note :: PandocMonad m => MarkdownParser m (F Inlines)
note = try $ do
guardEnabled Ext_footnotes
ref <- noteMarker
+ updateState $ \st -> st{ stateNoteRefs = Set.insert ref (stateNoteRefs st) }
return $ do
notes <- asksF stateNotes'
- case lookup ref notes of
+ case M.lookup ref notes of
Nothing -> return $ B.str $ "[^" ++ ref ++ "]"
- Just contents -> do
+ Just (_pos, contents) -> do
st <- askF
-- process the note in a context that doesn't resolve
-- notes, to avoid infinite looping with notes inside
-- notes:
- let contents' = runF contents st{ stateNotes' = [] }
+ let contents' = runF contents st{ stateNotes' = M.empty }
return $ B.note contents'
-inlineNote :: MarkdownParser (F Inlines)
+inlineNote :: PandocMonad m => MarkdownParser m (F Inlines)
inlineNote = try $ do
guardEnabled Ext_inline_notes
char '^'
contents <- inlinesInBalancedBrackets
return $ B.note . B.para <$> contents
-rawLaTeXInline' :: MarkdownParser (F Inlines)
+rawLaTeXInline' :: PandocMonad m => MarkdownParser m (F Inlines)
rawLaTeXInline' = try $ do
guardEnabled Ext_raw_tex
- lookAhead $ char '\\' >> notFollowedBy' (string "start") -- context env
- RawInline _ s <- rawLaTeXInline
- return $ return $ B.rawInline "tex" s
- -- "tex" because it might be context or latex
+ lookAhead $ try $ char '\\' >> letter
+ notFollowedBy' rawConTeXtEnvironment
+ s <- rawLaTeXInline
+ return $ return $ B.rawInline "tex" s -- "tex" because it might be context
-rawConTeXtEnvironment :: Parser [Char] st String
+rawConTeXtEnvironment :: PandocMonad m => ParserT [Char] st m String
rawConTeXtEnvironment = try $ do
string "\\start"
completion <- inBrackets (letter <|> digit <|> spaceChar)
- <|> (many1 letter)
- contents <- manyTill (rawConTeXtEnvironment <|> (count 1 anyChar))
+ <|> many1 letter
+ contents <- manyTill (rawConTeXtEnvironment <|> count 1 anyChar)
(try $ string "\\stop" >> string completion)
return $ "\\start" ++ completion ++ concat contents ++ "\\stop" ++ completion
-inBrackets :: (Parser [Char] st Char) -> Parser [Char] st String
+inBrackets :: PandocMonad m => ParserT [Char] st m Char -> ParserT [Char] st m String
inBrackets parser = do
char '['
contents <- many parser
char ']'
return $ "[" ++ contents ++ "]"
-spanHtml :: MarkdownParser (F Inlines)
+spanHtml :: PandocMonad m => MarkdownParser m (F Inlines)
spanHtml = try $ do
guardEnabled Ext_native_spans
(TagOpen _ attrs, _) <- htmlTag (~== TagOpen "span" [])
@@ -1911,14 +1942,11 @@ spanHtml = try $ do
let ident = fromMaybe "" $ lookup "id" attrs
let classes = maybe [] words $ lookup "class" attrs
let keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
- case lookup "style" keyvals of
- Just s | null ident && null classes &&
- map toLower (filter (`notElem` " \t;") s) ==
- "font-variant:small-caps"
- -> return $ B.smallcaps <$> contents
- _ -> return $ B.spanWith (ident, classes, keyvals) <$> contents
-
-divHtml :: MarkdownParser (F Blocks)
+ return $ if isSmallCaps (ident, classes, keyvals)
+ then B.smallcaps <$> contents
+ else B.spanWith (ident, classes, keyvals) <$> contents
+
+divHtml :: PandocMonad m => MarkdownParser m (F Blocks)
divHtml = try $ do
guardEnabled Ext_native_divs
(TagOpen _ attrs, rawtag) <- htmlTag (~== TagOpen "div" [])
@@ -1940,7 +1968,29 @@ divHtml = try $ do
else -- avoid backtracing
return $ return (B.rawBlock "html" (rawtag <> bls)) <> contents
-rawHtmlInline :: MarkdownParser (F Inlines)
+divFenced :: PandocMonad m => MarkdownParser m (F Blocks)
+divFenced = try $ do
+ guardEnabled Ext_fenced_divs
+ string ":::"
+ skipMany (char ':')
+ skipMany spaceChar
+ attribs <- attributes <|> ((\x -> ("",[x],[])) <$> many1 nonspaceChar)
+ skipMany spaceChar
+ skipMany (char ':')
+ blankline
+ updateState $ \st -> st{ stateFencedDivLevel = stateFencedDivLevel st + 1 }
+ bs <- mconcat <$> manyTill block divFenceEnd
+ updateState $ \st -> st{ stateFencedDivLevel = stateFencedDivLevel st - 1 }
+ return $ B.divWith attribs <$> bs
+
+divFenceEnd :: PandocMonad m => MarkdownParser m ()
+divFenceEnd = try $ do
+ string ":::"
+ skipMany (char ':')
+ blanklines
+ return ()
+
+rawHtmlInline :: PandocMonad m => MarkdownParser m (F Inlines)
rawHtmlInline = do
guardEnabled Ext_raw_html
inHtmlBlock <- stateInHtmlBlock <$> getState
@@ -1962,7 +2012,7 @@ rawHtmlInline = do
emojiChars :: [Char]
emojiChars = ['a'..'z'] ++ ['0'..'9'] ++ ['_','+','-']
-emoji :: MarkdownParser (F Inlines)
+emoji :: PandocMonad m => MarkdownParser m (F Inlines)
emoji = try $ do
guardEnabled Ext_emoji
char ':'
@@ -1974,21 +2024,22 @@ emoji = try $ do
-- Citations
-cite :: MarkdownParser (F Inlines)
+cite :: PandocMonad m => MarkdownParser m (F Inlines)
cite = do
guardEnabled Ext_citations
- citations <- textualCite
+ textualCite
<|> do (cs, raw) <- withRaw normalCite
- return $ (flip B.cite (B.text raw)) <$> cs
- return citations
+ return $ flip B.cite (B.text raw) <$> cs
-textualCite :: MarkdownParser (F Inlines)
+textualCite :: PandocMonad m => MarkdownParser m (F Inlines)
textualCite = try $ do
- (_, key) <- citeKey
+ (suppressAuthor, key) <- citeKey
let first = Citation{ citationId = key
, citationPrefix = []
, citationSuffix = []
- , citationMode = AuthorInText
+ , citationMode = if suppressAuthor
+ then SuppressAuthor
+ else AuthorInText
, citationNoteNum = 0
, citationHash = 0
}
@@ -2003,7 +2054,7 @@ textualCite = try $ do
let (spaces',raw') = span isSpace raw
spc | null spaces' = mempty
| otherwise = B.space
- lab <- parseFromString (mconcat <$> many inline) $ dropBrackets raw'
+ lab <- parseFromString' inlines $ dropBrackets raw'
fallback <- referenceLink B.linkWith (lab,raw')
return $ do
fallback' <- fallback
@@ -2017,7 +2068,7 @@ textualCite = try $ do
Just n -> B.str (show n)
_ -> B.cite [first] $ B.str $ '@':key)
-bareloc :: Citation -> MarkdownParser (F [Citation])
+bareloc :: PandocMonad m => Citation -> MarkdownParser m (F [Citation])
bareloc c = try $ do
spnl
char '['
@@ -2032,7 +2083,7 @@ bareloc c = try $ do
rest' <- rest
return $ c{ citationSuffix = B.toList suff' } : rest'
-normalCite :: MarkdownParser (F [Citation])
+normalCite :: PandocMonad m => MarkdownParser m (F [Citation])
normalCite = try $ do
char '['
spnl
@@ -2041,7 +2092,7 @@ normalCite = try $ do
char ']'
return citations
-suffix :: MarkdownParser (F Inlines)
+suffix :: PandocMonad m => MarkdownParser m (F Inlines)
suffix = try $ do
hasSpace <- option False (notFollowedBy nonspaceChar >> return True)
spnl
@@ -2050,14 +2101,14 @@ suffix = try $ do
then (B.space <>) <$> rest
else rest
-prefix :: MarkdownParser (F Inlines)
+prefix :: PandocMonad m => MarkdownParser m (F Inlines)
prefix = trimInlinesF . mconcat <$>
- manyTill inline (char ']' <|> liftM (const ']') (lookAhead citeKey))
+ manyTill inline (char ']' <|> fmap (const ']') (lookAhead citeKey))
-citeList :: MarkdownParser (F [Citation])
+citeList :: PandocMonad m => MarkdownParser m (F [Citation])
citeList = fmap sequence $ sepBy1 citation (try $ char ';' >> spnl)
-citation :: MarkdownParser (F Citation)
+citation :: PandocMonad m => MarkdownParser m (F Citation)
citation = try $ do
pref <- prefix
(suppress_author, key) <- citeKey
@@ -2065,23 +2116,23 @@ citation = try $ do
return $ do
x <- pref
y <- suff
- return $ Citation{ citationId = key
- , citationPrefix = B.toList x
- , citationSuffix = B.toList y
- , citationMode = if suppress_author
- then SuppressAuthor
- else NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
-
-smart :: MarkdownParser (F Inlines)
+ return Citation{ citationId = key
+ , citationPrefix = B.toList x
+ , citationSuffix = B.toList y
+ , citationMode = if suppress_author
+ then SuppressAuthor
+ else NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+
+smart :: PandocMonad m => MarkdownParser m (F Inlines)
smart = do
- getOption readerSmart >>= guard
+ guardEnabled Ext_smart
doubleQuoted <|> singleQuoted <|>
choice (map (return <$>) [apostrophe, dash, ellipses])
-singleQuoted :: MarkdownParser (F Inlines)
+singleQuoted :: PandocMonad m => MarkdownParser m (F Inlines)
singleQuoted = try $ do
singleQuoteStart
withQuoteContext InSingleQuote $
@@ -2091,10 +2142,10 @@ singleQuoted = try $ do
-- doubleQuoted will handle regular double-quoted sections, as well
-- as dialogues with an open double-quote without a close double-quote
-- in the same paragraph.
-doubleQuoted :: MarkdownParser (F Inlines)
+doubleQuoted :: PandocMonad m => MarkdownParser m (F Inlines)
doubleQuoted = try $ do
doubleQuoteStart
contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
- (withQuoteContext InDoubleQuote $ doubleQuoteEnd >> return
+ withQuoteContext InDoubleQuote (doubleQuoteEnd >> return
(fmap B.doubleQuoted . trimInlinesF $ contents))
- <|> (return $ return (B.str "\8220") <> contents)
+ <|> return (return (B.str "\8220") <> contents)
diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs
index 0dea22c53..c19ef2f46 100644
--- a/src/Text/Pandoc/Readers/MediaWiki.hs
+++ b/src/Text/Pandoc/Readers/MediaWiki.hs
@@ -1,7 +1,9 @@
-{-# LANGUAGE RelaxedPolyRec, FlexibleInstances, TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE RelaxedPolyRec #-}
+{-# LANGUAGE TypeSynonymInstances #-}
-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
{-
- Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
+ Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.MediaWiki
- Copyright : Copyright (C) 2012-2015 John MacFarlane
+ Copyright : Copyright (C) 2012-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -36,43 +38,50 @@ _ parse templates?
-}
module Text.Pandoc.Readers.MediaWiki ( readMediaWiki ) where
-import Text.Pandoc.Definition
-import qualified Text.Pandoc.Builder as B
-import Text.Pandoc.Builder (Inlines, Blocks, trimInlines)
-import Data.Monoid ((<>))
-import Text.Pandoc.Options
-import Text.Pandoc.Readers.HTML ( htmlTag, isBlockTag, isCommentTag )
-import Text.Pandoc.XML ( fromEntities )
-import Text.Pandoc.Parsing hiding ( nested )
-import Text.Pandoc.Walk ( walk )
-import Text.Pandoc.Shared ( stripTrailingNewlines, safeRead, stringify, trim )
import Control.Monad
-import Data.List (intersperse, intercalate, isPrefixOf )
-import Text.HTML.TagSoup
-import Data.Sequence (viewl, ViewL(..), (<|))
+import Control.Monad.Except (throwError)
+import Data.Char (isDigit, isSpace)
import qualified Data.Foldable as F
+import Data.List (intercalate, intersperse, isPrefixOf)
import qualified Data.Map as M
+import Data.Maybe (fromMaybe, maybeToList)
+import Data.Monoid ((<>))
+import Data.Sequence (ViewL (..), viewl, (<|))
import qualified Data.Set as Set
-import Data.Char (isDigit, isSpace)
-import Data.Maybe (fromMaybe)
-import Text.Printf (printf)
-import Debug.Trace (trace)
-
-import Text.Pandoc.Error
+import Data.Text (Text, unpack)
+import Text.HTML.TagSoup
+import Text.Pandoc.Builder (Blocks, Inlines, trimInlines)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad (..))
+import Text.Pandoc.Definition
+import Text.Pandoc.Logging
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (nested)
+import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isCommentTag)
+import Text.Pandoc.Shared (crFilter, safeRead, stringify, stripTrailingNewlines,
+ trim)
+import Text.Pandoc.Walk (walk)
+import Text.Pandoc.XML (fromEntities)
-- | Read mediawiki from an input string and return a Pandoc document.
-readMediaWiki :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError Pandoc
-readMediaWiki opts s =
- readWith parseMediaWiki MWState{ mwOptions = opts
- , mwMaxNestingLevel = 4
- , mwNextLinkNumber = 1
- , mwCategoryLinks = []
- , mwHeaderMap = M.empty
- , mwIdentifierList = Set.empty
- }
- (s ++ "\n")
+readMediaWiki :: PandocMonad m
+ => ReaderOptions -- ^ Reader options
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
+ -> m Pandoc
+readMediaWiki opts s = do
+ parsed <- readWithM parseMediaWiki MWState{ mwOptions = opts
+ , mwMaxNestingLevel = 4
+ , mwNextLinkNumber = 1
+ , mwCategoryLinks = []
+ , mwHeaderMap = M.empty
+ , mwIdentifierList = Set.empty
+ , mwLogMessages = []
+ , mwInTT = False
+ }
+ (unpack (crFilter s) ++ "\n")
+ case parsed of
+ Right result -> return result
+ Left e -> throwError e
data MWState = MWState { mwOptions :: ReaderOptions
, mwMaxNestingLevel :: Int
@@ -80,9 +89,11 @@ data MWState = MWState { mwOptions :: ReaderOptions
, mwCategoryLinks :: [Inlines]
, mwHeaderMap :: M.Map Inlines String
, mwIdentifierList :: Set.Set String
+ , mwLogMessages :: [LogMessage]
+ , mwInTT :: Bool
}
-type MWParser = Parser [Char] MWState
+type MWParser m = ParserT [Char] MWState m
instance HasReaderOptions MWState where
extractReaderOptions = mwOptions
@@ -95,13 +106,17 @@ instance HasIdentifierList MWState where
extractIdentifierList = mwIdentifierList
updateIdentifierList f st = st{ mwIdentifierList = f $ mwIdentifierList st }
+instance HasLogMessages MWState where
+ addLogMessage m s = s{ mwLogMessages = m : mwLogMessages s }
+ getLogMessages = reverse . mwLogMessages
+
--
-- auxiliary functions
--
-- This is used to prevent exponential blowups for things like:
-- ''a'''a''a'''a''a'''a''a'''a
-nested :: MWParser a -> MWParser a
+nested :: PandocMonad m => MWParser m a -> MWParser m a
nested p = do
nestlevel <- mwMaxNestingLevel `fmap` getState
guard $ nestlevel > 0
@@ -116,7 +131,7 @@ specialChars = "'[]<=&*{}|\":\\"
spaceChars :: [Char]
spaceChars = " \n\t"
-sym :: String -> MWParser ()
+sym :: PandocMonad m => String -> MWParser m ()
sym s = () <$ try (string s)
newBlockTags :: [String]
@@ -131,16 +146,16 @@ isBlockTag' tag = isBlockTag tag
isInlineTag' :: Tag String -> Bool
isInlineTag' (TagComment _) = True
-isInlineTag' t = not (isBlockTag' t)
+isInlineTag' t = not (isBlockTag' t)
eitherBlockOrInline :: [String]
eitherBlockOrInline = ["applet", "button", "del", "iframe", "ins",
"map", "area", "object"]
-htmlComment :: MWParser ()
+htmlComment :: PandocMonad m => MWParser m ()
htmlComment = () <$ htmlTag isCommentTag
-inlinesInTags :: String -> MWParser Inlines
+inlinesInTags :: PandocMonad m => String -> MWParser m Inlines
inlinesInTags tag = try $ do
(_,raw) <- htmlTag (~== TagOpen tag [])
if '/' `elem` raw -- self-closing tag
@@ -148,7 +163,7 @@ inlinesInTags tag = try $ do
else trimInlines . mconcat <$>
manyTill inline (htmlTag (~== TagClose tag))
-blocksInTags :: String -> MWParser Blocks
+blocksInTags :: PandocMonad m => String -> MWParser m Blocks
blocksInTags tag = try $ do
(_,raw) <- htmlTag (~== TagOpen tag [])
let closer = if tag == "li"
@@ -162,7 +177,7 @@ blocksInTags tag = try $ do
then return mempty
else mconcat <$> manyTill block closer
-charsInTags :: String -> MWParser [Char]
+charsInTags :: PandocMonad m => String -> MWParser m [Char]
charsInTags tag = try $ do
(_,raw) <- htmlTag (~== TagOpen tag [])
if '/' `elem` raw -- self-closing tag
@@ -173,7 +188,7 @@ charsInTags tag = try $ do
-- main parser
--
-parseMediaWiki :: MWParser Pandoc
+parseMediaWiki :: PandocMonad m => MWParser m Pandoc
parseMediaWiki = do
bs <- mconcat <$> many block
spaces
@@ -182,16 +197,15 @@ parseMediaWiki = do
let categories = if null categoryLinks
then mempty
else B.para $ mconcat $ intersperse B.space categoryLinks
+ reportLogMessages
return $ B.doc $ bs <> categories
--
-- block parsers
--
-block :: MWParser Blocks
+block :: PandocMonad m => MWParser m Blocks
block = do
- tr <- getOption readerTrace
- pos <- getPosition
res <- mempty <$ skipMany1 blankline
<|> table
<|> header
@@ -204,28 +218,28 @@ block = do
<|> blockTag
<|> (B.rawBlock "mediawiki" <$> template)
<|> para
- when tr $
- trace (printf "line %d: %s" (sourceLine pos)
- (take 60 $ show $ B.toList res)) (return ())
+ trace (take 60 $ show $ B.toList res)
return res
-para :: MWParser Blocks
+para :: PandocMonad m => MWParser m Blocks
para = do
contents <- trimInlines . mconcat <$> many1 inline
if F.all (==Space) contents
then return mempty
else return $ B.para contents
-table :: MWParser Blocks
+table :: PandocMonad m => MWParser m Blocks
table = do
tableStart
- styles <- option [] parseAttrs <* blankline
+ styles <- option [] parseAttrs
+ skipMany spaceChar
+ optional blanklines
let tableWidth = case lookup "width" styles of
Just w -> fromMaybe 1.0 $ parseWidth w
Nothing -> 1.0
caption <- option mempty tableCaption
optional rowsep
- hasheader <- option False $ True <$ (lookAhead (skipSpaces *> char '!'))
+ hasheader <- option False $ True <$ lookAhead (skipSpaces *> char '!')
(cellspecs',hdr) <- unzip <$> tableRow
let widths = map ((tableWidth *) . snd) cellspecs'
let restwidth = tableWidth - sum widths
@@ -244,10 +258,10 @@ table = do
else (replicate cols mempty, hdr:rows')
return $ B.table caption cellspecs headers rows
-parseAttrs :: MWParser [(String,String)]
+parseAttrs :: PandocMonad m => MWParser m [(String,String)]
parseAttrs = many1 parseAttr
-parseAttr :: MWParser (String, String)
+parseAttr :: PandocMonad m => MWParser m (String, String)
parseAttr = try $ do
skipMany spaceChar
k <- many1 letter
@@ -256,27 +270,23 @@ parseAttr = try $ do
<|> many1 (satisfy $ \c -> not (isSpace c) && c /= '|')
return (k,v)
-tableStart :: MWParser ()
+tableStart :: PandocMonad m => MWParser m ()
tableStart = try $ guardColumnOne *> skipSpaces *> sym "{|"
-tableEnd :: MWParser ()
+tableEnd :: PandocMonad m => MWParser m ()
tableEnd = try $ guardColumnOne *> skipSpaces *> sym "|}"
-rowsep :: MWParser ()
+rowsep :: PandocMonad m => MWParser m ()
rowsep = try $ guardColumnOne *> skipSpaces *> sym "|-" <*
- optional parseAttr <* blanklines
-
-cellsep :: MWParser ()
-cellsep = try $
- (guardColumnOne *> skipSpaces <*
- ( (char '|' <* notFollowedBy (oneOf "-}+"))
- <|> (char '!')
- )
- )
- <|> (() <$ try (string "||"))
- <|> (() <$ try (string "!!"))
-
-tableCaption :: MWParser Inlines
+ many (char '-') <* optional parseAttr <* blanklines
+
+cellsep :: PandocMonad m => MWParser m ()
+cellsep = try $ do
+ skipSpaces
+ (char '|' *> notFollowedBy (oneOf "-}+") *> optional (char '|'))
+ <|> (char '!' *> optional (char '!'))
+
+tableCaption :: PandocMonad m => MWParser m Inlines
tableCaption = try $ do
guardColumnOne
skipSpaces
@@ -284,19 +294,21 @@ tableCaption = try $ do
optional (try $ parseAttr *> skipSpaces *> char '|' *> skipSpaces)
(trimInlines . mconcat) <$> many (notFollowedBy (cellsep <|> rowsep) *> inline)
-tableRow :: MWParser [((Alignment, Double), Blocks)]
+tableRow :: PandocMonad m => MWParser m [((Alignment, Double), Blocks)]
tableRow = try $ skipMany htmlComment *> many tableCell
-tableCell :: MWParser ((Alignment, Double), Blocks)
+tableCell :: PandocMonad m => MWParser m ((Alignment, Double), Blocks)
tableCell = try $ do
cellsep
skipMany spaceChar
attrs <- option [] $ try $ parseAttrs <* skipSpaces <* char '|' <*
notFollowedBy (char '|')
skipMany spaceChar
+ pos' <- getPosition
ls <- concat <$> many (notFollowedBy (cellsep <|> rowsep <|> tableEnd) *>
((snd <$> withRaw table) <|> count 1 anyChar))
- bs <- parseFromString (mconcat <$> many block) ls
+ bs <- parseFromString (do setPosition pos'
+ mconcat <$> many block) ls
let align = case lookup "align" attrs of
Just "left" -> AlignLeft
Just "right" -> AlignRight
@@ -311,9 +323,9 @@ parseWidth :: String -> Maybe Double
parseWidth s =
case reverse s of
('%':ds) | all isDigit ds -> safeRead ('0':'.':reverse ds)
- _ -> Nothing
+ _ -> Nothing
-template :: MWParser String
+template :: PandocMonad m => MWParser m String
template = try $ do
string "{{"
notFollowedBy (char '{')
@@ -322,7 +334,7 @@ template = try $ do
contents <- manyTill chunk (try $ string "}}")
return $ "{{" ++ concat contents ++ "}}"
-blockTag :: MWParser Blocks
+blockTag :: PandocMonad m => MWParser m Blocks
blockTag = do
(tag, _) <- lookAhead $ htmlTag isBlockTag'
case tag of
@@ -341,27 +353,27 @@ trimCode :: String -> String
trimCode ('\n':xs) = stripTrailingNewlines xs
trimCode xs = stripTrailingNewlines xs
-syntaxhighlight :: String -> [Attribute String] -> MWParser Blocks
+syntaxhighlight :: PandocMonad m => String -> [Attribute String] -> MWParser m Blocks
syntaxhighlight tag attrs = try $ do
let mblang = lookup "lang" attrs
let mbstart = lookup "start" attrs
let mbline = lookup "line" attrs
- let classes = maybe [] (:[]) mblang ++ maybe [] (const ["numberLines"]) mbline
+ let classes = maybeToList mblang ++ maybe [] (const ["numberLines"]) mbline
let kvs = maybe [] (\x -> [("startFrom",x)]) mbstart
contents <- charsInTags tag
return $ B.codeBlockWith ("",classes,kvs) $ trimCode contents
-hrule :: MWParser Blocks
+hrule :: PandocMonad m => MWParser m Blocks
hrule = B.horizontalRule <$ try (string "----" *> many (char '-') *> newline)
-guardColumnOne :: MWParser ()
+guardColumnOne :: PandocMonad m => MWParser m ()
guardColumnOne = getPosition >>= \pos -> guard (sourceColumn pos == 1)
-preformatted :: MWParser Blocks
+preformatted :: PandocMonad m => MWParser m Blocks
preformatted = try $ do
guardColumnOne
char ' '
- let endline' = B.linebreak <$ (try $ newline <* char ' ')
+ let endline' = B.linebreak <$ try (newline <* char ' ')
let whitespace' = B.str <$> many1 ('\160' <$ spaceChar)
let spToNbsp ' ' = '\160'
spToNbsp x = x
@@ -370,7 +382,7 @@ preformatted = try $ do
(htmlTag (~== TagOpen "nowiki" []) *>
manyTill anyChar (htmlTag (~== TagClose "nowiki")))
let inline' = whitespace' <|> endline' <|> nowiki'
- <|> (try $ notFollowedBy newline *> inline)
+ <|> try (notFollowedBy newline *> inline)
contents <- mconcat <$> many1 inline'
let spacesStr (Str xs) = all isSpace xs
spacesStr _ = False
@@ -385,10 +397,10 @@ encode = B.fromList . normalizeCode . B.toList . walk strToCode
strToCode x = x
normalizeCode [] = []
normalizeCode (Code a1 x : Code a2 y : zs) | a1 == a2 =
- normalizeCode $ (Code a1 (x ++ y)) : zs
+ normalizeCode $ Code a1 (x ++ y) : zs
normalizeCode (x:xs) = x : normalizeCode xs
-header :: MWParser Blocks
+header :: PandocMonad m => MWParser m Blocks
header = try $ do
guardColumnOne
eqs <- many1 (char '=')
@@ -398,13 +410,13 @@ header = try $ do
attr <- registerHeader nullAttr contents
return $ B.headerWith attr lev contents
-bulletList :: MWParser Blocks
+bulletList :: PandocMonad m => MWParser m Blocks
bulletList = B.bulletList <$>
( many1 (listItem '*')
<|> (htmlTag (~== TagOpen "ul" []) *> spaces *> many (listItem '*' <|> li) <*
optional (htmlTag (~== TagClose "ul"))) )
-orderedList :: MWParser Blocks
+orderedList :: PandocMonad m => MWParser m Blocks
orderedList =
(B.orderedList <$> many1 (listItem '#'))
<|> try
@@ -415,10 +427,10 @@ orderedList =
let start = fromMaybe 1 $ safeRead $ fromAttrib "start" tag
return $ B.orderedListWith (start, DefaultStyle, DefaultDelim) items)
-definitionList :: MWParser Blocks
+definitionList :: PandocMonad m => MWParser m Blocks
definitionList = B.definitionList <$> many1 defListItem
-defListItem :: MWParser (Inlines, [Blocks])
+defListItem :: PandocMonad m => MWParser m (Inlines, [Blocks])
defListItem = try $ do
terms <- mconcat . intersperse B.linebreak <$> many defListTerm
-- we allow dd with no dt, or dt with no dd
@@ -429,44 +441,49 @@ defListItem = try $ do
else many (listItem ':')
return (terms, defs)
-defListTerm :: MWParser Inlines
-defListTerm = char ';' >> skipMany spaceChar >> anyLine >>=
- parseFromString (trimInlines . mconcat <$> many inline)
+defListTerm :: PandocMonad m => MWParser m Inlines
+defListTerm = do
+ guardColumnOne
+ char ';'
+ skipMany spaceChar
+ pos' <- getPosition
+ anyLine >>= parseFromString (do setPosition pos'
+ trimInlines . mconcat <$> many inline)
-listStart :: Char -> MWParser ()
+listStart :: PandocMonad m => Char -> MWParser m ()
listStart c = char c *> notFollowedBy listStartChar
-listStartChar :: MWParser Char
+listStartChar :: PandocMonad m => MWParser m Char
listStartChar = oneOf "*#;:"
-anyListStart :: MWParser Char
-anyListStart = char '*'
- <|> char '#'
- <|> char ':'
- <|> char ';'
+anyListStart :: PandocMonad m => MWParser m Char
+anyListStart = guardColumnOne >> oneOf "*#:;"
-li :: MWParser Blocks
+li :: PandocMonad m => MWParser m Blocks
li = lookAhead (htmlTag (~== TagOpen "li" [])) *>
(firstParaToPlain <$> blocksInTags "li") <* spaces
-listItem :: Char -> MWParser Blocks
+listItem :: PandocMonad m => Char -> MWParser m Blocks
listItem c = try $ do
+ guardColumnOne
extras <- many (try $ char c <* lookAhead listStartChar)
if null extras
then listItem' c
else do
skipMany spaceChar
+ pos' <- getPosition
first <- concat <$> manyTill listChunk newline
rest <- many
(try $ string extras *> lookAhead listStartChar *>
(concat <$> manyTill listChunk newline))
- contents <- parseFromString (many1 $ listItem' c)
+ contents <- parseFromString (do setPosition pos'
+ many1 $ listItem' c)
(unlines (first : rest))
case c of
- '*' -> return $ B.bulletList contents
- '#' -> return $ B.orderedList contents
- ':' -> return $ B.definitionList [(mempty, contents)]
- _ -> mzero
+ '*' -> return $ B.bulletList contents
+ '#' -> return $ B.orderedList contents
+ ':' -> return $ B.definitionList [(mempty, contents)]
+ _ -> mzero
-- The point of this is to handle stuff like
-- * {{cite book
@@ -475,30 +492,32 @@ listItem c = try $ do
-- }}
-- * next list item
-- which seems to be valid mediawiki.
-listChunk :: MWParser String
+listChunk :: PandocMonad m => MWParser m String
listChunk = template <|> count 1 anyChar
-listItem' :: Char -> MWParser Blocks
+listItem' :: PandocMonad m => Char -> MWParser m Blocks
listItem' c = try $ do
listStart c
skipMany spaceChar
+ pos' <- getPosition
first <- concat <$> manyTill listChunk newline
rest <- many (try $ char c *> lookAhead listStartChar *>
(concat <$> manyTill listChunk newline))
- parseFromString (firstParaToPlain . mconcat <$> many1 block)
+ parseFromString (do setPosition pos'
+ firstParaToPlain . mconcat <$> many1 block)
$ unlines $ first : rest
firstParaToPlain :: Blocks -> Blocks
firstParaToPlain contents =
case viewl (B.unMany contents) of
- (Para xs) :< ys -> B.Many $ (Plain xs) <| ys
- _ -> contents
+ Para xs :< ys -> B.Many $ Plain xs <| ys
+ _ -> contents
--
-- inline parsers
--
-inline :: MWParser Inlines
+inline :: PandocMonad m => MWParser m Inlines
inline = whitespace
<|> url
<|> str
@@ -516,10 +535,10 @@ inline = whitespace
<|> (B.rawInline "mediawiki" <$> template)
<|> special
-str :: MWParser Inlines
+str :: PandocMonad m => MWParser m Inlines
str = B.str <$> many1 (noneOf $ specialChars ++ spaceChars)
-math :: MWParser Inlines
+math :: PandocMonad m => MWParser m Inlines
math = (B.displayMath . trim <$> try (many1 (char ':') >> charsInTags "math"))
<|> (B.math . trim <$> charsInTags "math")
<|> (B.displayMath . trim <$> try (dmStart *> manyTill anyChar dmEnd))
@@ -529,13 +548,13 @@ math = (B.displayMath . trim <$> try (many1 (char ':') >> charsInTags "math"))
mStart = string "\\("
mEnd = try (string "\\)")
-variable :: MWParser String
+variable :: PandocMonad m => MWParser m String
variable = try $ do
string "{{{"
contents <- manyTill anyChar (try $ string "}}}")
return $ "{{{" ++ contents ++ "}}}"
-inlineTag :: MWParser Inlines
+inlineTag :: PandocMonad m => MWParser m Inlines
inlineTag = do
(tag, _) <- lookAhead $ htmlTag isInlineTag'
case tag of
@@ -553,22 +572,27 @@ inlineTag = do
TagOpen "sub" _ -> B.subscript <$> inlinesInTags "sub"
TagOpen "sup" _ -> B.superscript <$> inlinesInTags "sup"
TagOpen "code" _ -> encode <$> inlinesInTags "code"
- TagOpen "tt" _ -> encode <$> inlinesInTags "tt"
+ TagOpen "tt" _ -> do
+ inTT <- mwInTT <$> getState
+ updateState $ \st -> st{ mwInTT = True }
+ result <- encode <$> inlinesInTags "tt"
+ updateState $ \st -> st{ mwInTT = inTT }
+ return result
TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> charsInTags "hask"
_ -> B.rawInline "html" . snd <$> htmlTag (~== tag)
-special :: MWParser Inlines
+special :: PandocMonad m => MWParser m Inlines
special = B.str <$> count 1 (notFollowedBy' (htmlTag isBlockTag') *>
oneOf specialChars)
-inlineHtml :: MWParser Inlines
+inlineHtml :: PandocMonad m => MWParser m Inlines
inlineHtml = B.rawInline "html" . snd <$> htmlTag isInlineTag'
-whitespace :: MWParser Inlines
+whitespace :: PandocMonad m => MWParser m Inlines
whitespace = B.space <$ (skipMany1 spaceChar <|> htmlComment)
<|> B.softbreak <$ endline
-endline :: MWParser ()
+endline :: PandocMonad m => MWParser m ()
endline = () <$ try (newline <*
notFollowedBy spaceChar <*
notFollowedBy newline <*
@@ -577,30 +601,30 @@ endline = () <$ try (newline <*
notFollowedBy' header <*
notFollowedBy anyListStart)
-imageIdentifiers :: [MWParser ()]
+imageIdentifiers :: PandocMonad m => [MWParser m ()]
imageIdentifiers = [sym (identifier ++ ":") | identifier <- identifiers]
where identifiers = ["File", "Image", "Archivo", "Datei", "Fichier",
"Bild"]
-image :: MWParser Inlines
+image :: PandocMonad m => MWParser m Inlines
image = try $ do
sym "[["
choice imageIdentifiers
fname <- addUnderscores <$> many1 (noneOf "|]")
_ <- many imageOption
- dims <- try (char '|' *> (sepBy (many digit) (char 'x')) <* string "px")
+ dims <- try (char '|' *> sepBy (many digit) (char 'x') <* string "px")
<|> return []
_ <- many imageOption
let kvs = case dims of
- w:[] -> [("width", w)]
- w:(h:[]) -> [("width", w), ("height", h)]
- _ -> []
+ [w] -> [("width", w)]
+ [w, h] -> [("width", w), ("height", h)]
+ _ -> []
let attr = ("", [], kvs)
caption <- (B.str fname <$ sym "]]")
<|> try (char '|' *> (mconcat <$> manyTill inline (sym "]]")))
return $ B.imageWith attr fname ("fig:" ++ stringify caption) caption
-imageOption :: MWParser String
+imageOption :: PandocMonad m => MWParser m String
imageOption = try $ char '|' *> opt
where
opt = try (oneOfStrings [ "border", "thumbnail", "frameless"
@@ -612,14 +636,14 @@ imageOption = try $ char '|' *> opt
<|> try (oneOfStrings ["link=","alt=","page=","class="] <* many (noneOf "|]"))
collapseUnderscores :: String -> String
-collapseUnderscores [] = []
+collapseUnderscores [] = []
collapseUnderscores ('_':'_':xs) = collapseUnderscores ('_':xs)
-collapseUnderscores (x:xs) = x : collapseUnderscores xs
+collapseUnderscores (x:xs) = x : collapseUnderscores xs
addUnderscores :: String -> String
addUnderscores = collapseUnderscores . intercalate "_" . words
-internalLink :: MWParser Inlines
+internalLink :: PandocMonad m => MWParser m Inlines
internalLink = try $ do
sym "[["
pagename <- unwords . words <$> many (noneOf "|]")
@@ -627,7 +651,7 @@ internalLink = try $ do
( (mconcat <$> many1 (notFollowedBy (char ']') *> inline))
-- the "pipe trick"
-- [[Help:Contents|] -> "Contents"
- <|> (return $ B.text $ drop 1 $ dropWhile (/=':') pagename) )
+ <|> return (B.text $ drop 1 $ dropWhile (/=':') pagename) )
sym "]]"
linktrail <- B.text <$> many letter
let link = B.link (addUnderscores pagename) "wikilink" (label <> linktrail)
@@ -637,7 +661,7 @@ internalLink = try $ do
return mempty
else return link
-externalLink :: MWParser Inlines
+externalLink :: PandocMonad m => MWParser m Inlines
externalLink = try $ do
char '['
(_, src) <- uri
@@ -649,29 +673,33 @@ externalLink = try $ do
return $ B.str $ show num
return $ B.link src "" lab
-url :: MWParser Inlines
+url :: PandocMonad m => MWParser m Inlines
url = do
(orig, src) <- uri
return $ B.link src "" (B.str orig)
-- | Parses a list of inlines between start and end delimiters.
-inlinesBetween :: (Show b) => MWParser a -> MWParser b -> MWParser Inlines
+inlinesBetween :: (PandocMonad m, Show b) => MWParser m a -> MWParser m b -> MWParser m Inlines
inlinesBetween start end =
(trimInlines . mconcat) <$> try (start >> many1Till inner end)
where inner = innerSpace <|> (notFollowedBy' (() <$ whitespace) >> inline)
innerSpace = try $ whitespace <* notFollowedBy' end
-emph :: MWParser Inlines
+emph :: PandocMonad m => MWParser m Inlines
emph = B.emph <$> nested (inlinesBetween start end)
where start = sym "''" >> lookAhead nonspaceChar
end = try $ notFollowedBy' (() <$ strong) >> sym "''"
-strong :: MWParser Inlines
+strong :: PandocMonad m => MWParser m Inlines
strong = B.strong <$> nested (inlinesBetween start end)
where start = sym "'''" >> lookAhead nonspaceChar
end = try $ sym "'''"
-doubleQuotes :: MWParser Inlines
-doubleQuotes = B.doubleQuoted <$> nested (inlinesBetween openDoubleQuote closeDoubleQuote)
+doubleQuotes :: PandocMonad m => MWParser m Inlines
+doubleQuotes = do
+ guardEnabled Ext_smart
+ inTT <- mwInTT <$> getState
+ guard (not inTT)
+ B.doubleQuoted <$> nested (inlinesBetween openDoubleQuote closeDoubleQuote)
where openDoubleQuote = sym "\"" >> lookAhead nonspaceChar
closeDoubleQuote = try $ sym "\""
diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs
new file mode 100644
index 000000000..4a9523e84
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Muse.hs
@@ -0,0 +1,924 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-
+ Copyright (C) 2017-2018 Alexander Krotov <ilabdsf@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Muse
+ Copyright : Copyright (C) 2017-2018 Alexander Krotov
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Alexander Krotov <ilabdsf@gmail.com>
+ Stability : alpha
+ Portability : portable
+
+Conversion of Muse text to 'Pandoc' document.
+-}
+{-
+TODO:
+- Page breaks (five "*")
+- Org tables
+- table.el tables
+- Images with attributes (floating and width)
+- Citations and <biblio>
+- <play> environment
+-}
+module Text.Pandoc.Readers.Muse (readMuse) where
+
+import Control.Monad
+import Control.Monad.Except (throwError)
+import Data.Char (isLetter)
+import Data.Default
+import Data.List (stripPrefix, intercalate)
+import Data.List.Split (splitOn)
+import qualified Data.Map as M
+import qualified Data.Set as Set
+import Data.Maybe (fromMaybe, isNothing)
+import Data.Text (Text, unpack)
+import System.FilePath (takeExtension)
+import Text.HTML.TagSoup
+import Text.Pandoc.Builder (Blocks, Inlines)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad (..))
+import Text.Pandoc.Definition
+import Text.Pandoc.Logging
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (F)
+import Text.Pandoc.Readers.HTML (htmlTag)
+import Text.Pandoc.Shared (crFilter, underlineSpan)
+
+-- | Read Muse from an input string and return a Pandoc document.
+readMuse :: PandocMonad m
+ => ReaderOptions
+ -> Text
+ -> m Pandoc
+readMuse opts s = do
+ res <- readWithM parseMuse def{ museOptions = opts } (unpack (crFilter s))
+ case res of
+ Left e -> throwError e
+ Right d -> return d
+
+type F = Future MuseState
+
+data MuseState = MuseState { museMeta :: F Meta -- ^ Document metadata
+ , museOptions :: ReaderOptions
+ , museHeaders :: M.Map Inlines String -- ^ List of headers and ids (used for implicit ref links)
+ , museIdentifierList :: Set.Set String
+ , museLastStrPos :: Maybe SourcePos -- ^ Position after last str parsed
+ , museLogMessages :: [LogMessage]
+ , museNotes :: M.Map String (SourcePos, F Blocks)
+ , museInLink :: Bool
+ , museInPara :: Bool
+ }
+
+instance Default MuseState where
+ def = defaultMuseState
+
+defaultMuseState :: MuseState
+defaultMuseState = MuseState { museMeta = return nullMeta
+ , museOptions = def
+ , museHeaders = M.empty
+ , museIdentifierList = Set.empty
+ , museLastStrPos = Nothing
+ , museLogMessages = []
+ , museNotes = M.empty
+ , museInLink = False
+ , museInPara = False
+ }
+
+type MuseParser = ParserT String MuseState
+
+instance HasReaderOptions MuseState where
+ extractReaderOptions = museOptions
+
+instance HasHeaderMap MuseState where
+ extractHeaderMap = museHeaders
+ updateHeaderMap f st = st{ museHeaders = f $ museHeaders st }
+
+instance HasIdentifierList MuseState where
+ extractIdentifierList = museIdentifierList
+ updateIdentifierList f st = st{ museIdentifierList = f $ museIdentifierList st }
+
+instance HasLastStrPosition MuseState where
+ setLastStrPos pos st = st{ museLastStrPos = Just pos }
+ getLastStrPos st = museLastStrPos st
+
+instance HasLogMessages MuseState where
+ addLogMessage m s = s{ museLogMessages = m : museLogMessages s }
+ getLogMessages = reverse . museLogMessages
+
+--
+-- main parser
+--
+
+parseMuse :: PandocMonad m => MuseParser m Pandoc
+parseMuse = do
+ many directive
+ blocks <- parseBlocks
+ st <- getState
+ let doc = runF (do Pandoc _ bs <- B.doc <$> blocks
+ meta <- museMeta st
+ return $ Pandoc meta bs) st
+ reportLogMessages
+ return doc
+
+--
+-- utility functions
+--
+
+eol :: Stream s m Char => ParserT s st m ()
+eol = void newline <|> eof
+
+htmlElement :: PandocMonad m => String -> MuseParser m (Attr, String)
+htmlElement tag = try $ do
+ (TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
+ content <- manyTill anyChar endtag
+ return (htmlAttrToPandoc attr, content)
+ where
+ endtag = void $ htmlTag (~== TagClose tag)
+
+htmlBlock :: PandocMonad m => String -> MuseParser m (Attr, String)
+htmlBlock tag = try $ do
+ many spaceChar
+ res <- htmlElement tag
+ manyTill spaceChar eol
+ return res
+
+htmlAttrToPandoc :: [Attribute String] -> Attr
+htmlAttrToPandoc attrs = (ident, classes, keyvals)
+ where
+ ident = fromMaybe "" $ lookup "id" attrs
+ classes = maybe [] words $ lookup "class" attrs
+ keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
+
+parseHtmlContent :: PandocMonad m
+ => String -> MuseParser m (Attr, F Blocks)
+parseHtmlContent tag = try $ do
+ many spaceChar
+ (TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
+ manyTill spaceChar eol
+ content <- parseBlocksTill (try $ manyTill spaceChar endtag)
+ manyTill spaceChar eol -- closing tag must be followed by optional whitespace and newline
+ return (htmlAttrToPandoc attr, content)
+ where
+ endtag = void $ htmlTag (~== TagClose tag)
+
+commonPrefix :: String -> String -> String
+commonPrefix _ [] = []
+commonPrefix [] _ = []
+commonPrefix (x:xs) (y:ys)
+ | x == y = x : commonPrefix xs ys
+ | otherwise = []
+
+atStart :: PandocMonad m => MuseParser m a -> MuseParser m a
+atStart p = do
+ pos <- getPosition
+ st <- getState
+ guard $ museLastStrPos st /= Just pos
+ p
+
+someUntil :: (Stream s m t)
+ => ParserT s u m a
+ -> ParserT s u m b
+ -> ParserT s u m ([a], b)
+someUntil p end = do
+ first <- p
+ (rest, e) <- manyUntil p end
+ return (first:rest, e)
+
+--
+-- directive parsers
+--
+
+-- While not documented, Emacs Muse allows "-" in directive name
+parseDirectiveKey :: PandocMonad m => MuseParser m String
+parseDirectiveKey = do
+ char '#'
+ many (letter <|> char '-')
+
+parseEmacsDirective :: PandocMonad m => MuseParser m (String, F Inlines)
+parseEmacsDirective = do
+ key <- parseDirectiveKey
+ spaceChar
+ value <- trimInlinesF . mconcat <$> manyTill (choice inlineList) eol
+ return (key, value)
+
+parseAmuseDirective :: PandocMonad m => MuseParser m (String, F Inlines)
+parseAmuseDirective = do
+ key <- parseDirectiveKey
+ many1 spaceChar
+ value <- trimInlinesF . mconcat <$> many1Till inline endOfDirective
+ many blankline
+ return (key, value)
+ where
+ endOfDirective = lookAhead $ eof <|> try (newline >> (void blankline <|> void parseDirectiveKey))
+
+directive :: PandocMonad m => MuseParser m ()
+directive = do
+ ext <- getOption readerExtensions
+ (key, value) <- if extensionEnabled Ext_amuse ext then parseAmuseDirective else parseEmacsDirective
+ updateState $ \st -> st { museMeta = B.setMeta (translateKey key) <$> value <*> museMeta st }
+ where translateKey "cover" = "cover-image"
+ translateKey x = x
+
+--
+-- block parsers
+--
+
+parseBlocks :: PandocMonad m
+ => MuseParser m (F Blocks)
+parseBlocks =
+ try parseEnd <|>
+ try blockStart <|>
+ try listStart <|>
+ try paraStart
+ where
+ parseEnd = mempty <$ eof
+ blockStart = do first <- header <|> blockElements <|> emacsNoteBlock
+ rest <- parseBlocks
+ return $ first B.<> rest
+ listStart = do
+ updateState (\st -> st { museInPara = False })
+ (first, rest) <- anyListUntil parseBlocks <|> amuseNoteBlockUntil parseBlocks
+ return $ first B.<> rest
+ paraStart = do
+ indent <- length <$> many spaceChar
+ (first, rest) <- paraUntil parseBlocks
+ let first' = if indent >= 2 && indent < 6 then B.blockQuote <$> first else first
+ return $ first' B.<> rest
+
+parseBlocksTill :: PandocMonad m
+ => MuseParser m a
+ -> MuseParser m (F Blocks)
+parseBlocksTill end =
+ try parseEnd <|>
+ try blockStart <|>
+ try listStart <|>
+ try paraStart
+ where
+ parseEnd = mempty <$ end
+ blockStart = do first <- blockElements
+ rest <- continuation
+ return $ first B.<> rest
+ listStart = do
+ updateState (\st -> st { museInPara = False })
+ (first, e) <- anyListUntil ((Left <$> end) <|> (Right <$> continuation))
+ case e of
+ Left _ -> return first
+ Right rest -> return $ first B.<> rest
+ paraStart = do (first, e) <- paraUntil ((Left <$> end) <|> (Right <$> continuation))
+ case e of
+ Left _ -> return first
+ Right rest -> return $ first B.<> rest
+ continuation = parseBlocksTill end
+
+listItemContentsUntil :: PandocMonad m
+ => Int
+ -> MuseParser m a
+ -> MuseParser m a
+ -> MuseParser m (F Blocks, a)
+listItemContentsUntil col pre end =
+ try blockStart <|>
+ try listStart <|>
+ try paraStart
+ where
+ parsePre = do e <- pre
+ return (mempty, e)
+ parseEnd = do e <- end
+ return (mempty, e)
+ paraStart = do
+ (first, e) <- paraUntil ((Left <$> pre) <|> (Right <$> continuation) <|> (Left <$> end))
+ case e of
+ Left ee -> return (first, ee)
+ Right (rest, ee) -> return (first B.<> rest, ee)
+ blockStart = do first <- blockElements
+ (rest, e) <- parsePre <|> continuation <|> parseEnd
+ return (first B.<> rest, e)
+ listStart = do
+ updateState (\st -> st { museInPara = False })
+ (first, e) <- anyListUntil ((Left <$> pre) <|> (Right <$> continuation) <|> (Left <$> end))
+ case e of
+ Left ee -> return (first, ee)
+ Right (rest, ee) -> return (first B.<> rest, ee)
+ continuation = try $ do blank <- optionMaybe blankline
+ skipMany blankline
+ indentWith col
+ updateState (\st -> st { museInPara = museInPara st && isNothing blank })
+ listItemContentsUntil col pre end
+
+parseBlock :: PandocMonad m => MuseParser m (F Blocks)
+parseBlock = do
+ res <- blockElements <|> para
+ trace (take 60 $ show $ B.toList $ runF res def)
+ return res
+ where para = fst <$> paraUntil (try (eof <|> void (lookAhead blockElements)))
+
+blockElements :: PandocMonad m => MuseParser m (F Blocks)
+blockElements = do
+ updateState (\st -> st { museInPara = False })
+ choice [ mempty <$ blankline
+ , comment
+ , separator
+ , example
+ , exampleTag
+ , literalTag
+ , centerTag
+ , rightTag
+ , quoteTag
+ , divTag
+ , verseTag
+ , lineBlock
+ , table
+ , commentTag
+ ]
+
+comment :: PandocMonad m => MuseParser m (F Blocks)
+comment = try $ do
+ char ';'
+ optional (spaceChar >> many (noneOf "\n"))
+ eol
+ return mempty
+
+separator :: PandocMonad m => MuseParser m (F Blocks)
+separator = try $ do
+ string "----"
+ many $ char '-'
+ many spaceChar
+ eol
+ return $ return B.horizontalRule
+
+header :: PandocMonad m => MuseParser m (F Blocks)
+header = try $ do
+ getPosition >>= \pos -> guard (sourceColumn pos == 1)
+ level <- fmap length $ many1 $ char '*'
+ guard $ level <= 5
+ spaceChar
+ content <- trimInlinesF . mconcat <$> manyTill inline eol
+ anchorId <- option "" parseAnchor
+ attr <- registerHeader (anchorId, [], []) (runF content def)
+ return $ B.headerWith attr level <$> content
+
+example :: PandocMonad m => MuseParser m (F Blocks)
+example = try $ do
+ string "{{{"
+ optional blankline
+ contents <- manyTill anyChar $ try (optional blankline >> string "}}}")
+ return $ return $ B.codeBlock contents
+
+-- Trim up to one newline from the beginning of the string.
+lchop :: String -> String
+lchop s = case s of
+ '\n':ss -> ss
+ _ -> s
+
+-- Trim up to one newline from the end of the string.
+rchop :: String -> String
+rchop = reverse . lchop . reverse
+
+dropSpacePrefix :: [String] -> [String]
+dropSpacePrefix lns =
+ map (drop maxIndent) lns
+ where flns = filter (not . all (== ' ')) lns
+ maxIndent = if null flns then maximum (map length lns) else length $ takeWhile (== ' ') $ foldl1 commonPrefix flns
+
+exampleTag :: PandocMonad m => MuseParser m (F Blocks)
+exampleTag = try $ do
+ (attr, contents) <- htmlBlock "example"
+ return $ return $ B.codeBlockWith attr $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop contents
+
+literalTag :: PandocMonad m => MuseParser m (F Blocks)
+literalTag =
+ (return . rawBlock) <$> htmlBlock "literal"
+ where
+ -- FIXME: Emacs Muse inserts <literal> without style into all output formats, but we assume HTML
+ format (_, _, kvs) = fromMaybe "html" $ lookup "style" kvs
+ rawBlock (attrs, content) = B.rawBlock (format attrs) $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content
+
+-- <center> tag is ignored
+centerTag :: PandocMonad m => MuseParser m (F Blocks)
+centerTag = snd <$> parseHtmlContent "center"
+
+-- <right> tag is ignored
+rightTag :: PandocMonad m => MuseParser m (F Blocks)
+rightTag = snd <$> parseHtmlContent "right"
+
+quoteTag :: PandocMonad m => MuseParser m (F Blocks)
+quoteTag = fmap B.blockQuote . snd <$> parseHtmlContent "quote"
+
+-- <div> tag is supported by Emacs Muse, but not Amusewiki 2.025
+divTag :: PandocMonad m => MuseParser m (F Blocks)
+divTag = do
+ (attrs, content) <- parseHtmlContent "div"
+ return $ B.divWith attrs <$> content
+
+verseLine :: PandocMonad m => MuseParser m (F Inlines)
+verseLine = do
+ indent <- (B.str <$> many1 (char ' ' >> pure '\160')) <|> pure mempty
+ rest <- manyTill (choice inlineList) newline
+ return $ trimInlinesF $ mconcat (pure indent : rest)
+
+verseLines :: PandocMonad m => MuseParser m (F Blocks)
+verseLines = do
+ lns <- many verseLine
+ return $ B.lineBlock <$> sequence lns
+
+verseTag :: PandocMonad m => MuseParser m (F Blocks)
+verseTag = do
+ (_, content) <- htmlBlock "verse"
+ parseFromString verseLines (intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content)
+
+commentTag :: PandocMonad m => MuseParser m (F Blocks)
+commentTag = htmlBlock "comment" >> return mempty
+
+-- Indented paragraph is either center, right or quote
+paraUntil :: PandocMonad m
+ => MuseParser m a
+ -> MuseParser m (F Blocks, a)
+paraUntil end = do
+ state <- getState
+ guard $ not $ museInPara state
+ setState $ state{ museInPara = True }
+ (l, e) <- someUntil inline $ try (manyTill spaceChar eol >> end)
+ updateState (\st -> st { museInPara = False })
+ return (fmap B.para $ trimInlinesF $ mconcat l, e)
+
+noteMarker :: PandocMonad m => MuseParser m String
+noteMarker = try $ do
+ char '['
+ first <- oneOf "123456789"
+ rest <- manyTill digit (char ']')
+ return $ first:rest
+
+-- Amusewiki version of note
+-- Parsing is similar to list item, except that note marker is used instead of list marker
+amuseNoteBlockUntil :: PandocMonad m
+ => MuseParser m a
+ -> MuseParser m (F Blocks, a)
+amuseNoteBlockUntil end = try $ do
+ guardEnabled Ext_amuse
+ ref <- noteMarker <* spaceChar
+ pos <- getPosition
+ updateState (\st -> st { museInPara = False })
+ (content, e) <- listItemContentsUntil (sourceColumn pos - 1) (fail "x") end
+ oldnotes <- museNotes <$> getState
+ case M.lookup ref oldnotes of
+ Just _ -> logMessage $ DuplicateNoteReference ref pos
+ Nothing -> return ()
+ updateState $ \s -> s{ museNotes = M.insert ref (pos, content) oldnotes }
+ return (mempty, e)
+
+-- Emacs version of note
+-- Notes are allowed only at the end of text, no indentation is required.
+emacsNoteBlock :: PandocMonad m => MuseParser m (F Blocks)
+emacsNoteBlock = try $ do
+ guardDisabled Ext_amuse
+ pos <- getPosition
+ ref <- noteMarker <* skipSpaces
+ content <- mconcat <$> blocksTillNote
+ oldnotes <- museNotes <$> getState
+ case M.lookup ref oldnotes of
+ Just _ -> logMessage $ DuplicateNoteReference ref pos
+ Nothing -> return ()
+ updateState $ \s -> s{ museNotes = M.insert ref (pos, content) oldnotes }
+ return mempty
+ where
+ blocksTillNote =
+ many1Till parseBlock (eof <|> () <$ lookAhead noteMarker)
+
+--
+-- Verse markup
+--
+
+lineVerseLine :: PandocMonad m => MuseParser m (F Inlines)
+lineVerseLine = try $ do
+ string "> "
+ indent <- B.str <$> many (char ' ' >> pure '\160')
+ rest <- manyTill (choice inlineList) eol
+ return $ trimInlinesF $ mconcat (pure indent : rest)
+
+blanklineVerseLine :: PandocMonad m => MuseParser m (F Inlines)
+blanklineVerseLine = try $ do
+ char '>'
+ blankline
+ pure mempty
+
+lineBlock :: PandocMonad m => MuseParser m (F Blocks)
+lineBlock = try $ do
+ col <- sourceColumn <$> getPosition
+ lns <- (blanklineVerseLine <|> lineVerseLine) `sepBy1'` try (indentWith (col - 1))
+ return $ B.lineBlock <$> sequence lns
+
+--
+-- lists
+--
+
+bulletListItemsUntil :: PandocMonad m
+ => Int
+ -> MuseParser m a
+ -> MuseParser m ([F Blocks], a)
+bulletListItemsUntil indent end = try $ do
+ char '-'
+ void spaceChar <|> lookAhead eol
+ updateState (\st -> st { museInPara = False })
+ (x, e) <- listItemContentsUntil (indent + 2) (Right <$> try (optional blankline >> indentWith indent >> bulletListItemsUntil indent end)) (Left <$> end)
+ case e of
+ Left ee -> return ([x], ee)
+ Right (xs, ee) -> return (x:xs, ee)
+
+bulletListUntil :: PandocMonad m
+ => MuseParser m a
+ -> MuseParser m (F Blocks, a)
+bulletListUntil end = try $ do
+ many spaceChar
+ pos <- getPosition
+ let indent = sourceColumn pos - 1
+ guard $ indent /= 0
+ (items, e) <- bulletListItemsUntil indent end
+ return (B.bulletList <$> sequence items, e)
+
+-- | Parses an ordered list marker and returns list attributes.
+anyMuseOrderedListMarker :: PandocMonad m => MuseParser m ListAttributes
+anyMuseOrderedListMarker = do
+ (style, start) <- decimal <|> lowerRoman <|> upperRoman <|> lowerAlpha <|> upperAlpha
+ char '.'
+ return (start, style, Period)
+
+museOrderedListMarker :: PandocMonad m
+ => ListNumberStyle
+ -> MuseParser m Int
+museOrderedListMarker style = do
+ (_, start) <- case style of
+ Decimal -> decimal
+ UpperRoman -> upperRoman
+ LowerRoman -> lowerRoman
+ UpperAlpha -> upperAlpha
+ LowerAlpha -> lowerAlpha
+ _ -> fail "Unhandled case"
+ char '.'
+ return start
+
+orderedListItemsUntil :: PandocMonad m
+ => Int
+ -> ListNumberStyle
+ -> MuseParser m a
+ -> MuseParser m ([F Blocks], a)
+orderedListItemsUntil indent style end =
+ continuation
+ where
+ continuation = try $ do
+ pos <- getPosition
+ void spaceChar <|> lookAhead eol
+ updateState (\st -> st { museInPara = False })
+ (x, e) <- listItemContentsUntil (sourceColumn pos) (Right <$> try (optionMaybe blankline >> indentWith indent >> museOrderedListMarker style >> continuation)) (Left <$> end)
+ case e of
+ Left ee -> return ([x], ee)
+ Right (xs, ee) -> return (x:xs, ee)
+
+orderedListUntil :: PandocMonad m
+ => MuseParser m a
+ -> MuseParser m (F Blocks, a)
+orderedListUntil end = try $ do
+ many spaceChar
+ pos <- getPosition
+ let indent = sourceColumn pos - 1
+ guard $ indent /= 0
+ p@(_, style, _) <- anyMuseOrderedListMarker
+ guard $ style `elem` [Decimal, LowerAlpha, UpperAlpha, LowerRoman, UpperRoman]
+ (items, e) <- orderedListItemsUntil indent style end
+ return (B.orderedListWith p <$> sequence items, e)
+
+descriptionsUntil :: PandocMonad m
+ => Int
+ -> MuseParser m a
+ -> MuseParser m ([F Blocks], a)
+descriptionsUntil indent end = do
+ void spaceChar <|> lookAhead eol
+ updateState (\st -> st { museInPara = False })
+ (x, e) <- listItemContentsUntil indent (Right <$> try (optional blankline >> indentWith indent >> manyTill spaceChar (string "::") >> descriptionsUntil indent end)) (Left <$> end)
+ case e of
+ Right (xs, ee) -> return (x:xs, ee)
+ Left ee -> return ([x], ee)
+
+definitionListItemsUntil :: PandocMonad m
+ => Int
+ -> MuseParser m a
+ -> MuseParser m ([F (Inlines, [Blocks])], a)
+definitionListItemsUntil indent end =
+ continuation
+ where
+ continuation = try $ do
+ pos <- getPosition
+ term <- trimInlinesF . mconcat <$> manyTill (choice inlineList) (try $ string "::")
+ (x, e) <- descriptionsUntil (sourceColumn pos) ((Right <$> try (optional blankline >> indentWith indent >> continuation)) <|> (Left <$> end))
+ let xx = do
+ term' <- term
+ x' <- sequence x
+ return (term', x')
+ case e of
+ Left ee -> return ([xx], ee)
+ Right (xs, ee) -> return (xx:xs, ee)
+
+definitionListUntil :: PandocMonad m
+ => MuseParser m a
+ -> MuseParser m (F Blocks, a)
+definitionListUntil end = try $ do
+ many spaceChar
+ pos <- getPosition
+ let indent = sourceColumn pos - 1
+ guardDisabled Ext_amuse <|> guard (indent /= 0) -- Initial space is required by Amusewiki, but not Emacs Muse
+ (items, e) <- definitionListItemsUntil indent end
+ return (B.definitionList <$> sequence items, e)
+
+anyListUntil :: PandocMonad m
+ => MuseParser m a
+ -> MuseParser m (F Blocks, a)
+anyListUntil end =
+ bulletListUntil end <|> orderedListUntil end <|> definitionListUntil end
+
+--
+-- tables
+--
+
+data MuseTable = MuseTable
+ { museTableCaption :: Inlines
+ , museTableHeaders :: [[Blocks]]
+ , museTableRows :: [[Blocks]]
+ , museTableFooters :: [[Blocks]]
+ }
+
+data MuseTableElement = MuseHeaderRow (F [Blocks])
+ | MuseBodyRow (F [Blocks])
+ | MuseFooterRow (F [Blocks])
+ | MuseCaption (F Inlines)
+
+museToPandocTable :: MuseTable -> Blocks
+museToPandocTable (MuseTable caption headers body footers) =
+ B.table caption attrs headRow rows
+ where ncol = maximum (0 : map length (headers ++ body ++ footers))
+ attrs = replicate ncol (AlignDefault, 0.0)
+ headRow = if null headers then [] else head headers
+ rows = (if null headers then [] else tail headers) ++ body ++ footers
+
+museAppendElement :: MuseTable
+ -> MuseTableElement
+ -> F MuseTable
+museAppendElement tbl element =
+ case element of
+ MuseHeaderRow row -> do
+ row' <- row
+ return tbl{ museTableHeaders = museTableHeaders tbl ++ [row'] }
+ MuseBodyRow row -> do
+ row' <- row
+ return tbl{ museTableRows = museTableRows tbl ++ [row'] }
+ MuseFooterRow row-> do
+ row' <- row
+ return tbl{ museTableFooters = museTableFooters tbl ++ [row'] }
+ MuseCaption inlines -> do
+ inlines' <- inlines
+ return tbl{ museTableCaption = inlines' }
+
+tableCell :: PandocMonad m => MuseParser m (F Blocks)
+tableCell = try $ fmap B.plain . trimInlinesF . mconcat <$> manyTill inline (lookAhead cellEnd)
+ where cellEnd = try $ void (many1 spaceChar >> char '|') <|> eol
+
+tableElements :: PandocMonad m => MuseParser m [MuseTableElement]
+tableElements = tableParseElement `sepEndBy1` eol
+
+elementsToTable :: [MuseTableElement] -> F MuseTable
+elementsToTable = foldM museAppendElement emptyTable
+ where emptyTable = MuseTable mempty mempty mempty mempty
+
+table :: PandocMonad m => MuseParser m (F Blocks)
+table = try $ do
+ rows <- tableElements
+ let tbl = elementsToTable rows
+ let pandocTbl = museToPandocTable <$> tbl :: F Blocks
+ return pandocTbl
+
+tableParseElement :: PandocMonad m => MuseParser m MuseTableElement
+tableParseElement = tableParseHeader
+ <|> tableParseBody
+ <|> tableParseFooter
+ <|> tableParseCaption
+
+tableParseRow :: PandocMonad m => Int -> MuseParser m (F [Blocks])
+tableParseRow n = try $ do
+ fields <- tableCell `sepBy2` fieldSep
+ return $ sequence fields
+ where p `sepBy2` sep = (:) <$> p <*> many1 (sep >> p)
+ fieldSep = many1 spaceChar >> count n (char '|') >> (void (many1 spaceChar) <|> void (lookAhead newline))
+
+tableParseHeader :: PandocMonad m => MuseParser m MuseTableElement
+tableParseHeader = MuseHeaderRow <$> tableParseRow 2
+
+tableParseBody :: PandocMonad m => MuseParser m MuseTableElement
+tableParseBody = MuseBodyRow <$> tableParseRow 1
+
+tableParseFooter :: PandocMonad m => MuseParser m MuseTableElement
+tableParseFooter = MuseFooterRow <$> tableParseRow 3
+
+tableParseCaption :: PandocMonad m => MuseParser m MuseTableElement
+tableParseCaption = try $ do
+ many spaceChar
+ string "|+"
+ MuseCaption <$> (trimInlinesF . mconcat <$> many1Till inline (string "+|"))
+
+--
+-- inline parsers
+--
+
+inlineList :: PandocMonad m => [MuseParser m (F Inlines)]
+inlineList = [ whitespace
+ , br
+ , anchor
+ , footnote
+ , strong
+ , strongTag
+ , emph
+ , emphTag
+ , underlined
+ , superscriptTag
+ , subscriptTag
+ , strikeoutTag
+ , verbatimTag
+ , nbsp
+ , link
+ , code
+ , codeTag
+ , inlineLiteralTag
+ , str
+ , symbol
+ ]
+
+inline :: PandocMonad m => MuseParser m (F Inlines)
+inline = endline <|> choice inlineList <?> "inline"
+
+endline :: PandocMonad m => MuseParser m (F Inlines)
+endline = try $ do
+ newline
+ notFollowedBy blankline
+ returnF B.softbreak
+
+parseAnchor :: PandocMonad m => MuseParser m String
+parseAnchor = try $ do
+ getPosition >>= \pos -> guard (sourceColumn pos == 1)
+ char '#'
+ first <- letter
+ rest <- many (letter <|> digit)
+ skipMany spaceChar <|> void newline
+ return $ first:rest
+
+anchor :: PandocMonad m => MuseParser m (F Inlines)
+anchor = try $ do
+ anchorId <- parseAnchor
+ return $ return $ B.spanWith (anchorId, [], []) mempty
+
+footnote :: PandocMonad m => MuseParser m (F Inlines)
+footnote = try $ do
+ ref <- noteMarker
+ return $ do
+ notes <- asksF museNotes
+ case M.lookup ref notes of
+ Nothing -> return $ B.str $ "[" ++ ref ++ "]"
+ Just (_pos, contents) -> do
+ st <- askF
+ let contents' = runF contents st { museNotes = M.empty }
+ return $ B.note contents'
+
+whitespace :: PandocMonad m => MuseParser m (F Inlines)
+whitespace = try $ do
+ skipMany1 spaceChar
+ return $ return B.space
+
+br :: PandocMonad m => MuseParser m (F Inlines)
+br = try $ do
+ string "<br>"
+ return $ return B.linebreak
+
+emphasisBetween :: (PandocMonad m, Show a) => MuseParser m a -> MuseParser m (F Inlines)
+emphasisBetween c = try $ enclosedInlines c c
+
+enclosedInlines :: (PandocMonad m, Show a, Show b)
+ => MuseParser m a
+ -> MuseParser m b
+ -> MuseParser m (F Inlines)
+enclosedInlines start end = try $
+ trimInlinesF . mconcat <$> (enclosed (atStart start) end inline <* notFollowedBy (satisfy isLetter))
+
+inlineTag :: PandocMonad m
+ => (Inlines -> Inlines)
+ -> String
+ -> MuseParser m (F Inlines)
+inlineTag f tag = try $ do
+ htmlTag (~== TagOpen tag [])
+ res <- manyTill inline (void $ htmlTag (~== TagClose tag))
+ return $ f <$> mconcat res
+
+strongTag :: PandocMonad m => MuseParser m (F Inlines)
+strongTag = inlineTag B.strong "strong"
+
+strong :: PandocMonad m => MuseParser m (F Inlines)
+strong = fmap B.strong <$> emphasisBetween (string "**")
+
+emph :: PandocMonad m => MuseParser m (F Inlines)
+emph = fmap B.emph <$> emphasisBetween (char '*')
+
+underlined :: PandocMonad m => MuseParser m (F Inlines)
+underlined = do
+ guardDisabled Ext_amuse -- Supported only by Emacs Muse
+ fmap underlineSpan <$> emphasisBetween (char '_')
+
+emphTag :: PandocMonad m => MuseParser m (F Inlines)
+emphTag = inlineTag B.emph "em"
+
+superscriptTag :: PandocMonad m => MuseParser m (F Inlines)
+superscriptTag = inlineTag B.superscript "sup"
+
+subscriptTag :: PandocMonad m => MuseParser m (F Inlines)
+subscriptTag = inlineTag B.subscript "sub"
+
+strikeoutTag :: PandocMonad m => MuseParser m (F Inlines)
+strikeoutTag = inlineTag B.strikeout "del"
+
+verbatimTag :: PandocMonad m => MuseParser m (F Inlines)
+verbatimTag = return . B.text . snd <$> htmlElement "verbatim"
+
+nbsp :: PandocMonad m => MuseParser m (F Inlines)
+nbsp = try $ do
+ string "~~"
+ return $ return $ B.str "\160"
+
+code :: PandocMonad m => MuseParser m (F Inlines)
+code = try $ do
+ atStart $ char '='
+ contents <- many1Till (noneOf "\n\r" <|> (newline <* notFollowedBy newline)) $ char '='
+ guard $ not $ null contents
+ guard $ head contents `notElem` " \t\n"
+ guard $ last contents `notElem` " \t\n"
+ notFollowedBy $ satisfy isLetter
+ return $ return $ B.code contents
+
+codeTag :: PandocMonad m => MuseParser m (F Inlines)
+codeTag = do
+ (attrs, content) <- htmlElement "code"
+ return $ return $ B.codeWith attrs content
+
+inlineLiteralTag :: PandocMonad m => MuseParser m (F Inlines)
+inlineLiteralTag =
+ (return . rawInline) <$> htmlElement "literal"
+ where
+ -- FIXME: Emacs Muse inserts <literal> without style into all output formats, but we assume HTML
+ format (_, _, kvs) = fromMaybe "html" $ lookup "style" kvs
+ rawInline (attrs, content) = B.rawInline (format attrs) content
+
+str :: PandocMonad m => MuseParser m (F Inlines)
+str = do
+ result <- many1 alphaNum
+ updateLastStrPos
+ return $ return $ B.str result
+
+symbol :: PandocMonad m => MuseParser m (F Inlines)
+symbol = return . B.str <$> count 1 nonspaceChar
+
+link :: PandocMonad m => MuseParser m (F Inlines)
+link = try $ do
+ st <- getState
+ guard $ not $ museInLink st
+ setState $ st{ museInLink = True }
+ (url, title, content) <- linkText
+ updateState (\state -> state { museInLink = False })
+ return $ case stripPrefix "URL:" url of
+ Nothing -> if isImageUrl url
+ then B.image url title <$> fromMaybe (return mempty) content
+ else B.link url title <$> fromMaybe (return $ B.str url) content
+ Just url' -> B.link url' title <$> fromMaybe (return $ B.str url') content
+ where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el
+ imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"]
+ isImageUrl = (`elem` imageExtensions) . takeExtension
+
+linkContent :: PandocMonad m => MuseParser m (F Inlines)
+linkContent = do
+ char '['
+ trimInlinesF . mconcat <$> many1Till inline (string "]")
+
+linkText :: PandocMonad m => MuseParser m (String, String, Maybe (F Inlines))
+linkText = do
+ string "[["
+ url <- many1Till anyChar $ char ']'
+ content <- optionMaybe linkContent
+ char ']'
+ return (url, "", content)
diff --git a/src/Text/Pandoc/Readers/Native.hs b/src/Text/Pandoc/Readers/Native.hs
index 4ec164e19..88f6bfe8f 100644
--- a/src/Text/Pandoc/Readers/Native.hs
+++ b/src/Text/Pandoc/Readers/Native.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2011-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Native
- Copyright : Copyright (C) 2011-2015 John MacFarlane
+ Copyright : Copyright (C) 2011-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,8 +31,12 @@ Conversion of a string representation of a pandoc type (@Pandoc@,
module Text.Pandoc.Readers.Native ( readNative ) where
import Text.Pandoc.Definition
+import Text.Pandoc.Options (ReaderOptions)
import Text.Pandoc.Shared (safeRead)
+import Control.Monad.Except (throwError)
+import Data.Text (Text, unpack)
+import Text.Pandoc.Class
import Text.Pandoc.Error
-- | Read native formatted text and return a Pandoc document.
@@ -45,19 +49,23 @@ import Text.Pandoc.Error
--
-- > Pandoc nullMeta [Plain [Str "hi"]]
--
-readNative :: String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError Pandoc
-readNative s = maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead s)
+readNative :: PandocMonad m
+ => ReaderOptions
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
+ -> m Pandoc
+readNative _ s =
+ case maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead (unpack s)) of
+ Right doc -> return doc
+ Left _ -> throwError $ PandocParseError "couldn't read native"
-readBlocks :: String -> Either PandocError [Block]
-readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead s)
+readBlocks :: Text -> Either PandocError [Block]
+readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead (unpack s))
-readBlock :: String -> Either PandocError Block
-readBlock s = maybe (Plain <$> readInlines s) Right (safeRead s)
+readBlock :: Text -> Either PandocError Block
+readBlock s = maybe (Plain <$> readInlines s) Right (safeRead (unpack s))
-readInlines :: String -> Either PandocError [Inline]
-readInlines s = maybe ((:[]) <$> readInline s) Right (safeRead s)
-
-readInline :: String -> Either PandocError Inline
-readInline s = maybe (Left . ParseFailure $ "Could not read: " ++ s) Right (safeRead s)
+readInlines :: Text -> Either PandocError [Inline]
+readInlines s = maybe ((:[]) <$> readInline s) Right (safeRead (unpack s))
+readInline :: Text -> Either PandocError Inline
+readInline s = maybe (Left . PandocParseError $ "Could not read: " ++ unpack s) Right (safeRead (unpack s))
diff --git a/src/Text/Pandoc/Readers/OPML.hs b/src/Text/Pandoc/Readers/OPML.hs
index 4dcf5e5a0..82266748f 100644
--- a/src/Text/Pandoc/Readers/OPML.hs
+++ b/src/Text/Pandoc/Readers/OPML.hs
@@ -1,26 +1,28 @@
{-# LANGUAGE FlexibleContexts #-}
module Text.Pandoc.Readers.OPML ( readOPML ) where
+import Control.Monad.State.Strict
import Data.Char (toUpper)
-import Text.Pandoc.Options
-import Text.Pandoc.Definition
+import Data.Default
+import Data.Generics
+import Data.Maybe (fromMaybe)
+import Data.Text (Text, pack, unpack)
+import Text.HTML.TagSoup.Entity (lookupEntity)
import Text.Pandoc.Builder
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Options
import Text.Pandoc.Readers.HTML (readHtml)
import Text.Pandoc.Readers.Markdown (readMarkdown)
+import Text.Pandoc.Shared (crFilter, blocksToInlines')
import Text.XML.Light
-import Text.HTML.TagSoup.Entity (lookupEntity)
-import Data.Generics
-import Control.Monad.State
-import Data.Default
-import Control.Monad.Except
-import Text.Pandoc.Error
-type OPML = ExceptT PandocError (State OPMLState)
+type OPML m = StateT OPMLState m
data OPMLState = OPMLState{
opmlSectionLevel :: Int
, opmlDocTitle :: Inlines
, opmlDocAuthors :: [Inlines]
, opmlDocDate :: Inlines
+ , opmlOptions :: ReaderOptions
} deriving Show
instance Default OPMLState where
@@ -28,14 +30,19 @@ instance Default OPMLState where
, opmlDocTitle = mempty
, opmlDocAuthors = []
, opmlDocDate = mempty
- }
+ , opmlOptions = def
+ }
-readOPML :: ReaderOptions -> String -> Either PandocError Pandoc
-readOPML _ inp = setTitle (opmlDocTitle st')
- . setAuthors (opmlDocAuthors st')
- . setDate (opmlDocDate st')
- . doc . mconcat <$> bs
- where (bs, st') = flip runState def . runExceptT $ (mapM parseBlock $ normalizeTree $ parseXML inp)
+readOPML :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
+readOPML opts inp = do
+ (bs, st') <- runStateT
+ (mapM parseBlock $ normalizeTree $
+ parseXML (unpack (crFilter inp))) def{ opmlOptions = opts }
+ return $
+ setTitle (opmlDocTitle st') $
+ setAuthors (opmlDocAuthors st') $
+ setDate (opmlDocDate st') $
+ doc $ mconcat bs
-- normalize input, consolidating adjacent Text and CRef elements
normalizeTree :: [Content] -> [Content]
@@ -53,30 +60,32 @@ normalizeTree = everywhere (mkT go)
go xs = xs
convertEntity :: String -> String
-convertEntity e = maybe (map toUpper e) id (lookupEntity e)
+convertEntity e = Data.Maybe.fromMaybe (map toUpper e) (lookupEntity e)
-- convenience function to get an attribute value, defaulting to ""
attrValue :: String -> Element -> String
attrValue attr elt =
- case lookupAttrBy (\x -> qName x == attr) (elAttribs elt) of
- Just z -> z
- Nothing -> ""
+ fromMaybe "" (lookupAttrBy (\x -> qName x == attr) (elAttribs elt))
-exceptT :: Either PandocError a -> OPML a
-exceptT = either throwError return
+-- exceptT :: PandocMonad m => Either PandocError a -> OPML m a
+-- exceptT = either throwError return
-asHtml :: String -> OPML Inlines
-asHtml s = (\(Pandoc _ bs) -> case bs of
- [Plain ils] -> fromList ils
- _ -> mempty) <$> exceptT (readHtml def s)
+asHtml :: PandocMonad m => String -> OPML m Inlines
+asHtml s = do
+ opts <- gets opmlOptions
+ Pandoc _ bs <- readHtml def{ readerExtensions = readerExtensions opts } (pack s)
+ return $ blocksToInlines' bs
-asMarkdown :: String -> OPML Blocks
-asMarkdown s = (\(Pandoc _ bs) -> fromList bs) <$> exceptT (readMarkdown def s)
+asMarkdown :: PandocMonad m => String -> OPML m Blocks
+asMarkdown s = do
+ opts <- gets opmlOptions
+ Pandoc _ bs <- readMarkdown def{ readerExtensions = readerExtensions opts } (pack s)
+ return $ fromList bs
-getBlocks :: Element -> OPML Blocks
-getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
+getBlocks :: PandocMonad m => Element -> OPML m Blocks
+getBlocks e = mconcat <$> mapM parseBlock (elContent e)
-parseBlock :: Content -> OPML Blocks
+parseBlock :: PandocMonad m => Content -> OPML m Blocks
parseBlock (Elem e) =
case qName (elName e) of
"ownerName" -> mempty <$ modify (\st ->
diff --git a/src/Text/Pandoc/Readers/Odt.hs b/src/Text/Pandoc/Readers/Odt.hs
index 046fb4d6d..875c18a85 100644
--- a/src/Text/Pandoc/Readers/Odt.hs
+++ b/src/Text/Pandoc/Readers/Odt.hs
@@ -32,31 +32,45 @@ Entry point to the odt reader.
module Text.Pandoc.Readers.Odt ( readOdt ) where
-import Codec.Archive.Zip
-import qualified Text.XML.Light as XML
+import Codec.Archive.Zip
+import qualified Text.XML.Light as XML
-import qualified Data.ByteString.Lazy as B
+import qualified Data.ByteString.Lazy as B
-import System.FilePath
+import System.FilePath
-import Text.Pandoc.Definition
-import Text.Pandoc.Error
-import Text.Pandoc.Options
-import Text.Pandoc.MediaBag
-import qualified Text.Pandoc.UTF8 as UTF8
+import Control.Monad.Except (throwError)
-import Text.Pandoc.Readers.Odt.ContentReader
-import Text.Pandoc.Readers.Odt.StyleReader
+import Text.Pandoc.Class (PandocMonad)
+import qualified Text.Pandoc.Class as P
+import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Text.Pandoc.MediaBag
+import Text.Pandoc.Options
+import qualified Text.Pandoc.UTF8 as UTF8
-import Text.Pandoc.Readers.Odt.Generic.XMLConverter
-import Text.Pandoc.Readers.Odt.Generic.Fallible
-import Text.Pandoc.Shared (filteredFilesFromArchive)
+import Text.Pandoc.Readers.Odt.ContentReader
+import Text.Pandoc.Readers.Odt.StyleReader
---
-readOdt :: ReaderOptions
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+import Text.Pandoc.Readers.Odt.Generic.XMLConverter
+import Text.Pandoc.Shared (filteredFilesFromArchive)
+
+readOdt :: PandocMonad m
+ => ReaderOptions
-> B.ByteString
- -> Either PandocError (Pandoc, MediaBag)
-readOdt _ bytes = bytesToOdt bytes-- of
+ -> m Pandoc
+readOdt opts bytes = case readOdt' opts bytes of
+ Right (doc, mb) -> do
+ P.setMediaBag mb
+ return doc
+ Left e -> throwError e
+
+--
+readOdt' :: ReaderOptions
+ -> B.ByteString
+ -> Either PandocError (Pandoc, MediaBag)
+readOdt' _ bytes = bytesToOdt bytes-- of
-- Right (pandoc, mediaBag) -> Right (pandoc , mediaBag)
-- Left err -> Left err
@@ -64,7 +78,7 @@ readOdt _ bytes = bytesToOdt bytes-- of
bytesToOdt :: B.ByteString -> Either PandocError (Pandoc, MediaBag)
bytesToOdt bytes = case toArchiveOrFail bytes of
Right archive -> archiveToOdt archive
- Left _ -> Left $ ParseFailure "Couldn't parse odt file."
+ Left _ -> Left $ PandocParseError "Couldn't parse odt file."
--
archiveToOdt :: Archive -> Either PandocError (Pandoc, MediaBag)
@@ -85,7 +99,7 @@ archiveToOdt archive
| otherwise
-- Not very detailed, but I don't think more information would be helpful
- = Left $ ParseFailure "Couldn't parse odt file."
+ = Left $ PandocParseError "Couldn't parse odt file."
where
filePathIsOdtMedia :: FilePath -> Bool
filePathIsOdtMedia fp =
diff --git a/src/Text/Pandoc/Readers/Odt/Arrows/State.hs b/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
index b056f1ecc..73bed545e 100644
--- a/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
+++ b/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
@@ -1,6 +1,6 @@
-{-# LANGUAGE Arrows #-}
-{-# LANGUAGE TupleSections #-}
+
{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TupleSections #-}
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -38,17 +38,17 @@ faster and easier to implement this way.
module Text.Pandoc.Readers.Odt.Arrows.State where
-import Prelude hiding ( foldr, foldl )
+import Prelude hiding (foldl, foldr)
-import qualified Control.Category as Cat
-import Control.Arrow
-import Control.Monad
+import Control.Arrow
+import qualified Control.Category as Cat
+import Control.Monad
-import Data.Foldable
-import Data.Monoid
+import Data.Foldable
+import Data.Monoid
-import Text.Pandoc.Readers.Odt.Arrows.Utils
-import Text.Pandoc.Readers.Odt.Generic.Fallible
+import Text.Pandoc.Readers.Odt.Arrows.Utils
+import Text.Pandoc.Readers.Odt.Generic.Fallible
newtype ArrowState state a b = ArrowState
@@ -59,10 +59,6 @@ withState :: (state -> a -> (state, b)) -> ArrowState state a b
withState = ArrowState . uncurry
-- | Constructor
-withState' :: ((state, a) -> (state, b)) -> ArrowState state a b
-withState' = ArrowState
-
--- | Constructor
modifyState :: (state -> state ) -> ArrowState state a a
modifyState = ArrowState . first
@@ -79,10 +75,6 @@ extractFromState :: (state -> b ) -> ArrowState state x b
extractFromState f = ArrowState $ \(state,_) -> (state, f state)
-- | Constructor
-withUnchangedState :: (state -> a -> b ) -> ArrowState state a b
-withUnchangedState f = ArrowState $ \(state,a) -> (state, f state a)
-
--- | Constructor
tryModifyState :: (state -> Either f state)
-> ArrowState state a (Either f a)
tryModifyState f = ArrowState $ \(state,a)
@@ -90,7 +82,7 @@ tryModifyState f = ArrowState $ \(state,a)
instance Cat.Category (ArrowState s) where
id = ArrowState id
- arrow2 . arrow1 = ArrowState $ (runArrowState arrow2).(runArrowState arrow1)
+ arrow2 . arrow1 = ArrowState $ runArrowState arrow2 . runArrowState arrow1
instance Arrow (ArrowState state) where
arr = ignoringState
@@ -107,43 +99,9 @@ instance ArrowChoice (ArrowState state) where
Left l -> (s, Left l)
Right r -> second Right $ runArrowState a (s,r)
-instance ArrowLoop (ArrowState state) where
- loop a = ArrowState $ \(s, x)
- -> let (s', (x', _d)) = runArrowState a (s, (x, _d))
- in (s', x')
-
instance ArrowApply (ArrowState state) where
app = ArrowState $ \(s, (f,b)) -> runArrowState f (s,b)
-
--- | Embedding of a state arrow in a state arrow with a different state type.
-switchState :: (s -> s') -> (s' -> s) -> ArrowState s' x y -> ArrowState s x y
-switchState there back a = ArrowState $ first there
- >>> runArrowState a
- >>> first back
-
--- | Lift a state arrow to modify the state of an arrow
--- with a different state type.
-liftToState :: (s -> s') -> ArrowState s' s s -> ArrowState s x x
-liftToState unlift a = modifyState $ unlift &&& id
- >>> runArrowState a
- >>> snd
-
--- | Switches the type of the state temporarily.
--- Drops the intermediate result state, behaving like the identity arrow,
--- save for side effects in the state.
-withSubState :: ArrowState s x s2 -> ArrowState s2 s s -> ArrowState s x x
-withSubState unlift a = keepingTheValue (withSubState unlift a) >>^ fst
-
--- | Switches the type of the state temporarily.
--- Returns the resulting sub-state.
-withSubState' :: ArrowState s x s' -> ArrowState s' s s -> ArrowState s x s'
-withSubState' unlift a = ArrowState $ runArrowState unlift
- >>> switch
- >>> runArrowState a
- >>> switch
- where switch (x,y) = (y,x)
-
-- | Switches the type of the state temporarily.
-- Drops the intermediate result state, behaving like a fallible
-- identity arrow, save for side effects in the state.
@@ -175,49 +133,13 @@ foldS :: (Foldable f, Monoid m) => ArrowState s x m -> ArrowState s (f x) m
foldS a = ArrowState $ \(s,f) -> foldr a' (s,mempty) f
where a' x (s',m) = second (m <>) $ runArrowState a (s',x)
--- | Fold a state arrow through something 'Foldable'. Collect the results
--- in a 'Monoid'.
--- Intermediate form of a fold between one with "only" a 'Monoid'
--- and one with any function.
-foldSL :: (Foldable f, Monoid m) => ArrowState s x m -> ArrowState s (f x) m
-foldSL a = ArrowState $ \(s,f) -> foldl a' (s,mempty) f
- where a' (s',m) x = second (m <>) $ runArrowState a (s',x)
-
--- | Fold a fallible state arrow through something 'Foldable'. Collect the
--- results in a 'Monoid'.
--- Intermediate form of a fold between one with "only" a 'Monoid'
--- and one with any function.
--- If the iteration fails, the state will be reset to the initial one.
-foldS' :: (Foldable f, Monoid m)
- => ArrowState s x (Either e m)
- -> ArrowState s (f x) (Either e m)
-foldS' a = ArrowState $ \(s,f) -> foldr (a' s) (s,Right mempty) f
- where a' s x (s',Right m) = case runArrowState a (s',x) of
- (s'',Right m') -> (s'', Right (m <> m'))
- (_ ,Left e ) -> (s , Left e)
- a' _ _ e = e
-
--- | Fold a fallible state arrow through something 'Foldable'. Collect the
--- results in a 'Monoid'.
--- Intermediate form of a fold between one with "only" a 'Monoid'
--- and one with any function.
--- If the iteration fails, the state will be reset to the initial one.
-foldSL' :: (Foldable f, Monoid m)
- => ArrowState s x (Either e m)
- -> ArrowState s (f x) (Either e m)
-foldSL' a = ArrowState $ \(s,f) -> foldl (a' s) (s,Right mempty) f
- where a' s (s',Right m) x = case runArrowState a (s',x) of
- (s'',Right m') -> (s'', Right (m <> m'))
- (_ ,Left e ) -> (s , Left e)
- a' _ e _ = e
-
-- | Fold a state arrow through something 'Foldable'. Collect the results in a
-- 'MonadPlus'.
iterateS :: (Foldable f, MonadPlus m)
=> ArrowState s x y
-> ArrowState s (f x) (m y)
iterateS a = ArrowState $ \(s,f) -> foldr a' (s,mzero) f
- where a' x (s',m) = second ((mplus m).return) $ runArrowState a (s',x)
+ where a' x (s',m) = second (mplus m.return) $ runArrowState a (s',x)
-- | Fold a state arrow through something 'Foldable'. Collect the results in a
-- 'MonadPlus'.
@@ -225,7 +147,7 @@ iterateSL :: (Foldable f, MonadPlus m)
=> ArrowState s x y
-> ArrowState s (f x) (m y)
iterateSL a = ArrowState $ \(s,f) -> foldl a' (s,mzero) f
- where a' (s',m) x = second ((mplus m).return) $ runArrowState a (s',x)
+ where a' (s',m) x = second (mplus m.return) $ runArrowState a (s',x)
-- | Fold a fallible state arrow through something 'Foldable'.
@@ -239,15 +161,3 @@ iterateS' a = ArrowState $ \(s,f) -> foldr (a' s) (s,Right mzero) f
(s'',Right m') -> (s'',Right $ mplus m $ return m')
(_ ,Left e ) -> (s ,Left e )
a' _ _ e = e
-
--- | Fold a fallible state arrow through something 'Foldable'.
--- Collect the results in a 'MonadPlus'.
--- If the iteration fails, the state will be reset to the initial one.
-iterateSL' :: (Foldable f, MonadPlus m)
- => ArrowState s x (Either e y )
- -> ArrowState s (f x) (Either e (m y))
-iterateSL' a = ArrowState $ \(s,f) -> foldl (a' s) (s,Right mzero) f
- where a' s (s',Right m) x = case runArrowState a (s',x) of
- (s'',Right m') -> (s'',Right $ mplus m $ return m')
- (_ ,Left e ) -> (s ,Left e )
- a' _ e _ = e
diff --git a/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
index 218a85661..ef8b2d18a 100644
--- a/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
+++ b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
@@ -39,14 +39,11 @@ with an equivalent return value.
-- We export everything
module Text.Pandoc.Readers.Odt.Arrows.Utils where
-import Control.Arrow
-import Control.Monad ( join, MonadPlus(..) )
+import Control.Arrow
+import Control.Monad (join)
-import qualified Data.Foldable as F
-import Data.Monoid
-
-import Text.Pandoc.Readers.Odt.Generic.Fallible
-import Text.Pandoc.Readers.Odt.Generic.Utils
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+import Text.Pandoc.Readers.Odt.Generic.Utils
and2 :: (Arrow a) => a b c -> a b c' -> a b (c,c')
and2 = (&&&)
@@ -63,12 +60,6 @@ and5 :: (Arrow a)
and6 :: (Arrow a)
=> a b c0->a b c1->a b c2->a b c3->a b c4->a b c5
-> a b (c0,c1,c2,c3,c4,c5 )
-and7 :: (Arrow a)
- => a b c0->a b c1->a b c2->a b c3->a b c4->a b c5->a b c6
- -> a b (c0,c1,c2,c3,c4,c5,c6 )
-and8 :: (Arrow a)
- => a b c0->a b c1->a b c2->a b c3->a b c4->a b c5->a b c6->a b c7
- -> a b (c0,c1,c2,c3,c4,c5,c6,c7)
and3 a b c = (and2 a b ) &&& c
>>^ \((z,y ) , x) -> (z,y,x )
@@ -78,10 +69,6 @@ and5 a b c d e = (and4 a b c d ) &&& e
>>^ \((z,y,x,w ) , v) -> (z,y,x,w,v )
and6 a b c d e f = (and5 a b c d e ) &&& f
>>^ \((z,y,x,w,v ) , u) -> (z,y,x,w,v,u )
-and7 a b c d e f g = (and6 a b c d e f ) &&& g
- >>^ \((z,y,x,w,v,u ) , t) -> (z,y,x,w,v,u,t )
-and8 a b c d e f g h = (and7 a b c d e f g) &&& h
- >>^ \((z,y,x,w,v,u,t) , s) -> (z,y,x,w,v,u,t,s)
liftA2 :: (Arrow a) => (x -> y -> z) -> a b x -> a b y -> a b z
liftA2 f a b = a &&& b >>^ uncurry f
@@ -98,19 +85,11 @@ liftA5 :: (Arrow a) => (z->y->x->w->v -> r)
liftA6 :: (Arrow a) => (z->y->x->w->v->u -> r)
-> a b z->a b y->a b x->a b w->a b v->a b u
-> a b r
-liftA7 :: (Arrow a) => (z->y->x->w->v->u->t -> r)
- -> a b z->a b y->a b x->a b w->a b v->a b u->a b t
- -> a b r
-liftA8 :: (Arrow a) => (z->y->x->w->v->u->t->s -> r)
- -> a b z->a b y->a b x->a b w->a b v->a b u->a b t->a b s
- -> a b r
liftA3 fun a b c = and3 a b c >>^ uncurry3 fun
liftA4 fun a b c d = and4 a b c d >>^ uncurry4 fun
liftA5 fun a b c d e = and5 a b c d e >>^ uncurry5 fun
liftA6 fun a b c d e f = and6 a b c d e f >>^ uncurry6 fun
-liftA7 fun a b c d e f g = and7 a b c d e f g >>^ uncurry7 fun
-liftA8 fun a b c d e f g h = and8 a b c d e f g h >>^ uncurry8 fun
liftA :: (Arrow a) => (y -> z) -> a b y -> a b z
liftA fun a = a >>^ fun
@@ -124,28 +103,12 @@ liftA fun a = a >>^ fun
duplicate :: (Arrow a) => a b (b,b)
duplicate = arr $ join (,)
--- | Lifts the combination of two values into an arrow.
-joinOn :: (Arrow a) => (x -> y -> z) -> a (x,y) z
-joinOn = arr.uncurry
-
-- | Applies a function to the uncurried result-pair of an arrow-application.
-- (The %-symbol was chosen to evoke an association with pairs.)
(>>%) :: (Arrow a) => a x (b,c) -> (b -> c -> d) -> a x d
a >>% f = a >>^ uncurry f
--- | '(>>%)' with its arguments flipped
-(%<<) :: (Arrow a) => (b -> c -> d) -> a x (b,c) -> a x d
-(%<<) = flip (>>%)
-
--- | Precomposition with an uncurried function
-(%>>) :: (Arrow a) => (b -> c -> d) -> a d r -> a (b,c) r
-f %>> a = uncurry f ^>> a
-
--- | Precomposition with an uncurried function (right to left variant)
-(<<%) :: (Arrow a) => a d r -> (b -> c -> d) -> a (b,c) r
-(<<%) = flip (%>>)
-
-infixr 2 >>%, %<<, %>>, <<%
+infixr 2 >>%
-- | Duplicate a value and apply an arrow to the second instance.
@@ -156,56 +119,6 @@ infixr 2 >>%, %<<, %>>, <<%
keepingTheValue :: (Arrow a) => a b c -> a b (b,c)
keepingTheValue a = returnA &&& a
--- | Duplicate a value and apply an arrow to the first instance.
--- Aequivalent to
--- > \a -> duplicate >>> first a
--- or
--- > \a -> a &&& returnA
-keepingTheValue' :: (Arrow a) => a b c -> a b (c,b)
-keepingTheValue' a = a &&& returnA
-
--- | 'bind' from the "Maybe"-Monad lifted into an 'ArrowChoice'.
--- Actually, it's the more complex '(>=>)', because 'bind' alone does not
--- combine as nicely in arrow form.
--- The current implementation is not the most efficient one, because it can
--- not return directly if a 'Nothing' is encountered. That in turn follows
--- from the type system, as 'Nothing' has an "invisible" type parameter that
--- can not be dropped early.
---
--- Also, there probably is a way to generalize this to other monads
--- or applicatives, but I'm leaving that as an exercise to the reader.
--- I have a feeling there is a new Arrow-typeclass to be found that is less
--- restrictive than 'ArrowApply'. If it is already out there,
--- I have not seen it yet. ('ArrowPlus' for example is not general enough.)
-(>>>=) :: (ArrowChoice a) => a x (Maybe b) -> a b (Maybe c) -> a x (Maybe c)
-a1 >>>= a2 = a1 >>> maybeToChoice >>> right a2 >>> choiceToMaybe >>^ join
-
-infixr 2 >>>=
-
--- | 'mplus' Lifted into an arrow. No 'ArrowPlus' required.
--- (But still different from a true bind)
-(>++<) :: (Arrow a, MonadPlus m) => a x (m b) -> a x (m b) -> a x (m b)
-(>++<) = liftA2 mplus
-
--- | Left-compose with a pure function
-leftLift :: (ArrowChoice a) => (l -> l') -> a (Either l r) (Either l' r)
-leftLift = left.arr
-
--- | Right-compose with a pure function
-rightLift :: (ArrowChoice a) => (r -> r') -> a (Either l r) (Either l r')
-rightLift = right.arr
-
-
-( ^+++ ) :: (ArrowChoice a) => (b -> c) -> a b' c' -> a (Either b b') (Either c c')
-( +++^ ) :: (ArrowChoice a) => a b c -> (b' -> c') -> a (Either b b') (Either c c')
-( ^+++^ ) :: (ArrowChoice a) => (b -> c) -> (b' -> c') -> a (Either b b') (Either c c')
-
-l ^+++ r = leftLift l >>> right r
-l +++^ r = left l >>> rightLift r
-l ^+++^ r = leftLift l >>> rightLift r
-
-infixr 2 ^+++, +++^, ^+++^
-
( ^||| ) :: (ArrowChoice a) => (b -> d) -> a c d -> a (Either b c) d
( |||^ ) :: (ArrowChoice a) => a b d -> (c -> d) -> a (Either b c) d
( ^|||^ ) :: (ArrowChoice a) => (b -> d) -> (c -> d) -> a (Either b c) d
@@ -218,33 +131,12 @@ infixr 2 ^||| , |||^, ^|||^
( ^&&& ) :: (Arrow a) => (b -> c) -> a b c' -> a b (c,c')
( &&&^ ) :: (Arrow a) => a b c -> (b -> c') -> a b (c,c')
-( ^&&&^ ) :: (Arrow a) => (b -> c) -> (b -> c') -> a b (c,c')
l ^&&& r = arr l &&& r
l &&&^ r = l &&& arr r
-l ^&&&^ r = arr l &&& arr r
-
-infixr 3 ^&&&, &&&^, ^&&&^
-( ^*** ) :: (Arrow a) => (b -> c) -> a b' c' -> a (b,b') (c,c')
-( ***^ ) :: (Arrow a) => a b c -> (b' -> c') -> a (b,b') (c,c')
-( ^***^ ) :: (Arrow a) => (b -> c) -> (b' -> c') -> a (b,b') (c,c')
+infixr 3 ^&&&, &&&^
-l ^*** r = arr l *** r
-l ***^ r = l *** arr r
-l ^***^ r = arr l *** arr r
-
-infixr 3 ^***, ***^, ^***^
-
--- | A version of
---
--- >>> \p -> arr (\x -> if p x the Right x else Left x)
---
--- but with p being an arrow
-choose :: (ArrowChoice a) => a b Bool -> a b (Either b b)
-choose checkValue = keepingTheValue checkValue >>^ select
- where select (x,True ) = Right x
- select (x,False ) = Left x
-- | Converts @Right a@ into @Just a@ and @Left _@ into @Nothing@.
choiceToMaybe :: (ArrowChoice a) => a (Either l r) (Maybe r)
@@ -258,130 +150,15 @@ maybeToChoice = arr maybeToEither
returnV :: (Arrow a) => c -> a x c
returnV = arr.const
--- | 'returnA' dropping everything
-returnA_ :: (Arrow a) => a _b ()
-returnA_ = returnV ()
-
--- | Wrapper for an arrow that can be evaluated im parallel. All
--- Arrows can be evaluated in parallel, as long as they return a
--- monoid.
-newtype ParallelArrow a b c = CoEval { evalParallelArrow :: a b c }
- deriving (Eq, Ord, Show)
-
-instance (Arrow a, Monoid m) => Monoid (ParallelArrow a b m) where
- mempty = CoEval $ returnV mempty
- (CoEval a) `mappend` (CoEval ~b) = CoEval $ a &&& b >>% mappend
-
--- | Evaluates a collection of arrows in a parallel fashion.
---
--- This is in essence a fold of '(&&&)' over the collection,
--- so the actual execution order and parallelity depends on the
--- implementation of '(&&&)' in the arrow in question.
--- The default implementation of '(&&&)' for example keeps the
--- order as given in the collection.
---
--- This function can be seen as a generalization of
--- 'Control.Applicative.sequenceA' to arrows or as an alternative to
--- a fold with 'Control.Applicative.WrappedArrow', which
--- substitutes the monoid with function application.
---
-coEval :: (Arrow a, F.Foldable f, Monoid m) => f (a b m) -> a b m
-coEval = evalParallelArrow . (F.foldMap CoEval)
-
-- | Defines Left as failure, Right as success
type FallibleArrow a input failure success = a input (Either failure success)
-type ReFallibleArrow a failure success success'
- = FallibleArrow a (Either failure success) failure success'
-
--- | Wrapper for fallible arrows. Fallible arrows are all arrows that return
--- an Either value where left is a faliure and right is a success value.
-newtype AlternativeArrow a input failure success
- = TryArrow { evalAlternativeArrow :: FallibleArrow a input failure success }
-
-
-instance (ArrowChoice a, Monoid failure)
- => Monoid (AlternativeArrow a input failure success) where
- mempty = TryArrow $ returnV $ Left mempty
- (TryArrow a) `mappend` (TryArrow b)
- = TryArrow $ a &&& b
- >>^ \(a',~b')
- -> ( (\a'' -> left (mappend a'') b') ||| Right )
- a'
-
--- | Evaluates a collection of fallible arrows, trying each one in succession.
--- Left values are interpreted as failures, right values as successes.
---
--- The evaluation is stopped once an arrow succeeds.
--- Up to that point, all failures are collected in the failure-monoid.
--- Note that '()' is a monoid, and thus can serve as a failure-collector if
--- you are uninterested in the exact failures.
---
--- This is in essence a fold of '(&&&)' over the collection, enhanced with a
--- little bit of repackaging, so the actual execution order depends on the
--- implementation of '(&&&)' in the arrow in question.
--- The default implementation of '(&&&)' for example keeps the
--- order as given in the collection.
---
-tryArrows :: (ArrowChoice a, F.Foldable f, Monoid failure)
- => f (FallibleArrow a b failure success)
- -> FallibleArrow a b failure success
-tryArrows = evalAlternativeArrow . (F.foldMap TryArrow)
-
---
-liftSuccess :: (ArrowChoice a)
- => (success -> success')
- -> ReFallibleArrow a failure success success'
-liftSuccess = rightLift
-
--
liftAsSuccess :: (ArrowChoice a)
=> a x success
-> FallibleArrow a x failure success
liftAsSuccess a = a >>^ Right
---
-asFallibleArrow :: (ArrowChoice a)
- => a x success
- -> FallibleArrow a x failure success
-asFallibleArrow a = a >>^ Right
-
--- | Raises an error into a 'ReFallibleArrow' if the arrow is already in
--- "error mode"
-liftError :: (ArrowChoice a, Monoid failure)
- => failure
- -> ReFallibleArrow a failure success success
-liftError e = leftLift (e <>)
-
--- | Raises an error into a 'FallibleArrow', droping both the arrow input
--- and any previously stored error value.
-_raiseA :: (ArrowChoice a)
- => failure
- -> FallibleArrow a x failure success
-_raiseA e = returnV (Left e)
-
--- | Raises an empty error into a 'FallibleArrow', droping both the arrow input
--- and any previously stored error value.
-_raiseAEmpty :: (ArrowChoice a, Monoid failure)
- => FallibleArrow a x failure success
-_raiseAEmpty = _raiseA mempty
-
--- | Raises an error into a 'ReFallibleArrow', possibly appending the new error
--- to an existing one
-raiseA :: (ArrowChoice a, Monoid failure)
- => failure
- -> ReFallibleArrow a failure success success
-raiseA e = arr $ Left.(either (<> e) (const e))
-
--- | Raises an empty error into a 'ReFallibleArrow'. If there already is an
--- error, nothing changes.
--- (Note that this function is only aequivalent to @raiseA mempty@ iff the
--- failure monoid follows the monoid laws.)
-raiseAEmpty :: (ArrowChoice a, Monoid failure)
- => ReFallibleArrow a failure success success
-raiseAEmpty = arr (fromRight (const mempty) >>> Left)
-
-
-- | Execute the second arrow if the first succeeds
(>>?) :: (ArrowChoice a)
=> FallibleArrow a x failure success
@@ -410,20 +187,6 @@ a >>?^? b = a >>> Left ^|||^ b
-> FallibleArrow a x failure success'
a ^>>? b = a ^>> Left ^||| b
--- | Execute the lifted second arrow if the lifted first arrow succeeds
-(^>>?^) :: (ArrowChoice a)
- => (x -> Either failure success)
- -> (success -> success')
- -> FallibleArrow a x failure success'
-a ^>>?^ f = arr $ a >>> right f
-
--- | Execute the lifted second arrow if the lifted first arrow succeeds
-(^>>?^?) :: (ArrowChoice a)
- => (x -> Either failure success)
- -> (success -> Either failure success')
- -> FallibleArrow a x failure success'
-a ^>>?^? f = a ^>> Left ^|||^ f
-
-- | Execute the second, non-fallible arrow if the first arrow succeeds
(>>?!) :: (ArrowChoice a)
=> FallibleArrow a x failure success
@@ -448,38 +211,14 @@ a ^>>?% f = arr a >>?^ (uncurry f)
---
(>>?%?) :: (ArrowChoice a)
=> FallibleArrow a x f (b,b')
- -> (b -> b' -> (Either f c))
+ -> (b -> b' -> Either f c)
-> FallibleArrow a x f c
-a >>?%? f = a >>?^? (uncurry f)
+a >>?%? f = a >>?^? uncurry f
infixr 1 >>?, >>?^, >>?^?
-infixr 1 ^>>?, ^>>?^, ^>>?^?, >>?!
+infixr 1 ^>>?, >>?!
infixr 1 >>?%, ^>>?%, >>?%?
--- | Keep values that are Right, replace Left values by a constant.
-ifFailedUse :: (ArrowChoice a) => v -> a (Either f v) v
-ifFailedUse v = arr $ either (const v) id
-
--- | '(&&)' lifted into an arrow
-(<&&>) :: (Arrow a) => a x Bool -> a x Bool -> a x Bool
-(<&&>) = liftA2 (&&)
-
--- | '(||)' lifted into an arrow
-(<||>) :: (Arrow a) => a x Bool -> a x Bool -> a x Bool
-(<||>) = liftA2 (||)
-
--- | An equivalent of '(&&)' in a fallible arrow
-(>&&<) :: (ArrowChoice a, Monoid f) => FallibleArrow a x f s
- -> FallibleArrow a x f s'
- -> FallibleArrow a x f (s,s')
-(>&&<) = liftA2 chooseMin
-
--- | An equivalent of '(||)' in some forms of fallible arrows
-(>||<) :: (ArrowChoice a, Monoid f, Monoid s) => FallibleArrow a x f s
- -> FallibleArrow a x f s
- -> FallibleArrow a x f s
-(>||<) = liftA2 chooseMax
-
-- | An arrow version of a short-circuit (<|>)
ifFailedDo :: (ArrowChoice a)
=> FallibleArrow a x f y
@@ -489,7 +228,4 @@ ifFailedDo a b = keepingTheValue a >>> repackage ^>> (b |||^ Right)
where repackage (x , Left _) = Left x
repackage (_ , Right y) = Right y
-infixr 4 <&&>, <||>, >&&<, >||<
infixr 1 `ifFailedDo`
-
-
diff --git a/src/Text/Pandoc/Readers/Odt/Base.hs b/src/Text/Pandoc/Readers/Odt/Base.hs
index 1f095bade..51c2da788 100644
--- a/src/Text/Pandoc/Readers/Odt/Base.hs
+++ b/src/Text/Pandoc/Readers/Odt/Base.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE PatternGuards #-}
+
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -32,12 +32,11 @@ Core types of the odt reader.
module Text.Pandoc.Readers.Odt.Base where
-import Text.Pandoc.Readers.Odt.Generic.XMLConverter
-import Text.Pandoc.Readers.Odt.Namespaces
+import Text.Pandoc.Readers.Odt.Generic.XMLConverter
+import Text.Pandoc.Readers.Odt.Namespaces
type OdtConverterState s = XMLConverterState Namespace s
type XMLReader s a b = FallibleXMLConverter Namespace s a b
type XMLReaderSafe s a b = XMLConverter Namespace s a b
-
diff --git a/src/Text/Pandoc/Readers/Odt/ContentReader.hs b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
index 2672b01ef..380f16c66 100644
--- a/src/Text/Pandoc/Readers/Odt/ContentReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
@@ -1,8 +1,8 @@
{-# LANGUAGE Arrows #-}
-{-# LANGUAGE TupleSections #-}
{-# LANGUAGE PatternGuards #-}
-{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -39,29 +39,28 @@ module Text.Pandoc.Readers.Odt.ContentReader
, read_body
) where
-import Control.Arrow
-import Control.Applicative hiding ( liftA, liftA2, liftA3 )
+import Control.Applicative hiding (liftA, liftA2, liftA3)
+import Control.Arrow
-import qualified Data.ByteString.Lazy as B
-import qualified Data.Map as M
-import Data.List ( find, intercalate )
-import Data.Maybe
+import qualified Data.ByteString.Lazy as B
+import Data.List (find, intercalate)
+import qualified Data.Map as M
+import Data.Maybe
-import qualified Text.XML.Light as XML
+import qualified Text.XML.Light as XML
-import Text.Pandoc.Definition
-import Text.Pandoc.Builder
-import Text.Pandoc.MediaBag (insertMedia, MediaBag)
-import Text.Pandoc.Shared
+import Text.Pandoc.Builder
+import Text.Pandoc.MediaBag (MediaBag, insertMedia)
+import Text.Pandoc.Shared
-import Text.Pandoc.Readers.Odt.Base
-import Text.Pandoc.Readers.Odt.Namespaces
-import Text.Pandoc.Readers.Odt.StyleReader
+import Text.Pandoc.Readers.Odt.Base
+import Text.Pandoc.Readers.Odt.Namespaces
+import Text.Pandoc.Readers.Odt.StyleReader
-import Text.Pandoc.Readers.Odt.Arrows.Utils
-import Text.Pandoc.Readers.Odt.Generic.XMLConverter
-import Text.Pandoc.Readers.Odt.Generic.Fallible
-import Text.Pandoc.Readers.Odt.Generic.Utils
+import Text.Pandoc.Readers.Odt.Arrows.Utils
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+import Text.Pandoc.Readers.Odt.Generic.Utils
+import Text.Pandoc.Readers.Odt.Generic.XMLConverter
import qualified Data.Set as Set
@@ -94,8 +93,6 @@ data ReaderState
, envMedia :: Media
-- | Hold binary resources used in the document
, odtMediaBag :: MediaBag
--- , sequences
--- , trackedChangeIDs
}
deriving ( Show )
@@ -250,7 +247,7 @@ getPrettyAnchor = proc (baseIdent, uglyAnchor) -> do
modifyExtraState (putPrettyAnchor uglyAnchor newPretty) -<< newPretty
-- | Input: basis for a new header anchor
--- Ouput: saved new anchor
+-- Output: saved new anchor
getHeaderAnchor :: OdtReaderSafe Inlines Anchor
getHeaderAnchor = proc title -> do
state <- getExtraState -< ()
@@ -296,7 +293,7 @@ withNewStyle a = proc x -> do
modifier <- arr modifierFromStyleDiff -< triple
fShouldTrace <- isStyleToTrace -< style
case fShouldTrace of
- Right shouldTrace -> do
+ Right shouldTrace ->
if shouldTrace
then do
pushStyle -< style
@@ -325,7 +322,7 @@ type InlineModifier = Inlines -> Inlines
modifierFromStyleDiff :: PropertyTriple -> InlineModifier
modifierFromStyleDiff propertyTriple =
composition $
- (getVPosModifier propertyTriple)
+ getVPosModifier propertyTriple
: map (first ($ propertyTriple) >>> ifThen_else ignore)
[ (hasEmphChanged , emph )
, (hasChanged isStrong , strong )
@@ -344,9 +341,9 @@ modifierFromStyleDiff propertyTriple =
Just oldVPos -> getVPosModifier' (oldVPos, verticalPosition textProps)
getVPosModifier' (oldVPos , newVPos ) | oldVPos == newVPos = ignore
- getVPosModifier' ( _ , VPosSub ) = subscript
- getVPosModifier' ( _ , VPosSuper ) = superscript
- getVPosModifier' ( _ , _ ) = ignore
+ getVPosModifier' ( _ , VPosSub ) = subscript
+ getVPosModifier' ( _ , VPosSuper ) = superscript
+ getVPosModifier' ( _ , _ ) = ignore
hasEmphChanged :: PropertyTriple -> Bool
hasEmphChanged = swing any [ hasChanged isEmphasised
@@ -355,17 +352,17 @@ modifierFromStyleDiff propertyTriple =
]
hasChanged property triple@(_, property -> newProperty, _) =
- maybe True (/=newProperty) (lookupPreviousValue property triple)
+ (/= Just newProperty) (lookupPreviousValue property triple)
hasChangedM property triple@(_, textProps,_) =
fromMaybe False $ (/=) <$> property textProps <*> lookupPreviousValueM property triple
- lookupPreviousValue f = lookupPreviousStyleValue ((fmap f).textProperties)
+ lookupPreviousValue f = lookupPreviousStyleValue (fmap f . textProperties)
lookupPreviousValueM f = lookupPreviousStyleValue ((f =<<).textProperties)
lookupPreviousStyleValue f (ReaderState{..},_,mFamily)
- = ( findBy f $ extendedStylePropertyChain styleTrace styleSet )
+ = findBy f (extendedStylePropertyChain styleTrace styleSet)
<|> ( f =<< fmap (lookupDefaultStyle' styleSet) mFamily )
@@ -569,7 +566,7 @@ read_text_seq = matchingElement NsText "sequence"
-- specifically. I honor that, although the current implementation of '(<>)'
--- for 'Inlines' in "Text.Pandoc.Builder" will collaps them agein.
+-- for 'Inlines' in "Text.Pandoc.Builder" will collapse them again.
-- The rational is to be prepared for future modifications.
read_spaces :: InlineMatcher
read_spaces = matchingElement NsText "s" (
@@ -663,7 +660,7 @@ read_list = matchingElement NsText "list"
--
read_list_item :: ElementMatcher [Blocks]
read_list_item = matchingElement NsText "list-item"
- $ liftA (compactify'.(:[]))
+ $ liftA (compactify.(:[]))
( matchChildContent' [ read_paragraph
, read_header
, read_list
@@ -749,7 +746,7 @@ read_table_row = matchingElement NsTable "table-row"
--
read_table_cell :: ElementMatcher [Blocks]
read_table_cell = matchingElement NsTable "table-cell"
- $ liftA (compactify'.(:[]))
+ $ liftA (compactify.(:[]))
$ matchChildContent' [ read_paragraph
]
@@ -796,8 +793,7 @@ read_image_src = matchingElement NsDraw "image"
Left _ -> returnV "" -< ()
read_frame_title :: InlineMatcher
-read_frame_title = matchingElement NsSVG "title"
- $ (matchChildContent [] read_plain_text)
+read_frame_title = matchingElement NsSVG "title" (matchChildContent [] read_plain_text)
read_frame_text_box :: InlineMatcher
read_frame_text_box = matchingElement NsDraw "text-box"
@@ -806,12 +802,12 @@ read_frame_text_box = matchingElement NsDraw "text-box"
arr read_img_with_caption -< toList paragraphs
read_img_with_caption :: [Block] -> Inlines
-read_img_with_caption ((Para ((Image attr alt (src,title)) : [])) : _) =
+read_img_with_caption (Para [Image attr alt (src,title)] : _) =
singleton (Image attr alt (src, 'f':'i':'g':':':title)) -- no text, default caption
-read_img_with_caption ((Para ((Image attr _ (src,title)) : txt)) : _) =
+read_img_with_caption (Para (Image attr _ (src,title) : txt) : _) =
singleton (Image attr txt (src, 'f':'i':'g':':':title) ) -- override caption with the text that follows
-read_img_with_caption ( (Para (_ : xs)) : ys) =
- read_img_with_caption ((Para xs) : ys)
+read_img_with_caption ( Para (_ : xs) : ys) =
+ read_img_with_caption (Para xs : ys)
read_img_with_caption _ =
mempty
@@ -899,9 +895,6 @@ read_reference_ref = matchingElement NsText "reference-ref"
-- Entry point
----------------------
---read_plain_content :: OdtReaderSafe _x Inlines
---read_plain_content = strContent >>^ text
-
read_text :: OdtReaderSafe _x Pandoc
read_text = matchChildContent' [ read_header
, read_paragraph
@@ -915,8 +908,8 @@ post_process (Pandoc m blocks) =
Pandoc m (post_process' blocks)
post_process' :: [Block] -> [Block]
-post_process' ((Table _ a w h r) : (Div ("", ["caption"], _) [Para inlines] ) : xs) =
- (Table inlines a w h r) : ( post_process' xs )
+post_process' (Table _ a w h r : Div ("", ["caption"], _) [Para inlines] : xs) =
+ Table inlines a w h r : post_process' xs
post_process' bs = bs
read_body :: OdtReader _x (Pandoc, MediaBag)
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs b/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
index 877443543..f8ea5c605 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -39,11 +39,7 @@ compatible instances of "ArrowChoice".
-- We export everything
module Text.Pandoc.Readers.Odt.Generic.Fallible where
-import Control.Applicative
-import Control.Monad
-
-import qualified Data.Foldable as F
-import Data.Monoid ((<>))
+import Data.Monoid ((<>))
-- | Default for now. Will probably become a class at some point.
type Failure = ()
@@ -51,16 +47,6 @@ type Failure = ()
type Fallible a = Either Failure a
--- | False -> Left (), True -> Right ()
-boolToEither :: Bool -> Fallible ()
-boolToEither False = Left ()
-boolToEither True = Right ()
-
--- | False -> Left (), True -> Right ()
-boolToChoice :: Bool -> Fallible ()
-boolToChoice False = Left ()
-boolToChoice True = Right ()
-
--
maybeToEither :: Maybe a -> Fallible a
maybeToEither (Just a) = Right a
@@ -71,21 +57,11 @@ eitherToMaybe :: Either _l a -> Maybe a
eitherToMaybe (Left _) = Nothing
eitherToMaybe (Right a) = Just a
--- | > untagEither === either id id
-untagEither :: Either a a -> a
-untagEither (Left a) = a
-untagEither (Right a) = a
-
-- | > fromLeft f === either f id
fromLeft :: (a -> b) -> Either a b -> b
fromLeft f (Left a) = f a
fromLeft _ (Right b) = b
--- | > fromRight f === either id f
-fromRight :: (a -> b) -> Either b a -> b
-fromRight _ (Left b) = b
-fromRight f (Right a) = f a
-
-- | > recover a === fromLeft (const a) === either (const a) id
recover :: a -> Either _f a -> a
recover a (Left _) = a
@@ -110,24 +86,6 @@ collapseEither (Left f ) = Left f
collapseEither (Right (Left f)) = Left f
collapseEither (Right (Right x)) = Right x
--- | If either of the values represents an error, the result is a
--- (possibly combined) error. If both values represent a success,
--- both are returned.
-chooseMin :: (Monoid a) => Either a b -> Either a b' -> Either a (b,b')
-chooseMin = chooseMinWith (,)
-
--- | If either of the values represents an error, the result is a
--- (possibly combined) error. If both values represent a success,
--- a combination is returned.
-chooseMinWith :: (Monoid a) => (b -> b' -> c)
- -> Either a b
- -> Either a b'
- -> Either a c
-chooseMinWith (><) (Right a) (Right b) = Right $ a >< b
-chooseMinWith _ (Left a) (Left b) = Left $ a <> b
-chooseMinWith _ (Left a) _ = Left a
-chooseMinWith _ _ (Left b) = Left b
-
-- | If either of the values represents a non-error, the result is a
-- (possibly combined) non-error. If both values represent an error, an error
-- is returned.
@@ -152,109 +110,17 @@ chooseMaxWith _ _ (Right b) = Right b
class ChoiceVector v where
spreadChoice :: v (Either f a) -> Either f (v a)
--- Let's do a few examples first
-
-instance ChoiceVector Maybe where
- spreadChoice (Just (Left f)) = Left f
- spreadChoice (Just (Right x)) = Right (Just x)
- spreadChoice Nothing = Right Nothing
-
-instance ChoiceVector (Either l) where
- spreadChoice (Right (Left f)) = Left f
- spreadChoice (Right (Right x)) = Right (Right x)
- spreadChoice (Left x ) = Right (Left x)
-
instance ChoiceVector ((,) a) where
spreadChoice (_, Left f) = Left f
spreadChoice (x, Right y) = Right (x,y)
-- Wasn't there a newtype somewhere with the elements flipped?
---
--- More instances later, first some discussion.
---
--- I'll have to freshen up on type system details to see how (or if) to do
--- something like
---
--- > instance (ChoiceVector a, ChoiceVector b) => ChoiceVector (a b) where
--- > :
---
--- But maybe it would be even better to use something like
---
--- > class ChoiceVector v v' f | v -> v' f where
--- > spreadChoice :: v -> Either f v'
---
--- That way, more places in @v@ could spread the cheer, e.g.:
---
--- As before:
--- -- ( a , Either f b) (a , b) f
--- > instance ChoiceVector ((,) a (Either f b)) ((,) a b) f where
--- > spreadChoice (_, Left f) = Left f
--- > spreadChoice (a, Right b) = Right (a,b)
---
--- But also:
--- -- ( Either f a , b) (a , b) f
--- > instance ChoiceVector ((,) (Either f a) b) ((,) a b) f where
--- > spreadChoice (Right a,b) = Right (a,b)
--- > spreadChoice (Left f,_) = Left f
---
--- And maybe even:
--- -- ( Either f a , Either f b) (a , b) f
--- > instance ChoiceVector ((,) (Either f a) (Either f b)) ((,) a b) f where
--- > spreadChoice (Right a , Right b) = Right (a,b)
--- > spreadChoice (Left f , _ ) = Left f
--- > spreadChoice ( _ , Left f) = Left f
---
--- Of course that would lead to a lot of overlapping instances...
--- But I can't think of a different way. A selector function might help,
--- but not even a "Data.Traversable" is powerful enough for that.
--- But maybe someone has already solved all this with a lens library.
---
--- Well, it's an interesting academic question. But for practical purposes,
--- I have more than enough right now.
-
-instance ChoiceVector ((,,) a b) where
- spreadChoice (_,_, Left f) = Left f
- spreadChoice (a,b, Right x) = Right (a,b,x)
-
-instance ChoiceVector ((,,,) a b c) where
- spreadChoice (_,_,_, Left f) = Left f
- spreadChoice (a,b,c, Right x) = Right (a,b,c,x)
-
-instance ChoiceVector ((,,,,) a b c d) where
- spreadChoice (_,_,_,_, Left f) = Left f
- spreadChoice (a,b,c,d, Right x) = Right (a,b,c,d,x)
-
-instance ChoiceVector (Const a) where
- spreadChoice (Const c) = Right (Const c) -- need to repackage because of implicit types
-
--- | Fails on the first error
-instance ChoiceVector [] where
- spreadChoice = sequence -- using the monad instance of Either.
- -- Could be generalized to "Data.Traversable" - but why play
- -- with UndecidableInstances unless this is really needed.
-
-- | Wrapper for a list. While the normal list instance of 'ChoiceVector'
-- fails whenever it can, this type will never fail.
newtype SuccessList a = SuccessList { collectNonFailing :: [a] }
deriving ( Eq, Ord, Show )
instance ChoiceVector SuccessList where
- spreadChoice = Right . SuccessList . (foldr unTagRight []) . collectNonFailing
+ spreadChoice = Right . SuccessList . foldr unTagRight [] . collectNonFailing
where unTagRight (Right x) = (x:)
unTagRight _ = id
-
--- | Like 'catMaybes', but for 'Either'.
-collectRights :: [Either _l r] -> [r]
-collectRights = collectNonFailing . untag . spreadChoice . SuccessList
- where untag = fromLeft (error "Unexpected Left")
-
--- | A version of 'collectRights' generalized to other containers. The
--- container must be both "reducible" and "buildable". Most general containers
--- should fullfill these requirements, but there is no single typeclass
--- (that I know of) for that.
--- Therefore, they are split between 'Foldable' and 'MonadPlus'.
--- (Note that 'Data.Traversable.Traversable' alone would not be enough, either.)
-collectRightsF :: (F.Foldable c, MonadPlus c) => c (Either _l r) -> c r
-collectRightsF = F.foldr unTagRight mzero
- where unTagRight (Right x) = mplus $ return x
- unTagRight _ = id
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
index 6c10ed61d..556517259 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
@@ -1,6 +1,6 @@
+
+
{-# LANGUAGE TypeOperators #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ViewPatterns #-}
{-
@@ -38,8 +38,6 @@ module Text.Pandoc.Readers.Odt.Generic.Utils
, uncurry4
, uncurry5
, uncurry6
-, uncurry7
-, uncurry8
, swap
, reverseComposition
, bool
@@ -53,12 +51,12 @@ module Text.Pandoc.Readers.Odt.Generic.Utils
, composition
) where
-import Control.Category ( Category, (>>>), (<<<) )
-import qualified Control.Category as Cat ( id )
-import Control.Monad ( msum )
+import Control.Category (Category, (<<<), (>>>))
+import qualified Control.Category as Cat (id)
+import Control.Monad (msum)
-import qualified Data.Foldable as F ( Foldable, foldr )
-import Data.Maybe
+import qualified Data.Foldable as F (Foldable, foldr)
+import Data.Maybe
-- | Aequivalent to
@@ -148,15 +146,11 @@ uncurry3 :: (a->b->c -> z) -> (a,b,c ) -> z
uncurry4 :: (a->b->c->d -> z) -> (a,b,c,d ) -> z
uncurry5 :: (a->b->c->d->e -> z) -> (a,b,c,d,e ) -> z
uncurry6 :: (a->b->c->d->e->f -> z) -> (a,b,c,d,e,f ) -> z
-uncurry7 :: (a->b->c->d->e->f->g -> z) -> (a,b,c,d,e,f,g ) -> z
-uncurry8 :: (a->b->c->d->e->f->g->h -> z) -> (a,b,c,d,e,f,g,h) -> z
uncurry3 fun (a,b,c ) = fun a b c
uncurry4 fun (a,b,c,d ) = fun a b c d
uncurry5 fun (a,b,c,d,e ) = fun a b c d e
uncurry6 fun (a,b,c,d,e,f ) = fun a b c d e f
-uncurry7 fun (a,b,c,d,e,f,g ) = fun a b c d e f g
-uncurry8 fun (a,b,c,d,e,f,g,h) = fun a b c d e f g h
swap :: (a,b) -> (b,a)
swap (a,b) = (b,a)
@@ -168,4 +162,3 @@ findBy :: (a -> Maybe b) -> [a] -> Maybe b
findBy _ [] = Nothing
findBy f ((f -> Just x):_ ) = Just x
findBy f ( _:xs) = findBy f xs
-
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
index 8c03d1a09..428048427 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
@@ -41,50 +41,17 @@ module Text.Pandoc.Readers.Odt.Generic.XMLConverter
, XMLConverterState
, XMLConverter
, FallibleXMLConverter
-, swapPosition
-, runConverter
-, runConverter''
, runConverter'
-, runConverterF'
-, runConverterF
-, getCurrentElement
, getExtraState
, setExtraState
, modifyExtraState
-, convertingExtraState
, producingExtraState
-, lookupNSiri
-, lookupNSprefix
-, readNSattributes
-, elemName
-, elemNameIs
-, strContent
-, elContent
-, currentElem
-, currentElemIs
-, expectElement
-, elChildren
-, findChildren
-, filterChildren
-, filterChildrenName
, findChild'
-, findChild
-, filterChild'
-, filterChild
-, filterChildName'
-, filterChildName
-, isSet
, isSet'
, isSetWithDefault
-, hasAttrValueOf'
-, failIfNotAttrValueOf
-, isThatTheAttrValue
-, searchAttrIn
-, searchAttrWith
, searchAttr
, lookupAttr
, lookupAttr'
-, lookupAttrWithDefault
, lookupDefaultingAttr
, findAttr'
, findAttr
@@ -93,25 +60,9 @@ module Text.Pandoc.Readers.Odt.Generic.XMLConverter
, readAttr'
, readAttrWithDefault
, getAttr
--- , (>/<)
--- , (?>/<)
, executeIn
-, collectEvery
, withEveryL
-, withEvery
, tryAll
-, tryAll'
-, IdXMLConverter
-, MaybeEConverter
-, ElementMatchConverter
-, MaybeCConverter
-, ContentMatchConverter
-, makeMatcherE
-, makeMatcherC
-, prepareMatchersE
-, prepareMatchersC
-, matchChildren
-, matchContent''
, matchContent'
, matchContent
) where
@@ -120,8 +71,8 @@ import Control.Applicative hiding ( liftA, liftA2 )
import Control.Monad ( MonadPlus )
import Control.Arrow
+import Data.Either ( rights )
import qualified Data.Map as M
-import qualified Data.Foldable as F
import Data.Default
import Data.Maybe
@@ -210,17 +161,6 @@ currentElement state = head (parentElements state)
-- | Replace the current position by another, modifying the extra state
-- in the process
-swapPosition :: (extraState -> extraState')
- -> [XML.Element]
- -> XMLConverterState nsID extraState
- -> XMLConverterState nsID extraState'
-swapPosition f stack state
- = state { parentElements = stack
- , moreState = f (moreState state)
- }
-
--- | Replace the current position by another, modifying the extra state
--- in the process
swapStack' :: XMLConverterState nsID extraState
-> [XML.Element]
-> ( XMLConverterState nsID extraState , [XML.Element] )
@@ -264,14 +204,6 @@ runConverter :: XMLConverter nsID extraState input output
-> output
runConverter converter state input = snd $ runArrowState converter (state,input)
---
-runConverter'' :: (NameSpaceID nsID)
- => XMLConverter nsID extraState (Fallible ()) output
- -> extraState
- -> XML.Element
- -> output
-runConverter'' converter extraState element = runConverter (readNSattributes >>> converter) (createStartState element extraState) ()
-
runConverter' :: (NameSpaceID nsID)
=> FallibleXMLConverter nsID extraState () success
-> extraState
@@ -280,20 +212,6 @@ runConverter' :: (NameSpaceID nsID)
runConverter' converter extraState element = runConverter (readNSattributes >>? converter) (createStartState element extraState) ()
--
-runConverterF' :: FallibleXMLConverter nsID extraState x y
- -> XMLConverterState nsID extraState
- -> Fallible x -> Fallible y
-runConverterF' a s e = runConverter (returnV e >>? a) s e
-
---
-runConverterF :: (NameSpaceID nsID)
- => FallibleXMLConverter nsID extraState XML.Element x
- -> extraState
- -> Fallible XML.Element -> Fallible x
-runConverterF a s = either failWith
- (\e -> runConverter a (createStartState e s) e)
-
---
getCurrentElement :: XMLConverter nsID extraState x XML.Element
getCurrentElement = extractFromState currentElement
@@ -430,57 +348,15 @@ elemNameIs nsID name = keepingTheValue (lookupNSiri nsID) >>% hasThatName
--------------------------------------------------------------------------------
--
-strContent :: XMLConverter nsID extraState x String
-strContent = getCurrentElement
- >>^ XML.strContent
-
---
elContent :: XMLConverter nsID extraState x [XML.Content]
elContent = getCurrentElement
>>^ XML.elContent
--------------------------------------------------------------------------------
--- Current element
---------------------------------------------------------------------------------
-
---
-currentElem :: XMLConverter nsID extraState x (XML.QName)
-currentElem = getCurrentElement
- >>^ XML.elName
-
-currentElemIs :: (NameSpaceID nsID)
- => nsID -> ElementName
- -> XMLConverter nsID extraState x Bool
-currentElemIs nsID name = getCurrentElement
- >>> elemNameIs nsID name
-
-
-
-{-
-currentElemIs'' nsID name = ( (getCurrentElement >>^ XML.elName >>>
- (XML.qName >>^ (&&).(== name) )
- ^&&&^
- (XML.qIRI >>^ (==) )
- ) >>% (.)
- ) &&& lookupNSiri nsID >>% ($)
--}
-
---
-expectElement :: (NameSpaceID nsID)
- => nsID -> ElementName
- -> FallibleXMLConverter nsID extraState x ()
-expectElement nsID name = currentElemIs nsID name
- >>^ boolToChoice
-
---------------------------------------------------------------------------------
-- Chilren
--------------------------------------------------------------------------------
--
-elChildren :: XMLConverter nsID extraState x [XML.Element]
-elChildren = getCurrentElement
- >>^ XML.elChildren
-
--
findChildren :: (NameSpaceID nsID)
=> nsID -> ElementName
@@ -490,18 +366,6 @@ findChildren nsID name = elemName nsID name
>>% XML.findChildren
--
-filterChildren :: (XML.Element -> Bool)
- -> XMLConverter nsID extraState x [XML.Element]
-filterChildren p = getCurrentElement
- >>^ XML.filterChildren p
-
---
-filterChildrenName :: (XML.QName -> Bool)
- -> XMLConverter nsID extraState x [XML.Element]
-filterChildrenName p = getCurrentElement
- >>^ XML.filterChildrenName p
-
---
findChild' :: (NameSpaceID nsID)
=> nsID
-> ElementName
@@ -517,45 +381,12 @@ findChild :: (NameSpaceID nsID)
findChild nsID name = findChild' nsID name
>>> maybeToChoice
---
-filterChild' :: (XML.Element -> Bool)
- -> XMLConverter nsID extraState x (Maybe XML.Element)
-filterChild' p = getCurrentElement
- >>^ XML.filterChild p
-
---
-filterChild :: (XML.Element -> Bool)
- -> FallibleXMLConverter nsID extraState x XML.Element
-filterChild p = filterChild' p
- >>> maybeToChoice
-
---
-filterChildName' :: (XML.QName -> Bool)
- -> XMLConverter nsID extraState x (Maybe XML.Element)
-filterChildName' p = getCurrentElement
- >>^ XML.filterChildName p
-
---
-filterChildName :: (XML.QName -> Bool)
- -> FallibleXMLConverter nsID extraState x XML.Element
-filterChildName p = filterChildName' p
- >>> maybeToChoice
-
--------------------------------------------------------------------------------
-- Attributes
--------------------------------------------------------------------------------
--
-isSet :: (NameSpaceID nsID)
- => nsID -> AttributeName
- -> (Either Failure Bool)
- -> FallibleXMLConverter nsID extraState x Bool
-isSet nsID attrName deflt
- = findAttr' nsID attrName
- >>^ maybe deflt stringToBool
-
---
isSet' :: (NameSpaceID nsID)
=> nsID -> AttributeName
-> XMLConverter nsID extraState x (Maybe Bool)
@@ -570,34 +401,6 @@ isSetWithDefault nsID attrName def'
= isSet' nsID attrName
>>^ fromMaybe def'
---
-hasAttrValueOf' :: (NameSpaceID nsID)
- => nsID -> AttributeName
- -> AttributeValue
- -> XMLConverter nsID extraState x Bool
-hasAttrValueOf' nsID attrName attrValue
- = findAttr nsID attrName
- >>> ( const False ^|||^ (==attrValue))
-
---
-failIfNotAttrValueOf :: (NameSpaceID nsID)
- => nsID -> AttributeName
- -> AttributeValue
- -> FallibleXMLConverter nsID extraState x ()
-failIfNotAttrValueOf nsID attrName attrValue
- = hasAttrValueOf' nsID attrName attrValue
- >>^ boolToChoice
-
--- | Is the value that is currently transported in the arrow the value of
--- the specified attribute?
-isThatTheAttrValue :: (NameSpaceID nsID)
- => nsID -> AttributeName
- -> FallibleXMLConverter nsID extraState AttributeValue Bool
-isThatTheAttrValue nsID attrName
- = keepingTheValue
- (findAttr nsID attrName)
- >>% right.(==)
-
-- | Lookup value in a dictionary, fail if no attribute found or value
-- not in dictionary
searchAttrIn :: (NameSpaceID nsID)
@@ -608,18 +411,6 @@ searchAttrIn nsID attrName dict
= findAttr nsID attrName
>>?^? maybeToChoice.(`lookup` dict )
-
--- | Lookup value in a dictionary. Fail if no attribute found. If value not in
--- dictionary, return default value
-searchAttrWith :: (NameSpaceID nsID)
- => nsID -> AttributeName
- -> a
- -> [(AttributeValue,a)]
- -> FallibleXMLConverter nsID extraState x a
-searchAttrWith nsID attrName defV dict
- = findAttr nsID attrName
- >>?^ (fromMaybe defV).(`lookup` dict )
-
-- | Lookup value in a dictionary. If attribute or value not found,
-- return default value
searchAttr :: (NameSpaceID nsID)
@@ -789,16 +580,6 @@ prepareIteration nsID name = keepingTheValue
(findChildren nsID name)
>>% distributeValue
--- | Applies a converter to every child element of a specific type.
--- Collects results in a 'Monoid'.
--- Fails completely if any conversion fails.
-collectEvery :: (NameSpaceID nsID, Monoid m)
- => nsID -> ElementName
- -> FallibleXMLConverter nsID extraState a m
- -> FallibleXMLConverter nsID extraState a m
-collectEvery nsID name a = prepareIteration nsID name
- >>> foldS' (switchingTheStack a)
-
--
withEveryL :: (NameSpaceID nsID)
=> nsID -> ElementName
@@ -824,17 +605,7 @@ tryAll :: (NameSpaceID nsID)
-> XMLConverter nsID extraState b [a]
tryAll nsID name a = prepareIteration nsID name
>>> iterateS (switchingTheStack a)
- >>^ collectRights
-
--- | Applies a converter to every child element of a specific type.
--- Collects all successful results.
-tryAll' :: (NameSpaceID nsID, F.Foldable c, MonadPlus c)
- => nsID -> ElementName
- -> FallibleXMLConverter nsID extraState b a
- -> XMLConverter nsID extraState b (c a)
-tryAll' nsID name a = prepareIteration nsID name
- >>> iterateS (switchingTheStack a)
- >>^ collectRightsF
+ >>^ rights
--------------------------------------------------------------------------------
-- Matching children
@@ -843,15 +614,6 @@ tryAll' nsID name a = prepareIteration nsID name
type IdXMLConverter nsID moreState x
= XMLConverter nsID moreState x x
-type MaybeEConverter nsID moreState x
- = Maybe (IdXMLConverter nsID moreState (x, XML.Element))
-
--- Chainable converter that helps deciding which converter to actually use.
-type ElementMatchConverter nsID extraState x
- = IdXMLConverter nsID
- extraState
- (MaybeEConverter nsID extraState x, XML.Element)
-
type MaybeCConverter nsID moreState x
= Maybe (IdXMLConverter nsID moreState (x, XML.Content))
@@ -862,26 +624,6 @@ type ContentMatchConverter nsID extraState x
(MaybeCConverter nsID extraState x, XML.Content)
-- Helper function: The @c@ is actually a converter that is to be selected by
--- matching XML elements to the first two parameters.
--- The fold used to match elements however is very simple, so to use it,
--- this function wraps the converter in another converter that unifies
--- the accumulator. Think of a lot of converters with the resulting type
--- chained together. The accumulator not only transports the element
--- unchanged to the next matcher, it also does the actual selecting by
--- combining the intermediate results with '(<|>)'.
-makeMatcherE :: (NameSpaceID nsID)
- => nsID -> ElementName
- -> FallibleXMLConverter nsID extraState a a
- -> ElementMatchConverter nsID extraState a
-makeMatcherE nsID name c = ( second (
- elemNameIs nsID name
- >>^ bool Nothing (Just tryC)
- )
- >>% (<|>)
- ) &&&^ snd
- where tryC = (fst ^&&& executeThere c >>% recover) &&&^ snd
-
--- Helper function: The @c@ is actually a converter that is to be selected by
-- matching XML content to the first two parameters.
-- The fold used to match elements however is very simple, so to use it,
-- this function wraps the converter in another converter that unifies
@@ -914,13 +656,6 @@ makeMatcherC nsID name c = ( second ( contentToElem
_ -> failEmpty
-- Creates and chains a bunch of matchers
-prepareMatchersE :: (NameSpaceID nsID)
- => [(nsID, ElementName, FallibleXMLConverter nsID extraState x x)]
- -> ElementMatchConverter nsID extraState x
---prepareMatchersE = foldSs . (map $ uncurry3 makeMatcherE)
-prepareMatchersE = reverseComposition . (map $ uncurry3 makeMatcherE)
-
--- Creates and chains a bunch of matchers
prepareMatchersC :: (NameSpaceID nsID)
=> [(nsID, ElementName, FallibleXMLConverter nsID extraState x x)]
-> ContentMatchConverter nsID extraState x
@@ -928,52 +663,6 @@ prepareMatchersC :: (NameSpaceID nsID)
prepareMatchersC = reverseComposition . (map $ uncurry3 makeMatcherC)
-- | Takes a list of element-data - converter groups and
--- * Finds all children of the current element
--- * Matches each group to each child in order (at most one group per child)
--- * Filters non-matched children
--- * Chains all found converters in child-order
--- * Applies the chain to the input element
-matchChildren :: (NameSpaceID nsID)
- => [(nsID, ElementName, FallibleXMLConverter nsID extraState a a)]
- -> XMLConverter nsID extraState a a
-matchChildren lookups = let matcher = prepareMatchersE lookups
- in keepingTheValue (
- elChildren
- >>> map (Nothing,)
- ^>> iterateSL matcher
- >>^ catMaybes.map (\(m,e) -> fmap (swallowElem e) m)
- -- >>> foldSs
- >>> reverseComposition
- )
- >>> swap
- ^>> app
- where
- -- let the converter swallow the element and drop the element
- -- in the return value
- swallowElem element converter = (,element) ^>> converter >>^ fst
-
---
-matchContent'' :: (NameSpaceID nsID)
- => [(nsID, ElementName, FallibleXMLConverter nsID extraState a a)]
- -> XMLConverter nsID extraState a a
-matchContent'' lookups = let matcher = prepareMatchersC lookups
- in keepingTheValue (
- elContent
- >>> map (Nothing,)
- ^>> iterateSL matcher
- >>^ catMaybes.map (\(m,c) -> fmap (swallowContent c) m)
- -- >>> foldSs
- >>> reverseComposition
- )
- >>> swap
- ^>> app
- where
- -- let the converter swallow the content and drop the content
- -- in the return value
- swallowContent content converter = (,content) ^>> converter >>^ fst
-
-
--- | Takes a list of element-data - converter groups and
-- * Finds all content of the current element
-- * Matches each group to each piece of content in order
-- (at most one group per piece of content)
@@ -1018,14 +707,6 @@ matchContent lookups fallback
-- Internals
--------------------------------------------------------------------------------
-stringToBool :: (Monoid failure) => String -> Either failure Bool
-stringToBool val -- stringToBool' val >>> maybeToChoice
- | val `elem` trueValues = succeedWith True
- | val `elem` falseValues = succeedWith False
- | otherwise = failEmpty
- where trueValues = ["true" ,"on" ,"1"]
- falseValues = ["false","off","0"]
-
stringToBool' :: String -> Maybe Bool
stringToBool' val | val `elem` trueValues = Just True
| val `elem` falseValues = Just False
diff --git a/src/Text/Pandoc/Readers/Odt/Namespaces.hs b/src/Text/Pandoc/Readers/Odt/Namespaces.hs
index deb009998..92e12931d 100644
--- a/src/Text/Pandoc/Readers/Odt/Namespaces.hs
+++ b/src/Text/Pandoc/Readers/Odt/Namespaces.hs
@@ -31,11 +31,11 @@ Namespaces used in odt files.
module Text.Pandoc.Readers.Odt.Namespaces ( Namespace (..)
) where
-import Data.List ( isPrefixOf )
-import Data.Maybe ( fromMaybe, listToMaybe )
-import qualified Data.Map as M ( empty, insert )
+import Data.List (isPrefixOf)
+import qualified Data.Map as M (empty, insert)
+import Data.Maybe (fromMaybe, listToMaybe)
-import Text.Pandoc.Readers.Odt.Generic.Namespaces
+import Text.Pandoc.Readers.Odt.Generic.Namespaces
instance NameSpaceID Namespace where
@@ -48,7 +48,7 @@ instance NameSpaceID Namespace where
findID :: NameSpaceIRI -> Maybe Namespace
-findID iri = listToMaybe [nsID | (iri',~nsID) <- nsIDs, iri' `isPrefixOf` iri]
+findID iri = listToMaybe [nsID | (iri',nsID) <- nsIDs, iri' `isPrefixOf` iri]
nsIDmap :: NameSpaceIRIs Namespace
nsIDmap = foldr (uncurry $ flip M.insert) M.empty nsIDs
diff --git a/src/Text/Pandoc/Readers/Odt/StyleReader.hs b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
index 26ba6df82..58be8e4a3 100644
--- a/src/Text/Pandoc/Readers/Odt/StyleReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
@@ -1,9 +1,8 @@
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE PatternGuards #-}
-{-# LANGUAGE ViewPatterns #-}
-{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE Arrows #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TupleSections #-}
+
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -50,49 +49,36 @@ module Text.Pandoc.Readers.Odt.StyleReader
, ListLevelType (..)
, LengthOrPercent (..)
, lookupStyle
-, getTextProperty
-, getTextProperty'
-, getParaProperty
-, getListStyle
, getListLevelStyle
, getStyleFamily
-, lookupDefaultStyle
, lookupDefaultStyle'
, lookupListStyleByName
-, getPropertyChain
-, textPropertyChain
-, stylePropertyChain
-, stylePropertyChain'
-, getStylePropertyChain
, extendedStylePropertyChain
-, extendedStylePropertyChain'
-, liftStyles
, readStylesAt
) where
-import Control.Arrow
-import Control.Applicative hiding ( liftA, liftA2, liftA3 )
+import Control.Applicative hiding (liftA, liftA2, liftA3)
+import Control.Arrow
-import qualified Data.Foldable as F
-import qualified Data.Map as M
-import qualified Data.Set as S
-import Data.Char ( isDigit )
-import Data.Default
-import Data.List ( unfoldr )
-import Data.Maybe
+import Data.Char (isDigit)
+import Data.Default
+import qualified Data.Foldable as F
+import Data.List (unfoldr)
+import qualified Data.Map as M
+import Data.Maybe
+import qualified Data.Set as S
-import qualified Text.XML.Light as XML
+import qualified Text.XML.Light as XML
-import Text.Pandoc.Readers.Odt.Arrows.State
-import Text.Pandoc.Readers.Odt.Arrows.Utils
+import Text.Pandoc.Readers.Odt.Arrows.Utils
-import Text.Pandoc.Readers.Odt.Generic.Utils
-import qualified Text.Pandoc.Readers.Odt.Generic.SetMap as SM
-import Text.Pandoc.Readers.Odt.Generic.Fallible
-import Text.Pandoc.Readers.Odt.Generic.XMLConverter
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+import qualified Text.Pandoc.Readers.Odt.Generic.SetMap as SM
+import Text.Pandoc.Readers.Odt.Generic.Utils
+import Text.Pandoc.Readers.Odt.Generic.XMLConverter
-import Text.Pandoc.Readers.Odt.Namespaces
-import Text.Pandoc.Readers.Odt.Base
+import Text.Pandoc.Readers.Odt.Base
+import Text.Pandoc.Readers.Odt.Namespaces
readStylesAt :: XML.Element -> Fallible Styles
@@ -118,7 +104,7 @@ instance Lookupable FontPitch where
instance Default FontPitch where
def = PitchVariable
--- The font pitch can be specifed in a style directly. Normally, however,
+-- The font pitch can be specified in a style directly. Normally, however,
-- it is defined in the font. That is also the specs' recommendation.
--
-- Thus, we want
@@ -145,13 +131,12 @@ type StyleReaderSafe a b = XMLReaderSafe FontPitches a b
-- | A reader for font pitches
fontPitchReader :: XMLReader _s _x FontPitches
fontPitchReader = executeIn NsOffice "font-face-decls" (
- ( withEveryL NsStyle "font-face" $ liftAsSuccess (
+ withEveryL NsStyle "font-face" (liftAsSuccess (
findAttr' NsStyle "name"
&&&
lookupDefaultingAttr NsStyle "font-pitch"
- )
- )
- >>?^ ( M.fromList . (foldl accumLegalPitches []) )
+ ))
+ >>?^ ( M.fromList . foldl accumLegalPitches [] )
)
where accumLegalPitches ls (Nothing,_) = ls
accumLegalPitches ls (Just n,p) = (n,p):ls
@@ -230,15 +215,15 @@ instance Lookupable StyleFamily where
]
-- | A named style
-data Style = Style { styleFamily :: Maybe StyleFamily
- , styleParentName :: Maybe StyleName
- , listStyle :: Maybe StyleName
- , styleProperties :: StyleProperties
+data Style = Style { styleFamily :: Maybe StyleFamily
+ , styleParentName :: Maybe StyleName
+ , listStyle :: Maybe StyleName
+ , styleProperties :: StyleProperties
}
deriving ( Eq, Show )
-data StyleProperties = SProps { textProperties :: Maybe TextProperties
- , paraProperties :: Maybe ParaProperties
+data StyleProperties = SProps { textProperties :: Maybe TextProperties
+ , paraProperties :: Maybe ParaProperties
-- , tableColProperties :: Maybe TColProperties
-- , tableRowProperties :: Maybe TRowProperties
-- , tableCellProperties :: Maybe TCellProperties
@@ -354,8 +339,8 @@ instance Read XslUnit where
readsPrec _ "em" = [(XslUnitEM , "")]
readsPrec _ _ = []
--- | Rough conversion of measures into millimeters.
--- Pixels and em's are actually implemetation dependant/relative measures,
+-- | Rough conversion of measures into millimetres.
+-- Pixels and em's are actually implementation dependant/relative measures,
-- so I could not really easily calculate anything exact here even if I wanted.
-- But I do not care about exactness right now, as I only use measures
-- to determine if a paragraph is "indented" or not.
@@ -397,11 +382,11 @@ data ListLevelStyle = ListLevelStyle { listLevelType :: ListLevelType
instance Show ListLevelStyle where
show ListLevelStyle{..} = "<LLS|"
- ++ (show listLevelType)
+ ++ show listLevelType
++ "|"
- ++ (maybeToString listItemPrefix)
- ++ (show listItemFormat)
- ++ (maybeToString listItemSuffix)
+ ++ maybeToString listItemPrefix
+ ++ show listItemFormat
+ ++ maybeToString listItemSuffix
++ ">"
where maybeToString = fromMaybe ""
@@ -439,7 +424,7 @@ instance Read ListItemNumberFormat where
--------------------------------------------------------------------------------
-- Readers
--
--- ...it seems like a whole lot of this should be automatically deriveable
+-- ...it seems like a whole lot of this should be automatically derivable
-- or at least moveable into a class. Most of this is data concealed in
-- code.
--------------------------------------------------------------------------------
@@ -497,14 +482,14 @@ readTextProperties =
( liftA6 PropT
( searchAttr NsXSL_FO "font-style" False isFontEmphasised )
( searchAttr NsXSL_FO "font-weight" False isFontBold )
- ( findPitch )
+ findPitch
( getAttr NsStyle "text-position" )
- ( readUnderlineMode )
- ( readStrikeThroughMode )
+ readUnderlineMode
+ readStrikeThroughMode
)
where isFontEmphasised = [("normal",False),("italic",True),("oblique",True)]
isFontBold = ("normal",False):("bold",True)
- :(map ((,True).show) ([100,200..900]::[Int]))
+ :map ((,True).show) ([100,200..900]::[Int])
readUnderlineMode :: StyleReaderSafe _x (Maybe UnderlineMode)
readUnderlineMode = readLineMode "text-underline-mode"
@@ -524,7 +509,7 @@ readLineMode modeAttr styleAttr = proc x -> do
Nothing -> returnA -< Just UnderlineModeNormal
else returnA -< Nothing
where
- isLinePresent = [("none",False)] ++ map (,True)
+ isLinePresent = ("none",False) : map (,True)
[ "dash" , "dot-dash" , "dot-dot-dash" , "dotted"
, "long-dash" , "solid" , "wave"
]
@@ -561,20 +546,18 @@ readListStyle =
findAttr NsStyle "name"
>>?! keepingTheValue
( liftA ListStyle
- $ ( liftA3 SM.union3
+ $ liftA3 SM.union3
( readListLevelStyles NsText "list-level-style-number" LltNumbered )
( readListLevelStyles NsText "list-level-style-bullet" LltBullet )
- ( readListLevelStyles NsText "list-level-style-image" LltImage )
- ) >>^ M.mapMaybe chooseMostSpecificListLevelStyle
+ ( readListLevelStyles NsText "list-level-style-image" LltImage ) >>^ M.mapMaybe chooseMostSpecificListLevelStyle
)
--
readListLevelStyles :: Namespace -> ElementName
-> ListLevelType
-> StyleReaderSafe _x (SM.SetMap Int ListLevelStyle)
readListLevelStyles namespace elementName levelType =
- ( tryAll namespace elementName (readListLevelStyle levelType)
+ tryAll namespace elementName (readListLevelStyle levelType)
>>^ SM.fromList
- )
--
readListLevelStyle :: ListLevelType -> StyleReader _x (Int, ListLevelStyle)
@@ -624,20 +607,11 @@ lookupStyle :: StyleName -> Styles -> Maybe Style
lookupStyle name Styles{..} = M.lookup name stylesByName
--
-lookupDefaultStyle :: StyleFamily -> Styles -> StyleProperties
-lookupDefaultStyle family Styles{..} = fromMaybe def
- (M.lookup family defaultStyleMap)
-
---
lookupDefaultStyle' :: Styles -> StyleFamily -> StyleProperties
lookupDefaultStyle' Styles{..} family = fromMaybe def
(M.lookup family defaultStyleMap)
--
-getListStyle :: Style -> Styles -> Maybe ListStyle
-getListStyle Style{..} styles = listStyle >>= (`lookupListStyleByName` styles)
-
---
lookupListStyleByName :: StyleName -> Styles -> Maybe ListStyle
lookupListStyleByName name Styles{..} = M.lookup name listStylesByName
@@ -655,7 +629,7 @@ parents style styles = unfoldr findNextParent style -- Ha!
getStyleFamily :: Style -> Styles -> Maybe StyleFamily
getStyleFamily style@Style{..} styles
= styleFamily
- <|> (F.asum $ map (`getStyleFamily` styles) $ parents style styles)
+ <|> F.asum (map (`getStyleFamily` styles) $ parents style styles)
-- | Each 'Style' has certain 'StyleProperties'. But sometimes not all property
-- values are specified. Instead, a value might be inherited from a
@@ -677,68 +651,7 @@ stylePropertyChain style styles
--
extendedStylePropertyChain :: [Style] -> Styles -> [StyleProperties]
extendedStylePropertyChain [] _ = []
-extendedStylePropertyChain [style] styles = (stylePropertyChain style styles)
- ++ (maybeToList (fmap (lookupDefaultStyle' styles) (getStyleFamily style styles)))
-extendedStylePropertyChain (style:trace) styles = (stylePropertyChain style styles)
- ++ (extendedStylePropertyChain trace styles)
--- Optimizable with Data.Sequence
-
---
-extendedStylePropertyChain' :: [Style] -> Styles -> Maybe [StyleProperties]
-extendedStylePropertyChain' [] _ = Nothing
-extendedStylePropertyChain' [style] styles = Just (
- (stylePropertyChain style styles)
- ++ (maybeToList (fmap (lookupDefaultStyle' styles) (getStyleFamily style styles)))
- )
-extendedStylePropertyChain' (style:trace) styles = fmap ((stylePropertyChain style styles) ++)
- (extendedStylePropertyChain' trace styles)
-
---
-stylePropertyChain' :: Styles -> Style -> [StyleProperties]
-stylePropertyChain' = flip stylePropertyChain
-
---
-getStylePropertyChain :: StyleName -> Styles -> [StyleProperties]
-getStylePropertyChain name styles = maybe []
- (`stylePropertyChain` styles)
- (lookupStyle name styles)
-
---
-getPropertyChain :: (StyleProperties -> Maybe a) -> Style -> Styles -> [a]
-getPropertyChain extract style styles = catMaybes
- $ map extract
- $ stylePropertyChain style styles
-
---
-textPropertyChain :: Style -> Styles -> [TextProperties]
-textPropertyChain = getPropertyChain textProperties
-
---
-paraPropertyChain :: Style -> Styles -> [ParaProperties]
-paraPropertyChain = getPropertyChain paraProperties
-
---
-getTextProperty :: (TextProperties -> a) -> Style -> Styles -> Maybe a
-getTextProperty extract style styles = fmap extract
- $ listToMaybe
- $ textPropertyChain style styles
-
---
-getTextProperty' :: (TextProperties -> Maybe a) -> Style -> Styles -> Maybe a
-getTextProperty' extract style styles = F.asum
- $ map extract
- $ textPropertyChain style styles
-
---
-getParaProperty :: (ParaProperties -> a) -> Style -> Styles -> Maybe a
-getParaProperty extract style styles = fmap extract
- $ listToMaybe
- $ paraPropertyChain style styles
-
--- | Lifts the reader into another readers' state.
-liftStyles :: (OdtConverterState s -> OdtConverterState Styles)
- -> (OdtConverterState Styles -> OdtConverterState s )
- -> XMLReader s x x
-liftStyles extract inject = switchState extract inject
- $ convertingExtraState M.empty readAllStyles
-
+extendedStylePropertyChain [style] styles = stylePropertyChain style styles
+ ++ maybeToList (fmap (lookupDefaultStyle' styles) (getStyleFamily style styles))
+extendedStylePropertyChain (style:trace) styles = stylePropertyChain style styles
+ ++ extendedStylePropertyChain trace styles
diff --git a/src/Text/Pandoc/Readers/Org.hs b/src/Text/Pandoc/Readers/Org.hs
index 4e1c926da..292830bd2 100644
--- a/src/Text/Pandoc/Readers/Org.hs
+++ b/src/Text/Pandoc/Readers/Org.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Org
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -27,29 +27,42 @@ Conversion of org-mode formatted plain text to 'Pandoc' document.
-}
module Text.Pandoc.Readers.Org ( readOrg ) where
-import Text.Pandoc.Readers.Org.Blocks ( blockList, meta )
-import Text.Pandoc.Readers.Org.Parsing ( OrgParser, readWithM )
-import Text.Pandoc.Readers.Org.ParserState ( optionsToParserState )
+import Text.Pandoc.Readers.Org.Blocks (blockList, meta)
+import Text.Pandoc.Readers.Org.ParserState (optionsToParserState)
+import Text.Pandoc.Readers.Org.Parsing (OrgParser, readWithM)
-import Text.Pandoc.Definition
-import Text.Pandoc.Error
-import Text.Pandoc.Options
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing (reportLogMessages)
+import Text.Pandoc.Shared (crFilter)
-import Control.Monad.Reader ( runReader )
+import Control.Monad.Except (throwError)
+import Control.Monad.Reader (runReaderT)
+import Data.Text (Text)
+import qualified Data.Text as T
-- | Parse org-mode string and return a Pandoc document.
-readOrg :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError Pandoc
-readOrg opts s = flip runReader def $
- readWithM parseOrg (optionsToParserState opts) (s ++ "\n\n")
+readOrg :: PandocMonad m
+ => ReaderOptions -- ^ Reader options
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
+ -> m Pandoc
+readOrg opts s = do
+ parsed <- flip runReaderT def $
+ readWithM parseOrg (optionsToParserState opts)
+ (T.unpack (crFilter s) ++ "\n\n")
+ case parsed of
+ Right result -> return result
+ Left _ -> throwError $ PandocParseError "problem parsing org"
--
-- Parser
--
-parseOrg :: OrgParser Pandoc
+parseOrg :: PandocMonad m => OrgParser m Pandoc
parseOrg = do
blocks' <- blockList
meta' <- meta
+ reportLogMessages
return $ Pandoc meta' blocks'
diff --git a/src/Text/Pandoc/Readers/Org/BlockStarts.hs b/src/Text/Pandoc/Readers/Org/BlockStarts.hs
index b1004dda6..424102cb0 100644
--- a/src/Text/Pandoc/Readers/Org/BlockStarts.hs
+++ b/src/Text/Pandoc/Readers/Org/BlockStarts.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,8 +17,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.BlockStarts
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -40,11 +40,11 @@ module Text.Pandoc.Readers.Org.BlockStarts
, endOfBlock
) where
-import Control.Monad ( void )
+import Control.Monad (void)
import Text.Pandoc.Readers.Org.Parsing
-- | Horizontal Line (five -- dashes or more)
-hline :: OrgParser ()
+hline :: Monad m => OrgParser m ()
hline = try $ do
skipSpaces
string "-----"
@@ -54,58 +54,66 @@ hline = try $ do
return ()
-- | Read the start of a header line, return the header level
-headerStart :: OrgParser Int
+headerStart :: Monad m => OrgParser m Int
headerStart = try $
(length <$> many1 (char '*')) <* many1 (char ' ') <* updateLastPreCharPos
-tableStart :: OrgParser Char
+tableStart :: Monad m => OrgParser m Char
tableStart = try $ skipSpaces *> char '|'
-latexEnvStart :: OrgParser String
-latexEnvStart = try $ do
+gridTableStart :: Monad m => OrgParser m ()
+gridTableStart = try $ skipSpaces <* char '+' <* char '-'
+
+
+latexEnvStart :: Monad m => OrgParser m String
+latexEnvStart = try $
skipSpaces *> string "\\begin{"
*> latexEnvName
<* string "}"
<* blankline
where
- latexEnvName :: OrgParser String
+ latexEnvName :: Monad m => OrgParser m String
latexEnvName = try $ mappend <$> many1 alphaNum <*> option "" (string "*")
-
--- | Parses bullet list marker.
-bulletListStart :: OrgParser ()
-bulletListStart = try $
- choice
- [ () <$ skipSpaces <* oneOf "+-" <* skipSpaces1
- , () <$ skipSpaces1 <* char '*' <* skipSpaces1
- ]
-
-genericListStart :: OrgParser String
- -> OrgParser Int
-genericListStart listMarker = try $
- (+) <$> (length <$> many spaceChar)
- <*> (length <$> listMarker <* many1 spaceChar)
-
-orderedListStart :: OrgParser Int
+bulletListStart :: Monad m => OrgParser m Int
+bulletListStart = try $ do
+ ind <- length <$> many spaceChar
+ -- Unindented lists cannot use '*' bullets.
+ oneOf (if ind == 0 then "+-" else "*+-")
+ skipSpaces1 <|> lookAhead eol
+ return (ind + 1)
+
+genericListStart :: Monad m
+ => OrgParser m String
+ -> OrgParser m Int
+genericListStart listMarker = try $ do
+ ind <- length <$> many spaceChar
+ void listMarker
+ skipSpaces1 <|> lookAhead eol
+ return (ind + 1)
+
+eol :: Monad m => OrgParser m ()
+eol = void (char '\n')
+
+orderedListStart :: Monad m => OrgParser m Int
orderedListStart = genericListStart orderedListMarker
-- Ordered list markers allowed in org-mode
where orderedListMarker = mappend <$> many1 digit <*> (pure <$> oneOf ".)")
-drawerStart :: OrgParser String
-drawerStart = try $
- skipSpaces *> drawerName <* skipSpaces <* newline
+drawerStart :: Monad m => OrgParser m String
+drawerStart = try $ skipSpaces *> drawerName <* skipSpaces <* newline
where drawerName = char ':' *> manyTill nonspaceChar (char ':')
-metaLineStart :: OrgParser ()
+metaLineStart :: Monad m => OrgParser m ()
metaLineStart = try $ skipSpaces <* string "#+"
-commentLineStart :: OrgParser ()
+commentLineStart :: Monad m => OrgParser m ()
commentLineStart = try $ skipSpaces <* string "# "
-exampleLineStart :: OrgParser ()
+exampleLineStart :: Monad m => OrgParser m ()
exampleLineStart = () <$ try (skipSpaces *> string ": ")
-noteMarker :: OrgParser String
+noteMarker :: Monad m => OrgParser m String
noteMarker = try $ do
char '['
choice [ many1Till digit (char ']')
@@ -114,17 +122,18 @@ noteMarker = try $ do
]
-- | Succeeds if the parser is at the end of a block.
-endOfBlock :: OrgParser ()
-endOfBlock = lookAhead . try $ do
- void blankline <|> anyBlockStart
+endOfBlock :: Monad m => OrgParser m ()
+endOfBlock = lookAhead . try $
+ void blankline <|> anyBlockStart
where
-- Succeeds if there is a new block starting at this position.
- anyBlockStart :: OrgParser ()
+ anyBlockStart :: Monad m => OrgParser m ()
anyBlockStart = try . choice $
[ exampleLineStart
, hline
, metaLineStart
, commentLineStart
+ , gridTableStart
, void noteMarker
, void tableStart
, void drawerStart
@@ -133,4 +142,3 @@ endOfBlock = lookAhead . try $ do
, void bulletListStart
, void orderedListStart
]
-
diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs
index 484d97482..fa016283c 100644
--- a/src/Text/Pandoc/Readers/Org/Blocks.hs
+++ b/src/Text/Pandoc/Readers/Org/Blocks.hs
@@ -1,8 +1,5 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ViewPatterns #-}
{-
-Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,10 +15,11 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
-
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RecordWildCards #-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2017 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.Blocks
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,247 +31,61 @@ module Text.Pandoc.Readers.Org.Blocks
, meta
) where
-import Text.Pandoc.Readers.Org.BlockStarts
-import Text.Pandoc.Readers.Org.Inlines
-import Text.Pandoc.Readers.Org.Meta ( metaExport, metaKey, metaLine )
-import Text.Pandoc.Readers.Org.ParserState
-import Text.Pandoc.Readers.Org.Parsing
-import Text.Pandoc.Readers.Org.Shared
- ( cleanLinkString, isImageFilename, rundocBlockClass
- , toRundocAttrib, translateLang )
+import Text.Pandoc.Readers.Org.BlockStarts
+import Text.Pandoc.Readers.Org.DocumentTree (documentTree, headlineToBlocks)
+import Text.Pandoc.Readers.Org.Inlines
+import Text.Pandoc.Readers.Org.Meta (metaExport, metaKey, metaLine)
+import Text.Pandoc.Readers.Org.ParserState
+import Text.Pandoc.Readers.Org.Parsing
+import Text.Pandoc.Readers.Org.Shared (cleanLinkString, isImageFilename,
+ originalLang, translateLang)
+
+import Text.Pandoc.Builder (Blocks, Inlines)
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import Text.Pandoc.Shared (compactify, compactifyDL, safeRead)
+
+import Control.Monad (foldM, guard, mzero, void)
+import Data.Char (isSpace, toLower, toUpper)
+import Data.Default (Default)
+import Data.List (foldl', isPrefixOf)
+import Data.Maybe (fromMaybe, isJust, isNothing)
+import Data.Monoid ((<>))
import qualified Text.Pandoc.Builder as B
-import Text.Pandoc.Builder ( Inlines, Blocks )
-import Text.Pandoc.Definition
-import Text.Pandoc.Options
-import Text.Pandoc.Shared ( compactify', compactify'DL, safeRead )
-
-import Control.Monad ( foldM, guard, mzero, void )
-import Data.Char ( isSpace, toLower, toUpper)
-import Data.Default ( Default )
-import Data.List ( foldl', isPrefixOf )
-import Data.Maybe ( fromMaybe, isNothing )
-import Data.Monoid ((<>))
-
---
--- Org headers
---
-newtype Tag = Tag { fromTag :: String }
- deriving (Show, Eq)
-
--- | Create a tag containing the given string.
-toTag :: String -> Tag
-toTag = Tag
-
--- | The key (also called name or type) of a property.
-newtype PropertyKey = PropertyKey { fromKey :: String }
- deriving (Show, Eq, Ord)
-
--- | Create a property key containing the given string. Org mode keys are
--- case insensitive and are hence converted to lower case.
-toPropertyKey :: String -> PropertyKey
-toPropertyKey = PropertyKey . map toLower
-
--- | The value assigned to a property.
-newtype PropertyValue = PropertyValue { fromValue :: String }
-
--- | Create a property value containing the given string.
-toPropertyValue :: String -> PropertyValue
-toPropertyValue = PropertyValue
-
--- | Check whether the property value is non-nil (i.e. truish).
-isNonNil :: PropertyValue -> Bool
-isNonNil p = map toLower (fromValue p) `notElem` ["()", "{}", "nil"]
-
--- | Key/value pairs from a PROPERTIES drawer
-type Properties = [(PropertyKey, PropertyValue)]
-
--- | Org mode headline (i.e. a document subtree).
-data Headline = Headline
- { headlineLevel :: Int
- , headlineTodoMarker :: Maybe TodoMarker
- , headlineText :: Inlines
- , headlineTags :: [Tag]
- , headlineProperties :: Properties
- , headlineContents :: Blocks
- , headlineChildren :: [Headline]
- }
-
---
--- Parsing headlines and subtrees
---
-
--- | Read an Org mode headline and its contents (i.e. a document subtree).
--- @lvl@ gives the minimum acceptable level of the tree.
-headline :: Int -> OrgParser (F Headline)
-headline lvl = try $ do
- level <- headerStart
- guard (lvl <= level)
- todoKw <- optionMaybe todoKeyword
- title <- trimInlinesF . mconcat <$> manyTill inline endOfTitle
- tags <- option [] headerTags
- newline
- properties <- option mempty propertiesDrawer
- contents <- blocks
- children <- many (headline (level + 1))
- return $ do
- title' <- title
- contents' <- contents
- children' <- sequence children
- return $ Headline
- { headlineLevel = level
- , headlineTodoMarker = todoKw
- , headlineText = title'
- , headlineTags = tags
- , headlineProperties = properties
- , headlineContents = contents'
- , headlineChildren = children'
- }
- where
- endOfTitle :: OrgParser ()
- endOfTitle = void . lookAhead $ optional headerTags *> newline
-
- headerTags :: OrgParser [Tag]
- headerTags = try $
- let tag = many1 (alphaNum <|> oneOf "@%#_") <* char ':'
- in map toTag <$> (skipSpaces *> char ':' *> many1 tag <* skipSpaces)
-
--- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks
-headlineToBlocks :: Headline -> OrgParser Blocks
-headlineToBlocks hdln@(Headline {..}) = do
- maxHeadlineLevels <- getExportSetting exportHeadlineLevels
- case () of
- _ | any isNoExportTag headlineTags -> return mempty
- _ | any isArchiveTag headlineTags -> archivedHeadlineToBlocks hdln
- _ | isCommentTitle headlineText -> return mempty
- _ | headlineLevel >= maxHeadlineLevels -> headlineToHeaderWithList hdln
- _ | otherwise -> headlineToHeaderWithContents hdln
-
-isNoExportTag :: Tag -> Bool
-isNoExportTag = (== toTag "noexport")
-
-isArchiveTag :: Tag -> Bool
-isArchiveTag = (== toTag "ARCHIVE")
-
--- | Check if the title starts with COMMENT.
--- FIXME: This accesses builder internals not intended for use in situations
--- like these. Replace once keyword parsing is supported.
-isCommentTitle :: Inlines -> Bool
-isCommentTitle (B.toList -> (Str "COMMENT":_)) = True
-isCommentTitle _ = False
-
-archivedHeadlineToBlocks :: Headline -> OrgParser Blocks
-archivedHeadlineToBlocks hdln = do
- archivedTreesOption <- getExportSetting exportArchivedTrees
- case archivedTreesOption of
- ArchivedTreesNoExport -> return mempty
- ArchivedTreesExport -> headlineToHeaderWithContents hdln
- ArchivedTreesHeadlineOnly -> headlineToHeader hdln
-
-headlineToHeaderWithList :: Headline -> OrgParser Blocks
-headlineToHeaderWithList hdln@(Headline {..}) = do
- maxHeadlineLevels <- getExportSetting exportHeadlineLevels
- header <- headlineToHeader hdln
- listElements <- sequence (map headlineToBlocks headlineChildren)
- let listBlock = if null listElements
- then mempty
- else B.orderedList listElements
- let headerText = if maxHeadlineLevels == headlineLevel
- then header
- else flattenHeader header
- return $ headerText <> headlineContents <> listBlock
- where
- flattenHeader :: Blocks -> Blocks
- flattenHeader blks =
- case B.toList blks of
- (Header _ _ inlns:_) -> B.para (B.fromList inlns)
- _ -> mempty
-
-headlineToHeaderWithContents :: Headline -> OrgParser Blocks
-headlineToHeaderWithContents hdln@(Headline {..}) = do
- header <- headlineToHeader hdln
- childrenBlocks <- mconcat <$> sequence (map headlineToBlocks headlineChildren)
- return $ header <> headlineContents <> childrenBlocks
-
-headlineToHeader :: Headline -> OrgParser Blocks
-headlineToHeader (Headline {..}) = do
- exportTodoKeyword <- getExportSetting exportWithTodoKeywords
- let todoText = if exportTodoKeyword
- then case headlineTodoMarker of
- Just kw -> todoKeywordToInlines kw <> B.space
- Nothing -> mempty
- else mempty
- let text = tagTitle (todoText <> headlineText) headlineTags
- let propAttr = propertiesToAttr headlineProperties
- attr <- registerHeader propAttr headlineText
- return $ B.headerWith attr headlineLevel text
-
-todoKeyword :: OrgParser TodoMarker
-todoKeyword = try $ do
- taskStates <- activeTodoMarkers <$> getState
- let kwParser tdm = try $ (tdm <$ string (todoMarkerName tdm) <* spaceChar)
- choice (map kwParser taskStates)
-
-todoKeywordToInlines :: TodoMarker -> Inlines
-todoKeywordToInlines tdm =
- let todoText = todoMarkerName tdm
- todoState = map toLower . show $ todoMarkerState tdm
- classes = [todoState, todoText]
- in B.spanWith (mempty, classes, mempty) (B.str todoText)
-
-propertiesToAttr :: Properties -> Attr
-propertiesToAttr properties =
- let
- toStringPair prop = (fromKey (fst prop), fromValue (snd prop))
- customIdKey = toPropertyKey "custom_id"
- classKey = toPropertyKey "class"
- unnumberedKey = toPropertyKey "unnumbered"
- specialProperties = [customIdKey, classKey, unnumberedKey]
- id' = fromMaybe mempty . fmap fromValue . lookup customIdKey $ properties
- cls = fromMaybe mempty . fmap fromValue . lookup classKey $ properties
- kvs' = map toStringPair . filter ((`notElem` specialProperties) . fst)
- $ properties
- isUnnumbered =
- fromMaybe False . fmap isNonNil . lookup unnumberedKey $ properties
- in
- (id', words cls ++ (if isUnnumbered then ["unnumbered"] else []), kvs')
-
-tagTitle :: Inlines -> [Tag] -> Inlines
-tagTitle title tags = title <> (mconcat $ map tagToInline tags)
-
-tagToInline :: Tag -> Inlines
-tagToInline t = B.spanWith ("", ["tag"], [("data-tag-name", fromTag t)]) mempty
-
+import qualified Text.Pandoc.Walk as Walk
--
-- parsing blocks
--
-- | Get a list of blocks.
-blockList :: OrgParser [Block]
+blockList :: PandocMonad m => OrgParser m [Block]
blockList = do
- initialBlocks <- blocks
- headlines <- sequence <$> manyTill (headline 1) eof
+ headlines <- documentTree blocks inline
st <- getState
- headlineBlocks <- fmap mconcat . sequence . map headlineToBlocks $ runF headlines st
- return . B.toList $ (runF initialBlocks st) <> headlineBlocks
+ headlineBlocks <- headlineToBlocks $ runF headlines st
+ -- ignore first headline, it's the document's title
+ return . drop 1 . B.toList $ headlineBlocks
--- | Get the meta information safed in the state.
-meta :: OrgParser Meta
+-- | Get the meta information saved in the state.
+meta :: Monad m => OrgParser m Meta
meta = do
meta' <- metaExport
runF meta' <$> getState
-blocks :: OrgParser (F Blocks)
+blocks :: PandocMonad m => OrgParser m (F Blocks)
blocks = mconcat <$> manyTill block (void (lookAhead headerStart) <|> eof)
-block :: OrgParser (F Blocks)
+block :: PandocMonad m => OrgParser m (F Blocks)
block = choice [ mempty <$ blanklines
, table
, orgBlock
, figure
, example
, genericDrawer
+ , include
, specialLine
, horizontalRule
, list
@@ -283,6 +95,11 @@ block = choice [ mempty <$ blanklines
] <?> "block"
+-- | Parse a horizontal rule into a block element
+horizontalRule :: Monad m => OrgParser m (F Blocks)
+horizontalRule = return B.horizontalRule <$ try hline
+
+
--
-- Block Attributes
--
@@ -297,7 +114,7 @@ data BlockAttributes = BlockAttributes
-- | Convert BlockAttributes into pandoc Attr
attrFromBlockAttributes :: BlockAttributes -> Attr
-attrFromBlockAttributes (BlockAttributes{..}) =
+attrFromBlockAttributes BlockAttributes{..} =
let
ident = fromMaybe mempty $ lookup "id" blockAttrKeyValues
classes = case lookup "class" blockAttrKeyValues of
@@ -306,18 +123,18 @@ attrFromBlockAttributes (BlockAttributes{..}) =
kv = filter ((`notElem` ["id", "class"]) . fst) blockAttrKeyValues
in (ident, classes, kv)
-stringyMetaAttribute :: (String -> Bool) -> OrgParser (String, String)
-stringyMetaAttribute attrCheck = try $ do
+stringyMetaAttribute :: Monad m => OrgParser m (String, String)
+stringyMetaAttribute = try $ do
metaLineStart
attrName <- map toUpper <$> many1Till nonspaceChar (char ':')
- guard $ attrCheck attrName
skipSpaces
- attrValue <- anyLine
+ attrValue <- anyLine <|> ("" <$ newline)
return (attrName, attrValue)
-blockAttributes :: OrgParser BlockAttributes
+blockAttributes :: PandocMonad m => OrgParser m BlockAttributes
blockAttributes = try $ do
- kv <- many (stringyMetaAttribute attrCheck)
+ kv <- many stringyMetaAttribute
+ guard $ all (attrCheck . fst) kv
let caption = foldl' (appendValues "CAPTION") Nothing kv
let kvAttrs = foldl' (appendValues "ATTR_HTML") Nothing kv
let name = lookup "NAME" kv
@@ -326,7 +143,7 @@ blockAttributes = try $ do
Nothing -> return Nothing
Just s -> Just <$> parseFromString inlines (s ++ "\n")
kvAttrs' <- parseFromString keyValues . (++ "\n") $ fromMaybe mempty kvAttrs
- return $ BlockAttributes
+ return BlockAttributes
{ blockAttrName = name
, blockAttrLabel = label
, blockAttrCaption = caption'
@@ -334,13 +151,7 @@ blockAttributes = try $ do
}
where
attrCheck :: String -> Bool
- attrCheck attr =
- case attr of
- "NAME" -> True
- "LABEL" -> True
- "CAPTION" -> True
- "ATTR_HTML" -> True
- _ -> False
+ attrCheck x = x `elem` ["NAME", "LABEL", "CAPTION", "ATTR_HTML", "RESULTS"]
appendValues :: String -> Maybe String -> (String, String) -> Maybe String
appendValues attrName accValue (key, value) =
@@ -350,17 +161,18 @@ blockAttributes = try $ do
Just acc -> Just $ acc ++ ' ':value
Nothing -> Just value
-keyValues :: OrgParser [(String, String)]
+-- | Parse key-value pairs for HTML attributes
+keyValues :: Monad m => OrgParser m [(String, String)]
keyValues = try $
manyTill ((,) <$> key <*> value) newline
where
- key :: OrgParser String
+ key :: Monad m => OrgParser m String
key = try $ skipSpaces *> char ':' *> many1 nonspaceChar
- value :: OrgParser String
+ value :: Monad m => OrgParser m String
value = skipSpaces *> manyTill anyChar endOfValue
- endOfValue :: OrgParser ()
+ endOfValue :: Monad m => OrgParser m ()
endOfValue =
lookAhead $ (() <$ try (many1 spaceChar <* key))
<|> () <$ newline
@@ -371,12 +183,12 @@ keyValues = try $
--
-- | Read an org-mode block delimited by #+BEGIN_TYPE and #+END_TYPE.
-orgBlock :: OrgParser (F Blocks)
+orgBlock :: PandocMonad m => OrgParser m (F Blocks)
orgBlock = try $ do
blockAttrs <- blockAttributes
blkType <- blockHeaderStart
($ blkType) $
- case (map toLower blkType) of
+ case map toLower blkType of
"export" -> exportBlock
"comment" -> rawBlockLines (const mempty)
"html" -> rawBlockLines (return . B.rawBlock (lowercase blkType))
@@ -390,25 +202,25 @@ orgBlock = try $ do
let (ident, classes, kv) = attrFromBlockAttributes blockAttrs
in fmap $ B.divWith (ident, classes ++ [blkType], kv)
where
- blockHeaderStart :: OrgParser String
+ blockHeaderStart :: Monad m => OrgParser m String
blockHeaderStart = try $ skipSpaces *> stringAnyCase "#+begin_" *> orgArgWord
lowercase :: String -> String
lowercase = map toLower
-rawBlockLines :: (String -> F Blocks) -> String -> OrgParser (F Blocks)
-rawBlockLines f blockType = (ignHeaders *> (f <$> rawBlockContent blockType))
+rawBlockLines :: Monad m => (String -> F Blocks) -> String -> OrgParser m (F Blocks)
+rawBlockLines f blockType = ignHeaders *> (f <$> rawBlockContent blockType)
-parseBlockLines :: (F Blocks -> F Blocks) -> String -> OrgParser (F Blocks)
-parseBlockLines f blockType = (ignHeaders *> (f <$> parsedBlockContent))
+parseBlockLines :: PandocMonad m => (F Blocks -> F Blocks) -> String -> OrgParser m (F Blocks)
+parseBlockLines f blockType = ignHeaders *> (f <$> parsedBlockContent)
where
- parsedBlockContent :: OrgParser (F Blocks)
+ parsedBlockContent :: PandocMonad m => OrgParser m (F Blocks)
parsedBlockContent = try $ do
raw <- rawBlockContent blockType
parseFromString blocks (raw ++ "\n")
-- | Read the raw string content of a block
-rawBlockContent :: String -> OrgParser String
+rawBlockContent :: Monad m => String -> OrgParser m String
rawBlockContent blockType = try $ do
blkLines <- manyTill rawLine blockEnder
tabLen <- getOption readerTabStop
@@ -418,18 +230,17 @@ rawBlockContent blockType = try $ do
. map (tabsToSpaces tabLen . commaEscaped)
$ blkLines
where
- rawLine :: OrgParser String
+ rawLine :: Monad m => OrgParser m String
rawLine = try $ ("" <$ blankline) <|> anyLine
- blockEnder :: OrgParser ()
+ blockEnder :: Monad m => OrgParser m ()
blockEnder = try $ skipSpaces <* stringAnyCase ("#+end_" <> blockType)
stripIndent :: [String] -> [String]
stripIndent strs = map (drop (shortestIndent strs)) strs
shortestIndent :: [String] -> Int
- shortestIndent = foldr min maxBound
- . map (length . takeWhile isSpace)
+ shortestIndent = foldr (min . length . takeWhile isSpace) maxBound
. filter (not . null)
tabsToSpaces :: Int -> String -> String
@@ -437,7 +248,7 @@ rawBlockContent blockType = try $ do
tabsToSpaces tabLen cs'@(c:cs) =
case c of
' ' -> ' ':tabsToSpaces tabLen cs
- '\t' -> (take tabLen $ repeat ' ') ++ tabsToSpaces tabLen cs
+ '\t' -> replicate tabLen ' ' ++ tabsToSpaces tabLen cs
_ -> cs'
commaEscaped :: String -> String
@@ -448,18 +259,18 @@ rawBlockContent blockType = try $ do
commaEscaped cs = cs
-- | Read but ignore all remaining block headers.
-ignHeaders :: OrgParser ()
+ignHeaders :: Monad m => OrgParser m ()
ignHeaders = (() <$ newline) <|> (() <$ anyLine)
-- | Read a block containing code intended for export in specific backends
-- only.
-exportBlock :: String -> OrgParser (F Blocks)
+exportBlock :: Monad m => String -> OrgParser m (F Blocks)
exportBlock blockType = try $ do
exportType <- skipSpaces *> orgArgWord <* ignHeaders
contents <- rawBlockContent blockType
returnF (B.rawBlock (map toLower exportType) contents)
-verseBlock :: String -> OrgParser (F Blocks)
+verseBlock :: PandocMonad m => String -> OrgParser m (F Blocks)
verseBlock blockType = try $ do
ignHeaders
content <- rawBlockContent blockType
@@ -468,7 +279,7 @@ verseBlock blockType = try $ do
where
-- replace initial spaces with nonbreaking spaces to preserve
-- indentation, parse the rest as normal inline
- parseVerseLine :: String -> OrgParser (F Inlines)
+ parseVerseLine :: PandocMonad m => String -> OrgParser m (F Inlines)
parseVerseLine cs = do
let (initialSpaces, indentedLine) = span isSpace cs
let nbspIndent = if null initialSpaces
@@ -480,23 +291,20 @@ verseBlock blockType = try $ do
-- | Read a code block and the associated results block if present. Which of
-- boths blocks is included in the output is determined using the "exports"
-- argument in the block header.
-codeBlock :: BlockAttributes -> String -> OrgParser (F Blocks)
+codeBlock :: PandocMonad m => BlockAttributes -> String -> OrgParser m (F Blocks)
codeBlock blockAttrs blockType = do
skipSpaces
(classes, kv) <- codeHeaderArgs <|> (mempty <$ ignHeaders)
content <- rawBlockContent blockType
- resultsContent <- trailingResultsBlock
+ resultsContent <- option mempty babelResultsBlock
let id' = fromMaybe mempty $ blockAttrName blockAttrs
- let includeCode = exportsCode kv
- let includeResults = exportsResults kv
let codeBlck = B.codeBlockWith ( id', classes, kv ) content
let labelledBlck = maybe (pure codeBlck)
(labelDiv codeBlck)
(blockAttrCaption blockAttrs)
- let resultBlck = fromMaybe mempty resultsContent
return $
- (if includeCode then labelledBlck else mempty) <>
- (if includeResults then resultBlck else mempty)
+ (if exportsCode kv then labelledBlck else mempty) <>
+ (if exportsResults kv then resultsContent else mempty)
where
labelDiv :: Blocks -> F Inlines -> F Blocks
labelDiv blk value =
@@ -505,60 +313,97 @@ codeBlock blockAttrs blockType = do
labelledBlock :: F Inlines -> F Blocks
labelledBlock = fmap (B.plain . B.spanWith ("", ["label"], []))
-exportsCode :: [(String, String)] -> Bool
-exportsCode attrs = not (("rundoc-exports", "none") `elem` attrs
- || ("rundoc-exports", "results") `elem` attrs)
+ exportsCode :: [(String, String)] -> Bool
+ exportsCode = maybe True (`elem` ["code", "both"]) . lookup "exports"
-exportsResults :: [(String, String)] -> Bool
-exportsResults attrs = ("rundoc-exports", "results") `elem` attrs
- || ("rundoc-exports", "both") `elem` attrs
+ exportsResults :: [(String, String)] -> Bool
+ exportsResults = maybe False (`elem` ["results", "both"]) . lookup "exports"
-trailingResultsBlock :: OrgParser (Maybe (F Blocks))
-trailingResultsBlock = optionMaybe . try $ do
+-- | Parse the result of an evaluated babel code block.
+babelResultsBlock :: PandocMonad m => OrgParser m (F Blocks)
+babelResultsBlock = try $ do
blanklines
- stringAnyCase "#+RESULTS:"
- blankline
+ resultsMarker <|>
+ (lookAhead . void . try $
+ manyTill (metaLineStart *> anyLineNewline) resultsMarker)
block
+ where
+ resultsMarker = try . void $ stringAnyCase "#+RESULTS:" *> blankline
-- | Parse code block arguments
--- TODO: We currently don't handle switches.
-codeHeaderArgs :: OrgParser ([String], [(String, String)])
+codeHeaderArgs :: Monad m => OrgParser m ([String], [(String, String)])
codeHeaderArgs = try $ do
language <- skipSpaces *> orgArgWord
- _ <- skipSpaces *> (try $ switch `sepBy` (many1 spaceChar))
+ (switchClasses, switchKv) <- switchesAsAttributes
parameters <- manyTill blockOption newline
- let pandocLang = translateLang language
- return $
- if hasRundocParameters parameters
- then ( [ pandocLang, rundocBlockClass ]
- , map toRundocAttrib (("language", language) : parameters)
+ return ( translateLang language : switchClasses
+ , originalLang language <> switchKv <> parameters
)
- else ([ pandocLang ], parameters)
- where
- hasRundocParameters = not . null
-switch :: OrgParser (Char, Maybe String)
-switch = try $ simpleSwitch <|> lineNumbersSwitch
+switchesAsAttributes :: Monad m => OrgParser m ([String], [(String, String)])
+switchesAsAttributes = try $ do
+ switches <- skipSpaces *> try (switch `sepBy` many1 spaceChar)
+ return $ foldr addToAttr ([], []) switches
where
- simpleSwitch = (\c -> (c, Nothing)) <$> (oneOf "-+" *> letter)
- lineNumbersSwitch = (\ls -> ('l', Just ls)) <$>
- (string "-l \"" *> many1Till nonspaceChar (char '"'))
+ addToAttr :: (Char, Maybe String, SwitchPolarity)
+ -> ([String], [(String, String)])
+ -> ([String], [(String, String)])
+ addToAttr ('n', lineNum, pol) (cls, kv) =
+ let kv' = case lineNum of
+ Just num -> ("startFrom", num):kv
+ Nothing -> kv
+ cls' = case pol of
+ SwitchPlus -> "continuedSourceBlock":cls
+ SwitchMinus -> cls
+ in ("numberLines":cls', kv')
+ addToAttr _ x = x
+
+-- | Whether a switch flag is specified with @+@ or @-@.
+data SwitchPolarity = SwitchPlus | SwitchMinus
+ deriving (Show, Eq)
+
+-- | Parses a switch's polarity.
+switchPolarity :: Monad m => OrgParser m SwitchPolarity
+switchPolarity = (SwitchMinus <$ char '-') <|> (SwitchPlus <$ char '+')
-blockOption :: OrgParser (String, String)
+-- | Parses a source block switch option.
+switch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity)
+switch = try $ lineNumberSwitch <|> labelSwitch <|> simpleSwitch
+ where
+ simpleSwitch = (\pol c -> (c, Nothing, pol)) <$> switchPolarity <*> letter
+ labelSwitch = genericSwitch 'l' $
+ char '"' *> many1Till nonspaceChar (char '"')
+
+-- | Generic source block switch-option parser.
+genericSwitch :: Monad m
+ => Char
+ -> OrgParser m String
+ -> OrgParser m (Char, Maybe String, SwitchPolarity)
+genericSwitch c p = try $ do
+ polarity <- switchPolarity <* char c <* skipSpaces
+ arg <- optionMaybe p
+ return (c, arg, polarity)
+
+-- | Reads a line number switch option. The line number switch can be used with
+-- example and source blocks.
+lineNumberSwitch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity)
+lineNumberSwitch = genericSwitch 'n' (many digit)
+
+blockOption :: Monad m => OrgParser m (String, String)
blockOption = try $ do
argKey <- orgArgKey
paramValue <- option "yes" orgParamValue
return (argKey, paramValue)
-orgParamValue :: OrgParser String
+orgParamValue :: Monad m => OrgParser m String
orgParamValue = try $
skipSpaces
- *> notFollowedBy (char ':' )
- *> many1 nonspaceChar
+ *> notFollowedBy orgArgKey
+ *> noneOf "\n\r" `many1Till` endOfValue
<* skipSpaces
-
-horizontalRule :: OrgParser (F Blocks)
-horizontalRule = return B.horizontalRule <$ try hline
+ where
+ endOfValue = lookAhead $ try (skipSpaces <* oneOf "\n\r")
+ <|> try (skipSpaces1 <* orgArgKey)
--
@@ -568,7 +413,7 @@ horizontalRule = return B.horizontalRule <$ try hline
-- | A generic drawer which has no special meaning for org-mode.
-- Whether or not this drawer is included in the output depends on the drawers
-- export setting.
-genericDrawer :: OrgParser (F Blocks)
+genericDrawer :: PandocMonad m => OrgParser m (F Blocks)
genericDrawer = try $ do
name <- map toUpper <$> drawerStart
content <- manyTill drawerLine (try drawerEnd)
@@ -576,44 +421,25 @@ genericDrawer = try $ do
-- Include drawer if it is explicitly included in or not explicitly excluded
-- from the list of drawers that should be exported. PROPERTIES drawers are
-- never exported.
- case (exportDrawers . orgStateExportSettings $ state) of
+ case exportDrawers . orgStateExportSettings $ state of
_ | name == "PROPERTIES" -> return mempty
Left names | name `elem` names -> return mempty
Right names | name `notElem` names -> return mempty
- _ -> drawerDiv name <$> parseLines content
+ _ -> drawerDiv name <$> parseLines content
where
- parseLines :: [String] -> OrgParser (F Blocks)
+ parseLines :: PandocMonad m => [String] -> OrgParser m (F Blocks)
parseLines = parseFromString blocks . (++ "\n") . unlines
drawerDiv :: String -> F Blocks -> F Blocks
drawerDiv drawerName = fmap $ B.divWith (mempty, [drawerName, "drawer"], mempty)
-drawerLine :: OrgParser String
+drawerLine :: Monad m => OrgParser m String
drawerLine = anyLine
-drawerEnd :: OrgParser String
+drawerEnd :: Monad m => OrgParser m String
drawerEnd = try $
skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* newline
--- | Read a :PROPERTIES: drawer and return the key/value pairs contained
--- within.
-propertiesDrawer :: OrgParser Properties
-propertiesDrawer = try $ do
- drawerType <- drawerStart
- guard $ map toUpper drawerType == "PROPERTIES"
- manyTill property (try drawerEnd)
- where
- property :: OrgParser (PropertyKey, PropertyValue)
- property = try $ (,) <$> key <*> value
-
- key :: OrgParser PropertyKey
- key = fmap toPropertyKey . try $
- skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
-
- value :: OrgParser PropertyValue
- value = fmap toPropertyValue . try $
- skipSpaces *> manyTill anyChar (try $ skipSpaces *> newline)
-
--
-- Figures
@@ -621,7 +447,7 @@ propertiesDrawer = try $ do
-- | Figures or an image paragraph (i.e. an image on a line by itself). Only
-- images with a caption attribute are interpreted as figures.
-figure :: OrgParser (F Blocks)
+figure :: PandocMonad m => OrgParser m (F Blocks)
figure = try $ do
figAttrs <- blockAttributes
src <- skipSpaces *> selfTarget <* skipSpaces <* endOfParagraph
@@ -629,10 +455,10 @@ figure = try $ do
Nothing -> mzero
Just imgSrc -> do
guard (isImageFilename imgSrc)
- let isFigure = not . isNothing $ blockAttrCaption figAttrs
+ let isFigure = isJust $ blockAttrCaption figAttrs
return $ imageBlock isFigure figAttrs imgSrc
where
- selfTarget :: OrgParser String
+ selfTarget :: PandocMonad m => OrgParser m String
selfTarget = try $ char '[' *> linkTarget <* char ']'
imageBlock :: Bool -> BlockAttributes -> String -> F Blocks
@@ -654,7 +480,7 @@ figure = try $ do
else "fig:" ++ cs
-- | Succeeds if looking at the end of the current paragraph
-endOfParagraph :: OrgParser ()
+endOfParagraph :: Monad m => OrgParser m ()
endOfParagraph = try $ skipSpaces *> newline *> endOfBlock
@@ -663,11 +489,10 @@ endOfParagraph = try $ skipSpaces *> newline *> endOfBlock
--
-- | Example code marked up by a leading colon.
-example :: OrgParser (F Blocks)
-example = try $ do
- return . return . exampleCode =<< unlines <$> many1 exampleLine
+example :: Monad m => OrgParser m (F Blocks)
+example = try $ returnF . exampleCode =<< unlines <$> many1 exampleLine
where
- exampleLine :: OrgParser String
+ exampleLine :: Monad m => OrgParser m String
exampleLine = try $ exampleLineStart *> anyLine
exampleCode :: String -> Blocks
@@ -678,10 +503,59 @@ exampleCode = B.codeBlockWith ("", ["example"], [])
-- Comments, Options and Metadata
--
-specialLine :: OrgParser (F Blocks)
+specialLine :: PandocMonad m => OrgParser m (F Blocks)
specialLine = fmap return . try $ rawExportLine <|> metaLine <|> commentLine
-rawExportLine :: OrgParser Blocks
+-- | Include the content of a file.
+include :: PandocMonad m => OrgParser m (F Blocks)
+include = try $ do
+ metaLineStart <* stringAnyCase "include:" <* skipSpaces
+ filename <- includeTarget
+ includeArgs <- many (try $ skipSpaces *> many1 alphaNum)
+ params <- keyValues
+ blocksParser <- case includeArgs of
+ ("example" : _) -> return $ pure . B.codeBlock <$> parseRaw
+ ["export"] -> return . returnF $ B.fromList []
+ ["export", format] -> return $ pure . B.rawBlock format <$> parseRaw
+ ("src" : rest) -> do
+ let attr = case rest of
+ [lang] -> (mempty, [lang], mempty)
+ _ -> nullAttr
+ return $ pure . B.codeBlockWith attr <$> parseRaw
+ _ -> return $ return . B.fromList . blockFilter params <$> blockList
+ insertIncludedFileF blocksParser ["."] filename
+ where
+ includeTarget :: PandocMonad m => OrgParser m FilePath
+ includeTarget = do
+ char '"'
+ manyTill (noneOf "\n\r\t") (char '"')
+
+ parseRaw :: PandocMonad m => OrgParser m String
+ parseRaw = many anyChar
+
+ blockFilter :: [(String, String)] -> [Block] -> [Block]
+ blockFilter params blks =
+ let minlvl = lookup "minlevel" params
+ in case (minlvl >>= safeRead :: Maybe Int) of
+ Nothing -> blks
+ Just lvl -> let levels = Walk.query headerLevel blks
+ -- CAVE: partial function in else
+ curMin = if null levels then 0 else minimum levels
+ in Walk.walk (shiftHeader (curMin - lvl)) blks
+
+ headerLevel :: Block -> [Int]
+ headerLevel (Header lvl _attr _content) = [lvl]
+ headerLevel _ = []
+
+ shiftHeader :: Int -> Block -> Block
+ shiftHeader shift blk =
+ if shift <= 0
+ then blk
+ else case blk of
+ (Header lvl attr content) -> Header (lvl - shift) attr content
+ _ -> blk
+
+rawExportLine :: PandocMonad m => OrgParser m Blocks
rawExportLine = try $ do
metaLineStart
key <- metaKey
@@ -689,7 +563,7 @@ rawExportLine = try $ do
then B.rawBlock key <$> anyLine
else mzero
-commentLine :: OrgParser Blocks
+commentLine :: Monad m => OrgParser m Blocks
commentLine = commentLineStart *> anyLine *> pure mempty
@@ -714,12 +588,21 @@ data OrgTableRow = OrgContentRow (F [Blocks])
-- should be generated using a builder function.
data OrgTable = OrgTable
{ orgTableColumnProperties :: [ColumnProperty]
- , orgTableHeader :: [Blocks]
- , orgTableRows :: [[Blocks]]
+ , orgTableHeader :: [Blocks]
+ , orgTableRows :: [[Blocks]]
}
-table :: OrgParser (F Blocks)
-table = try $ do
+table :: PandocMonad m => OrgParser m (F Blocks)
+table = gridTableWith blocks True <|> orgTable
+
+-- | A normal org table
+orgTable :: PandocMonad m => OrgParser m (F Blocks)
+orgTable = try $ do
+ -- don't allow a table on the first line of a list item; org requires that
+ -- tables start at first non-space character on the line
+ let isFirstInListItem st = orgStateParserContext st == ListItemState &&
+ isNothing (orgStateLastPreCharPos st)
+ guard =<< not . isFirstInListItem <$> getState
blockAttrs <- blockAttributes
lookAhead tableStart
do
@@ -731,7 +614,7 @@ orgToPandocTable :: OrgTable
-> Inlines
-> Blocks
orgToPandocTable (OrgTable colProps heads lns) caption =
- let totalWidth = if any (not . isNothing) (map columnRelWidth colProps)
+ let totalWidth = if any isJust (map columnRelWidth colProps)
then Just . sum $ map (fromMaybe 1 . columnRelWidth) colProps
else Nothing
in B.table caption (map (convertColProp totalWidth) colProps) heads lns
@@ -741,22 +624,22 @@ orgToPandocTable (OrgTable colProps heads lns) caption =
let
align' = fromMaybe AlignDefault $ columnAlignment colProp
width' = fromMaybe 0 $ (\w t -> (fromIntegral w / fromIntegral t))
- <$> (columnRelWidth colProp)
+ <$> columnRelWidth colProp
<*> totalWidth
in (align', width')
-tableRows :: OrgParser [OrgTableRow]
+tableRows :: PandocMonad m => OrgParser m [OrgTableRow]
tableRows = try $ many (tableAlignRow <|> tableHline <|> tableContentRow)
-tableContentRow :: OrgParser OrgTableRow
+tableContentRow :: PandocMonad m => OrgParser m OrgTableRow
tableContentRow = try $
OrgContentRow . sequence <$> (tableStart *> many1Till tableContentCell newline)
-tableContentCell :: OrgParser (F Blocks)
+tableContentCell :: PandocMonad m => OrgParser m (F Blocks)
tableContentCell = try $
fmap B.plain . trimInlinesF . mconcat <$> manyTill inline endOfCell
-tableAlignRow :: OrgParser OrgTableRow
+tableAlignRow :: Monad m => OrgParser m OrgTableRow
tableAlignRow = try $ do
tableStart
colProps <- many1Till columnPropertyCell newline
@@ -764,10 +647,10 @@ tableAlignRow = try $ do
guard $ any (/= def) colProps
return $ OrgAlignRow colProps
-columnPropertyCell :: OrgParser ColumnProperty
+columnPropertyCell :: Monad m => OrgParser m ColumnProperty
columnPropertyCell = emptyCell <|> propCell <?> "alignment info"
where
- emptyCell = ColumnProperty Nothing Nothing <$ (try $ skipSpaces *> endOfCell)
+ emptyCell = ColumnProperty Nothing Nothing <$ try (skipSpaces *> endOfCell)
propCell = try $ ColumnProperty
<$> (skipSpaces
*> char '<'
@@ -776,18 +659,18 @@ columnPropertyCell = emptyCell <|> propCell <?> "alignment info"
<* char '>'
<* emptyCell)
-tableAlignFromChar :: OrgParser Alignment
+tableAlignFromChar :: Monad m => OrgParser m Alignment
tableAlignFromChar = try $
choice [ char 'l' *> return AlignLeft
, char 'c' *> return AlignCenter
, char 'r' *> return AlignRight
]
-tableHline :: OrgParser OrgTableRow
+tableHline :: Monad m => OrgParser m OrgTableRow
tableHline = try $
OrgHlineRow <$ (tableStart *> char '-' *> anyLine)
-endOfCell :: OrgParser Char
+endOfCell :: Monad m => OrgParser m Char
endOfCell = try $ char '|' <|> lookAhead newline
rowsToTable :: [OrgTableRow]
@@ -813,45 +696,45 @@ normalizeTable (OrgTable colProps heads rows) =
rowToContent :: OrgTable
-> OrgTableRow
-> F OrgTable
-rowToContent orgTable row =
+rowToContent tbl row =
case row of
OrgHlineRow -> return singleRowPromotedToHeader
OrgAlignRow props -> return . setProperties $ props
OrgContentRow cs -> appendToBody cs
where
singleRowPromotedToHeader :: OrgTable
- singleRowPromotedToHeader = case orgTable of
- OrgTable{ orgTableHeader = [], orgTableRows = b:[] } ->
- orgTable{ orgTableHeader = b , orgTableRows = [] }
- _ -> orgTable
+ singleRowPromotedToHeader = case tbl of
+ OrgTable{ orgTableHeader = [], orgTableRows = [b] } ->
+ tbl{ orgTableHeader = b , orgTableRows = [] }
+ _ -> tbl
setProperties :: [ColumnProperty] -> OrgTable
- setProperties ps = orgTable{ orgTableColumnProperties = ps }
+ setProperties ps = tbl{ orgTableColumnProperties = ps }
appendToBody :: F [Blocks] -> F OrgTable
appendToBody frow = do
newRow <- frow
- let oldRows = orgTableRows orgTable
+ let oldRows = orgTableRows tbl
-- NOTE: This is an inefficient O(n) operation. This should be changed
-- if performance ever becomes a problem.
- return orgTable{ orgTableRows = oldRows ++ [newRow] }
+ return tbl{ orgTableRows = oldRows ++ [newRow] }
--
-- LaTeX fragments
--
-latexFragment :: OrgParser (F Blocks)
+latexFragment :: Monad m => OrgParser m (F Blocks)
latexFragment = try $ do
envName <- latexEnvStart
content <- mconcat <$> manyTill anyLineNewline (latexEnd envName)
- return . return $ B.rawBlock "latex" (content `inLatexEnv` envName)
+ returnF $ B.rawBlock "latex" (content `inLatexEnv` envName)
where
c `inLatexEnv` e = mconcat [ "\\begin{", e, "}\n"
, c
, "\\end{", e, "}\n"
]
-latexEnd :: String -> OrgParser ()
+latexEnd :: Monad m => String -> OrgParser m ()
latexEnd envName = try $
() <$ skipSpaces
<* string ("\\end{" ++ envName ++ "}")
@@ -861,74 +744,70 @@ latexEnd envName = try $
--
-- Footnote defintions
--
-noteBlock :: OrgParser (F Blocks)
+noteBlock :: PandocMonad m => OrgParser m (F Blocks)
noteBlock = try $ do
- ref <- noteMarker <* skipSpaces
- content <- mconcat <$> blocksTillHeaderOrNote
+ ref <- noteMarker <* skipSpaces <* updateLastPreCharPos
+ content <- mconcat <$> many1Till block endOfFootnote
addToNotesTable (ref, content)
return mempty
where
- blocksTillHeaderOrNote =
- many1Till block (eof <|> () <$ lookAhead noteMarker
- <|> () <$ lookAhead headerStart)
+ endOfFootnote = eof
+ <|> () <$ lookAhead noteMarker
+ <|> () <$ lookAhead headerStart
+ <|> () <$ lookAhead (try $ blankline *> blankline)
-- Paragraphs or Plain text
-paraOrPlain :: OrgParser (F Blocks)
+paraOrPlain :: PandocMonad m => OrgParser m (F Blocks)
paraOrPlain = try $ do
-- Make sure we are not looking at a headline
- notFollowedBy' (char '*' *> (oneOf " *"))
+ notFollowedBy' headerStart
ils <- inlines
nl <- option False (newline *> return True)
-- Read block as paragraph, except if we are in a list context and the block
-- is directly followed by a list item, in which case the block is read as
-- plain text.
try (guard nl
- *> notFollowedBy (inList *> (() <$ orderedListStart <|> bulletListStart))
+ *> notFollowedBy (inList *> (orderedListStart <|> bulletListStart))
*> return (B.para <$> ils))
- <|> (return (B.plain <$> ils))
+ <|> return (B.plain <$> ils)
--
-- list blocks
--
-list :: OrgParser (F Blocks)
+list :: PandocMonad m => OrgParser m (F Blocks)
list = choice [ definitionList, bulletList, orderedList ] <?> "list"
-definitionList :: OrgParser (F Blocks)
-definitionList = try $ do n <- lookAhead (bulletListStart' Nothing)
- fmap B.definitionList . fmap compactify'DL . sequence
- <$> many1 (definitionListItem $ bulletListStart' (Just n))
-
-bulletList :: OrgParser (F Blocks)
-bulletList = try $ do n <- lookAhead (bulletListStart' Nothing)
- fmap B.bulletList . fmap compactify' . sequence
- <$> many1 (listItem (bulletListStart' $ Just n))
-
-orderedList :: OrgParser (F Blocks)
-orderedList = fmap B.orderedList . fmap compactify' . sequence
- <$> many1 (listItem orderedListStart)
-
-bulletListStart' :: Maybe Int -> OrgParser Int
--- returns length of bulletList prefix, inclusive of marker
-bulletListStart' Nothing = do ind <- length <$> many spaceChar
- oneOf (bullets $ ind == 0)
- skipSpaces1
- return (ind + 1)
-bulletListStart' (Just n) = do count (n-1) spaceChar
- oneOf (bullets $ n == 1)
- many1 spaceChar
- return n
-
--- Unindented lists are legal, but they can't use '*' bullets.
--- We return n to maintain compatibility with the generic listItem.
-bullets :: Bool -> String
-bullets unindented = if unindented then "+-" else "*+-"
-
-definitionListItem :: OrgParser Int
- -> OrgParser (F (Inlines, [Blocks]))
-definitionListItem parseMarkerGetLength = try $ do
- markerLength <- parseMarkerGetLength
+definitionList :: PandocMonad m => OrgParser m (F Blocks)
+definitionList = try $ do
+ indent <- lookAhead bulletListStart
+ fmap (B.definitionList . compactifyDL) . sequence
+ <$> many1 (definitionListItem (bulletListStart `indented` indent))
+
+bulletList :: PandocMonad m => OrgParser m (F Blocks)
+bulletList = try $ do
+ indent <- lookAhead bulletListStart
+ fmap (B.bulletList . compactify) . sequence
+ <$> many1 (listItem (bulletListStart `indented` indent))
+
+indented :: Monad m => OrgParser m Int -> Int -> OrgParser m Int
+indented indentedMarker minIndent = try $ do
+ n <- indentedMarker
+ guard (minIndent <= n)
+ return n
+
+orderedList :: PandocMonad m => OrgParser m (F Blocks)
+orderedList = try $ do
+ indent <- lookAhead orderedListStart
+ fmap (B.orderedList . compactify) . sequence
+ <$> many1 (listItem (orderedListStart `indented` indent))
+
+definitionListItem :: PandocMonad m
+ => OrgParser m Int
+ -> OrgParser m (F (Inlines, [Blocks]))
+definitionListItem parseIndentedMarker = try $ do
+ markerLength <- parseIndentedMarker
term <- manyTill (noneOf "\n\r") (try definitionMarker)
line1 <- anyLineNewline
blank <- option "" ("\n" <$ blankline)
@@ -940,12 +819,12 @@ definitionListItem parseMarkerGetLength = try $ do
definitionMarker =
spaceChar *> string "::" <* (spaceChar <|> lookAhead newline)
-
--- parse raw text for one list item, excluding start marker and continuations
-listItem :: OrgParser Int
- -> OrgParser (F Blocks)
-listItem start = try . withContext ListItemState $ do
- markerLength <- try start
+-- | parse raw text for one list item
+listItem :: PandocMonad m
+ => OrgParser m Int
+ -> OrgParser m (F Blocks)
+listItem parseIndentedMarker = try . withContext ListItemState $ do
+ markerLength <- try parseIndentedMarker
firstLine <- anyLineNewline
blank <- option "" ("\n" <$ blankline)
rest <- concat <$> many (listContinuation markerLength)
@@ -953,24 +832,11 @@ listItem start = try . withContext ListItemState $ do
-- continuation of a list item - indented and separated by blankline or endline.
-- Note: nested lists are parsed as continuations.
-listContinuation :: Int
- -> OrgParser String
-listContinuation markerLength = try $
+listContinuation :: Monad m => Int
+ -> OrgParser m String
+listContinuation markerLength = try $ do
notFollowedBy' blankline
- *> (mappend <$> (concat <$> many1 listLine)
- <*> many blankline)
+ mappend <$> (concat <$> many1 listLine)
+ <*> many blankline
where
listLine = try $ indentWith markerLength *> anyLineNewline
-
- -- indent by specified number of spaces (or equiv. tabs)
- indentWith :: Int -> OrgParser String
- indentWith num = do
- tabStop <- getOption readerTabStop
- if num < tabStop
- then count num (char ' ')
- else choice [ try (count num (char ' '))
- , try (char '\t' >> count (num - tabStop) (char ' ')) ]
-
--- | Parse any line, include the final newline in the output.
-anyLineNewline :: OrgParser String
-anyLineNewline = (++ "\n") <$> anyLine
diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs
new file mode 100644
index 000000000..f77778ec9
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs
@@ -0,0 +1,304 @@
+{-
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ViewPatterns #-}
+{- |
+ Module : Text.Pandoc.Readers.Org.DocumentTree
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+Parsers for org-mode headlines and document subtrees
+-}
+module Text.Pandoc.Readers.Org.DocumentTree
+ ( documentTree
+ , headlineToBlocks
+ ) where
+
+import Control.Arrow ((***))
+import Control.Monad (guard, void)
+import Data.Char (toLower, toUpper)
+import Data.List (intersperse)
+import Data.Monoid ((<>))
+import Text.Pandoc.Builder (Blocks, Inlines)
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Definition
+import Text.Pandoc.Readers.Org.BlockStarts
+import Text.Pandoc.Readers.Org.ParserState
+import Text.Pandoc.Readers.Org.Parsing
+
+import qualified Data.Map as Map
+import qualified Text.Pandoc.Builder as B
+
+--
+-- Org headers
+--
+
+-- | Parse input as org document tree.
+documentTree :: PandocMonad m
+ => OrgParser m (F Blocks)
+ -> OrgParser m (F Inlines)
+ -> OrgParser m (F Headline)
+documentTree blocks inline = do
+ initialBlocks <- blocks
+ headlines <- sequence <$> manyTill (headline blocks inline 1) eof
+ title <- fmap (getTitle . unMeta) . orgStateMeta <$> getState
+ return $ do
+ headlines' <- headlines
+ initialBlocks' <- initialBlocks
+ title' <- title
+ return Headline
+ { headlineLevel = 0
+ , headlineTodoMarker = Nothing
+ , headlineText = B.fromList title'
+ , headlineTags = mempty
+ , headlineProperties = mempty
+ , headlineContents = initialBlocks'
+ , headlineChildren = headlines'
+ }
+ where
+ getTitle :: Map.Map String MetaValue -> [Inline]
+ getTitle metamap =
+ case Map.lookup "title" metamap of
+ Just (MetaInlines inlns) -> inlns
+ _ -> []
+
+newtype Tag = Tag { fromTag :: String }
+ deriving (Show, Eq)
+
+-- | Create a tag containing the given string.
+toTag :: String -> Tag
+toTag = Tag
+
+-- | The key (also called name or type) of a property.
+newtype PropertyKey = PropertyKey { fromKey :: String }
+ deriving (Show, Eq, Ord)
+
+-- | Create a property key containing the given string. Org mode keys are
+-- case insensitive and are hence converted to lower case.
+toPropertyKey :: String -> PropertyKey
+toPropertyKey = PropertyKey . map toLower
+
+-- | The value assigned to a property.
+newtype PropertyValue = PropertyValue { fromValue :: String }
+
+-- | Create a property value containing the given string.
+toPropertyValue :: String -> PropertyValue
+toPropertyValue = PropertyValue
+
+-- | Check whether the property value is non-nil (i.e. truish).
+isNonNil :: PropertyValue -> Bool
+isNonNil p = map toLower (fromValue p) `notElem` ["()", "{}", "nil"]
+
+-- | Key/value pairs from a PROPERTIES drawer
+type Properties = [(PropertyKey, PropertyValue)]
+
+-- | Org mode headline (i.e. a document subtree).
+data Headline = Headline
+ { headlineLevel :: Int
+ , headlineTodoMarker :: Maybe TodoMarker
+ , headlineText :: Inlines
+ , headlineTags :: [Tag]
+ , headlineProperties :: Properties
+ , headlineContents :: Blocks
+ , headlineChildren :: [Headline]
+ }
+
+-- | Read an Org mode headline and its contents (i.e. a document subtree).
+-- @lvl@ gives the minimum acceptable level of the tree.
+headline :: PandocMonad m
+ => OrgParser m (F Blocks)
+ -> OrgParser m (F Inlines)
+ -> Int
+ -> OrgParser m (F Headline)
+headline blocks inline lvl = try $ do
+ level <- headerStart
+ guard (lvl <= level)
+ todoKw <- optionMaybe todoKeyword
+ title <- trimInlinesF . mconcat <$> manyTill inline endOfTitle
+ tags <- option [] headerTags
+ newline
+ properties <- option mempty propertiesDrawer
+ contents <- blocks
+ children <- many (headline blocks inline (level + 1))
+ return $ do
+ title' <- title
+ contents' <- contents
+ children' <- sequence children
+ return Headline
+ { headlineLevel = level
+ , headlineTodoMarker = todoKw
+ , headlineText = title'
+ , headlineTags = tags
+ , headlineProperties = properties
+ , headlineContents = contents'
+ , headlineChildren = children'
+ }
+ where
+ endOfTitle :: Monad m => OrgParser m ()
+ endOfTitle = void . lookAhead $ optional headerTags *> newline
+
+ headerTags :: Monad m => OrgParser m [Tag]
+ headerTags = try $
+ let tag = many1 (alphaNum <|> oneOf "@%#_") <* char ':'
+ in map toTag <$> (skipSpaces *> char ':' *> many1 tag <* skipSpaces)
+
+-- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks
+headlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
+headlineToBlocks hdln@Headline {..} = do
+ maxHeadlineLevels <- getExportSetting exportHeadlineLevels
+ case () of
+ _ | any isNoExportTag headlineTags -> return mempty
+ _ | any isArchiveTag headlineTags -> archivedHeadlineToBlocks hdln
+ _ | isCommentTitle headlineText -> return mempty
+ _ | headlineLevel >= maxHeadlineLevels -> headlineToHeaderWithList hdln
+ _ | otherwise -> headlineToHeaderWithContents hdln
+
+isNoExportTag :: Tag -> Bool
+isNoExportTag = (== toTag "noexport")
+
+isArchiveTag :: Tag -> Bool
+isArchiveTag = (== toTag "ARCHIVE")
+
+-- | Check if the title starts with COMMENT.
+-- FIXME: This accesses builder internals not intended for use in situations
+-- like these. Replace once keyword parsing is supported.
+isCommentTitle :: Inlines -> Bool
+isCommentTitle (B.toList -> (Str "COMMENT":_)) = True
+isCommentTitle _ = False
+
+archivedHeadlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
+archivedHeadlineToBlocks hdln = do
+ archivedTreesOption <- getExportSetting exportArchivedTrees
+ case archivedTreesOption of
+ ArchivedTreesNoExport -> return mempty
+ ArchivedTreesExport -> headlineToHeaderWithContents hdln
+ ArchivedTreesHeadlineOnly -> headlineToHeader hdln
+
+headlineToHeaderWithList :: Monad m => Headline -> OrgParser m Blocks
+headlineToHeaderWithList hdln@Headline {..} = do
+ maxHeadlineLevels <- getExportSetting exportHeadlineLevels
+ header <- headlineToHeader hdln
+ listElements <- mapM headlineToBlocks headlineChildren
+ let listBlock = if null listElements
+ then mempty
+ else B.orderedList listElements
+ let headerText = if maxHeadlineLevels == headlineLevel
+ then header
+ else flattenHeader header
+ return $ headerText <> headlineContents <> listBlock
+ where
+ flattenHeader :: Blocks -> Blocks
+ flattenHeader blks =
+ case B.toList blks of
+ (Header _ _ inlns:_) -> B.para (B.fromList inlns)
+ _ -> mempty
+
+headlineToHeaderWithContents :: Monad m => Headline -> OrgParser m Blocks
+headlineToHeaderWithContents hdln@Headline {..} = do
+ header <- headlineToHeader hdln
+ childrenBlocks <- mconcat <$> mapM headlineToBlocks headlineChildren
+ return $ header <> headlineContents <> childrenBlocks
+
+headlineToHeader :: Monad m => Headline -> OrgParser m Blocks
+headlineToHeader Headline {..} = do
+ exportTodoKeyword <- getExportSetting exportWithTodoKeywords
+ exportTags <- getExportSetting exportWithTags
+ let todoText = if exportTodoKeyword
+ then case headlineTodoMarker of
+ Just kw -> todoKeywordToInlines kw <> B.space
+ Nothing -> mempty
+ else mempty
+ let text = todoText <> headlineText <>
+ if exportTags
+ then tagsToInlines headlineTags
+ else mempty
+ let propAttr = propertiesToAttr headlineProperties
+ attr <- registerHeader propAttr headlineText
+ return $ B.headerWith attr headlineLevel text
+
+todoKeyword :: Monad m => OrgParser m TodoMarker
+todoKeyword = try $ do
+ taskStates <- activeTodoMarkers <$> getState
+ let kwParser tdm = try (tdm <$ string (todoMarkerName tdm) <* spaceChar)
+ choice (map kwParser taskStates)
+
+todoKeywordToInlines :: TodoMarker -> Inlines
+todoKeywordToInlines tdm =
+ let todoText = todoMarkerName tdm
+ todoState = map toLower . show $ todoMarkerState tdm
+ classes = [todoState, todoText]
+ in B.spanWith (mempty, classes, mempty) (B.str todoText)
+
+propertiesToAttr :: Properties -> Attr
+propertiesToAttr properties =
+ let
+ toStringPair = fromKey *** fromValue
+ customIdKey = toPropertyKey "custom_id"
+ classKey = toPropertyKey "class"
+ unnumberedKey = toPropertyKey "unnumbered"
+ specialProperties = [customIdKey, classKey, unnumberedKey]
+ id' = maybe mempty fromValue . lookup customIdKey $ properties
+ cls = maybe mempty fromValue . lookup classKey $ properties
+ kvs' = map toStringPair . filter ((`notElem` specialProperties) . fst)
+ $ properties
+ isUnnumbered =
+ maybe False isNonNil . lookup unnumberedKey $ properties
+ in
+ (id', words cls ++ ["unnumbered" | isUnnumbered], kvs')
+
+tagsToInlines :: [Tag] -> Inlines
+tagsToInlines [] = mempty
+tagsToInlines tags =
+ (B.space <>) . mconcat . intersperse (B.str "\160") . map tagToInline $ tags
+ where
+ tagToInline :: Tag -> Inlines
+ tagToInline t = tagSpan t . B.smallcaps . B.str $ fromTag t
+
+-- | Wrap the given inline in a span, marking it as a tag.
+tagSpan :: Tag -> Inlines -> Inlines
+tagSpan t = B.spanWith ("", ["tag"], [("tag-name", fromTag t)])
+
+
+
+
+
+-- | Read a :PROPERTIES: drawer and return the key/value pairs contained
+-- within.
+propertiesDrawer :: Monad m => OrgParser m Properties
+propertiesDrawer = try $ do
+ drawerType <- drawerStart
+ guard $ map toUpper drawerType == "PROPERTIES"
+ manyTill property (try endOfDrawer)
+ where
+ property :: Monad m => OrgParser m (PropertyKey, PropertyValue)
+ property = try $ (,) <$> key <*> value
+
+ key :: Monad m => OrgParser m PropertyKey
+ key = fmap toPropertyKey . try $
+ skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
+
+ value :: Monad m => OrgParser m PropertyValue
+ value = fmap toPropertyValue . try $
+ skipSpaces *> manyTill anyChar (try $ skipSpaces *> newline)
+
+ endOfDrawer :: Monad m => OrgParser m String
+ endOfDrawer = try $
+ skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* newline
diff --git a/src/Text/Pandoc/Readers/Org/ExportSettings.hs b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
index 764e5b0d5..6a70c50b9 100644
--- a/src/Text/Pandoc/Readers/Org/ExportSettings.hs
+++ b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2016-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,8 +17,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.ExportSettings
+ Copyright : © 2016–2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -29,22 +29,22 @@ module Text.Pandoc.Readers.Org.ExportSettings
( exportSettings
) where
-import Text.Pandoc.Readers.Org.ParserState
-import Text.Pandoc.Readers.Org.Parsing
+import Text.Pandoc.Readers.Org.ParserState
+import Text.Pandoc.Readers.Org.Parsing
-import Control.Monad ( mzero, void )
-import Data.Char ( toLower )
-import Data.Maybe ( listToMaybe )
+import Control.Monad (mzero, void)
+import Data.Char (toLower)
+import Data.Maybe (listToMaybe)
-- | Read and handle space separated org-mode export settings.
-exportSettings :: OrgParser ()
+exportSettings :: Monad m => OrgParser m ()
exportSettings = void $ sepBy spaces exportSetting
-- | Setter function for export settings.
type ExportSettingSetter a = a -> ExportSettings -> ExportSettings
-- | Read and process a single org-mode export option.
-exportSetting :: OrgParser ()
+exportSetting :: Monad m => OrgParser m ()
exportSetting = choice
[ booleanSetting "^" (\val es -> es { exportSubSuperscripts = val })
, booleanSetting "'" (\val es -> es { exportSmartQuotes = val })
@@ -52,7 +52,7 @@ exportSetting = choice
, booleanSetting "-" (\val es -> es { exportSpecialStrings = val })
, ignoredSetting ":"
, ignoredSetting "<"
- , ignoredSetting "\\n"
+ , booleanSetting "\\n" (\val es -> es { exportPreserveBreaks = val })
, archivedTreeSetting "arch" (\val es -> es { exportArchivedTrees = val })
, booleanSetting "author" (\val es -> es { exportWithAuthor = val })
, ignoredSetting "c"
@@ -71,7 +71,7 @@ exportSetting = choice
, ignoredSetting "pri"
, ignoredSetting "prop"
, ignoredSetting "stat"
- , ignoredSetting "tags"
+ , booleanSetting "tags" (\val es -> es { exportWithTags = val })
, ignoredSetting "tasks"
, ignoredSetting "tex"
, ignoredSetting "timestamp"
@@ -81,10 +81,11 @@ exportSetting = choice
, ignoredSetting "|"
] <?> "export setting"
-genericExportSetting :: OrgParser a
+genericExportSetting :: Monad m
+ => OrgParser m a
-> String
-> ExportSettingSetter a
- -> OrgParser ()
+ -> OrgParser m ()
genericExportSetting optionParser settingIdentifier setter = try $ do
_ <- string settingIdentifier *> char ':'
value <- optionParser
@@ -94,11 +95,11 @@ genericExportSetting optionParser settingIdentifier setter = try $ do
st { orgStateExportSettings = setter val . orgStateExportSettings $ st }
-- | A boolean option, either nil (False) or non-nil (True).
-booleanSetting :: String -> ExportSettingSetter Bool -> OrgParser ()
+booleanSetting :: Monad m => String -> ExportSettingSetter Bool -> OrgParser m ()
booleanSetting = genericExportSetting elispBoolean
-- | An integer-valued option.
-integerSetting :: String -> ExportSettingSetter Int -> OrgParser ()
+integerSetting :: Monad m => String -> ExportSettingSetter Int -> OrgParser m ()
integerSetting = genericExportSetting parseInt
where
parseInt = try $
@@ -106,9 +107,10 @@ integerSetting = genericExportSetting parseInt
-- | Either the string "headline" or an elisp boolean and treated as an
-- @ArchivedTreesOption@.
-archivedTreeSetting :: String
+archivedTreeSetting :: Monad m
+ => String
-> ExportSettingSetter ArchivedTreesOption
- -> OrgParser ()
+ -> OrgParser m ()
archivedTreeSetting =
genericExportSetting $ archivedTreesHeadlineSetting <|> archivedTreesBoolean
where
@@ -125,9 +127,10 @@ archivedTreeSetting =
else ArchivedTreesNoExport
-- | A list or a complement list (i.e. a list starting with `not`).
-complementableListSetting :: String
+complementableListSetting :: Monad m
+ => String
-> ExportSettingSetter (Either [String] [String])
- -> OrgParser ()
+ -> OrgParser m ()
complementableListSetting = genericExportSetting $ choice
[ Left <$> complementStringList
, Right <$> stringList
@@ -135,31 +138,31 @@ complementableListSetting = genericExportSetting $ choice
]
where
-- Read a plain list of strings.
- stringList :: OrgParser [String]
+ stringList :: Monad m => OrgParser m [String]
stringList = try $
char '('
*> sepBy elispString spaces
<* char ')'
-- Read an emacs lisp list specifying a complement set.
- complementStringList :: OrgParser [String]
+ complementStringList :: Monad m => OrgParser m [String]
complementStringList = try $
string "(not "
*> sepBy elispString spaces
<* char ')'
- elispString :: OrgParser String
+ elispString :: Monad m => OrgParser m String
elispString = try $
char '"'
*> manyTill alphaNum (char '"')
-- | Read but ignore the export setting.
-ignoredSetting :: String -> OrgParser ()
+ignoredSetting :: Monad m => String -> OrgParser m ()
ignoredSetting s = try (() <$ string s <* char ':' <* many1 nonspaceChar)
-- | Read an elisp boolean. Only NIL is treated as false, non-NIL values are
-- interpreted as true.
-elispBoolean :: OrgParser Bool
+elispBoolean :: Monad m => OrgParser m Bool
elispBoolean = try $ do
value <- many1 nonspaceChar
return $ case map toLower value of
diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs
index 7e1bb61c2..3a12f38d0 100644
--- a/src/Text/Pandoc/Readers/Org/Inlines.hs
+++ b/src/Text/Pandoc/Readers/Org/Inlines.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,8 +18,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.Inlines
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,73 +33,75 @@ module Text.Pandoc.Readers.Org.Inlines
, linkTarget
) where
-import Text.Pandoc.Readers.Org.BlockStarts ( endOfBlock, noteMarker )
-import Text.Pandoc.Readers.Org.ParserState
-import Text.Pandoc.Readers.Org.Parsing
-import Text.Pandoc.Readers.Org.Shared
- ( cleanLinkString, isImageFilename, rundocBlockClass
- , toRundocAttrib, translateLang )
+import Text.Pandoc.Readers.Org.BlockStarts (endOfBlock, noteMarker)
+import Text.Pandoc.Readers.Org.ParserState
+import Text.Pandoc.Readers.Org.Parsing
+import Text.Pandoc.Readers.Org.Shared (cleanLinkString, isImageFilename,
+ originalLang, translateLang)
+import Text.Pandoc.Builder (Inlines)
import qualified Text.Pandoc.Builder as B
-import Text.Pandoc.Builder ( Inlines )
-import Text.Pandoc.Definition
-import Text.Pandoc.Options
-import Text.Pandoc.Readers.LaTeX ( inlineCommand, rawLaTeXInline )
-import Text.TeXMath ( readTeX, writePandoc, DisplayType(..) )
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
+import Text.Pandoc.Shared (underlineSpan)
+import Text.TeXMath (DisplayType (..), readTeX, writePandoc)
import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
-import Prelude hiding (sequence)
-import Control.Monad ( guard, mplus, mzero, when, void )
-import Data.Char ( isAlphaNum, isSpace )
-import Data.List ( intersperse )
-import Data.Maybe ( fromMaybe )
+import Control.Monad (guard, mplus, mzero, unless, void, when)
+import Control.Monad.Trans (lift)
+import Data.Char (isAlphaNum, isSpace)
+import Data.List (intersperse)
import qualified Data.Map as M
-import Data.Monoid ( (<>) )
-import Data.Traversable (sequence)
+import Data.Maybe (fromMaybe)
+import Data.Monoid ((<>))
+import Data.Traversable (sequence)
+import Prelude hiding (sequence)
--
-- Functions acting on the parser state
--
-recordAnchorId :: String -> OrgParser ()
+recordAnchorId :: PandocMonad m => String -> OrgParser m ()
recordAnchorId i = updateState $ \s ->
- s{ orgStateAnchorIds = i : (orgStateAnchorIds s) }
+ s{ orgStateAnchorIds = i : orgStateAnchorIds s }
-pushToInlineCharStack :: Char -> OrgParser ()
+pushToInlineCharStack :: PandocMonad m => Char -> OrgParser m ()
pushToInlineCharStack c = updateState $ \s ->
s{ orgStateEmphasisCharStack = c:orgStateEmphasisCharStack s }
-popInlineCharStack :: OrgParser ()
+popInlineCharStack :: PandocMonad m => OrgParser m ()
popInlineCharStack = updateState $ \s ->
s{ orgStateEmphasisCharStack = drop 1 . orgStateEmphasisCharStack $ s }
-surroundingEmphasisChar :: OrgParser [Char]
+surroundingEmphasisChar :: PandocMonad m => OrgParser m [Char]
surroundingEmphasisChar =
take 1 . drop 1 . orgStateEmphasisCharStack <$> getState
-startEmphasisNewlinesCounting :: Int -> OrgParser ()
+startEmphasisNewlinesCounting :: PandocMonad m => Int -> OrgParser m ()
startEmphasisNewlinesCounting maxNewlines = updateState $ \s ->
s{ orgStateEmphasisNewlines = Just maxNewlines }
-decEmphasisNewlinesCount :: OrgParser ()
+decEmphasisNewlinesCount :: PandocMonad m => OrgParser m ()
decEmphasisNewlinesCount = updateState $ \s ->
s{ orgStateEmphasisNewlines = (\n -> n - 1) <$> orgStateEmphasisNewlines s }
-newlinesCountWithinLimits :: OrgParser Bool
+newlinesCountWithinLimits :: PandocMonad m => OrgParser m Bool
newlinesCountWithinLimits = do
st <- getState
return $ ((< 0) <$> orgStateEmphasisNewlines st) /= Just True
-resetEmphasisNewlines :: OrgParser ()
+resetEmphasisNewlines :: PandocMonad m => OrgParser m ()
resetEmphasisNewlines = updateState $ \s ->
s{ orgStateEmphasisNewlines = Nothing }
-addToNotesTable :: OrgNoteRecord -> OrgParser ()
+addToNotesTable :: PandocMonad m => OrgNoteRecord -> OrgParser m ()
addToNotesTable note = do
oldnotes <- orgStateNotes' <$> getState
updateState $ \s -> s{ orgStateNotes' = note:oldnotes }
-- | Parse a single Org-mode inline element
-inline :: OrgParser (F Inlines)
+inline :: PandocMonad m => OrgParser m (F Inlines)
inline =
choice [ whitespace
, linebreak
@@ -119,13 +121,14 @@ inline =
, superscript
, inlineLaTeX
, exportSnippet
+ , macro
, smart
, symbol
] <* (guard =<< newlinesCountWithinLimits)
<?> "inline"
-- | Read the rest of the input as inlines.
-inlines :: OrgParser (F Inlines)
+inlines :: PandocMonad m => OrgParser m (F Inlines)
inlines = trimInlinesF . mconcat <$> many1 inline
-- treat these as potentially non-text when parsing inline:
@@ -133,30 +136,31 @@ specialChars :: [Char]
specialChars = "\"$'()*+-,./:;<=>@[\\]^_{|}~"
-whitespace :: OrgParser (F Inlines)
+whitespace :: PandocMonad m => OrgParser m (F Inlines)
whitespace = pure B.space <$ skipMany1 spaceChar
<* updateLastPreCharPos
<* updateLastForbiddenCharPos
<?> "whitespace"
-linebreak :: OrgParser (F Inlines)
+linebreak :: PandocMonad m => OrgParser m (F Inlines)
linebreak = try $ pure B.linebreak <$ string "\\\\" <* skipSpaces <* newline
-str :: OrgParser (F Inlines)
+str :: PandocMonad m => OrgParser m (F Inlines)
str = return . B.str <$> many1 (noneOf $ specialChars ++ "\n\r ")
<* updateLastStrPos
-- | An endline character that can be treated as a space, not a structural
-- break. This should reflect the values of the Emacs variable
-- @org-element-pagaraph-separate@.
-endline :: OrgParser (F Inlines)
+endline :: PandocMonad m => OrgParser m (F Inlines)
endline = try $ do
newline
notFollowedBy' endOfBlock
decEmphasisNewlinesCount
guard =<< newlinesCountWithinLimits
updateLastPreCharPos
- return . return $ B.softbreak
+ useHardBreaks <- exportPreserveBreaks . orgStateExportSettings <$> getState
+ returnF (if useHardBreaks then B.linebreak else B.softbreak)
--
@@ -174,7 +178,7 @@ endline = try $ do
-- contributors. All this should be consolidated once an official Org-mode
-- citation syntax has emerged.
-cite :: OrgParser (F Inlines)
+cite :: PandocMonad m => OrgParser m (F Inlines)
cite = try $ berkeleyCite <|> do
guardEnabled Ext_citations
(cs, raw) <- withRaw $ choice
@@ -182,43 +186,44 @@ cite = try $ berkeleyCite <|> do
, orgRefCite
, berkeleyTextualCite
]
- return $ (flip B.cite (B.text raw)) <$> cs
+ return $ flip B.cite (B.text raw) <$> cs
-- | A citation in Pandoc Org-mode style (@[prefix \@citekey suffix]@).
-pandocOrgCite :: OrgParser (F [Citation])
+pandocOrgCite :: PandocMonad m => OrgParser m (F [Citation])
pandocOrgCite = try $
char '[' *> skipSpaces *> citeList <* skipSpaces <* char ']'
-orgRefCite :: OrgParser (F [Citation])
+orgRefCite :: PandocMonad m => OrgParser m (F [Citation])
orgRefCite = try $ choice
[ normalOrgRefCite
, fmap (:[]) <$> linkLikeOrgRefCite
]
-normalOrgRefCite :: OrgParser (F [Citation])
+normalOrgRefCite :: PandocMonad m => OrgParser m (F [Citation])
normalOrgRefCite = try $ do
mode <- orgRefCiteMode
- -- org-ref style citation key, parsed into a citation of the given mode
- let orgRefCiteItem :: OrgParser (F Citation)
- orgRefCiteItem = try $ do
- key <- orgRefCiteKey
- returnF $ Citation
- { citationId = key
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = mode
- , citationNoteNum = 0
- , citationHash = 0
- }
- firstCitation <- orgRefCiteItem
- moreCitations <- many (try $ char ',' *> orgRefCiteItem)
+ firstCitation <- orgRefCiteList mode
+ moreCitations <- many (try $ char ',' *> orgRefCiteList mode)
return . sequence $ firstCitation : moreCitations
- where
+ where
+ -- | A list of org-ref style citation keys, parsed as citation of the given
+ -- citation mode.
+ orgRefCiteList :: PandocMonad m => CitationMode -> OrgParser m (F Citation)
+ orgRefCiteList citeMode = try $ do
+ key <- orgRefCiteKey
+ returnF Citation
+ { citationId = key
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = citeMode
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
-- | Read an Berkeley-style Org-mode citation. Berkeley citation style was
-- develop and adjusted to Org-mode style by John MacFarlane and Richard
-- Lawrence, respectively, both philosophers at UC Berkeley.
-berkeleyCite :: OrgParser (F Inlines)
+berkeleyCite :: PandocMonad m => OrgParser m (F Inlines)
berkeleyCite = try $ do
bcl <- berkeleyCitationList
return $ do
@@ -229,11 +234,11 @@ berkeleyCite = try $ do
return $
if parens
then toCite
- . maybe id (\p -> alterFirst (prependPrefix p)) prefix
- . maybe id (\s -> alterLast (appendSuffix s)) suffix
+ . maybe id (alterFirst . prependPrefix) prefix
+ . maybe id (alterLast . appendSuffix) suffix
$ citationList
else maybe mempty (<> " ") prefix
- <> (toListOfCites $ map toInTextMode citationList)
+ <> toListOfCites (map toInTextMode citationList)
<> maybe mempty (", " <>) suffix
where
toCite :: [Citation] -> Inlines
@@ -247,7 +252,7 @@ berkeleyCite = try $ do
alterFirst, alterLast :: (a -> a) -> [a] -> [a]
alterFirst _ [] = []
- alterFirst f (c:cs) = (f c):cs
+ alterFirst f (c:cs) = f c : cs
alterLast f = reverse . alterFirst f . reverse
prependPrefix, appendSuffix :: Inlines -> Citation -> Citation
@@ -255,12 +260,12 @@ berkeleyCite = try $ do
appendSuffix suf c = c { citationSuffix = citationSuffix c <> B.toList suf }
data BerkeleyCitationList = BerkeleyCitationList
- { berkeleyCiteParens :: Bool
+ { berkeleyCiteParens :: Bool
, berkeleyCiteCommonPrefix :: Maybe Inlines
, berkeleyCiteCommonSuffix :: Maybe Inlines
- , berkeleyCiteCitations :: [Citation]
+ , berkeleyCiteCitations :: [Citation]
}
-berkeleyCitationList :: OrgParser (F BerkeleyCitationList)
+berkeleyCitationList :: PandocMonad m => OrgParser m (F BerkeleyCitationList)
berkeleyCitationList = try $ do
char '['
parens <- choice [ False <$ berkeleyBareTag, True <$ berkeleyParensTag ]
@@ -268,29 +273,29 @@ berkeleyCitationList = try $ do
skipSpaces
commonPrefix <- optionMaybe (try $ citationListPart <* char ';')
citations <- citeList
- commonSuffix <- optionMaybe (try $ citationListPart)
+ commonSuffix <- optionMaybe (try citationListPart)
char ']'
return (BerkeleyCitationList parens
<$> sequence commonPrefix
<*> sequence commonSuffix
<*> citations)
where
- citationListPart :: OrgParser (F Inlines)
+ citationListPart :: PandocMonad m => OrgParser m (F Inlines)
citationListPart = fmap (trimInlinesF . mconcat) . try . many1 $ do
notFollowedBy' citeKey
notFollowedBy (oneOf ";]")
inline
-berkeleyBareTag :: OrgParser ()
+berkeleyBareTag :: PandocMonad m => OrgParser m ()
berkeleyBareTag = try $ void berkeleyBareTag'
-berkeleyParensTag :: OrgParser ()
+berkeleyParensTag :: PandocMonad m => OrgParser m ()
berkeleyParensTag = try . void $ enclosedByPair '(' ')' berkeleyBareTag'
-berkeleyBareTag' :: OrgParser ()
+berkeleyBareTag' :: PandocMonad m => OrgParser m ()
berkeleyBareTag' = try $ void (string "cite")
-berkeleyTextualCite :: OrgParser (F [Citation])
+berkeleyTextualCite :: PandocMonad m => OrgParser m (F [Citation])
berkeleyTextualCite = try $ do
(suppressAuthor, key) <- citeKey
returnF . return $ Citation
@@ -305,14 +310,14 @@ berkeleyTextualCite = try $ do
-- The following is what a Berkeley-style bracketed textual citation parser
-- would look like. However, as these citations are a subset of Pandoc's Org
-- citation style, this isn't used.
--- berkeleyBracketedTextualCite :: OrgParser (F [Citation])
+-- berkeleyBracketedTextualCite :: PandocMonad m => OrgParser m (F [Citation])
-- berkeleyBracketedTextualCite = try . (fmap head) $
-- enclosedByPair '[' ']' berkeleyTextualCite
-- | Read a link-like org-ref style citation. The citation includes pre and
-- post text. However, multiple citations are not possible due to limitations
-- in the syntax.
-linkLikeOrgRefCite :: OrgParser (F Citation)
+linkLikeOrgRefCite :: PandocMonad m => OrgParser m (F Citation)
linkLikeOrgRefCite = try $ do
_ <- string "[["
mode <- orgRefCiteMode
@@ -335,13 +340,20 @@ linkLikeOrgRefCite = try $ do
-- | Read a citation key. The characters allowed in citation keys are taken
-- from the `org-ref-cite-re` variable in `org-ref.el`.
-orgRefCiteKey :: OrgParser String
-orgRefCiteKey = try . many1 . satisfy $ \c ->
- isAlphaNum c || c `elem` ("-_:\\./"::String)
+orgRefCiteKey :: PandocMonad m => OrgParser m String
+orgRefCiteKey =
+ let citeKeySpecialChars = "-_:\\./," :: String
+ isCiteKeySpecialChar c = c `elem` citeKeySpecialChars
+ isCiteKeyChar c = isAlphaNum c || isCiteKeySpecialChar c
+ endOfCitation = try $ do
+ many $ satisfy isCiteKeySpecialChar
+ satisfy $ not . isCiteKeyChar
+ in try $ satisfy isCiteKeyChar `many1Till` lookAhead endOfCitation
+
-- | Supported citation types. Only a small subset of org-ref types is
-- supported for now. TODO: rewrite this, use LaTeX reader as template.
-orgRefCiteMode :: OrgParser CitationMode
+orgRefCiteMode :: PandocMonad m => OrgParser m CitationMode
orgRefCiteMode =
choice $ map (\(s, mode) -> mode <$ try (string s <* char ':'))
[ ("cite", AuthorInText)
@@ -352,10 +364,10 @@ orgRefCiteMode =
, ("citeyear", SuppressAuthor)
]
-citeList :: OrgParser (F [Citation])
+citeList :: PandocMonad m => OrgParser m (F [Citation])
citeList = sequence <$> sepEndBy1 citation (try $ char ';' *> skipSpaces)
-citation :: OrgParser (F Citation)
+citation :: PandocMonad m => OrgParser m (F Citation)
citation = try $ do
pref <- prefix
(suppress_author, key) <- citeKey
@@ -363,15 +375,16 @@ citation = try $ do
return $ do
x <- pref
y <- suff
- return $ Citation{ citationId = key
- , citationPrefix = B.toList x
- , citationSuffix = B.toList y
- , citationMode = if suppress_author
- then SuppressAuthor
- else NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
+ return Citation
+ { citationId = key
+ , citationPrefix = B.toList x
+ , citationSuffix = B.toList y
+ , citationMode = if suppress_author
+ then SuppressAuthor
+ else NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
where
prefix = trimInlinesF . mconcat <$>
manyTill inline (char ']' <|> (']' <$ lookAhead citeKey))
@@ -384,39 +397,39 @@ citation = try $ do
then (B.space <>) <$> rest
else rest
-footnote :: OrgParser (F Inlines)
+footnote :: PandocMonad m => OrgParser m (F Inlines)
footnote = try $ inlineNote <|> referencedNote
-inlineNote :: OrgParser (F Inlines)
+inlineNote :: PandocMonad m => OrgParser m (F Inlines)
inlineNote = try $ do
string "[fn:"
ref <- many alphaNum
char ':'
note <- fmap B.para . trimInlinesF . mconcat <$> many1Till inline (char ']')
- when (not $ null ref) $
+ unless (null ref) $
addToNotesTable ("fn:" ++ ref, note)
return $ B.note <$> note
-referencedNote :: OrgParser (F Inlines)
+referencedNote :: PandocMonad m => OrgParser m (F Inlines)
referencedNote = try $ do
ref <- noteMarker
return $ do
notes <- asksF orgStateNotes'
case lookup ref notes of
- Nothing -> return $ B.str $ "[" ++ ref ++ "]"
+ Nothing -> return . B.str $ "[" ++ ref ++ "]"
Just contents -> do
st <- askF
let contents' = runF contents st{ orgStateNotes' = [] }
return $ B.note contents'
-linkOrImage :: OrgParser (F Inlines)
+linkOrImage :: PandocMonad m => OrgParser m (F Inlines)
linkOrImage = explicitOrImageLink
<|> selflinkOrImage
<|> angleLink
<|> plainLink
<?> "link or image"
-explicitOrImageLink :: OrgParser (F Inlines)
+explicitOrImageLink :: PandocMonad m => OrgParser m (F Inlines)
explicitOrImageLink = try $ do
char '['
srcF <- applyCustomLinkFormat =<< possiblyEmptyLinkTarget
@@ -427,34 +440,34 @@ explicitOrImageLink = try $ do
src <- srcF
case cleanLinkString title of
Just imgSrc | isImageFilename imgSrc ->
- pure $ B.link src "" $ B.image imgSrc mempty mempty
+ pure . B.link src "" $ B.image imgSrc mempty mempty
_ ->
linkToInlinesF src =<< title'
-selflinkOrImage :: OrgParser (F Inlines)
+selflinkOrImage :: PandocMonad m => OrgParser m (F Inlines)
selflinkOrImage = try $ do
src <- char '[' *> linkTarget <* char ']'
return $ linkToInlinesF src (B.str src)
-plainLink :: OrgParser (F Inlines)
+plainLink :: PandocMonad m => OrgParser m (F Inlines)
plainLink = try $ do
(orig, src) <- uri
returnF $ B.link src "" (B.str orig)
-angleLink :: OrgParser (F Inlines)
+angleLink :: PandocMonad m => OrgParser m (F Inlines)
angleLink = try $ do
char '<'
link <- plainLink
char '>'
return link
-linkTarget :: OrgParser String
+linkTarget :: PandocMonad m => OrgParser m String
linkTarget = enclosedByPair '[' ']' (noneOf "\n\r[]")
-possiblyEmptyLinkTarget :: OrgParser String
+possiblyEmptyLinkTarget :: PandocMonad m => OrgParser m String
possiblyEmptyLinkTarget = try linkTarget <|> ("" <$ string "[]")
-applyCustomLinkFormat :: String -> OrgParser (F String)
+applyCustomLinkFormat :: String -> OrgParser m (F String)
applyCustomLinkFormat link = do
let (linkType, rest) = break (== ':') link
return $ do
@@ -487,7 +500,7 @@ internalLink link title = do
-- @anchor-id@ contains spaces, we are more restrictive in what is accepted as
-- an anchor.
-anchor :: OrgParser (F Inlines)
+anchor :: PandocMonad m => OrgParser m (F Inlines)
anchor = try $ do
anchorId <- parseAnchor
recordAnchorId anchorId
@@ -509,23 +522,23 @@ solidify = map replaceSpecialChar
| otherwise = '-'
-- | Parses an inline code block and marks it as an babel block.
-inlineCodeBlock :: OrgParser (F Inlines)
+inlineCodeBlock :: PandocMonad m => OrgParser m (F Inlines)
inlineCodeBlock = try $ do
string "src_"
lang <- many1 orgArgWordChar
opts <- option [] $ enclosedByPair '[' ']' inlineBlockOption
inlineCode <- enclosedByPair '{' '}' (noneOf "\n\r")
- let attrClasses = [translateLang lang, rundocBlockClass]
- let attrKeyVal = map toRundocAttrib (("language", lang) : opts)
+ let attrClasses = [translateLang lang]
+ let attrKeyVal = originalLang lang <> opts
returnF $ B.codeWith ("", attrClasses, attrKeyVal) inlineCode
where
- inlineBlockOption :: OrgParser (String, String)
+ inlineBlockOption :: PandocMonad m => OrgParser m (String, String)
inlineBlockOption = try $ do
argKey <- orgArgKey
paramValue <- option "yes" orgInlineParamValue
return (argKey, paramValue)
- orgInlineParamValue :: OrgParser String
+ orgInlineParamValue :: PandocMonad m => OrgParser m String
orgInlineParamValue = try $
skipSpaces
*> notFollowedBy (char ':')
@@ -533,7 +546,7 @@ inlineCodeBlock = try $ do
<* skipSpaces
-emphasizedText :: OrgParser (F Inlines)
+emphasizedText :: PandocMonad m => OrgParser m (F Inlines)
emphasizedText = do
state <- getState
guard . exportEmphasizedText . orgStateExportSettings $ state
@@ -544,60 +557,64 @@ emphasizedText = do
, underline
]
-enclosedByPair :: Char -- ^ opening char
+enclosedByPair :: PandocMonad m
+ => Char -- ^ opening char
-> Char -- ^ closing char
- -> OrgParser a -- ^ parser
- -> OrgParser [a]
+ -> OrgParser m a -- ^ parser
+ -> OrgParser m [a]
enclosedByPair s e p = char s *> many1Till p (char e)
-emph :: OrgParser (F Inlines)
+emph :: PandocMonad m => OrgParser m (F Inlines)
emph = fmap B.emph <$> emphasisBetween '/'
-strong :: OrgParser (F Inlines)
+strong :: PandocMonad m => OrgParser m (F Inlines)
strong = fmap B.strong <$> emphasisBetween '*'
-strikeout :: OrgParser (F Inlines)
+strikeout :: PandocMonad m => OrgParser m (F Inlines)
strikeout = fmap B.strikeout <$> emphasisBetween '+'
--- There is no underline, so we use strong instead.
-underline :: OrgParser (F Inlines)
-underline = fmap B.strong <$> emphasisBetween '_'
+underline :: PandocMonad m => OrgParser m (F Inlines)
+underline = fmap underlineSpan <$> emphasisBetween '_'
-verbatim :: OrgParser (F Inlines)
+verbatim :: PandocMonad m => OrgParser m (F Inlines)
verbatim = return . B.code <$> verbatimBetween '='
-code :: OrgParser (F Inlines)
+code :: PandocMonad m => OrgParser m (F Inlines)
code = return . B.code <$> verbatimBetween '~'
-subscript :: OrgParser (F Inlines)
+subscript :: PandocMonad m => OrgParser m (F Inlines)
subscript = fmap B.subscript <$> try (char '_' *> subOrSuperExpr)
-superscript :: OrgParser (F Inlines)
+superscript :: PandocMonad m => OrgParser m (F Inlines)
superscript = fmap B.superscript <$> try (char '^' *> subOrSuperExpr)
-math :: OrgParser (F Inlines)
+math :: PandocMonad m => OrgParser m (F Inlines)
math = return . B.math <$> choice [ math1CharBetween '$'
, mathStringBetween '$'
, rawMathBetween "\\(" "\\)"
]
-displayMath :: OrgParser (F Inlines)
+displayMath :: PandocMonad m => OrgParser m (F Inlines)
displayMath = return . B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
, rawMathBetween "$$" "$$"
]
-updatePositions :: Char
- -> OrgParser Char
+updatePositions :: PandocMonad m
+ => Char
+ -> OrgParser m Char
updatePositions c = do
+ st <- getState
+ let emphasisPreChars = orgStateEmphasisPreChars st
when (c `elem` emphasisPreChars) updateLastPreCharPos
when (c `elem` emphasisForbiddenBorderChars) updateLastForbiddenCharPos
return c
-symbol :: OrgParser (F Inlines)
+symbol :: PandocMonad m => OrgParser m (F Inlines)
symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
-emphasisBetween :: Char
- -> OrgParser (F Inlines)
+emphasisBetween :: PandocMonad m
+ => Char
+ -> OrgParser m (F Inlines)
emphasisBetween c = try $ do
startEmphasisNewlinesCounting emphasisAllowedNewlines
res <- enclosedInlines (emphasisStart c) (emphasisEnd c)
@@ -606,8 +623,9 @@ emphasisBetween c = try $ do
resetEmphasisNewlines
return res
-verbatimBetween :: Char
- -> OrgParser String
+verbatimBetween :: PandocMonad m
+ => Char
+ -> OrgParser m String
verbatimBetween c = try $
emphasisStart c *>
many1TillNOrLessNewlines 1 verbatimChar (emphasisEnd c)
@@ -615,8 +633,9 @@ verbatimBetween c = try $
verbatimChar = noneOf "\n\r" >>= updatePositions
-- | Parses a raw string delimited by @c@ using Org's math rules
-mathStringBetween :: Char
- -> OrgParser String
+mathStringBetween :: PandocMonad m
+ => Char
+ -> OrgParser m String
mathStringBetween c = try $ do
mathStart c
body <- many1TillNOrLessNewlines mathAllowedNewlines
@@ -626,8 +645,9 @@ mathStringBetween c = try $ do
return $ body ++ [final]
-- | Parse a single character between @c@ using math rules
-math1CharBetween :: Char
- -> OrgParser String
+math1CharBetween :: PandocMonad m
+ => Char
+ -> OrgParser m String
math1CharBetween c = try $ do
char c
res <- noneOf $ c:mathForbiddenBorderChars
@@ -635,13 +655,14 @@ math1CharBetween c = try $ do
eof <|> () <$ lookAhead (oneOf mathPostChars)
return [res]
-rawMathBetween :: String
+rawMathBetween :: PandocMonad m
+ => String
-> String
- -> OrgParser String
+ -> OrgParser m String
rawMathBetween s e = try $ string s *> manyTill anyChar (try $ string e)
-- | Parses the start (opening character) of emphasis
-emphasisStart :: Char -> OrgParser Char
+emphasisStart :: PandocMonad m => Char -> OrgParser m Char
emphasisStart c = try $ do
guard =<< afterEmphasisPreChar
guard =<< notAfterString
@@ -654,7 +675,7 @@ emphasisStart c = try $ do
return c
-- | Parses the closing character of emphasis
-emphasisEnd :: Char -> OrgParser Char
+emphasisEnd :: PandocMonad m => Char -> OrgParser m Char
emphasisEnd c = try $ do
guard =<< notAfterForbiddenBorderChar
char c
@@ -662,14 +683,16 @@ emphasisEnd c = try $ do
updateLastStrPos
popInlineCharStack
return c
- where acceptablePostChars =
- surroundingEmphasisChar >>= \x -> oneOf (x ++ emphasisPostChars)
+ where
+ acceptablePostChars = do
+ emphasisPostChars <- orgStateEmphasisPostChars <$> getState
+ surroundingEmphasisChar >>= \x -> oneOf (x ++ emphasisPostChars)
-mathStart :: Char -> OrgParser Char
+mathStart :: PandocMonad m => Char -> OrgParser m Char
mathStart c = try $
char c <* notFollowedBy' (oneOf (c:mathForbiddenBorderChars))
-mathEnd :: Char -> OrgParser Char
+mathEnd :: PandocMonad m => Char -> OrgParser m Char
mathEnd c = try $ do
res <- noneOf (c:mathForbiddenBorderChars)
char c
@@ -677,15 +700,15 @@ mathEnd c = try $ do
return res
-enclosedInlines :: OrgParser a
- -> OrgParser b
- -> OrgParser (F Inlines)
+enclosedInlines :: (PandocMonad m, Show b) => OrgParser m a
+ -> OrgParser m b
+ -> OrgParser m (F Inlines)
enclosedInlines start end = try $
trimInlinesF . mconcat <$> enclosed start end inline
-enclosedRaw :: OrgParser a
- -> OrgParser b
- -> OrgParser String
+enclosedRaw :: (PandocMonad m, Show b) => OrgParser m a
+ -> OrgParser m b
+ -> OrgParser m String
enclosedRaw start end = try $
start *> (onSingleLine <|> spanningTwoLines)
where onSingleLine = try $ many1Till (noneOf "\n\r") end
@@ -694,10 +717,10 @@ enclosedRaw start end = try $
-- | Like many1Till, but parses at most @n+1@ lines. @p@ must not consume
-- newlines.
-many1TillNOrLessNewlines :: Int
- -> OrgParser Char
- -> OrgParser a
- -> OrgParser String
+many1TillNOrLessNewlines :: PandocMonad m => Int
+ -> OrgParser m Char
+ -> OrgParser m a
+ -> OrgParser m String
many1TillNOrLessNewlines n p end = try $
nMoreLines (Just n) mempty >>= oneOrMore
where
@@ -715,17 +738,9 @@ many1TillNOrLessNewlines n p end = try $
-- here (see, e.g., the Emacs Lisp variable `org-emphasis-regexp-components`
-- for details).
--- | Chars allowed to occur before emphasis (spaces and newlines are ok, too)
-emphasisPreChars :: [Char]
-emphasisPreChars = "\t \"'({"
-
--- | Chars allowed at after emphasis
-emphasisPostChars :: [Char]
-emphasisPostChars = "\t\n !\"'),-.:;?\\}"
-
-- | Chars not allowed at the (inner) border of emphasis
emphasisForbiddenBorderChars :: [Char]
-emphasisForbiddenBorderChars = "\t\n\r \"',"
+emphasisForbiddenBorderChars = "\t\n\r "
-- | The maximum number of newlines within
emphasisAllowedNewlines :: Int
@@ -746,29 +761,29 @@ mathAllowedNewlines :: Int
mathAllowedNewlines = 2
-- | Whether we are right behind a char allowed before emphasis
-afterEmphasisPreChar :: OrgParser Bool
+afterEmphasisPreChar :: PandocMonad m => OrgParser m Bool
afterEmphasisPreChar = do
pos <- getPosition
lastPrePos <- orgStateLastPreCharPos <$> getState
return . fromMaybe True $ (== pos) <$> lastPrePos
-- | Whether the parser is right after a forbidden border char
-notAfterForbiddenBorderChar :: OrgParser Bool
+notAfterForbiddenBorderChar :: PandocMonad m => OrgParser m Bool
notAfterForbiddenBorderChar = do
pos <- getPosition
lastFBCPos <- orgStateLastForbiddenCharPos <$> getState
return $ lastFBCPos /= Just pos
-- | Read a sub- or superscript expression
-subOrSuperExpr :: OrgParser (F Inlines)
+subOrSuperExpr :: PandocMonad m => OrgParser m (F Inlines)
subOrSuperExpr = try $
- choice [ id <$> charsInBalanced '{' '}' (noneOf "\n\r")
+ choice [ charsInBalanced '{' '}' (noneOf "\n\r")
, enclosing ('(', ')') <$> charsInBalanced '(' ')' (noneOf "\n\r")
, simpleSubOrSuperString
] >>= parseFromString (mconcat <$> many inline)
where enclosing (left, right) s = left : s ++ [right]
-simpleSubOrSuperString :: OrgParser String
+simpleSubOrSuperString :: PandocMonad m => OrgParser m String
simpleSubOrSuperString = try $ do
state <- getState
guard . exportSubSuperscripts . orgStateExportSettings $ state
@@ -777,17 +792,18 @@ simpleSubOrSuperString = try $ do
<*> many1 alphaNum
]
-inlineLaTeX :: OrgParser (F Inlines)
+inlineLaTeX :: PandocMonad m => OrgParser m (F Inlines)
inlineLaTeX = try $ do
cmd <- inlineLaTeXCommand
+ ils <- (lift . lift) $ parseAsInlineLaTeX cmd
maybe mzero returnF $
- parseAsMath cmd `mplus` parseAsMathMLSym cmd `mplus` parseAsInlineLaTeX cmd
+ parseAsMath cmd `mplus` parseAsMathMLSym cmd `mplus` ils
where
parseAsMath :: String -> Maybe Inlines
parseAsMath cs = B.fromList <$> texMathToPandoc cs
- parseAsInlineLaTeX :: String -> Maybe Inlines
- parseAsInlineLaTeX cs = maybeRight $ runParser inlineCommand state "" cs
+ parseAsInlineLaTeX :: PandocMonad m => String -> m (Maybe Inlines)
+ parseAsInlineLaTeX cs = maybeRight <$> runParserT inlineCommand state "" cs
parseAsMathMLSym :: String -> Maybe Inlines
parseAsMathMLSym cs = B.str <$> MathMLEntityMap.getUnicode (clean cs)
@@ -795,19 +811,22 @@ inlineLaTeX = try $ do
where clean = dropWhileEnd (`elem` ("{}" :: String)) . drop 1
state :: ParserState
- state = def{ stateOptions = def{ readerParseRaw = True }}
+ state = def{ stateOptions = def{ readerExtensions =
+ enableExtension Ext_raw_tex (readerExtensions def) } }
texMathToPandoc :: String -> Maybe [Inline]
- texMathToPandoc cs = (maybeRight $ readTeX cs) >>= writePandoc DisplayInline
+ texMathToPandoc cs = maybeRight (readTeX cs) >>= writePandoc DisplayInline
maybeRight :: Either a b -> Maybe b
maybeRight = either (const Nothing) Just
-inlineLaTeXCommand :: OrgParser String
+inlineLaTeXCommand :: PandocMonad m => OrgParser m String
inlineLaTeXCommand = try $ do
rest <- getInput
- case runParser rawLaTeXInline def "source" rest of
- Right (RawInline _ cs) -> do
+ st <- getState
+ parsed <- (lift . lift) $ runParserT rawLaTeXInline st "source" rest
+ case parsed of
+ Right cs -> do
-- drop any trailing whitespace, those are not be part of the command as
-- far as org mode is concerned.
let cmdNoSpc = dropWhileEnd isSpace cs
@@ -820,33 +839,56 @@ inlineLaTeXCommand = try $ do
dropWhileEnd :: (a -> Bool) -> [a] -> [a]
dropWhileEnd p = foldr (\x xs -> if p x && null xs then [] else x : xs) []
-exportSnippet :: OrgParser (F Inlines)
+exportSnippet :: PandocMonad m => OrgParser m (F Inlines)
exportSnippet = try $ do
string "@@"
format <- many1Till (alphaNum <|> char '-') (char ':')
snippet <- manyTill anyChar (try $ string "@@")
returnF $ B.rawInline format snippet
-smart :: OrgParser (F Inlines)
-smart = do
- getOption readerSmart >>= guard
- doubleQuoted <|> singleQuoted <|>
- choice (map (return <$>) [orgApostrophe, orgDash, orgEllipses])
+macro :: PandocMonad m => OrgParser m (F Inlines)
+macro = try $ do
+ recursionDepth <- orgStateMacroDepth <$> getState
+ guard $ recursionDepth < 15
+ string "{{{"
+ name <- many alphaNum
+ args <- ([] <$ string "}}}")
+ <|> char '(' *> argument `sepBy` char ',' <* eoa
+ expander <- lookupMacro name <$> getState
+ case expander of
+ Nothing -> mzero
+ Just fn -> do
+ updateState $ \s -> s { orgStateMacroDepth = recursionDepth + 1 }
+ res <- parseFromString (mconcat <$> many inline) $ fn args
+ updateState $ \s -> s { orgStateMacroDepth = recursionDepth }
+ return res
+ where
+ argument = many $ notFollowedBy eoa *> noneOf ","
+ eoa = string ")}}}"
+
+smart :: PandocMonad m => OrgParser m (F Inlines)
+smart = choice [doubleQuoted, singleQuoted, orgApostrophe, orgDash, orgEllipses]
where
orgDash = do
- guard =<< getExportSetting exportSpecialStrings
- dash <* updatePositions '-'
+ guardOrSmartEnabled =<< getExportSetting exportSpecialStrings
+ pure <$> dash <* updatePositions '-'
orgEllipses = do
- guard =<< getExportSetting exportSpecialStrings
- ellipses <* updatePositions '.'
- orgApostrophe =
- (char '\'' <|> char '\8217') <* updateLastPreCharPos
- <* updateLastForbiddenCharPos
- *> return (B.str "\x2019")
-
-singleQuoted :: OrgParser (F Inlines)
+ guardOrSmartEnabled =<< getExportSetting exportSpecialStrings
+ pure <$> ellipses <* updatePositions '.'
+ orgApostrophe = do
+ guardEnabled Ext_smart
+ (char '\'' <|> char '\8217') <* updateLastPreCharPos
+ <* updateLastForbiddenCharPos
+ returnF (B.str "\x2019")
+
+guardOrSmartEnabled :: PandocMonad m => Bool -> OrgParser m ()
+guardOrSmartEnabled b = do
+ smartExtension <- extensionEnabled Ext_smart <$> getOption readerExtensions
+ guard (b || smartExtension)
+
+singleQuoted :: PandocMonad m => OrgParser m (F Inlines)
singleQuoted = try $ do
- guard =<< getExportSetting exportSmartQuotes
+ guardOrSmartEnabled =<< getExportSetting exportSmartQuotes
singleQuoteStart
updatePositions '\''
withQuoteContext InSingleQuote $
@@ -856,12 +898,15 @@ singleQuoted = try $ do
-- doubleQuoted will handle regular double-quoted sections, as well
-- as dialogues with an open double-quote without a close double-quote
-- in the same paragraph.
-doubleQuoted :: OrgParser (F Inlines)
+doubleQuoted :: PandocMonad m => OrgParser m (F Inlines)
doubleQuoted = try $ do
- guard =<< getExportSetting exportSmartQuotes
+ guardOrSmartEnabled =<< getExportSetting exportSmartQuotes
doubleQuoteStart
updatePositions '"'
contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
- (withQuoteContext InDoubleQuote $ (doubleQuoteEnd <* updateLastForbiddenCharPos) >> return
- (fmap B.doubleQuoted . trimInlinesF $ contents))
- <|> (return $ return (B.str "\8220") <> contents)
+ let doubleQuotedContent = withQuoteContext InDoubleQuote $ do
+ doubleQuoteEnd
+ updateLastForbiddenCharPos
+ return . fmap B.doubleQuoted . trimInlinesF $ contents
+ let leftQuoteAndContent = return $ pure (B.str "\8220") <> contents
+ doubleQuotedContent <|> leftQuoteAndContent
diff --git a/src/Text/Pandoc/Readers/Org/Meta.hs b/src/Text/Pandoc/Readers/Org/Meta.hs
index 1fea3e890..6ad403fd8 100644
--- a/src/Text/Pandoc/Readers/Org/Meta.hs
+++ b/src/Text/Pandoc/Readers/Org/Meta.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE TupleSections #-}
{-
-Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Org.Meta
- Copyright : Copyright (C) 2014-2017 Albert Krewinkel
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,25 +33,26 @@ module Text.Pandoc.Readers.Org.Meta
, metaLine
) where
-import Text.Pandoc.Readers.Org.BlockStarts
-import Text.Pandoc.Readers.Org.ExportSettings ( exportSettings )
-import Text.Pandoc.Readers.Org.Inlines
-import Text.Pandoc.Readers.Org.ParserState
-import Text.Pandoc.Readers.Org.Parsing
+import Text.Pandoc.Readers.Org.BlockStarts
+import Text.Pandoc.Readers.Org.ExportSettings (exportSettings)
+import Text.Pandoc.Readers.Org.Inlines
+import Text.Pandoc.Readers.Org.ParserState
+import Text.Pandoc.Readers.Org.Parsing
+import Text.Pandoc.Builder (Blocks, Inlines)
import qualified Text.Pandoc.Builder as B
-import Text.Pandoc.Builder ( Blocks, Inlines )
-import Text.Pandoc.Definition
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared (safeRead)
-import Control.Monad ( mzero, void )
-import Data.Char ( toLower )
-import Data.List ( intersperse )
+import Control.Monad (mzero, void, when)
+import Data.Char (toLower)
+import Data.List (intersperse)
import qualified Data.Map as M
-import Data.Monoid ( (<>) )
-import Network.HTTP ( urlEncode )
+import Network.HTTP (urlEncode)
-- | Returns the current meta, respecting export options.
-metaExport :: OrgParser (F Meta)
+metaExport :: Monad m => OrgParser m (F Meta)
metaExport = do
st <- getState
let settings = orgStateExportSettings st
@@ -68,29 +69,32 @@ removeMeta key meta' =
-- | Parse and handle a single line containing meta information
-- The order, in which blocks are tried, makes sure that we're not looking at
-- the beginning of a block, so we don't need to check for it
-metaLine :: OrgParser Blocks
+metaLine :: PandocMonad m => OrgParser m Blocks
metaLine = mempty <$ metaLineStart <* (optionLine <|> declarationLine)
-declarationLine :: OrgParser ()
+declarationLine :: PandocMonad m => OrgParser m ()
declarationLine = try $ do
key <- map toLower <$> metaKey
(key', value) <- metaValue key
- updateState $ \st ->
- let meta' = B.setMeta key' <$> value <*> pure nullMeta
- in st { orgStateMeta = meta' <> orgStateMeta st }
+ let addMetaValue st =
+ st { orgStateMeta = B.setMeta key' <$> value <*> orgStateMeta st }
+ when (key' /= "results") $ updateState addMetaValue
-metaKey :: OrgParser String
+metaKey :: Monad m => OrgParser m String
metaKey = map toLower <$> many1 (noneOf ": \n\r")
<* char ':'
<* skipSpaces
-metaValue :: String -> OrgParser (String, (F MetaValue))
+metaValue :: PandocMonad m => String -> OrgParser m (String, F MetaValue)
metaValue key =
let inclKey = "header-includes"
in case key of
"author" -> (key,) <$> metaInlinesCommaSeparated
+ "keywords" -> (key,) <$> metaInlinesCommaSeparated
"title" -> (key,) <$> metaInlines
+ "subtitle" -> (key,) <$> metaInlines
"date" -> (key,) <$> metaInlines
+ "nocite" -> (key,) <$> accumulatingList key metaInlines
"header-includes" -> (key,) <$> accumulatingList key metaInlines
"latex_header" -> (inclKey,) <$>
accumulatingList inclKey (metaExportSnippet "latex")
@@ -103,32 +107,32 @@ metaValue key =
accumulatingList inclKey (metaExportSnippet "html")
_ -> (key,) <$> metaString
-metaInlines :: OrgParser (F MetaValue)
+metaInlines :: PandocMonad m => OrgParser m (F MetaValue)
metaInlines = fmap (MetaInlines . B.toList) <$> inlinesTillNewline
-metaInlinesCommaSeparated :: OrgParser (F MetaValue)
+metaInlinesCommaSeparated :: PandocMonad m => OrgParser m (F MetaValue)
metaInlinesCommaSeparated = do
- authStrs <- (many1 (noneOf ",\n")) `sepBy1` (char ',')
+ itemStrs <- many1 (noneOf ",\n") `sepBy1` char ','
newline
- authors <- mapM (parseFromString inlinesTillNewline . (++ "\n")) authStrs
+ items <- mapM (parseFromString inlinesTillNewline . (++ "\n")) itemStrs
let toMetaInlines = MetaInlines . B.toList
- return $ MetaList . map toMetaInlines <$> sequence authors
+ return $ MetaList . map toMetaInlines <$> sequence items
-metaString :: OrgParser (F MetaValue)
+metaString :: Monad m => OrgParser m (F MetaValue)
metaString = metaModifiedString id
-metaModifiedString :: (String -> String) -> OrgParser (F MetaValue)
+metaModifiedString :: Monad m => (String -> String) -> OrgParser m (F MetaValue)
metaModifiedString f = return . MetaString . f <$> anyLine
-- | Read an format specific meta definition
-metaExportSnippet :: String -> OrgParser (F MetaValue)
+metaExportSnippet :: Monad m => String -> OrgParser m (F MetaValue)
metaExportSnippet format =
return . MetaInlines . B.toList . B.rawInline format <$> anyLine
-- | Accumulate the result of the @parser@ in a list under @key@.
-accumulatingList :: String
- -> OrgParser (F MetaValue)
- -> OrgParser (F MetaValue)
+accumulatingList :: Monad m => String
+ -> OrgParser m (F MetaValue)
+ -> OrgParser m (F MetaValue)
accumulatingList key p = do
value <- p
meta' <- orgStateMeta <$> getState
@@ -141,7 +145,7 @@ accumulatingList key p = do
--
-- export options
--
-optionLine :: OrgParser ()
+optionLine :: Monad m => OrgParser m ()
optionLine = try $ do
key <- metaKey
case key of
@@ -150,16 +154,19 @@ optionLine = try $ do
"todo" -> todoSequence >>= updateState . registerTodoSequence
"seq_todo" -> todoSequence >>= updateState . registerTodoSequence
"typ_todo" -> todoSequence >>= updateState . registerTodoSequence
- _ -> mzero
+ "macro" -> macroDefinition >>= updateState . registerMacro
+ "pandoc-emphasis-pre" -> emphChars >>= updateState . setEmphasisPreChar
+ "pandoc-emphasis-post" -> emphChars >>= updateState . setEmphasisPostChar
+ _ -> mzero
-addLinkFormat :: String
+addLinkFormat :: Monad m => String
-> (String -> String)
- -> OrgParser ()
+ -> OrgParser m ()
addLinkFormat key formatter = updateState $ \s ->
let fs = orgStateLinkFormatters s
in s{ orgStateLinkFormatters = M.insert key formatter fs }
-parseLinkFormat :: OrgParser ((String, String -> String))
+parseLinkFormat :: Monad m => OrgParser m (String, String -> String)
parseLinkFormat = try $ do
linkType <- (:) <$> letter <*> many (alphaNum <|> oneOf "-_") <* skipSpaces
linkSubst <- parseFormat
@@ -167,9 +174,8 @@ parseLinkFormat = try $ do
-- | An ad-hoc, single-argument-only implementation of a printf-style format
-- parser.
-parseFormat :: OrgParser (String -> String)
-parseFormat = try $ do
- replacePlain <|> replaceUrl <|> justAppend
+parseFormat :: Monad m => OrgParser m (String -> String)
+parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend
where
-- inefficient, but who cares
replacePlain = try $ (\x -> concat . flip intersperse x)
@@ -181,13 +187,34 @@ parseFormat = try $ do
rest = manyTill anyChar (eof <|> () <$ oneOf "\n\r")
tillSpecifier c = manyTill (noneOf "\n\r") (try $ string ('%':c:""))
-inlinesTillNewline :: OrgParser (F Inlines)
-inlinesTillNewline = trimInlinesF . mconcat <$> manyTill inline newline
+setEmphasisPreChar :: Maybe [Char] -> OrgParserState -> OrgParserState
+setEmphasisPreChar csMb st =
+ let preChars = case csMb of
+ Nothing -> orgStateEmphasisPreChars defaultOrgParserState
+ Just cs -> cs
+ in st { orgStateEmphasisPreChars = preChars }
+
+setEmphasisPostChar :: Maybe [Char] -> OrgParserState -> OrgParserState
+setEmphasisPostChar csMb st =
+ let postChars = case csMb of
+ Nothing -> orgStateEmphasisPostChars defaultOrgParserState
+ Just cs -> cs
+ in st { orgStateEmphasisPostChars = postChars }
+
+emphChars :: Monad m => OrgParser m (Maybe [Char])
+emphChars = do
+ skipSpaces
+ safeRead <$> anyLine
+
+inlinesTillNewline :: PandocMonad m => OrgParser m (F Inlines)
+inlinesTillNewline = do
+ updateLastPreCharPos
+ trimInlinesF . mconcat <$> manyTill inline newline
--
-- ToDo Sequences and Keywords
--
-todoSequence :: OrgParser TodoSequence
+todoSequence :: Monad m => OrgParser m TodoSequence
todoSequence = try $ do
todoKws <- todoKeywords
doneKws <- optionMaybe $ todoDoneSep *> todoKeywords
@@ -201,13 +228,13 @@ todoSequence = try $ do
(x:xs) -> return $ keywordsToSequence (reverse xs) [x]
where
- todoKeywords :: OrgParser [String]
+ todoKeywords :: Monad m => OrgParser m [String]
todoKeywords = try $
let keyword = many1 nonspaceChar <* skipSpaces
endOfKeywords = todoDoneSep <|> void newline
in manyTill keyword (lookAhead endOfKeywords)
- todoDoneSep :: OrgParser ()
+ todoDoneSep :: Monad m => OrgParser m ()
todoDoneSep = void . try $ skipSpaces *> char '|' <* skipSpaces1
keywordsToSequence :: [String] -> [String] -> TodoSequence
@@ -215,3 +242,27 @@ todoSequence = try $ do
let todoMarkers = map (TodoMarker Todo) todo
doneMarkers = map (TodoMarker Done) done
in todoMarkers ++ doneMarkers
+
+macroDefinition :: Monad m => OrgParser m (String, [String] -> String)
+macroDefinition = try $ do
+ macroName <- many1 nonspaceChar <* skipSpaces
+ firstPart <- expansionPart
+ (elemOrder, parts) <- unzip <$> many ((,) <$> placeholder <*> expansionPart)
+ let expander = mconcat . alternate (firstPart:parts) . reorder elemOrder
+ return (macroName, expander)
+ where
+ placeholder :: Monad m => OrgParser m Int
+ placeholder = try . fmap read $ char '$' *> many1 digit
+
+ expansionPart :: Monad m => OrgParser m String
+ expansionPart = try $ many (notFollowedBy placeholder *> noneOf "\n\r")
+
+ alternate :: [a] -> [a] -> [a]
+ alternate [] ys = ys
+ alternate xs [] = xs
+ alternate (x:xs) (y:ys) = x : y : alternate xs ys
+
+ reorder :: [Int] -> [String] -> [String]
+ reorder perm xs =
+ let element n = take 1 $ drop (n - 1) xs
+ in concatMap element perm
diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs
index 38f95ca95..6316766fa 100644
--- a/src/Text/Pandoc/Readers/Org/ParserState.hs
+++ b/src/Text/Pandoc/Readers/Org/ParserState.hs
@@ -1,8 +1,7 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,8 +19,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.ParserState
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -30,16 +29,21 @@ Define the Org-mode parser state.
-}
module Text.Pandoc.Readers.Org.ParserState
( OrgParserState (..)
+ , defaultOrgParserState
, OrgParserLocal (..)
, OrgNoteRecord
, HasReaderOptions (..)
, HasQuoteContext (..)
+ , HasMacros (..)
, TodoMarker (..)
, TodoSequence
, TodoState (..)
, activeTodoMarkers
, registerTodoSequence
- , F(..)
+ , MacroExpander
+ , lookupMacro
+ , registerMacro
+ , F
, askF
, asksF
, trimInlinesF
@@ -50,24 +54,28 @@ module Text.Pandoc.Readers.Org.ParserState
, optionsToParserState
) where
-import Control.Monad (liftM, liftM2)
-import Control.Monad.Reader (Reader, runReader, ask, asks, local)
+import Control.Monad.Reader (ReaderT, asks, local)
-import Data.Default (Default(..))
+import Data.Default (Default (..))
import qualified Data.Map as M
import qualified Data.Set as Set
-
-import Text.Pandoc.Builder ( Inlines, Blocks, trimInlines )
-import Text.Pandoc.Definition ( Meta(..), nullMeta )
-import Text.Pandoc.Options ( ReaderOptions(..) )
-import Text.Pandoc.Parsing ( HasHeaderMap(..)
- , HasIdentifierList(..)
- , HasLastStrPosition(..)
- , HasQuoteContext(..)
- , HasReaderOptions(..)
- , ParserContext(..)
- , QuoteContext(..)
- , SourcePos )
+import Data.Text (Text)
+
+import Text.Pandoc.Builder (Blocks, Inlines)
+import Text.Pandoc.Definition (Meta (..), nullMeta)
+import Text.Pandoc.Logging
+import Text.Pandoc.Options (ReaderOptions (..))
+import Text.Pandoc.Parsing (Future, HasHeaderMap (..), HasIdentifierList (..),
+ HasIncludeFiles (..), HasLastStrPosition (..),
+ HasLogMessages (..), HasMacros (..),
+ HasQuoteContext (..), HasReaderOptions (..),
+ ParserContext (..), QuoteContext (..), SourcePos,
+ askF, asksF, returnF, runF, trimInlinesF)
+import Text.Pandoc.Readers.LaTeX.Types (Macro)
+
+-- | This is used to delay evaluation until all relevant information has been
+-- parsed and made available in the parser state.
+type F = Future OrgParserState
-- | An inline note / footnote containing the note key and its (inline) value.
type OrgNoteRecord = (String, F Blocks)
@@ -76,6 +84,8 @@ type OrgNoteTable = [OrgNoteRecord]
-- | Map of functions for link transformations. The map key is refers to the
-- link-type, the corresponding function transforms the given link string.
type OrgLinkFormatters = M.Map String (String -> String)
+-- | Macro expander function
+type MacroExpander = [String] -> String
-- | The states in which a todo item can be
data TodoState = Todo | Done
@@ -95,22 +105,34 @@ type TodoSequence = [TodoMarker]
data OrgParserState = OrgParserState
{ orgStateAnchorIds :: [String]
, orgStateEmphasisCharStack :: [Char]
+ , orgStateEmphasisPreChars :: [Char] -- ^ Chars allowed to occur before
+ -- emphasis; spaces and newlines are
+ -- always ok in addition to what is
+ -- specified here.
+ , orgStateEmphasisPostChars :: [Char] -- ^ Chars allowed at after emphasis
, orgStateEmphasisNewlines :: Maybe Int
, orgStateExportSettings :: ExportSettings
, orgStateHeaderMap :: M.Map Inlines String
, orgStateIdentifiers :: Set.Set String
+ , orgStateIncludeFiles :: [String]
, orgStateLastForbiddenCharPos :: Maybe SourcePos
, orgStateLastPreCharPos :: Maybe SourcePos
, orgStateLastStrPos :: Maybe SourcePos
, orgStateLinkFormatters :: OrgLinkFormatters
+ , orgStateMacros :: M.Map String MacroExpander
+ , orgStateMacroDepth :: Int
, orgStateMeta :: F Meta
, orgStateNotes' :: OrgNoteTable
, orgStateOptions :: ReaderOptions
, orgStateParserContext :: ParserContext
, orgStateTodoSequences :: [TodoSequence]
+ , orgLogMessages :: [LogMessage]
+ , orgMacros :: M.Map Text Macro
}
-data OrgParserLocal = OrgParserLocal { orgLocalQuoteContext :: QuoteContext }
+data OrgParserLocal = OrgParserLocal
+ { orgLocalQuoteContext :: QuoteContext
+ }
instance Default OrgParserLocal where
def = OrgParserLocal NoQuote
@@ -122,7 +144,7 @@ instance HasLastStrPosition OrgParserState where
getLastStrPos = orgStateLastStrPos
setLastStrPos pos st = st{ orgStateLastStrPos = Just pos }
-instance HasQuoteContext st (Reader OrgParserLocal) where
+instance Monad m => HasQuoteContext st (ReaderT OrgParserLocal m) where
getQuoteContext = asks orgLocalQuoteContext
withQuoteContext q = local (\s -> s{orgLocalQuoteContext = q})
@@ -134,26 +156,47 @@ instance HasHeaderMap OrgParserState where
extractHeaderMap = orgStateHeaderMap
updateHeaderMap f s = s{ orgStateHeaderMap = f (orgStateHeaderMap s) }
+instance HasLogMessages OrgParserState where
+ addLogMessage msg st = st{ orgLogMessages = msg : orgLogMessages st }
+ getLogMessages st = reverse $ orgLogMessages st
+
+instance HasMacros OrgParserState where
+ extractMacros st = orgMacros st
+ updateMacros f st = st{ orgMacros = f (orgMacros st) }
+
+instance HasIncludeFiles OrgParserState where
+ getIncludeFiles = orgStateIncludeFiles
+ addIncludeFile f st = st { orgStateIncludeFiles = f : orgStateIncludeFiles st }
+ dropLatestIncludeFile st =
+ st { orgStateIncludeFiles = drop 1 $ orgStateIncludeFiles st }
+
instance Default OrgParserState where
def = defaultOrgParserState
defaultOrgParserState :: OrgParserState
defaultOrgParserState = OrgParserState
{ orgStateAnchorIds = []
+ , orgStateEmphasisPreChars = "-\t ('\"{"
+ , orgStateEmphasisPostChars = "-\t\n .,:!?;'\")}["
, orgStateEmphasisCharStack = []
, orgStateEmphasisNewlines = Nothing
, orgStateExportSettings = def
, orgStateHeaderMap = M.empty
, orgStateIdentifiers = Set.empty
+ , orgStateIncludeFiles = []
, orgStateLastForbiddenCharPos = Nothing
, orgStateLastPreCharPos = Nothing
, orgStateLastStrPos = Nothing
, orgStateLinkFormatters = M.empty
+ , orgStateMacros = M.empty
+ , orgStateMacroDepth = 0
, orgStateMeta = return nullMeta
, orgStateNotes' = []
, orgStateOptions = def
, orgStateParserContext = NullState
, orgStateTodoSequences = []
+ , orgLogMessages = []
+ , orgMacros = M.empty
}
optionsToParserState :: ReaderOptions -> OrgParserState
@@ -177,6 +220,15 @@ activeTodoSequences st =
activeTodoMarkers :: OrgParserState -> TodoSequence
activeTodoMarkers = concat . activeTodoSequences
+lookupMacro :: String -> OrgParserState -> Maybe MacroExpander
+lookupMacro macroName = M.lookup macroName . orgStateMacros
+
+registerMacro :: (String, MacroExpander) -> OrgParserState -> OrgParserState
+registerMacro (name, expander) st =
+ let curMacros = orgStateMacros st
+ in st{ orgStateMacros = M.insert name expander curMacros }
+
+
--
-- Export Settings
@@ -191,20 +243,22 @@ data ArchivedTreesOption =
-- | Export settings <http://orgmode.org/manual/Export-settings.html>
-- These settings can be changed via OPTIONS statements.
data ExportSettings = ExportSettings
- { exportArchivedTrees :: ArchivedTreesOption -- ^ How to treat archived trees
- , exportDrawers :: Either [String] [String]
+ { exportArchivedTrees :: ArchivedTreesOption -- ^ How to treat archived trees
+ , exportDrawers :: Either [String] [String]
-- ^ Specify drawer names which should be exported. @Left@ names are
-- explicitly excluded from the resulting output while @Right@ means that
-- only the listed drawer names should be included.
- , exportEmphasizedText :: Bool -- ^ Parse emphasized text
- , exportHeadlineLevels :: Int
+ , exportEmphasizedText :: Bool -- ^ Parse emphasized text
+ , exportHeadlineLevels :: Int
-- ^ Maximum depth of headlines, deeper headlines are convert to list
- , exportSmartQuotes :: Bool -- ^ Parse quotes smartly
- , exportSpecialStrings :: Bool -- ^ Parse ellipses and dashes smartly
- , exportSubSuperscripts :: Bool -- ^ TeX-like syntax for sub- and superscripts
- , exportWithAuthor :: Bool -- ^ Include author in final meta-data
- , exportWithCreator :: Bool -- ^ Include creator in final meta-data
- , exportWithEmail :: Bool -- ^ Include email in final meta-data
+ , exportPreserveBreaks :: Bool -- ^ Whether to preserve linebreaks
+ , exportSmartQuotes :: Bool -- ^ Parse quotes smartly
+ , exportSpecialStrings :: Bool -- ^ Parse ellipses and dashes smartly
+ , exportSubSuperscripts :: Bool -- ^ TeX-like syntax for sub- and superscripts
+ , exportWithAuthor :: Bool -- ^ Include author in final meta-data
+ , exportWithCreator :: Bool -- ^ Include creator in final meta-data
+ , exportWithEmail :: Bool -- ^ Include email in final meta-data
+ , exportWithTags :: Bool -- ^ Keep tags as part of headlines
, exportWithTodoKeywords :: Bool -- ^ Keep TODO keywords in headers
}
@@ -217,43 +271,13 @@ defaultExportSettings = ExportSettings
, exportDrawers = Left ["LOGBOOK"]
, exportEmphasizedText = True
, exportHeadlineLevels = 3
- , exportSmartQuotes = True
+ , exportPreserveBreaks = False
+ , exportSmartQuotes = False
, exportSpecialStrings = True
, exportSubSuperscripts = True
, exportWithAuthor = True
, exportWithCreator = True
, exportWithEmail = True
+ , exportWithTags = True
, exportWithTodoKeywords = True
}
-
-
---
--- Parser state reader
---
-
--- | Reader monad wrapping the parser state. This is used to delay evaluation
--- until all relevant information has been parsed and made available in the
--- parser state. See also the newtype of the same name in
--- Text.Pandoc.Parsing.
-newtype F a = F { unF :: Reader OrgParserState a
- } deriving (Functor, Applicative, Monad)
-
-instance Monoid a => Monoid (F a) where
- mempty = return mempty
- mappend = liftM2 mappend
- mconcat = fmap mconcat . sequence
-
-runF :: F a -> OrgParserState -> a
-runF = runReader . unF
-
-askF :: F OrgParserState
-askF = F ask
-
-asksF :: (OrgParserState -> a) -> F a
-asksF f = F $ asks f
-
-trimInlinesF :: F Inlines -> F Inlines
-trimInlinesF = liftM trimInlines
-
-returnF :: Monad m => a -> m (F a)
-returnF = return . return
diff --git a/src/Text/Pandoc/Readers/Org/Parsing.hs b/src/Text/Pandoc/Readers/Org/Parsing.hs
index 95415f823..36420478b 100644
--- a/src/Text/Pandoc/Readers/Org/Parsing.hs
+++ b/src/Text/Pandoc/Readers/Org/Parsing.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,8 +17,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.Parsing
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -31,6 +31,8 @@ functions are adapted to Org-mode specific functionality.
module Text.Pandoc.Readers.Org.Parsing
( OrgParser
, anyLine
+ , anyLineNewline
+ , indentWith
, blanklines
, newline
, parseFromString
@@ -70,8 +72,11 @@ module Text.Pandoc.Readers.Org.Parsing
, dash
, ellipses
, citeKey
+ , gridTableWith
+ , insertIncludedFileF
-- * Re-exports from Text.Pandoc.Parsec
, runParser
+ , runParserT
, getInput
, char
, letter
@@ -107,24 +112,24 @@ module Text.Pandoc.Readers.Org.Parsing
, getPosition
) where
-import Text.Pandoc.Readers.Org.ParserState
+import Text.Pandoc.Readers.Org.ParserState
+import Text.Pandoc.Parsing hiding (F, anyLine, blanklines, newline,
+ parseFromString)
import qualified Text.Pandoc.Parsing as P
-import Text.Pandoc.Parsing hiding ( anyLine, blanklines, newline
- , parseFromString )
-import Control.Monad ( guard )
-import Control.Monad.Reader ( Reader )
+import Control.Monad (guard)
+import Control.Monad.Reader (ReaderT)
-- | The parser used to read org files.
-type OrgParser = ParserT [Char] OrgParserState (Reader OrgParserLocal)
+type OrgParser m = ParserT [Char] OrgParserState (ReaderT OrgParserLocal m)
--
-- Adaptions and specializations of parsing utilities
--
-- | Parse any line of text
-anyLine :: OrgParser String
+anyLine :: Monad m => OrgParser m String
anyLine =
P.anyLine
<* updateLastPreCharPos
@@ -132,7 +137,7 @@ anyLine =
-- The version Text.Pandoc.Parsing cannot be used, as we need additional parts
-- of the state saved and restored.
-parseFromString :: OrgParser a -> String -> OrgParser a
+parseFromString :: Monad m => OrgParser m a -> String -> OrgParser m a
parseFromString parser str' = do
oldLastPreCharPos <- orgStateLastPreCharPos <$> getState
updateState $ \s -> s{ orgStateLastPreCharPos = Nothing }
@@ -141,33 +146,34 @@ parseFromString parser str' = do
return result
-- | Skip one or more tab or space characters.
-skipSpaces1 :: OrgParser ()
+skipSpaces1 :: Monad m => OrgParser m ()
skipSpaces1 = skipMany1 spaceChar
-- | Like @Text.Parsec.Char.newline@, but causes additional state changes.
-newline :: OrgParser Char
+newline :: Monad m => OrgParser m Char
newline =
P.newline
<* updateLastPreCharPos
<* updateLastForbiddenCharPos
-- | Like @Text.Parsec.Char.blanklines@, but causes additional state changes.
-blanklines :: OrgParser [Char]
+blanklines :: Monad m => OrgParser m [Char]
blanklines =
P.blanklines
<* updateLastPreCharPos
<* updateLastForbiddenCharPos
-- | Succeeds when we're in list context.
-inList :: OrgParser ()
+inList :: Monad m => OrgParser m ()
inList = do
ctx <- orgStateParserContext <$> getState
guard (ctx == ListItemState)
-- | Parse in different context
-withContext :: ParserContext -- ^ New parser context
- -> OrgParser a -- ^ Parser to run in that context
- -> OrgParser a
+withContext :: Monad m
+ => ParserContext -- ^ New parser context
+ -> OrgParser m a -- ^ Parser to run in that context
+ -> OrgParser m a
withContext context parser = do
oldContext <- orgStateParserContext <$> getState
updateState $ \s -> s{ orgStateParserContext = context }
@@ -180,19 +186,19 @@ withContext context parser = do
--
-- | Get an export setting.
-getExportSetting :: (ExportSettings -> a) -> OrgParser a
+getExportSetting :: Monad m => (ExportSettings -> a) -> OrgParser m a
getExportSetting s = s . orgStateExportSettings <$> getState
-- | Set the current position as the last position at which a forbidden char
-- was found (i.e. a character which is not allowed at the inner border of
-- markup).
-updateLastForbiddenCharPos :: OrgParser ()
+updateLastForbiddenCharPos :: Monad m => OrgParser m ()
updateLastForbiddenCharPos = getPosition >>= \p ->
updateState $ \s -> s{ orgStateLastForbiddenCharPos = Just p}
-- | Set the current parser position as the position at which a character was
-- seen which allows inline markup to follow.
-updateLastPreCharPos :: OrgParser ()
+updateLastPreCharPos :: Monad m => OrgParser m ()
updateLastPreCharPos = getPosition >>= \p ->
updateState $ \s -> s{ orgStateLastPreCharPos = Just p}
@@ -201,15 +207,15 @@ updateLastPreCharPos = getPosition >>= \p ->
--
-- | Read the key of a plist style key-value list.
-orgArgKey :: OrgParser String
+orgArgKey :: Monad m => OrgParser m String
orgArgKey = try $
skipSpaces *> char ':'
*> many1 orgArgWordChar
-- | Read the value of a plist style key-value list.
-orgArgWord :: OrgParser String
+orgArgWord :: Monad m => OrgParser m String
orgArgWord = many1 orgArgWordChar
-- | Chars treated as part of a word in plists.
-orgArgWordChar :: OrgParser Char
+orgArgWordChar :: Monad m => OrgParser m Char
orgArgWordChar = alphaNum <|> oneOf "-_"
diff --git a/src/Text/Pandoc/Readers/Org/Shared.hs b/src/Text/Pandoc/Readers/Org/Shared.hs
index 8c87cfa25..cba72cc07 100644
--- a/src/Text/Pandoc/Readers/Org/Shared.hs
+++ b/src/Text/Pandoc/Readers/Org/Shared.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,8 +18,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.Shared
+ Copyright : Copyright (C) 2014-2018 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -29,14 +29,12 @@ Utility functions used in other Pandoc Org modules.
module Text.Pandoc.Readers.Org.Shared
( cleanLinkString
, isImageFilename
- , rundocBlockClass
- , toRundocAttrib
+ , originalLang
, translateLang
) where
-import Control.Arrow ( first )
-import Data.Char ( isAlphaNum )
-import Data.List ( isPrefixOf, isSuffixOf )
+import Data.Char (isAlphaNum)
+import Data.List (isPrefixOf, isSuffixOf)
-- | Check whether the given string looks like the path to of URL of an image.
@@ -58,8 +56,8 @@ cleanLinkString s =
'.':'/':_ -> Just s -- relative path
'.':'.':'/':_ -> Just s -- relative path
-- Relative path or URL (file schema)
- 'f':'i':'l':'e':':':s' -> Just $ if ("//" `isPrefixOf` s') then s else s'
- _ | isUrl s -> Just s -- URL
+ 'f':'i':'l':'e':':':s' -> Just $ if "//" `isPrefixOf` s' then s else s'
+ _ | isUrl s -> Just s -- URL
_ -> Nothing
where
isUrl :: String -> Bool
@@ -68,17 +66,17 @@ cleanLinkString s =
in all (\c -> isAlphaNum c || c `elem` (".-"::String)) scheme
&& not (null path)
--- | Prefix used for Rundoc classes and arguments.
-rundocPrefix :: String
-rundocPrefix = "rundoc-"
+-- | Creates an key-value pair marking the original language name specified for
+-- a piece of source code.
--- | The class-name used to mark rundoc blocks.
-rundocBlockClass :: String
-rundocBlockClass = rundocPrefix ++ "block"
-
--- | Prefix the name of a attribute, marking it as a code execution parameter.
-toRundocAttrib :: (String, String) -> (String, String)
-toRundocAttrib = first (rundocPrefix ++)
+-- | Creates an key-value attributes marking the original language name
+-- specified for a piece of source code.
+originalLang :: String -> [(String, String)]
+originalLang lang =
+ let transLang = translateLang lang
+ in if transLang == lang
+ then []
+ else [("org-language", lang)]
-- | Translate from Org-mode's programming language identifiers to those used
-- by Pandoc. This is useful to allow for proper syntax highlighting in
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs
index e05b6cba2..e88d997f0 100644
--- a/src/Text/Pandoc/Readers/RST.hs
+++ b/src/Text/Pandoc/Readers/RST.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.RST
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,38 +30,50 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion from reStructuredText to 'Pandoc' document.
-}
-module Text.Pandoc.Readers.RST (
- readRST,
- readRSTWithWarnings
- ) where
-import Text.Pandoc.Definition
-import Text.Pandoc.Builder (setMeta, fromList)
-import Text.Pandoc.Shared
-import Text.Pandoc.Parsing
-import Text.Pandoc.Options
-import Control.Monad ( when, liftM, guard, mzero )
-import Data.List ( findIndex, intercalate,
- transpose, sort, deleteFirstsBy, isSuffixOf , nub, union)
-import Data.Maybe (fromMaybe)
+module Text.Pandoc.Readers.RST ( readRST ) where
+import Control.Arrow (second)
+import Control.Monad (forM_, guard, liftM, mplus, mzero, when)
+import Control.Monad.Except (throwError)
+import Control.Monad.Identity (Identity (..))
+import Data.Char (isHexDigit, isSpace, toLower, toUpper)
+import Data.List (deleteFirstsBy, elemIndex, intercalate, isInfixOf, isSuffixOf,
+ nub, sort, transpose, union)
import qualified Data.Map as M
-import Text.Printf ( printf )
-import Text.Pandoc.Builder (Inlines, Blocks, trimInlines)
-import qualified Text.Pandoc.Builder as B
-import Data.Sequence (viewr, ViewR(..))
-import Data.Char (toLower, isHexDigit, isSpace)
+import Data.Maybe (fromMaybe, isJust)
import Data.Monoid ((<>))
+import Data.Sequence (ViewR (..), viewr)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.Pandoc.Builder (Blocks, Inlines, fromList, setMeta, trimInlines)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad, fetchItem, readFileFromDirs)
+import Text.Pandoc.CSV (CSVOptions (..), defaultCSVOptions, parseCSV)
+import Text.Pandoc.Definition
import Text.Pandoc.Error
+import Text.Pandoc.ImageSize (lengthToDim, scaleDimension)
+import Text.Pandoc.Logging
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing
+import Text.Pandoc.Shared
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.Printf (printf)
--- | Parse reStructuredText string and return Pandoc document.
-readRST :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError Pandoc
-readRST opts s = (readWith parseRST) def{ stateOptions = opts } (s ++ "\n\n")
-
-readRSTWithWarnings :: ReaderOptions -> String -> Either PandocError (Pandoc, [String])
-readRSTWithWarnings opts s = (readWithWarnings parseRST) def{ stateOptions = opts } (s ++ "\n\n")
+-- TODO:
+-- [ ] .. parsed-literal
-type RSTParser = Parser [Char] ParserState
+-- | Parse reStructuredText string and return Pandoc document.
+readRST :: PandocMonad m
+ => ReaderOptions -- ^ Reader options
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
+ -> m Pandoc
+readRST opts s = do
+ parsed <- readWithM parseRST def{ stateOptions = opts }
+ (T.unpack (crFilter s) ++ "\n\n")
+ case parsed of
+ Right result -> return result
+ Left e -> throwError e
+
+type RSTParser m = ParserT [Char] ParserState m
--
-- Constants and data structure definitions
@@ -87,9 +100,9 @@ isHeader _ _ = False
-- | Promote all headers in a list of blocks. (Part of
-- title transformation for RST.)
promoteHeaders :: Int -> [Block] -> [Block]
-promoteHeaders num ((Header level attr text):rest) =
- (Header (level - num) attr text):(promoteHeaders num rest)
-promoteHeaders num (other:rest) = other:(promoteHeaders num rest)
+promoteHeaders num (Header level attr text:rest) =
+ Header (level - num) attr text:promoteHeaders num rest
+promoteHeaders num (other:rest) = other:promoteHeaders num rest
promoteHeaders _ [] = []
-- | If list of blocks starts with a header (or a header and subheader)
@@ -101,11 +114,11 @@ titleTransform :: ([Block], Meta) -- ^ list of blocks, metadata
titleTransform (bs, meta) =
let (bs', meta') =
case bs of
- ((Header 1 _ head1):(Header 2 _ head2):rest)
+ (Header 1 _ head1:Header 2 _ head2:rest)
| not (any (isHeader 1) rest || any (isHeader 2) rest) -> -- tit/sub
(promoteHeaders 2 rest, setMeta "title" (fromList head1) $
setMeta "subtitle" (fromList head2) meta)
- ((Header 1 _ head1):rest)
+ (Header 1 _ head1:rest)
| not (any (isHeader 1) rest) -> -- title only
(promoteHeaders 1 rest,
setMeta "title" (fromList head1) meta)
@@ -121,8 +134,10 @@ metaFromDefList ds meta = adjustAuthors $ foldr f meta ds
adjustAuthors (Meta metamap) = Meta $ M.adjust splitAuthors "author"
$ M.adjust toPlain "date"
$ M.adjust toPlain "title"
- $ M.mapKeys (\k -> if k == "authors" then "author" else k)
- $ metamap
+ $ M.mapKeys (\k ->
+ if k == "authors"
+ then "author"
+ else k) metamap
toPlain (MetaBlocks [Para xs]) = MetaInlines xs
toPlain x = x
splitAuthors (MetaBlocks [Para xs])
@@ -131,6 +146,12 @@ metaFromDefList ds meta = adjustAuthors $ foldr f meta ds
splitAuthors x = x
splitAuthors' = map normalizeSpaces .
splitOnSemi . concatMap factorSemi
+ normalizeSpaces = reverse . dropWhile isSp . reverse .
+ dropWhile isSp
+ isSp Space = True
+ isSp SoftBreak = True
+ isSp LineBreak = True
+ isSp _ = False
splitOnSemi = splitBy (==Str ";")
factorSemi (Str []) = []
factorSemi (Str s) = case break (==';') s of
@@ -141,41 +162,61 @@ metaFromDefList ds meta = adjustAuthors $ foldr f meta ds
factorSemi (Str ys)
factorSemi x = [x]
-parseRST :: RSTParser Pandoc
+parseRST :: PandocMonad m => RSTParser m Pandoc
parseRST = do
optional blanklines -- skip blank lines at beginning of file
startPos <- getPosition
-- go through once just to get list of reference keys and notes
-- docMinusKeys is the raw document with blanks where the keys were...
docMinusKeys <- concat <$>
- manyTill (referenceKey <|> noteBlock <|> lineClump) eof
+ manyTill (referenceKey <|> anchorDef <|>
+ noteBlock <|> citationBlock <|>
+ headerBlock <|> lineClump) eof
setInput docMinusKeys
setPosition startPos
st' <- getState
let reversedNotes = stateNotes st'
- updateState $ \s -> s { stateNotes = reverse reversedNotes }
+ updateState $ \s -> s { stateNotes = reverse reversedNotes
+ , stateHeaders = mempty
+ , stateIdentifiers = mempty }
-- now parse it for real...
blocks <- B.toList <$> parseBlocks
+ citations <- (sort . M.toList . stateCitations) <$> getState
+ citationItems <- mapM parseCitation citations
+ let refBlock = if null citationItems
+ then []
+ else [Div ("citations",[],[]) $
+ B.toList $ B.definitionList citationItems]
standalone <- getOption readerStandalone
state <- getState
let meta = stateMeta state
let (blocks', meta') = if standalone
then titleTransform (blocks, meta)
else (blocks, meta)
- return $ Pandoc meta' blocks'
+ reportLogMessages
+ return $ Pandoc meta' (blocks' ++ refBlock)
+
+parseCitation :: PandocMonad m
+ => (String, String) -> RSTParser m (Inlines, [Blocks])
+parseCitation (ref, raw) = do
+ contents <- parseFromString' parseBlocks raw
+ return (B.spanWith (ref, ["citation-label"], []) (B.str ref),
+ [contents])
+
--
-- parsing blocks
--
-parseBlocks :: RSTParser Blocks
+parseBlocks :: PandocMonad m => RSTParser m Blocks
parseBlocks = mconcat <$> manyTill block eof
-block :: RSTParser Blocks
+block :: PandocMonad m => RSTParser m Blocks
block = choice [ codeBlock
, blockQuote
, fieldList
, directive
+ , anchor
, comment
, header
, hrule
@@ -191,7 +232,7 @@ block = choice [ codeBlock
-- field list
--
-rawFieldListItem :: Int -> RSTParser (String, String)
+rawFieldListItem :: Monad m => Int -> RSTParser m (String, String)
rawFieldListItem minIndent = try $ do
indent <- length <$> many (char ' ')
guard $ indent >= minIndent
@@ -204,15 +245,15 @@ rawFieldListItem minIndent = try $ do
let raw = (if null first then "" else (first ++ "\n")) ++ rest ++ "\n"
return (name, raw)
-fieldListItem :: Int -> RSTParser (Inlines, [Blocks])
+fieldListItem :: PandocMonad m => Int -> RSTParser m (Inlines, [Blocks])
fieldListItem minIndent = try $ do
(name, raw) <- rawFieldListItem minIndent
term <- parseInlineFromString name
- contents <- parseFromString parseBlocks raw
+ contents <- parseFromString' parseBlocks raw
optional blanklines
return (term, [contents])
-fieldList :: RSTParser Blocks
+fieldList :: PandocMonad m => RSTParser m Blocks
fieldList = try $ do
indent <- length <$> lookAhead (many spaceChar)
items <- many1 $ fieldListItem indent
@@ -224,43 +265,62 @@ fieldList = try $ do
-- line block
--
-lineBlock :: RSTParser Blocks
+lineBlock :: PandocMonad m => RSTParser m Blocks
lineBlock = try $ do
lines' <- lineBlockLines
lines'' <- mapM parseInlineFromString lines'
return $ B.lineBlock lines''
+lineBlockDirective :: PandocMonad m => String -> RSTParser m Blocks
+lineBlockDirective body = do
+ lines' <- mapM parseInlineFromString $ lines $ stripTrailingNewlines body
+ return $ B.lineBlock lines'
+
--
-- paragraph block
--
-- note: paragraph can end in a :: starting a code block
-para :: RSTParser Blocks
+para :: PandocMonad m => RSTParser m Blocks
para = try $ do
result <- trimInlines . mconcat <$> many1 inline
option (B.plain result) $ try $ do
newline
blanklines
case viewr (B.unMany result) of
- ys :> (Str xs) | "::" `isSuffixOf` xs -> do
+ ys :> Str xs | "::" `isSuffixOf` xs -> do
raw <- option mempty codeBlockBody
return $ B.para (B.Many ys <> B.str (take (length xs - 1) xs))
<> raw
_ -> return (B.para result)
-plain :: RSTParser Blocks
+plain :: PandocMonad m => RSTParser m Blocks
plain = B.plain . trimInlines . mconcat <$> many1 inline
--
-- header blocks
--
-header :: RSTParser Blocks
+header :: PandocMonad m => RSTParser m Blocks
header = doubleHeader <|> singleHeader <?> "header"
-- a header with lines on top and bottom
-doubleHeader :: RSTParser Blocks
-doubleHeader = try $ do
+doubleHeader :: PandocMonad m => RSTParser m Blocks
+doubleHeader = do
+ (txt, c) <- doubleHeader'
+ -- check to see if we've had this kind of header before.
+ -- if so, get appropriate level. if not, add to list.
+ state <- getState
+ let headerTable = stateHeaderTable state
+ let (headerTable',level) = case elemIndex (DoubleHeader c) headerTable of
+ Just ind -> (headerTable, ind + 1)
+ Nothing -> (headerTable ++ [DoubleHeader c], length headerTable + 1)
+ setState (state { stateHeaderTable = headerTable' })
+ attr <- registerHeader nullAttr txt
+ return $ B.headerWith attr level txt
+
+doubleHeader' :: PandocMonad m => RSTParser m (Inlines, Char)
+doubleHeader' = try $ do
c <- oneOf underlineChars
rest <- many (char c) -- the top line
let lenTop = length (c:rest)
@@ -268,48 +328,45 @@ doubleHeader = try $ do
newline
txt <- trimInlines . mconcat <$> many1 (notFollowedBy blankline >> inline)
pos <- getPosition
- let len = (sourceColumn pos) - 1
- if (len > lenTop) then fail "title longer than border" else return ()
+ let len = sourceColumn pos - 1
+ when (len > lenTop) $ fail "title longer than border"
blankline -- spaces and newline
count lenTop (char c) -- the bottom line
blanklines
- -- check to see if we've had this kind of header before.
- -- if so, get appropriate level. if not, add to list.
+ return (txt, c)
+
+-- a header with line on the bottom only
+singleHeader :: PandocMonad m => RSTParser m Blocks
+singleHeader = do
+ (txt, c) <- singleHeader'
state <- getState
let headerTable = stateHeaderTable state
- let (headerTable',level) = case findIndex (== DoubleHeader c) headerTable of
+ let (headerTable',level) = case elemIndex (SingleHeader c) headerTable of
Just ind -> (headerTable, ind + 1)
- Nothing -> (headerTable ++ [DoubleHeader c], (length headerTable) + 1)
+ Nothing -> (headerTable ++ [SingleHeader c], length headerTable + 1)
setState (state { stateHeaderTable = headerTable' })
attr <- registerHeader nullAttr txt
return $ B.headerWith attr level txt
--- a header with line on the bottom only
-singleHeader :: RSTParser Blocks
-singleHeader = try $ do
+singleHeader' :: PandocMonad m => RSTParser m (Inlines, Char)
+singleHeader' = try $ do
notFollowedBy' whitespace
- txt <- trimInlines . mconcat <$> many1 (do {notFollowedBy blankline; inline})
+ lookAhead $ anyLine >> oneOf underlineChars
+ txt <- trimInlines . mconcat <$> many1 (notFollowedBy blankline >> inline)
pos <- getPosition
- let len = (sourceColumn pos) - 1
+ let len = sourceColumn pos - 1
blankline
c <- oneOf underlineChars
count (len - 1) (char c)
many (char c)
blanklines
- state <- getState
- let headerTable = stateHeaderTable state
- let (headerTable',level) = case findIndex (== SingleHeader c) headerTable of
- Just ind -> (headerTable, ind + 1)
- Nothing -> (headerTable ++ [SingleHeader c], (length headerTable) + 1)
- setState (state { stateHeaderTable = headerTable' })
- attr <- registerHeader nullAttr txt
- return $ B.headerWith attr level txt
+ return (txt, c)
--
-- hrule block
--
-hrule :: Parser [Char] st Blocks
+hrule :: Monad m => ParserT [Char] st m Blocks
hrule = try $ do
chr <- oneOf underlineChars
count 3 (char chr)
@@ -323,14 +380,14 @@ hrule = try $ do
--
-- read a line indented by a given string
-indentedLine :: String -> Parser [Char] st [Char]
+indentedLine :: Monad m => String -> ParserT [Char] st m [Char]
indentedLine indents = try $ do
string indents
anyLine
-- one or more indented lines, possibly separated by blank lines.
-- any amount of indentation will work.
-indentedBlock :: Parser [Char] st [Char]
+indentedBlock :: Monad m => ParserT [Char] st m [Char]
indentedBlock = try $ do
indents <- lookAhead $ many1 spaceChar
lns <- many1 $ try $ do b <- option "" blanklines
@@ -339,24 +396,24 @@ indentedBlock = try $ do
optional blanklines
return $ unlines lns
-quotedBlock :: Parser [Char] st [Char]
+quotedBlock :: Monad m => ParserT [Char] st m [Char]
quotedBlock = try $ do
quote <- lookAhead $ oneOf "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
lns <- many1 $ lookAhead (char quote) >> anyLine
optional blanklines
return $ unlines lns
-codeBlockStart :: Parser [Char] st Char
+codeBlockStart :: Monad m => ParserT [Char] st m Char
codeBlockStart = string "::" >> blankline >> blankline
-codeBlock :: Parser [Char] st Blocks
+codeBlock :: Monad m => ParserT [Char] st m Blocks
codeBlock = try $ codeBlockStart >> codeBlockBody
-codeBlockBody :: Parser [Char] st Blocks
+codeBlockBody :: Monad m => ParserT [Char] st m Blocks
codeBlockBody = try $ B.codeBlock . stripTrailingNewlines <$>
(indentedBlock <|> quotedBlock)
-lhsCodeBlock :: RSTParser Blocks
+lhsCodeBlock :: Monad m => RSTParser m Blocks
lhsCodeBlock = try $ do
getPosition >>= guard . (==1) . sourceColumn
guardEnabled Ext_literate_haskell
@@ -366,14 +423,14 @@ lhsCodeBlock = try $ do
return $ B.codeBlockWith ("", ["sourceCode", "literate", "haskell"], [])
$ intercalate "\n" lns
-latexCodeBlock :: Parser [Char] st [[Char]]
+latexCodeBlock :: Monad m => ParserT [Char] st m [[Char]]
latexCodeBlock = try $ do
try (latexBlockLine "\\begin{code}")
many1Till anyLine (try $ latexBlockLine "\\end{code}")
where
latexBlockLine s = skipMany spaceChar >> string s >> blankline
-birdCodeBlock :: Parser [Char] st [[Char]]
+birdCodeBlock :: Monad m => ParserT [Char] st m [[Char]]
birdCodeBlock = filterSpace <$> many1 birdTrackLine
where filterSpace lns =
-- if (as is normal) there is always a space after >, drop it
@@ -381,99 +438,159 @@ birdCodeBlock = filterSpace <$> many1 birdTrackLine
then map (drop 1) lns
else lns
-birdTrackLine :: Parser [Char] st [Char]
+birdTrackLine :: Monad m => ParserT [Char] st m [Char]
birdTrackLine = char '>' >> anyLine
--
-- block quotes
--
-blockQuote :: RSTParser Blocks
+blockQuote :: PandocMonad m => RSTParser m Blocks
blockQuote = do
raw <- indentedBlock
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString parseBlocks $ raw ++ "\n\n"
+ contents <- parseFromString' parseBlocks $ raw ++ "\n\n"
return $ B.blockQuote contents
+{-
+Unsupported options for include:
+tab-width
+encoding
+-}
+
+includeDirective :: PandocMonad m
+ => String -> [(String, String)] -> String
+ -> RSTParser m Blocks
+includeDirective top fields body = do
+ let f = trim top
+ guard $ not (null f)
+ guard $ null (trim body)
+ -- options
+ let (startLine :: Maybe Int) = lookup "start-line" fields >>= safeRead
+ let (endLine :: Maybe Int) = lookup "end-line" fields >>= safeRead
+ oldPos <- getPosition
+ oldInput <- getInput
+ containers <- stateContainers <$> getState
+ when (f `elem` containers) $
+ throwError $ PandocParseError $ "Include file loop at " ++ show oldPos
+ updateState $ \s -> s{ stateContainers = f : stateContainers s }
+ mbContents <- readFileFromDirs ["."] f
+ contentLines <- case mbContents of
+ Just s -> return $ lines s
+ Nothing -> do
+ logMessage $ CouldNotLoadIncludeFile f oldPos
+ return []
+ let numLines = length contentLines
+ let startLine' = case startLine of
+ Nothing -> 1
+ Just x | x >= 0 -> x
+ | otherwise -> numLines + x -- negative from end
+ let endLine' = case endLine of
+ Nothing -> numLines + 1
+ Just x | x >= 0 -> x
+ | otherwise -> numLines + x -- negative from end
+ let contentLines' = drop (startLine' - 1)
+ $ take (endLine' - 1) contentLines
+ let contentLines'' = (case trim <$> lookup "end-before" fields of
+ Just patt -> takeWhile (not . (patt `isInfixOf`))
+ Nothing -> id) .
+ (case trim <$> lookup "start-after" fields of
+ Just patt -> drop 1 .
+ dropWhile (not . (patt `isInfixOf`))
+ Nothing -> id) $ contentLines'
+ let contents' = unlines contentLines'' ++ "\n"
+ case lookup "code" fields of
+ Just lang -> do
+ let numberLines = lookup "number-lines" fields
+ let classes = trimr lang : ["numberLines" | isJust numberLines] ++
+ maybe [] words (lookup "class" fields)
+ let kvs = maybe [] (\n -> [("startFrom", trimr n)]) numberLines
+ let ident = maybe "" trimr $ lookup "name" fields
+ let attribs = (ident, classes, kvs)
+ return $ B.codeBlockWith attribs contents'
+ Nothing -> case lookup "literal" fields of
+ Just _ -> return $ B.rawBlock "rst" contents'
+ Nothing -> do
+ setPosition $ newPos f 1 1
+ setInput contents'
+ bs <- optional blanklines >>
+ (mconcat <$> many block)
+ setInput oldInput
+ setPosition oldPos
+ updateState $ \s -> s{ stateContainers =
+ tail $ stateContainers s }
+ return bs
+
+
--
-- list blocks
--
-list :: RSTParser Blocks
+list :: PandocMonad m => RSTParser m Blocks
list = choice [ bulletList, orderedList, definitionList ] <?> "list"
-definitionListItem :: RSTParser (Inlines, [Blocks])
+definitionListItem :: PandocMonad m => RSTParser m (Inlines, [Blocks])
definitionListItem = try $ do
-- avoid capturing a directive or comment
notFollowedBy (try $ char '.' >> char '.')
term <- trimInlines . mconcat <$> many1Till inline endline
raw <- indentedBlock
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString parseBlocks $ raw ++ "\n"
+ contents <- parseFromString' parseBlocks $ raw ++ "\n"
return (term, [contents])
-definitionList :: RSTParser Blocks
+definitionList :: PandocMonad m => RSTParser m Blocks
definitionList = B.definitionList <$> many1 definitionListItem
-- parses bullet list start and returns its length (inc. following whitespace)
-bulletListStart :: Parser [Char] st Int
+bulletListStart :: Monad m => ParserT [Char] st m Int
bulletListStart = try $ do
notFollowedBy' hrule -- because hrules start out just like lists
marker <- oneOf bulletListMarkers
- white <- many1 spaceChar
+ white <- many1 spaceChar <|> "" <$ lookAhead (char '\n')
return $ length (marker:white)
-- parses ordered list start and returns its length (inc following whitespace)
-orderedListStart :: ListNumberStyle
+orderedListStart :: Monad m => ListNumberStyle
-> ListNumberDelim
- -> RSTParser Int
+ -> RSTParser m Int
orderedListStart style delim = try $ do
(_, markerLen) <- withHorizDisplacement (orderedListMarker style delim)
- white <- many1 spaceChar
+ white <- many1 spaceChar <|> "" <$ lookAhead (char '\n')
return $ markerLen + length white
-- parse a line of a list item
-listLine :: Int -> RSTParser [Char]
+listLine :: Monad m => Int -> RSTParser m [Char]
listLine markerLength = try $ do
notFollowedBy blankline
indentWith markerLength
- line <- anyLine
- return $ line ++ "\n"
-
--- indent by specified number of spaces (or equiv. tabs)
-indentWith :: Int -> RSTParser [Char]
-indentWith num = do
- tabStop <- getOption readerTabStop
- if (num < tabStop)
- then count num (char ' ')
- else choice [ try (count num (char ' ')),
- (try (char '\t' >> count (num - tabStop) (char ' '))) ]
+ anyLineNewline
-- parse raw text for one list item, excluding start marker and continuations
-rawListItem :: RSTParser Int
- -> RSTParser (Int, [Char])
+rawListItem :: Monad m => RSTParser m Int
+ -> RSTParser m (Int, [Char])
rawListItem start = try $ do
markerLength <- start
- firstLine <- anyLine
+ firstLine <- anyLineNewline
restLines <- many (listLine markerLength)
- return (markerLength, (firstLine ++ "\n" ++ (concat restLines)))
+ return (markerLength, firstLine ++ concat restLines)
-- continuation of a list item - indented and separated by blankline or
-- (in compact lists) endline.
-- Note: nested lists are parsed as continuations.
-listContinuation :: Int -> RSTParser [Char]
+listContinuation :: Monad m => Int -> RSTParser m [Char]
listContinuation markerLength = try $ do
blanks <- many1 blankline
result <- many1 (listLine markerLength)
return $ blanks ++ concat result
-listItem :: RSTParser Int
- -> RSTParser Blocks
+listItem :: PandocMonad m
+ => RSTParser m Int
+ -> RSTParser m Blocks
listItem start = try $ do
(markerLength, first) <- rawListItem start
rest <- many (listContinuation markerLength)
- blanks <- choice [ try (many blankline <* lookAhead start),
- many1 blankline ] -- whole list must end with blank.
+ skipMany1 blankline <|> () <$ lookAhead start
-- parsing with ListItemState forces markers at beginning of lines to
-- count as list item markers, even if not separated by blank space.
-- see definition of "endline"
@@ -481,52 +598,52 @@ listItem start = try $ do
let oldContext = stateParserContext state
setState $ state {stateParserContext = ListItemState}
-- parse the extracted block, which may itself contain block elements
- parsed <- parseFromString parseBlocks $ concat (first:rest) ++ blanks
+ parsed <- parseFromString' parseBlocks $ concat (first:rest) ++ "\n"
updateState (\st -> st {stateParserContext = oldContext})
return $ case B.toList parsed of
- [Para xs] -> B.singleton $ Plain xs
- [Para xs, BulletList ys] -> B.fromList [Plain xs, BulletList ys]
- [Para xs, OrderedList s ys] -> B.fromList [Plain xs, OrderedList s ys]
- [Para xs, DefinitionList ys] -> B.fromList [Plain xs, DefinitionList ys]
+ [Para xs] ->
+ B.singleton $ Plain xs
+ [Para xs, BulletList ys] ->
+ B.fromList [Plain xs, BulletList ys]
+ [Para xs, OrderedList s ys] ->
+ B.fromList [Plain xs, OrderedList s ys]
+ [Para xs, DefinitionList ys] ->
+ B.fromList [Plain xs, DefinitionList ys]
_ -> parsed
-orderedList :: RSTParser Blocks
+orderedList :: PandocMonad m => RSTParser m Blocks
orderedList = try $ do
(start, style, delim) <- lookAhead (anyOrderedListMarker <* spaceChar)
items <- many1 (listItem (orderedListStart style delim))
- let items' = compactify' items
+ let items' = compactify items
return $ B.orderedListWith (start, style, delim) items'
-bulletList :: RSTParser Blocks
-bulletList = B.bulletList . compactify' <$> many1 (listItem bulletListStart)
+bulletList :: PandocMonad m => RSTParser m Blocks
+bulletList = B.bulletList . compactify <$> many1 (listItem bulletListStart)
--
-- directive (e.g. comment, container, compound-paragraph)
--
-comment :: RSTParser Blocks
+comment :: Monad m => RSTParser m Blocks
comment = try $ do
string ".."
skipMany1 spaceChar <|> (() <$ lookAhead newline)
- notFollowedBy' directiveLabel
+ -- notFollowedBy' directiveLabel -- comment comes after directive so unnec.
manyTill anyChar blanklines
optional indentedBlock
return mempty
-directiveLabel :: RSTParser String
+directiveLabel :: Monad m => RSTParser m String
directiveLabel = map toLower
<$> many1Till (letter <|> char '-') (try $ string "::")
-directive :: RSTParser Blocks
+directive :: PandocMonad m => RSTParser m Blocks
directive = try $ do
string ".."
directive'
--- TODO: line-block, parsed-literal, table, csv-table, list-table
--- date
--- include
--- title
-directive' :: RSTParser Blocks
+directive' :: PandocMonad m => RSTParser m Blocks
directive' = do
skipMany1 spaceChar
label <- directiveLabel
@@ -541,43 +658,71 @@ directive' = do
body <- option "" $ try $ blanklines >> indentedBlock
optional blanklines
let body' = body ++ "\n\n"
- imgAttr cl = ("", classes, getAtt "width" ++ getAtt "height")
+ name = trim $ fromMaybe "" (lookup "name" fields)
+ imgAttr cl = ("", classes, widthAttr ++ heightAttr)
where
- classes = words $ maybe "" trim $ lookup cl fields
- getAtt k = case lookup k fields of
- Just v -> [(k, filter (not . isSpace) v)]
- Nothing -> []
+ classes = words $ maybe "" trim (lookup cl fields) ++
+ maybe "" (\x -> "align-" ++ trim x)
+ (lookup "align" fields)
+ scale = case trim <$> lookup "scale" fields of
+ Just v -> case reverse v of
+ '%':vv ->
+ case safeRead (reverse vv) of
+ Just (percent :: Double)
+ -> percent / 100.0
+ Nothing -> 1.0
+ _ ->
+ case safeRead v of
+ Just (s :: Double) -> s
+ Nothing -> 1.0
+ Nothing -> 1.0
+ widthAttr = maybe [] (\x -> [("width",
+ show $ scaleDimension scale x)])
+ $ lookup "width" fields >>=
+ (lengthToDim . filter (not . isSpace))
+ heightAttr = maybe [] (\x -> [("height",
+ show $ scaleDimension scale x)])
+ $ lookup "height" fields >>=
+ (lengthToDim . filter (not . isSpace))
case label of
+ "include" -> includeDirective top fields body'
+ "table" -> tableDirective top fields body'
+ "list-table" -> listTableDirective top fields body'
+ "csv-table" -> csvTableDirective top fields body'
+ "line-block" -> lineBlockDirective body'
"raw" -> return $ B.rawBlock (trim top) (stripTrailingNewlines body)
- "role" -> addNewRole top $ map (\(k,v) -> (k, trim v)) fields
- "container" -> parseFromString parseBlocks body'
+ "role" -> addNewRole top $ map (second trim) fields
+ "container" -> B.divWith (name, "container" : words top, []) <$>
+ parseFromString' parseBlocks body'
"replace" -> B.para <$> -- consumed by substKey
parseInlineFromString (trim top)
"unicode" -> B.para <$> -- consumed by substKey
parseInlineFromString (trim $ unicodeTransform top)
- "compound" -> parseFromString parseBlocks body'
- "pull-quote" -> B.blockQuote <$> parseFromString parseBlocks body'
- "epigraph" -> B.blockQuote <$> parseFromString parseBlocks body'
- "highlights" -> B.blockQuote <$> parseFromString parseBlocks body'
+ "compound" -> parseFromString' parseBlocks body'
+ "pull-quote" -> B.blockQuote <$> parseFromString' parseBlocks body'
+ "epigraph" -> B.blockQuote <$> parseFromString' parseBlocks body'
+ "highlights" -> B.blockQuote <$> parseFromString' parseBlocks body'
"rubric" -> B.para . B.strong <$> parseInlineFromString top
_ | label `elem` ["attention","caution","danger","error","hint",
- "important","note","tip","warning"] ->
- do bod <- parseFromString parseBlocks $ top ++ "\n\n" ++ body'
- return $ B.divWith ("",["admonition", label],[]) bod
- "admonition" ->
- do bod <- parseFromString parseBlocks $ top ++ "\n\n" ++ body'
- return $ B.divWith ("",["admonition"],[]) bod
+ "important","note","tip","warning","admonition"] ->
+ do bod <- parseFromString' parseBlocks $ top ++ "\n\n" ++ body'
+ let lab = case label of
+ "admonition" -> mempty
+ (l:ls) -> B.divWith ("",["admonition-title"],[])
+ (B.para (B.str (toUpper l : ls)))
+ [] -> mempty
+ return $ B.divWith ("",[label],[]) (lab <> bod)
"sidebar" ->
do let subtit = maybe "" trim $ lookup "subtitle" fields
tit <- B.para . B.strong <$> parseInlineFromString
(trim top ++ if null subtit
then ""
else (": " ++ subtit))
- bod <- parseFromString parseBlocks body'
+ bod <- parseFromString' parseBlocks body'
return $ B.divWith ("",["sidebar"],[]) $ tit <> bod
"topic" ->
do tit <- B.para . B.strong <$> parseInlineFromString top
- bod <- parseFromString parseBlocks body'
+ bod <- parseFromString' parseBlocks body'
return $ B.divWith ("",["topic"],[]) $ tit <> bod
"default-role" -> mempty <$ updateState (\s ->
s { stateRstDefaultRole =
@@ -588,14 +733,15 @@ directive' = do
codeblock (words $ fromMaybe [] $ lookup "class" fields)
(lookup "number-lines" fields) (trim top) body
"aafig" -> do
- let attribs = ("", ["aafig"], map (\(k,v) -> (k, trimr v)) fields)
+ let attribs = ("", ["aafig"], map (second trimr) fields)
return $ B.codeBlockWith attribs $ stripTrailingNewlines body
"math" -> return $ B.para $ mconcat $ map B.displayMath
$ toChunks $ top ++ "\n\n" ++ body
"figure" -> do
- (caption, legend) <- parseFromString extractCaption body'
+ (caption, legend) <- parseFromString' extractCaption body'
let src = escapeURI $ trim top
- return $ B.para (B.imageWith (imgAttr "figclass") src "fig:" caption) <> legend
+ return $ B.para (B.imageWith (imgAttr "figclass") src "fig:"
+ caption) <> legend
"image" -> do
let src = escapeURI $ trim top
let alt = B.str $ maybe "image" trim $ lookup "alt" fields
@@ -606,28 +752,150 @@ directive' = do
$ B.imageWith attr src "" alt
Nothing -> B.imageWith attr src "" alt
"class" -> do
- let attrs = ("", (splitBy isSpace $ trim top), map (\(k,v) -> (k, trimr v)) fields)
+ let attrs = ("", splitBy isSpace $ trim top,
+ map (second trimr) fields)
-- directive content or the first immediately following element
children <- case body of
"" -> block
- _ -> parseFromString parseBlocks body'
+ _ -> parseFromString' parseBlocks body'
return $ B.divWith attrs children
other -> do
pos <- getPosition
- addWarning (Just pos) $ "ignoring unknown directive: " ++ other
- return mempty
+ logMessage $ SkippedContent (".. " ++ other) pos
+ bod <- parseFromString' parseBlocks $ top ++ "\n\n" ++ body'
+ return $ B.divWith ("",[other],[]) bod
+
+tableDirective :: PandocMonad m
+ => String -> [(String, String)] -> String -> RSTParser m Blocks
+tableDirective top fields body = do
+ bs <- parseFromString' parseBlocks body
+ case B.toList bs of
+ [Table _ aligns' widths' header' rows'] -> do
+ title <- parseFromString' (trimInlines . mconcat <$> many inline) top
+ columns <- getOption readerColumns
+ let numOfCols = length header'
+ let normWidths ws =
+ map (/ max 1.0 (fromIntegral (columns - numOfCols))) ws
+ let widths = case trim <$> lookup "widths" fields of
+ Just "auto" -> replicate numOfCols 0.0
+ Just "grid" -> widths'
+ Just specs -> normWidths
+ $ map (fromMaybe (0 :: Double) . safeRead)
+ $ splitBy (`elem` (" ," :: String)) specs
+ Nothing -> widths'
+ -- align is not applicable since we can't represent whole table align
+ return $ B.singleton $ Table (B.toList title)
+ aligns' widths header' rows'
+ _ -> return mempty
+
+
+-- TODO: :stub-columns:.
+-- Only the first row becomes the header even if header-rows: > 1,
+-- since Pandoc doesn't support a table with multiple header rows.
+-- We don't need to parse :align: as it represents the whole table align.
+listTableDirective :: PandocMonad m
+ => String -> [(String, String)] -> String
+ -> RSTParser m Blocks
+listTableDirective top fields body = do
+ bs <- parseFromString' parseBlocks body
+ title <- parseFromString' (trimInlines . mconcat <$> many inline) top
+ let rows = takeRows $ B.toList bs
+ headerRowsNum = fromMaybe (0 :: Int) $
+ lookup "header-rows" fields >>= safeRead
+ (headerRow,bodyRows,numOfCols) = case rows of
+ x:xs -> if headerRowsNum > 0
+ then (x, xs, length x)
+ else ([], rows, length x)
+ _ -> ([],[],0)
+ widths = case trim <$> lookup "widths" fields of
+ Just "auto" -> replicate numOfCols 0
+ Just specs -> normWidths $ map (fromMaybe (0 :: Double) . safeRead) $
+ splitBy (`elem` (" ," :: String)) specs
+ _ -> replicate numOfCols 0
+ return $ B.table title
+ (zip (replicate numOfCols AlignDefault) widths)
+ headerRow
+ bodyRows
+ where takeRows [BulletList rows] = map takeCells rows
+ takeRows _ = []
+ takeCells [BulletList cells] = map B.fromList cells
+ takeCells _ = []
+ normWidths ws = map (/ max 1 (sum ws)) ws
+
+csvTableDirective :: PandocMonad m
+ => String -> [(String, String)] -> String
+ -> RSTParser m Blocks
+csvTableDirective top fields rawcsv = do
+ let explicitHeader = trim <$> lookup "header" fields
+ let opts = defaultCSVOptions{
+ csvDelim = case trim <$> lookup "delim" fields of
+ Just "tab" -> '\t'
+ Just "space" -> ' '
+ Just [c] -> c
+ _ -> ','
+ , csvQuote = case trim <$> lookup "quote" fields of
+ Just [c] -> c
+ _ -> '"'
+ , csvEscape = case trim <$> lookup "escape" fields of
+ Just [c] -> Just c
+ _ -> Nothing
+ , csvKeepSpace = case trim <$> lookup "keepspace" fields of
+ Just "true" -> True
+ _ -> False
+ }
+ let headerRowsNum = fromMaybe (case explicitHeader of
+ Just _ -> 1 :: Int
+ Nothing -> 0 :: Int) $
+ lookup "header-rows" fields >>= safeRead
+ rawcsv' <- case trim <$>
+ lookup "file" fields `mplus` lookup "url" fields of
+ Just u -> do
+ (bs, _) <- fetchItem u
+ return $ UTF8.toString bs
+ Nothing -> return rawcsv
+ let res = parseCSV opts (T.pack $ case explicitHeader of
+ Just h -> h ++ "\n" ++ rawcsv'
+ Nothing -> rawcsv')
+ case res of
+ Left e ->
+ throwError $ PandocParsecError "csv table" e
+ Right rawrows -> do
+ let parseCell = parseFromString' (plain <|> return mempty) . T.unpack
+ let parseRow = mapM parseCell
+ rows <- mapM parseRow rawrows
+ let (headerRow,bodyRows,numOfCols) =
+ case rows of
+ x:xs -> if headerRowsNum > 0
+ then (x, xs, length x)
+ else ([], rows, length x)
+ _ -> ([],[],0)
+ title <- parseFromString' (trimInlines . mconcat <$> many inline) top
+ let normWidths ws = map (/ max 1 (sum ws)) ws
+ let widths =
+ case trim <$> lookup "widths" fields of
+ Just "auto" -> replicate numOfCols 0
+ Just specs -> normWidths
+ $ map (fromMaybe (0 :: Double) . safeRead)
+ $ splitBy (`elem` (" ," :: String)) specs
+ _ -> replicate numOfCols 0
+ return $ B.table title
+ (zip (replicate numOfCols AlignDefault) widths)
+ headerRow
+ bodyRows
-- TODO:
-- - Only supports :format: fields with a single format for :raw: roles,
-- change Text.Pandoc.Definition.Format to fix
-addNewRole :: String -> [(String, String)] -> RSTParser Blocks
+addNewRole :: PandocMonad m
+ => String -> [(String, String)] -> RSTParser m Blocks
addNewRole roleString fields = do
- (role, parentRole) <- parseFromString inheritedRole roleString
+ pos <- getPosition
+ (role, parentRole) <- parseFromString' inheritedRole roleString
customRoles <- stateRstCustomRoles <$> getState
let getBaseRole (r, f, a) roles =
case M.lookup r roles of
Just (r', f', a') -> getBaseRole (r', f', a') roles
- Nothing -> (r, f, a)
+ Nothing -> (r, f, a)
(baseRole, baseFmt, baseAttr) =
getBaseRole (parentRole, Nothing, nullAttr) customRoles
fmt = if parentRole == "raw" then lookup "format" fields else baseFmt
@@ -641,34 +909,32 @@ addNewRole roleString fields = do
in (ident, nub . (role :) . annotate $ classes, keyValues)
-- warn about syntax we ignore
- flip mapM_ fields $ \(key, _) -> case key of
- "language" -> when (baseRole /= "code") $ addWarning Nothing $
- "ignoring :language: field because the parent of role :" ++
- role ++ ": is :" ++ baseRole ++ ": not :code:"
- "format" -> when (baseRole /= "raw") $ addWarning Nothing $
- "ignoring :format: field because the parent of role :" ++
- role ++ ": is :" ++ baseRole ++ ": not :raw:"
- _ -> addWarning Nothing $ "ignoring unknown field :" ++ key ++
- ": in definition of role :" ++ role ++ ": in"
+ forM_ fields $ \(key, _) -> case key of
+ "language" -> when (baseRole /= "code") $ logMessage $
+ SkippedContent ":language: [because parent of role is not :code:]"
+ pos
+ "format" -> when (baseRole /= "raw") $ logMessage $
+ SkippedContent ":format: [because parent of role is not :raw:]" pos
+ _ -> logMessage $ SkippedContent (":" ++ key ++ ":") pos
when (parentRole == "raw" && countKeys "format" > 1) $
- addWarning Nothing $
- "ignoring :format: fields after the first in the definition of role :"
- ++ role ++": in"
+ logMessage $ SkippedContent
+ ":format: [after first in definition of role]"
+ pos
when (parentRole == "code" && countKeys "language" > 1) $
- addWarning Nothing $
- "ignoring :language: fields after the first in the definition of role :"
- ++ role ++": in"
+ logMessage $ SkippedContent
+ ":language: [after first in definition of role]" pos
updateState $ \s -> s {
stateRstCustomRoles =
M.insert role (baseRole, fmt, attr) customRoles
}
- return $ B.singleton Null
+ return mempty
where
countKeys k = length . filter (== k) . map fst $ fields
inheritedRole =
- (,) <$> roleName <*> ((char '(' *> roleName <* char ')') <|> pure "span")
+ (,) <$> roleName <*> ((char '(' *> roleName <* char ')')
+ <|> pure "span")
-- Can contain character codes as decimal numbers or
@@ -700,24 +966,29 @@ extractUnicodeChar s = maybe Nothing (\c -> Just (c,rest)) mbc
where (ds,rest) = span isHexDigit s
mbc = safeRead ('\'':'\\':'x':ds ++ "'")
-extractCaption :: RSTParser (Inlines, Blocks)
+extractCaption :: PandocMonad m => RSTParser m (Inlines, Blocks)
extractCaption = do
capt <- trimInlines . mconcat <$> many inline
legend <- optional blanklines >> (mconcat <$> many block)
return (capt,legend)
--- divide string by blanklines
+-- divide string by blanklines, and surround with
+-- \begin{aligned}...\end{aligned} if needed.
toChunks :: String -> [String]
toChunks = dropWhile null
- . map (trim . unlines)
+ . map (addAligned . trim . unlines)
. splitBy (all (`elem` (" \t" :: String))) . lines
+ -- we put this in an aligned environment if it contains \\, see #4254
+ where addAligned s = if "\\\\" `isInfixOf` s
+ then "\\begin{aligned}\n" ++ s ++ "\n\\end{aligned}"
+ else s
-codeblock :: [String] -> Maybe String -> String -> String -> RSTParser Blocks
+codeblock :: [String] -> Maybe String -> String -> String -> RSTParser m Blocks
codeblock classes numberLines lang body =
return $ B.codeBlockWith attribs $ stripTrailingNewlines body
where attribs = ("", classes', kvs)
classes' = "sourceCode" : lang
- : maybe [] (\_ -> ["numberLines"]) numberLines
+ : maybe [] (const ["numberLines"]) numberLines
++ classes
kvs = case numberLines of
Just "" -> []
@@ -728,30 +999,52 @@ codeblock classes numberLines lang body =
--- note block
---
-noteBlock :: RSTParser [Char]
+noteBlock :: Monad m => RSTParser m [Char]
noteBlock = try $ do
+ (ref, raw, replacement) <- noteBlock' noteMarker
+ updateState $ \s -> s { stateNotes = (ref, raw) : stateNotes s }
+ -- return blanks so line count isn't affected
+ return replacement
+
+citationBlock :: Monad m => RSTParser m [Char]
+citationBlock = try $ do
+ (ref, raw, replacement) <- noteBlock' citationMarker
+ updateState $ \s ->
+ s { stateCitations = M.insert ref raw (stateCitations s),
+ stateKeys = M.insert (toKey ref) (('#':ref,""), ("",["citation"],[]))
+ (stateKeys s) }
+ -- return blanks so line count isn't affected
+ return replacement
+
+noteBlock' :: Monad m
+ => RSTParser m String -> RSTParser m (String, String, String)
+noteBlock' marker = try $ do
startPos <- getPosition
string ".."
spaceChar >> skipMany spaceChar
- ref <- noteMarker
+ ref <- marker
first <- (spaceChar >> skipMany spaceChar >> anyLine)
<|> (newline >> return "")
blanks <- option "" blanklines
rest <- option "" indentedBlock
endPos <- getPosition
let raw = first ++ "\n" ++ blanks ++ rest ++ "\n"
- let newnote = (ref, raw)
- st <- getState
- let oldnotes = stateNotes st
- updateState $ \s -> s { stateNotes = newnote : oldnotes }
- -- return blanks so line count isn't affected
- return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
+ let replacement =replicate (sourceLine endPos - sourceLine startPos) '\n'
+ return (ref, raw, replacement)
+
+citationMarker :: Monad m => RSTParser m [Char]
+citationMarker = do
+ char '['
+ res <- simpleReferenceName
+ char ']'
+ return res
-noteMarker :: RSTParser [Char]
+noteMarker :: Monad m => RSTParser m [Char]
noteMarker = do
char '['
res <- many1 digit
- <|> (try $ char '#' >> liftM ('#':) simpleReferenceName')
+ <|>
+ try (char '#' >> liftM ('#':) simpleReferenceName)
<|> count 1 (oneOf "#*")
char ']'
return res
@@ -760,39 +1053,26 @@ noteMarker = do
-- reference key
--
-quotedReferenceName :: RSTParser Inlines
+quotedReferenceName :: PandocMonad m => RSTParser m String
quotedReferenceName = try $ do
char '`' >> notFollowedBy (char '`') -- `` means inline code!
- label' <- trimInlines . mconcat <$> many1Till inline (char '`')
- return label'
-
-unquotedReferenceName :: RSTParser Inlines
-unquotedReferenceName = try $ do
- label' <- trimInlines . mconcat <$> many1Till inline (lookAhead $ char ':')
- return label'
+ manyTill anyChar (char '`')
-- Simple reference names are single words consisting of alphanumerics
-- plus isolated (no two adjacent) internal hyphens, underscores,
-- periods, colons and plus signs; no whitespace or other characters
-- are allowed.
-simpleReferenceName' :: Parser [Char] st String
-simpleReferenceName' = do
+simpleReferenceName :: Monad m => ParserT [Char] st m String
+simpleReferenceName = do
x <- alphaNum
xs <- many $ alphaNum
- <|> (try $ oneOf "-_:+." <* lookAhead alphaNum)
+ <|> try (oneOf "-_:+." <* lookAhead alphaNum)
return (x:xs)
-simpleReferenceName :: Parser [Char] st Inlines
-simpleReferenceName = do
- raw <- simpleReferenceName'
- return $ B.str raw
+referenceName :: PandocMonad m => RSTParser m String
+referenceName = quotedReferenceName <|> simpleReferenceName
-referenceName :: RSTParser Inlines
-referenceName = quotedReferenceName <|>
- (try $ simpleReferenceName <* lookAhead (char ':')) <|>
- unquotedReferenceName
-
-referenceKey :: RSTParser [Char]
+referenceKey :: PandocMonad m => RSTParser m [Char]
referenceKey = do
startPos <- getPosition
choice [substKey, anonymousKey, regularKey]
@@ -801,16 +1081,16 @@ referenceKey = do
-- return enough blanks to replace key
return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
-targetURI :: Parser [Char] st [Char]
+targetURI :: Monad m => ParserT [Char] st m [Char]
targetURI = do
skipSpaces
optional newline
contents <- many1 (try (many spaceChar >> newline >>
many1 spaceChar >> noneOf " \t\n") <|> noneOf "\n")
blanklines
- return $ escapeURI $ trim $ contents
+ return $ escapeURI $ trim contents
-substKey :: RSTParser ()
+substKey :: PandocMonad m => RSTParser m ()
substKey = try $ do
string ".."
skipMany1 spaceChar
@@ -826,31 +1106,85 @@ substKey = try $ do
[Para ils] -> return $ B.fromList ils
_ -> mzero
let key = toKey $ stripFirstAndLast ref
- updateState $ \s -> s{ stateSubstitutions = M.insert key il $ stateSubstitutions s }
+ updateState $ \s -> s{ stateSubstitutions =
+ M.insert key il $ stateSubstitutions s }
-anonymousKey :: RSTParser ()
+anonymousKey :: Monad m => RSTParser m ()
anonymousKey = try $ do
oneOfStrings [".. __:", "__"]
src <- targetURI
pos <- getPosition
let key = toKey $ "_" ++ printf "%09d" (sourceLine pos)
- --TODO: parse width, height, class and name attributes
- updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $ stateKeys s }
-
-stripTicks :: String -> String
-stripTicks = reverse . stripTick . reverse . stripTick
- where stripTick ('`':xs) = xs
- stripTick xs = xs
-
-regularKey :: RSTParser ()
+ updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $
+ stateKeys s }
+
+referenceNames :: PandocMonad m => RSTParser m [String]
+referenceNames = do
+ let rn = try $ do
+ string ".. _"
+ ref <- quotedReferenceName
+ <|> many ( noneOf ":\n"
+ <|> try (char '\n' <*
+ string " " <*
+ notFollowedBy blankline)
+ <|> try (char ':' <* lookAhead alphaNum)
+ )
+ char ':'
+ return ref
+ first <- rn
+ rest <- many (try (blanklines *> rn))
+ return (first:rest)
+
+regularKey :: PandocMonad m => RSTParser m ()
regularKey = try $ do
- string ".. _"
- (_,ref) <- withRaw referenceName
- char ':'
+ -- we allow several references to the same URL, e.g.
+ -- .. _hello:
+ -- .. _goodbye: url.com
+ refs <- referenceNames
src <- targetURI
- let key = toKey $ stripTicks ref
- --TODO: parse width, height, class and name attributes
- updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $ stateKeys s }
+ guard $ not (null src)
+ let keys = map toKey refs
+ forM_ keys $ \key ->
+ updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $
+ stateKeys s }
+
+anchorDef :: PandocMonad m => RSTParser m [Char]
+anchorDef = try $ do
+ (refs, raw) <- withRaw $ try (referenceNames <* blanklines)
+ forM_ refs $ \rawkey ->
+ updateState $ \s -> s { stateKeys =
+ M.insert (toKey rawkey) (('#':rawkey,""), nullAttr) $ stateKeys s }
+ -- keep this for 2nd round of parsing, where we'll add the divs (anchor)
+ return raw
+
+anchor :: PandocMonad m => RSTParser m Blocks
+anchor = try $ do
+ refs <- referenceNames
+ blanklines
+ b <- block
+ let addDiv ref = B.divWith (ref, [], [])
+ let emptySpanWithId id' = Span (id',[],[]) []
+ -- put identifier on next block:
+ case B.toList b of
+ [Header lev (_,classes,kvs) txt] ->
+ case reverse refs of
+ [] -> return b
+ (r:rs) -> return $ B.singleton $
+ Header lev (r,classes,kvs)
+ (txt ++ map emptySpanWithId rs)
+ -- we avoid generating divs for headers,
+ -- because it hides them from promoteHeader, see #4240
+ _ -> return $ foldr addDiv b refs
+
+headerBlock :: PandocMonad m => RSTParser m [Char]
+headerBlock = do
+ ((txt, _), raw) <- withRaw (doubleHeader' <|> singleHeader')
+ (ident,_,_) <- registerHeader nullAttr txt
+ let key = toKey (stringify txt)
+ updateState $ \s -> s { stateKeys = M.insert key (('#':ident,""), nullAttr)
+ $ stateKeys s }
+ return raw
+
--
-- tables
@@ -869,45 +1203,53 @@ regularKey = try $ do
-- Grid tables TODO:
-- - column spans
-dashedLine :: Char -> Parser [Char] st (Int, Int)
+dashedLine :: Monad m => Char -> ParserT [Char] st m (Int, Int)
dashedLine ch = do
dashes <- many1 (char ch)
sp <- many (char ' ')
return (length dashes, length $ dashes ++ sp)
-simpleDashedLines :: Char -> Parser [Char] st [(Int,Int)]
+simpleDashedLines :: Monad m => Char -> ParserT [Char] st m [(Int,Int)]
simpleDashedLines ch = try $ many1 (dashedLine ch)
-- Parse a table row separator
-simpleTableSep :: Char -> RSTParser Char
+simpleTableSep :: Monad m => Char -> RSTParser m Char
simpleTableSep ch = try $ simpleDashedLines ch >> newline
-- Parse a table footer
-simpleTableFooter :: RSTParser [Char]
+simpleTableFooter :: Monad m => RSTParser m [Char]
simpleTableFooter = try $ simpleTableSep '=' >> blanklines
-- Parse a raw line and split it into chunks by indices.
-simpleTableRawLine :: [Int] -> RSTParser [String]
-simpleTableRawLine indices = do
- line <- many1Till anyChar newline
- return (simpleTableSplitLine indices line)
+simpleTableRawLine :: Monad m => [Int] -> RSTParser m [String]
+simpleTableRawLine indices = simpleTableSplitLine indices <$> anyLine
+
+simpleTableRawLineWithEmptyCell :: Monad m => [Int] -> RSTParser m [String]
+simpleTableRawLineWithEmptyCell indices = try $ do
+ cs <- simpleTableRawLine indices
+ let isEmptyCell = all (\c -> c == ' ' || c == '\t')
+ guard $ any isEmptyCell cs
+ return cs
-- Parse a table row and return a list of blocks (columns).
-simpleTableRow :: [Int] -> RSTParser [[Block]]
+simpleTableRow :: PandocMonad m => [Int] -> RSTParser m [Blocks]
simpleTableRow indices = do
notFollowedBy' simpleTableFooter
firstLine <- simpleTableRawLine indices
- colLines <- return [] -- TODO
- let cols = map unlines . transpose $ firstLine : colLines
- mapM (parseFromString (B.toList . mconcat <$> many plain)) cols
+ conLines <- many $ simpleTableRawLineWithEmptyCell indices
+ let cols = map unlines . transpose $ firstLine : conLines ++
+ [replicate (length indices) ""
+ | not (null conLines)]
+ mapM (parseFromString' parseBlocks) cols
simpleTableSplitLine :: [Int] -> String -> [String]
simpleTableSplitLine indices line =
- map trim
+ map trimr
$ tail $ splitByIndices (init indices) line
-simpleTableHeader :: Bool -- ^ Headerless table
- -> RSTParser ([[Block]], [Alignment], [Int])
+simpleTableHeader :: PandocMonad m
+ => Bool -- ^ Headerless table
+ -> RSTParser m ([Blocks], [Alignment], [Int])
simpleTableHeader headless = try $ do
optional blanklines
rawContent <- if headless
@@ -921,26 +1263,37 @@ simpleTableHeader headless = try $ do
let rawHeads = if headless
then replicate (length dashes) ""
else simpleTableSplitLine indices rawContent
- heads <- mapM (parseFromString (B.toList . mconcat <$> many plain)) $
- map trim rawHeads
+ heads <- mapM ( parseFromString' (mconcat <$> many plain) . trim) rawHeads
return (heads, aligns, indices)
-- Parse a simple table.
-simpleTable :: Bool -- ^ Headerless table
- -> RSTParser Blocks
+simpleTable :: PandocMonad m
+ => Bool -- ^ Headerless table
+ -> RSTParser m Blocks
simpleTable headless = do
- Table c a _w h l <- tableWith (simpleTableHeader headless) simpleTableRow sep simpleTableFooter
+ let wrapIdFst (a, b, c) = (Identity a, b, c)
+ wrapId = fmap Identity
+ tbl <- runIdentity <$> tableWith
+ (wrapIdFst <$> simpleTableHeader headless)
+ (wrapId <$> simpleTableRow)
+ sep simpleTableFooter
-- Simple tables get 0s for relative column widths (i.e., use default)
- return $ B.singleton $ Table c a (replicate (length a) 0) h l
+ case B.toList tbl of
+ [Table c a _w h l] -> return $ B.singleton $
+ Table c a (replicate (length a) 0) h l
+ _ ->
+ throwError $ PandocShouldNeverHappenError
+ "tableWith returned something unexpected"
where
sep = return () -- optional (simpleTableSep '-')
-gridTable :: Bool -- ^ Headerless table
- -> RSTParser Blocks
-gridTable headerless = B.singleton
- <$> gridTableWith (B.toList <$> parseBlocks) headerless
+gridTable :: PandocMonad m
+ => Bool -- ^ Headerless table
+ -> RSTParser m Blocks
+gridTable headerless = runIdentity <$>
+ gridTableWith (Identity <$> parseBlocks) headerless
-table :: RSTParser Blocks
+table :: PandocMonad m => RSTParser m Blocks
table = gridTable False <|> simpleTable False <|>
gridTable True <|> simpleTable True <?> "table"
@@ -948,7 +1301,7 @@ table = gridTable False <|> simpleTable False <|>
-- inline
--
-inline :: RSTParser Inlines
+inline :: PandocMonad m => RSTParser m Inlines
inline = choice [ note -- can start with whitespace, so try before ws
, whitespace
, link
@@ -964,29 +1317,30 @@ inline = choice [ note -- can start with whitespace, so try before ws
, escapedChar
, symbol ] <?> "inline"
-parseInlineFromString :: String -> RSTParser Inlines
-parseInlineFromString = parseFromString (trimInlines . mconcat <$> many inline)
+parseInlineFromString :: PandocMonad m => String -> RSTParser m Inlines
+parseInlineFromString = parseFromString' (trimInlines . mconcat <$> many inline)
-hyphens :: RSTParser Inlines
+hyphens :: Monad m => RSTParser m Inlines
hyphens = do
result <- many1 (char '-')
optional endline
-- don't want to treat endline after hyphen or dash as a space
return $ B.str result
-escapedChar :: Parser [Char] st Inlines
+escapedChar :: Monad m => ParserT [Char] st m Inlines
escapedChar = do c <- escaped anyChar
- return $ if c == ' ' -- '\ ' is null in RST
+ return $ if c == ' ' || c == '\n' || c == '\r'
+ -- '\ ' is null in RST
then mempty
else B.str [c]
-symbol :: RSTParser Inlines
+symbol :: Monad m => RSTParser m Inlines
symbol = do
result <- oneOf specialChars
return $ B.str [result]
-- parses inline code, between codeStart and codeEnd
-code :: RSTParser Inlines
+code :: Monad m => RSTParser m Inlines
code = try $ do
string "``"
result <- manyTill anyChar (try (string "``"))
@@ -994,7 +1348,7 @@ code = try $ do
$ trim $ unwords $ lines result
-- succeeds only if we're not right after a str (ie. in middle of word)
-atStart :: RSTParser a -> RSTParser a
+atStart :: Monad m => RSTParser m a -> RSTParser m a
atStart p = do
pos <- getPosition
st <- getState
@@ -1002,11 +1356,11 @@ atStart p = do
guard $ stateLastStrPos st /= Just pos
p
-emph :: RSTParser Inlines
+emph :: PandocMonad m => RSTParser m Inlines
emph = B.emph . trimInlines . mconcat <$>
enclosed (atStart $ char '*') (char '*') inline
-strong :: RSTParser Inlines
+strong :: PandocMonad m => RSTParser m Inlines
strong = B.strong . trimInlines . mconcat <$>
enclosed (atStart $ string "**") (try $ string "**") inline
@@ -1018,12 +1372,13 @@ strong = B.strong . trimInlines . mconcat <$>
-- - Classes are silently discarded in addNewRole
-- - Lacks sensible implementation for title-reference (which is the default)
-- - Allows direct use of the :raw: role, rST only allows inherited use.
-interpretedRole :: RSTParser Inlines
+interpretedRole :: PandocMonad m => RSTParser m Inlines
interpretedRole = try $ do
(role, contents) <- roleBefore <|> roleAfter
renderRole contents Nothing role nullAttr
-renderRole :: String -> Maybe String -> String -> Attr -> RSTParser Inlines
+renderRole :: PandocMonad m
+ => String -> Maybe String -> String -> Attr -> RSTParser m Inlines
renderRole contents fmt role attr = case role of
"sup" -> return $ B.superscript $ B.str contents
"superscript" -> return $ B.superscript $ B.str contents
@@ -1048,10 +1403,8 @@ renderRole contents fmt role attr = case role of
case M.lookup custom customRoles of
Just (newRole, newFmt, newAttr) ->
renderRole contents newFmt newRole newAttr
- Nothing -> do
- pos <- getPosition
- addWarning (Just pos) $ "ignoring unknown role :" ++ custom ++ ": in"
- return $ B.str contents -- Undefined role
+ Nothing -> -- undefined role
+ return $ B.spanWith ("",[],[("role",role)]) (B.str contents)
where
titleRef ref = return $ B.str ref -- FIXME: Not a sensible behaviour
rfcLink rfcNo = B.link rfcUrl ("RFC " ++ rfcNo) $ B.str ("RFC " ++ rfcNo)
@@ -1061,33 +1414,33 @@ renderRole contents fmt role attr = case role of
pepUrl = "http://www.python.org/dev/peps/pep-" ++ padNo ++ "/"
addClass :: String -> Attr -> Attr
-addClass c (ident, classes, keyValues) = (ident, union classes [c], keyValues)
+addClass c (ident, classes, keyValues) = (ident, classes `union` [c], keyValues)
-roleName :: RSTParser String
+roleName :: PandocMonad m => RSTParser m String
roleName = many1 (letter <|> char '-')
-roleMarker :: RSTParser String
+roleMarker :: PandocMonad m => RSTParser m String
roleMarker = char ':' *> roleName <* char ':'
-roleBefore :: RSTParser (String,String)
+roleBefore :: PandocMonad m => RSTParser m (String,String)
roleBefore = try $ do
role <- roleMarker
contents <- unmarkedInterpretedText
return (role,contents)
-roleAfter :: RSTParser (String,String)
+roleAfter :: PandocMonad m => RSTParser m (String,String)
roleAfter = try $ do
contents <- unmarkedInterpretedText
role <- roleMarker <|> (stateRstDefaultRole <$> getState)
return (role,contents)
-unmarkedInterpretedText :: RSTParser [Char]
+unmarkedInterpretedText :: PandocMonad m => RSTParser m [Char]
unmarkedInterpretedText = enclosed (atStart $ char '`') (char '`') anyChar
-whitespace :: RSTParser Inlines
+whitespace :: PandocMonad m => RSTParser m Inlines
whitespace = B.space <$ skipMany1 spaceChar <?> "whitespace"
-str :: RSTParser Inlines
+str :: Monad m => RSTParser m Inlines
str = do
let strChar = noneOf ("\t\n " ++ specialChars)
result <- many1 strChar
@@ -1095,26 +1448,24 @@ str = do
return $ B.str result
-- an endline character that can be treated as a space, not a structural break
-endline :: RSTParser Inlines
+endline :: Monad m => RSTParser m Inlines
endline = try $ do
newline
notFollowedBy blankline
-- parse potential list-starts at beginning of line differently in a list:
st <- getState
- if (stateParserContext st) == ListItemState
- then notFollowedBy (anyOrderedListMarker >> spaceChar) >>
+ when (stateParserContext st == ListItemState) $ notFollowedBy (anyOrderedListMarker >> spaceChar) >>
notFollowedBy' bulletListStart
- else return ()
return B.softbreak
--
-- links
--
-link :: RSTParser Inlines
+link :: PandocMonad m => RSTParser m Inlines
link = choice [explicitLink, referenceLink, autoLink] <?> "link"
-explicitLink :: RSTParser Inlines
+explicitLink :: PandocMonad m => RSTParser m Inlines
explicitLink = try $ do
char '`'
notFollowedBy (char '`') -- `` marks start of inline code
@@ -1128,61 +1479,73 @@ explicitLink = try $ do
then B.str src
else label'
-- `link <google_>` is a reference link to _google!
- (src',tit,attr) <- case reverse src of
- '_':xs -> do
- keyTable <- stateKeys <$> getState
- let key = toKey $ reverse xs
- case M.lookup key keyTable of
- Nothing -> do
- pos <- getPosition
- addWarning (Just pos) $
- "Could not find reference for " ++
- show key
- return ("","",nullAttr)
- Just ((s,t),a) -> return (s,t,a)
- _ -> return (src, "", nullAttr)
+ ((src',tit),attr) <- case reverse src of
+ '_':xs -> lookupKey [] (toKey (reverse xs))
+ _ -> return ((src, ""), nullAttr)
return $ B.linkWith attr (escapeURI src') tit label''
-referenceLink :: RSTParser Inlines
+citationName :: PandocMonad m => RSTParser m String
+citationName = do
+ raw <- citationMarker
+ return $ "[" ++ raw ++ "]"
+
+referenceLink :: PandocMonad m => RSTParser m Inlines
referenceLink = try $ do
- (label',ref) <- withRaw (quotedReferenceName <|> simpleReferenceName) <*
- char '_'
- state <- getState
- let keyTable = stateKeys state
+ ref <- (referenceName <|> citationName) <* char '_'
+ let label' = B.text ref
let isAnonKey (Key ('_':_)) = True
isAnonKey _ = False
- key <- option (toKey $ stripTicks ref) $
+ state <- getState
+ let keyTable = stateKeys state
+ key <- option (toKey ref) $
do char '_'
let anonKeys = sort $ filter isAnonKey $ M.keys keyTable
- if null anonKeys
- then mzero
- else return (head anonKeys)
- ((src,tit), attr) <- case M.lookup key keyTable of
- Nothing -> do
- pos <- getPosition
- addWarning (Just pos) $
- "Could not find reference for " ++
- show key
- return (("",""),nullAttr)
- Just val -> return val
+ case anonKeys of
+ [] -> mzero
+ (k:_) -> return k
+ ((src,tit), attr) <- lookupKey [] key
-- if anonymous link, remove key so it won't be used again
- when (isAnonKey key) $ updateState $ \s -> s{ stateKeys = M.delete key keyTable }
+ when (isAnonKey key) $ updateState $ \s ->
+ s{ stateKeys = M.delete key keyTable }
return $ B.linkWith attr src tit label'
-autoURI :: RSTParser Inlines
+-- We keep a list of oldkeys so we can detect lookup loops.
+lookupKey :: PandocMonad m
+ => [Key] -> Key -> RSTParser m ((String, String), Attr)
+lookupKey oldkeys key = do
+ pos <- getPosition
+ state <- getState
+ let keyTable = stateKeys state
+ case M.lookup key keyTable of
+ Nothing -> do
+ let Key key' = key
+ logMessage $ ReferenceNotFound key' pos
+ return (("",""),nullAttr)
+ -- check for keys of the form link_, which need to be resolved:
+ Just ((u@(_:_),""),_) | last u == '_' -> do
+ let rawkey = init u
+ let newkey = toKey rawkey
+ if newkey `elem` oldkeys
+ then do
+ logMessage $ CircularReference rawkey pos
+ return (("",""),nullAttr)
+ else lookupKey (key:oldkeys) newkey
+ Just val -> return val
+
+autoURI :: Monad m => RSTParser m Inlines
autoURI = do
(orig, src) <- uri
return $ B.link src "" $ B.str orig
-autoEmail :: RSTParser Inlines
+autoEmail :: Monad m => RSTParser m Inlines
autoEmail = do
(orig, src) <- emailAddress
return $ B.link src "" $ B.str orig
-autoLink :: RSTParser Inlines
+autoLink :: PandocMonad m => RSTParser m Inlines
autoLink = autoURI <|> autoEmail
-subst :: RSTParser Inlines
+subst :: PandocMonad m => RSTParser m Inlines
subst = try $ do
(_,ref) <- withRaw $ enclosed (char '|') (char '|') inline
state <- getState
@@ -1191,12 +1554,11 @@ subst = try $ do
case M.lookup key substTable of
Nothing -> do
pos <- getPosition
- addWarning (Just pos) $
- "Could not find reference for " ++ show key
+ logMessage $ ReferenceNotFound (show key) pos
return mempty
Just target -> return target
-note :: RSTParser Inlines
+note :: PandocMonad m => RSTParser m Inlines
note = try $ do
optional whitespace
ref <- noteMarker
@@ -1206,8 +1568,7 @@ note = try $ do
case lookup ref notes of
Nothing -> do
pos <- getPosition
- addWarning (Just pos) $
- "Could not find note for " ++ show ref
+ logMessage $ ReferenceNotFound ref pos
return mempty
Just raw -> do
-- We temporarily empty the note list while parsing the note,
@@ -1215,8 +1576,8 @@ note = try $ do
-- Note references inside other notes are allowed in reST, but
-- not yet in this implementation.
updateState $ \st -> st{ stateNotes = [] }
- contents <- parseFromString parseBlocks raw
- let newnotes = if (ref == "*" || ref == "#") -- auto-numbered
+ contents <- parseFromString' parseBlocks raw
+ let newnotes = if ref == "*" || ref == "#" -- auto-numbered
-- delete the note so the next auto-numbered note
-- doesn't get the same contents:
then deleteFirstsBy (==) notes [(ref,raw)]
@@ -1224,20 +1585,20 @@ note = try $ do
updateState $ \st -> st{ stateNotes = newnotes }
return $ B.note contents
-smart :: RSTParser Inlines
+smart :: PandocMonad m => RSTParser m Inlines
smart = do
- getOption readerSmart >>= guard
+ guardEnabled Ext_smart
doubleQuoted <|> singleQuoted <|>
choice [apostrophe, dash, ellipses]
-singleQuoted :: RSTParser Inlines
+singleQuoted :: PandocMonad m => RSTParser m Inlines
singleQuoted = try $ do
singleQuoteStart
withQuoteContext InSingleQuote $
B.singleQuoted . trimInlines . mconcat <$>
many1Till inline singleQuoteEnd
-doubleQuoted :: RSTParser Inlines
+doubleQuoted :: PandocMonad m => RSTParser m Inlines
doubleQuoted = try $ do
doubleQuoteStart
withQuoteContext InDoubleQuote $
diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs
index 76a25ad82..75e3f89eb 100644
--- a/src/Text/Pandoc/Readers/TWiki.hs
+++ b/src/Text/Pandoc/Readers/TWiki.hs
@@ -1,4 +1,7 @@
-{-# LANGUAGE RelaxedPolyRec, FlexibleInstances, TypeSynonymInstances, FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE RelaxedPolyRec #-}
+{-# LANGUAGE TypeSynonymInstances #-}
-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
{-
Copyright (C) 2014 Alexander Sulfrian <alexander.sulfrian@fu-berlin.de>
@@ -30,54 +33,50 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of twiki text to 'Pandoc' document.
-}
module Text.Pandoc.Readers.TWiki ( readTWiki
- , readTWikiWithWarnings
) where
-import Text.Pandoc.Definition
+import Control.Monad
+import Control.Monad.Except (throwError)
+import Data.Char (isAlphaNum)
+import qualified Data.Foldable as F
+import Data.Maybe (fromMaybe)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.HTML.TagSoup
import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad (..))
+import Text.Pandoc.Definition
import Text.Pandoc.Options
-import Text.Pandoc.Parsing hiding (enclosed, macro, nested)
+import Text.Pandoc.Parsing hiding (enclosed, nested)
import Text.Pandoc.Readers.HTML (htmlTag, isCommentTag)
-import Control.Monad
-import Text.Printf (printf)
-import Debug.Trace (trace)
+import Text.Pandoc.Shared (crFilter)
import Text.Pandoc.XML (fromEntities)
-import Data.Maybe (fromMaybe)
-import Text.HTML.TagSoup
-import Data.Char (isAlphaNum)
-import qualified Data.Foldable as F
-import Text.Pandoc.Error
-- | Read twiki from an input string and return a Pandoc document.
-readTWiki :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError Pandoc
-readTWiki opts s =
- (readWith parseTWiki) def{ stateOptions = opts } (s ++ "\n\n")
-
-readTWikiWithWarnings :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError (Pandoc, [String])
-readTWikiWithWarnings opts s =
- (readWith parseTWikiWithWarnings) def{ stateOptions = opts } (s ++ "\n\n")
- where parseTWikiWithWarnings = do
- doc <- parseTWiki
- warnings <- stateWarnings <$> getState
- return (doc, warnings)
-
-type TWParser = Parser [Char] ParserState
+readTWiki :: PandocMonad m
+ => ReaderOptions
+ -> Text
+ -> m Pandoc
+readTWiki opts s = do
+ res <- readWithM parseTWiki def{ stateOptions = opts }
+ (T.unpack (crFilter s) ++ "\n\n")
+ case res of
+ Left e -> throwError e
+ Right d -> return d
+
+type TWParser = ParserT [Char] ParserState
--
-- utility functions
--
-tryMsg :: String -> TWParser a -> TWParser a
+tryMsg :: String -> TWParser m a -> TWParser m a
tryMsg msg p = try p <?> msg
-skip :: TWParser a -> TWParser ()
+skip :: TWParser m a -> TWParser m ()
skip parser = parser >> return ()
-nested :: TWParser a -> TWParser a
+nested :: PandocMonad m => TWParser m a -> TWParser m a
nested p = do
nestlevel <- stateMaxNestingLevel <$> getState
guard $ nestlevel > 0
@@ -86,7 +85,7 @@ nested p = do
updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
return res
-htmlElement :: String -> TWParser (Attr, String)
+htmlElement :: PandocMonad m => String -> TWParser m (Attr, String)
htmlElement tag = tryMsg tag $ do
(TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
content <- manyTill anyChar (endtag <|> endofinput)
@@ -103,23 +102,24 @@ htmlAttrToPandoc attrs = (ident, classes, keyvals)
classes = maybe [] words $ lookup "class" attrs
keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
-parseHtmlContentWithAttrs :: String -> TWParser a -> TWParser (Attr, [a])
+parseHtmlContentWithAttrs :: PandocMonad m
+ => String -> TWParser m a -> TWParser m (Attr, [a])
parseHtmlContentWithAttrs tag parser = do
(attr, content) <- htmlElement tag
parsedContent <- try $ parseContent content
return (attr, parsedContent)
where
- parseContent = parseFromString $ nested $ manyTill parser endOfContent
+ parseContent = parseFromString' $ nested $ manyTill parser endOfContent
endOfContent = try $ skipMany blankline >> skipSpaces >> eof
-parseHtmlContent :: String -> TWParser a -> TWParser [a]
+parseHtmlContent :: PandocMonad m => String -> TWParser m a -> TWParser m [a]
parseHtmlContent tag p = parseHtmlContentWithAttrs tag p >>= return . snd
--
-- main parser
--
-parseTWiki :: TWParser Pandoc
+parseTWiki :: PandocMonad m => TWParser m Pandoc
parseTWiki = do
bs <- mconcat <$> many block
spaces
@@ -131,20 +131,16 @@ parseTWiki = do
-- block parsers
--
-block :: TWParser B.Blocks
+block :: PandocMonad m => TWParser m B.Blocks
block = do
- tr <- getOption readerTrace
- pos <- getPosition
res <- mempty <$ skipMany1 blankline
<|> blockElements
<|> para
skipMany blankline
- when tr $
- trace (printf "line %d: %s" (sourceLine pos)
- (take 60 $ show $ B.toList res)) (return ())
+ trace (take 60 $ show $ B.toList res)
return res
-blockElements :: TWParser B.Blocks
+blockElements :: PandocMonad m => TWParser m B.Blocks
blockElements = choice [ separator
, header
, verbatim
@@ -155,10 +151,10 @@ blockElements = choice [ separator
, noautolink
]
-separator :: TWParser B.Blocks
+separator :: PandocMonad m => TWParser m B.Blocks
separator = tryMsg "separator" $ string "---" >> newline >> return B.horizontalRule
-header :: TWParser B.Blocks
+header :: PandocMonad m => TWParser m B.Blocks
header = tryMsg "header" $ do
string "---"
level <- many1 (char '+') >>= return . length
@@ -167,45 +163,47 @@ header = tryMsg "header" $ do
skipSpaces
content <- B.trimInlines . mconcat <$> manyTill inline newline
attr <- registerHeader ("", classes, []) content
- return $ B.headerWith attr level $ content
+ return $ B.headerWith attr level content
-verbatim :: TWParser B.Blocks
+verbatim :: PandocMonad m => TWParser m B.Blocks
verbatim = (htmlElement "verbatim" <|> htmlElement "pre")
>>= return . (uncurry B.codeBlockWith)
-literal :: TWParser B.Blocks
+literal :: PandocMonad m => TWParser m B.Blocks
literal = htmlElement "literal" >>= return . rawBlock
where
format (_, _, kvs) = fromMaybe "html" $ lookup "format" kvs
rawBlock (attrs, content) = B.rawBlock (format attrs) content
-list :: String -> TWParser B.Blocks
+list :: PandocMonad m => String -> TWParser m B.Blocks
list prefix = choice [ bulletList prefix
, orderedList prefix
, definitionList prefix]
-definitionList :: String -> TWParser B.Blocks
+definitionList :: PandocMonad m => String -> TWParser m B.Blocks
definitionList prefix = tryMsg "definitionList" $ do
indent <- lookAhead $ string prefix *> (many1 $ string " ") <* string "$ "
elements <- many $ parseDefinitionListItem (prefix ++ concat indent)
return $ B.definitionList elements
where
- parseDefinitionListItem :: String -> TWParser (B.Inlines, [B.Blocks])
+ parseDefinitionListItem :: PandocMonad m
+ => String -> TWParser m (B.Inlines, [B.Blocks])
parseDefinitionListItem indent = do
string (indent ++ "$ ") >> skipSpaces
term <- many1Till inline $ string ": "
line <- listItemLine indent $ string "$ "
return $ (mconcat term, [line])
-bulletList :: String -> TWParser B.Blocks
+bulletList :: PandocMonad m => String -> TWParser m B.Blocks
bulletList prefix = tryMsg "bulletList" $
parseList prefix (char '*') (char ' ')
-orderedList :: String -> TWParser B.Blocks
+orderedList :: PandocMonad m => String -> TWParser m B.Blocks
orderedList prefix = tryMsg "orderedList" $
parseList prefix (oneOf "1iIaA") (string ". ")
-parseList :: String -> TWParser Char -> TWParser a -> TWParser B.Blocks
+parseList :: PandocMonad m
+ => String -> TWParser m Char -> TWParser m a -> TWParser m B.Blocks
parseList prefix marker delim = do
(indent, style) <- lookAhead $ string prefix *> listStyle <* delim
blocks <- many $ parseListItem (prefix ++ indent) (char style <* delim)
@@ -222,10 +220,12 @@ parseList prefix marker delim = do
style <- marker
return (concat indent, style)
-parseListItem :: Show a => String -> TWParser a -> TWParser B.Blocks
+parseListItem :: (PandocMonad m, Show a)
+ => String -> TWParser m a -> TWParser m B.Blocks
parseListItem prefix marker = string prefix >> marker >> listItemLine prefix marker
-listItemLine :: Show a => String -> TWParser a -> TWParser B.Blocks
+listItemLine :: (PandocMonad m, Show a)
+ => String -> TWParser m a -> TWParser m B.Blocks
listItemLine prefix marker = lineContent >>= parseContent >>= return . mconcat
where
lineContent = do
@@ -235,14 +235,14 @@ listItemLine prefix marker = lineContent >>= parseContent >>= return . mconcat
filterSpaces = reverse . dropWhile (== ' ') . reverse
listContinuation = notFollowedBy (string prefix >> marker) >>
string " " >> lineContent
- parseContent = parseFromString $ many1 $ nestedList <|> parseInline
+ parseContent = parseFromString' $ many1 $ nestedList <|> parseInline
parseInline = many1Till inline (lastNewline <|> newlineBeforeNestedList) >>=
return . B.plain . mconcat
nestedList = list prefix
lastNewline = try $ char '\n' <* eof
newlineBeforeNestedList = try $ char '\n' <* lookAhead nestedList
-table :: TWParser B.Blocks
+table :: PandocMonad m => TWParser m B.Blocks
table = try $ do
tableHead <- optionMaybe $ many1Till tableParseHeader newline >>= return . unzip
rows <- many1 tableParseRow
@@ -254,7 +254,7 @@ table = try $ do
columns rows = replicate (columCount rows) mempty
columCount rows = length $ head rows
-tableParseHeader :: TWParser ((Alignment, Double), B.Blocks)
+tableParseHeader :: PandocMonad m => TWParser m ((Alignment, Double), B.Blocks)
tableParseHeader = try $ do
char '|'
leftSpaces <- many spaceChar >>= return . length
@@ -270,27 +270,27 @@ tableParseHeader = try $ do
| left > right = (AlignRight, 0)
| otherwise = (AlignLeft, 0)
-tableParseRow :: TWParser [B.Blocks]
+tableParseRow :: PandocMonad m => TWParser m [B.Blocks]
tableParseRow = many1Till tableParseColumn newline
-tableParseColumn :: TWParser B.Blocks
+tableParseColumn :: PandocMonad m => TWParser m B.Blocks
tableParseColumn = char '|' *> skipSpaces *>
tableColumnContent (skipSpaces >> char '|')
<* skipSpaces <* optional tableEndOfRow
-tableEndOfRow :: TWParser Char
+tableEndOfRow :: PandocMonad m => TWParser m Char
tableEndOfRow = lookAhead (try $ char '|' >> char '\n') >> char '|'
-tableColumnContent :: TWParser a -> TWParser B.Blocks
+tableColumnContent :: PandocMonad m => TWParser m a -> TWParser m B.Blocks
tableColumnContent end = manyTill content (lookAhead $ try end) >>= return . B.plain . mconcat
where
content = continuation <|> inline
continuation = try $ char '\\' >> newline >> return mempty
-blockQuote :: TWParser B.Blocks
+blockQuote :: PandocMonad m => TWParser m B.Blocks
blockQuote = parseHtmlContent "blockquote" block >>= return . B.blockQuote . mconcat
-noautolink :: TWParser B.Blocks
+noautolink :: PandocMonad m => TWParser m B.Blocks
noautolink = do
(_, content) <- htmlElement "noautolink"
st <- getState
@@ -299,9 +299,9 @@ noautolink = do
setState $ st{ stateAllowLinks = True }
return $ mconcat blocks
where
- parseContent = parseFromString $ many $ block
+ parseContent = parseFromString' $ many $ block
-para :: TWParser B.Blocks
+para :: PandocMonad m => TWParser m B.Blocks
para = many1Till inline endOfParaElement >>= return . result . mconcat
where
endOfParaElement = lookAhead $ endOfInput <|> endOfPara <|> newBlockElement
@@ -317,7 +317,7 @@ para = many1Till inline endOfParaElement >>= return . result . mconcat
-- inline parsers
--
-inline :: TWParser B.Inlines
+inline :: PandocMonad m => TWParser m B.Inlines
inline = choice [ whitespace
, br
, macro
@@ -338,36 +338,39 @@ inline = choice [ whitespace
, symbol
] <?> "inline"
-whitespace :: TWParser B.Inlines
+whitespace :: PandocMonad m => TWParser m B.Inlines
whitespace = (lb <|> regsp) >>= return
where lb = try $ skipMany spaceChar >> linebreak >> return B.space
regsp = try $ skipMany1 spaceChar >> return B.space
-br :: TWParser B.Inlines
+br :: PandocMonad m => TWParser m B.Inlines
br = try $ string "%BR%" >> return B.linebreak
-linebreak :: TWParser B.Inlines
+linebreak :: PandocMonad m => TWParser m B.Inlines
linebreak = newline >> notFollowedBy newline >> (lastNewline <|> innerNewline)
where lastNewline = eof >> return mempty
innerNewline = return B.space
-between :: (Monoid c) => TWParser a -> TWParser b -> (TWParser b -> TWParser c) -> TWParser c
+between :: (Monoid c, PandocMonad m, Show b)
+ => TWParser m a -> TWParser m b -> (TWParser m b -> TWParser m c)
+ -> TWParser m c
between start end p =
mconcat <$> try (start >> notFollowedBy whitespace >> many1Till (p end) end)
-enclosed :: (Monoid b) => TWParser a -> (TWParser a -> TWParser b) -> TWParser b
+enclosed :: (Monoid b, PandocMonad m, Show a)
+ => TWParser m a -> (TWParser m a -> TWParser m b) -> TWParser m b
enclosed sep p = between sep (try $ sep <* endMarker) p
where
endMarker = lookAhead $ skip endSpace <|> skip (oneOf ".,!?:)|") <|> eof
endSpace = (spaceChar <|> newline) >> return B.space
-macro :: TWParser B.Inlines
+macro :: PandocMonad m => TWParser m B.Inlines
macro = macroWithParameters <|> withoutParameters
where
withoutParameters = enclosed (char '%') (\_ -> macroName) >>= return . emptySpan
emptySpan name = buildSpan name [] mempty
-macroWithParameters :: TWParser B.Inlines
+macroWithParameters :: PandocMonad m => TWParser m B.Inlines
macroWithParameters = try $ do
char '%'
name <- macroName
@@ -382,22 +385,22 @@ buildSpan className kvs = B.spanWith attrs
additionalClasses = maybe [] words $ lookup "class" kvs
kvsWithoutClasses = [(k,v) | (k,v) <- kvs, k /= "class"]
-macroName :: TWParser String
+macroName :: PandocMonad m => TWParser m String
macroName = do
first <- letter
rest <- many $ alphaNum <|> char '_'
return (first:rest)
-attributes :: TWParser (String, [(String, String)])
+attributes :: PandocMonad m => TWParser m (String, [(String, String)])
attributes = char '{' *> spnl *> many (attribute <* spnl) <* char '}' >>=
return . foldr (either mkContent mkKvs) ([], [])
where
spnl = skipMany (spaceChar <|> newline)
- mkContent c ([], kvs) = (c, kvs)
- mkContent c (rest, kvs) = (c ++ " " ++ rest, kvs)
+ mkContent c ([], kvs) = (c, kvs)
+ mkContent c (rest, kvs) = (c ++ " " ++ rest, kvs)
mkKvs kv (cont, rest) = (cont, (kv : rest))
-attribute :: TWParser (Either String (String, String))
+attribute :: PandocMonad m => TWParser m (Either String (String, String))
attribute = withKey <|> withoutKey
where
withKey = try $ do
@@ -411,49 +414,51 @@ attribute = withKey <|> withoutKey
| allowSpaces == True = many1 $ noneOf "}"
| otherwise = many1 $ noneOf " }"
-nestedInlines :: Show a => TWParser a -> TWParser B.Inlines
+nestedInlines :: (Show a, PandocMonad m)
+ => TWParser m a -> TWParser m B.Inlines
nestedInlines end = innerSpace <|> nestedInline
where
innerSpace = try $ whitespace <* (notFollowedBy end)
nestedInline = notFollowedBy whitespace >> nested inline
-strong :: TWParser B.Inlines
+strong :: PandocMonad m => TWParser m B.Inlines
strong = try $ enclosed (char '*') nestedInlines >>= return . B.strong
-strongHtml :: TWParser B.Inlines
+strongHtml :: PandocMonad m => TWParser m B.Inlines
strongHtml = (parseHtmlContent "strong" inline <|> parseHtmlContent "b" inline)
>>= return . B.strong . mconcat
-strongAndEmph :: TWParser B.Inlines
+strongAndEmph :: PandocMonad m => TWParser m B.Inlines
strongAndEmph = try $ enclosed (string "__") nestedInlines >>= return . B.emph . B.strong
-emph :: TWParser B.Inlines
+emph :: PandocMonad m => TWParser m B.Inlines
emph = try $ enclosed (char '_') nestedInlines >>= return . B.emph
-emphHtml :: TWParser B.Inlines
+emphHtml :: PandocMonad m => TWParser m B.Inlines
emphHtml = (parseHtmlContent "em" inline <|> parseHtmlContent "i" inline)
>>= return . B.emph . mconcat
-nestedString :: Show a => TWParser a -> TWParser String
+nestedString :: (Show a, PandocMonad m)
+ => TWParser m a -> TWParser m String
nestedString end = innerSpace <|> (count 1 nonspaceChar)
where
innerSpace = try $ many1 spaceChar <* notFollowedBy end
-boldCode :: TWParser B.Inlines
+boldCode :: PandocMonad m => TWParser m B.Inlines
boldCode = try $ enclosed (string "==") nestedString >>= return . B.strong . B.code . fromEntities
-htmlComment :: TWParser B.Inlines
+htmlComment :: PandocMonad m => TWParser m B.Inlines
htmlComment = htmlTag isCommentTag >> return mempty
-code :: TWParser B.Inlines
+code :: PandocMonad m => TWParser m B.Inlines
code = try $ enclosed (char '=') nestedString >>= return . B.code . fromEntities
-codeHtml :: TWParser B.Inlines
+codeHtml :: PandocMonad m => TWParser m B.Inlines
codeHtml = do
(attrs, content) <- parseHtmlContentWithAttrs "code" anyChar
return $ B.codeWith attrs $ fromEntities content
-autoLink :: TWParser B.Inlines
+autoLink :: PandocMonad m => TWParser m B.Inlines
autoLink = try $ do
state <- getState
guard $ stateAllowLinks state
@@ -467,36 +472,36 @@ autoLink = try $ do
| c == '/' = True
| otherwise = isAlphaNum c
-str :: TWParser B.Inlines
+str :: PandocMonad m => TWParser m B.Inlines
str = (many1 alphaNum <|> count 1 characterReference) >>= return . B.str
-nop :: TWParser B.Inlines
+nop :: PandocMonad m => TWParser m B.Inlines
nop = try $ (skip exclamation <|> skip nopTag) >> followContent
where
exclamation = char '!'
nopTag = stringAnyCase "<nop>"
followContent = many1 nonspaceChar >>= return . B.str . fromEntities
-symbol :: TWParser B.Inlines
+symbol :: PandocMonad m => TWParser m B.Inlines
symbol = count 1 nonspaceChar >>= return . B.str
-smart :: TWParser B.Inlines
+smart :: PandocMonad m => TWParser m B.Inlines
smart = do
- getOption readerSmart >>= guard
+ guardEnabled Ext_smart
doubleQuoted <|> singleQuoted <|>
choice [ apostrophe
, dash
, ellipses
]
-singleQuoted :: TWParser B.Inlines
+singleQuoted :: PandocMonad m => TWParser m B.Inlines
singleQuoted = try $ do
singleQuoteStart
withQuoteContext InSingleQuote $
many1Till inline singleQuoteEnd >>=
(return . B.singleQuoted . B.trimInlines . mconcat)
-doubleQuoted :: TWParser B.Inlines
+doubleQuoted :: PandocMonad m => TWParser m B.Inlines
doubleQuoted = try $ do
doubleQuoteStart
contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
@@ -504,7 +509,7 @@ doubleQuoted = try $ do
return (B.doubleQuoted $ B.trimInlines contents))
<|> (return $ (B.str "\8220") B.<> contents)
-link :: TWParser B.Inlines
+link :: PandocMonad m => TWParser m B.Inlines
link = try $ do
st <- getState
guard $ stateAllowLinks st
@@ -513,13 +518,13 @@ link = try $ do
setState $ st{ stateAllowLinks = True }
return $ B.link url title content
-linkText :: TWParser (String, String, B.Inlines)
+linkText :: PandocMonad m => TWParser m (String, String, B.Inlines)
linkText = do
string "[["
url <- many1Till anyChar (char ']')
- content <- option [B.str url] linkContent
+ content <- option (B.str url) (mconcat <$> linkContent)
char ']'
- return (url, "", mconcat content)
+ return (url, "", content)
where
linkContent = (char '[') >> many1Till anyChar (char ']') >>= parseLinkContent
- parseLinkContent = parseFromString $ many1 inline
+ parseLinkContent = parseFromString' $ many1 inline
diff --git a/src/Text/Pandoc/Readers/TeXMath.hs b/src/Text/Pandoc/Readers/TeXMath.hs
deleted file mode 100644
index e5778b123..000000000
--- a/src/Text/Pandoc/Readers/TeXMath.hs
+++ /dev/null
@@ -1,48 +0,0 @@
-{-
-Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--}
-
-{- |
- Module : Text.Pandoc.Readers.TeXMath
- Copyright : Copyright (C) 2007-2015 John MacFarlane
- License : GNU GPL, version 2 or above
-
- Maintainer : John MacFarlane <jgm@berkeley.edu>
- Stability : alpha
- Portability : portable
-
-Conversion of TeX math to a list of 'Pandoc' inline elements.
--}
-module Text.Pandoc.Readers.TeXMath ( texMathToInlines ) where
-
-import Text.Pandoc.Definition
-import Text.TeXMath
-
--- | Converts a raw TeX math formula to a list of 'Pandoc' inlines.
--- Defaults to raw formula between @$@ or @$$@ characters if entire formula
--- can't be converted.
-texMathToInlines :: MathType
- -> String -- ^ String to parse (assumes @'\n'@ line endings)
- -> [Inline]
-texMathToInlines mt inp =
- case writePandoc dt `fmap` readTeX inp of
- Right (Just ils) -> ils
- _ -> [Str (delim ++ inp ++ delim)]
- where (dt, delim) = case mt of
- DisplayMath -> (DisplayBlock, "$$")
- InlineMath -> (DisplayInline, "$")
-
diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs
index 8dbbf7be2..30bb6a715 100644
--- a/src/Text/Pandoc/Readers/Textile.hs
+++ b/src/Text/Pandoc/Readers/Textile.hs
@@ -1,6 +1,6 @@
{-
-Copyright (C) 2010-2015 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
- and John MacFarlane
+Copyright (C) 2010-2012 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
+ 2010-2018 John MacFarlane
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Textile
- Copyright : Copyright (C) 2010-2015 Paul Rivier and John MacFarlane
+ Copyright : Copyright (C) 2010-2012 Paul Rivier
+ 2010-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Paul Rivier <paul*rivier#demotera*com>
@@ -51,44 +52,42 @@ TODO : refactor common patterns across readers :
module Text.Pandoc.Readers.Textile ( readTextile) where
+import Control.Monad (guard, liftM)
+import Control.Monad.Except (throwError)
+import Data.Char (digitToInt, isUpper)
+import Data.List (intercalate, intersperse, transpose)
+import Data.Monoid ((<>))
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.HTML.TagSoup (Tag (..), fromAttrib)
+import Text.HTML.TagSoup.Match
+import Text.Pandoc.Builder (Blocks, Inlines, trimInlines)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad (..))
import Text.Pandoc.CSS
import Text.Pandoc.Definition
-import Text.Pandoc.Builder (Inlines, Blocks, trimInlines)
-import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Options
import Text.Pandoc.Parsing
-import Text.Pandoc.Readers.HTML ( htmlTag, isBlockTag, isInlineTag )
-import Text.Pandoc.Shared (trim)
-import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXBlock )
-import Text.HTML.TagSoup (fromAttrib, Tag(..))
-import Text.HTML.TagSoup.Match
-import Data.List ( intercalate, transpose, intersperse )
-import Data.Char ( digitToInt, isUpper )
-import Control.Monad ( guard, liftM, when )
-import Data.Monoid ((<>))
-import Text.Printf
-import Debug.Trace (trace)
-import Text.Pandoc.Error
+import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isInlineTag)
+import Text.Pandoc.Readers.LaTeX (rawLaTeXBlock, rawLaTeXInline)
+import Text.Pandoc.Shared (crFilter, trim, underlineSpan)
-- | Parse a Textile text and return a Pandoc document.
-readTextile :: ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Either PandocError Pandoc
-readTextile opts s =
- (readWith parseTextile) def{ stateOptions = opts } (s ++ "\n\n")
+readTextile :: PandocMonad m
+ => ReaderOptions -- ^ Reader options
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
+ -> m Pandoc
+readTextile opts s = do
+ parsed <- readWithM parseTextile def{ stateOptions = opts }
+ (T.unpack (crFilter s) ++ "\n\n")
+ case parsed of
+ Right result -> return result
+ Left e -> throwError e
-- | Generate a Pandoc ADT from a textile document
-parseTextile :: Parser [Char] ParserState Pandoc
+parseTextile :: PandocMonad m => ParserT [Char] ParserState m Pandoc
parseTextile = do
- -- textile allows raw HTML and does smart punctuation by default,
- -- but we do not enable smart punctuation unless it is explicitly
- -- asked for, for better conversion to other light markup formats
- oldOpts <- stateOptions `fmap` getState
- updateState $ \state -> state{ stateOptions =
- oldOpts{ readerParseRaw = True
- , readerOldDashes = True
- } }
many blankline
startPos <- getPosition
-- go through once just to get list of reference keys and notes
@@ -103,15 +102,15 @@ parseTextile = do
blocks <- parseBlocks
return $ Pandoc nullMeta (B.toList blocks) -- FIXME
-noteMarker :: Parser [Char] ParserState [Char]
+noteMarker :: PandocMonad m => ParserT [Char] ParserState m [Char]
noteMarker = skipMany spaceChar >> string "fn" >> manyTill digit (char '.')
-noteBlock :: Parser [Char] ParserState [Char]
+noteBlock :: PandocMonad m => ParserT [Char] ParserState m [Char]
noteBlock = try $ do
startPos <- getPosition
ref <- noteMarker
optional blankline
- contents <- liftM unlines $ many1Till anyLine (blanklines <|> noteBlock)
+ contents <- unlines <$> many1Till anyLine (blanklines <|> noteBlock)
endPos <- getPosition
let newnote = (ref, contents ++ "\n")
st <- getState
@@ -121,11 +120,11 @@ noteBlock = try $ do
return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
-- | Parse document blocks
-parseBlocks :: Parser [Char] ParserState Blocks
+parseBlocks :: PandocMonad m => ParserT [Char] ParserState m Blocks
parseBlocks = mconcat <$> manyTill block eof
-- | Block parsers list tried in definition order
-blockParsers :: [Parser [Char] ParserState Blocks]
+blockParsers :: PandocMonad m => [ParserT [Char] ParserState m Blocks]
blockParsers = [ codeBlock
, header
, blockQuote
@@ -140,26 +139,22 @@ blockParsers = [ codeBlock
]
-- | Any block in the order of definition of blockParsers
-block :: Parser [Char] ParserState Blocks
+block :: PandocMonad m => ParserT [Char] ParserState m Blocks
block = do
res <- choice blockParsers <?> "block"
- pos <- getPosition
- tr <- getOption readerTrace
- when tr $
- trace (printf "line %d: %s" (sourceLine pos)
- (take 60 $ show $ B.toList res)) (return ())
+ trace (take 60 $ show $ B.toList res)
return res
-commentBlock :: Parser [Char] ParserState Blocks
+commentBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
commentBlock = try $ do
string "###."
manyTill anyLine blanklines
return mempty
-codeBlock :: Parser [Char] ParserState Blocks
+codeBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
codeBlock = codeBlockBc <|> codeBlockPre
-codeBlockBc :: Parser [Char] ParserState Blocks
+codeBlockBc :: PandocMonad m => ParserT [Char] ParserState m Blocks
codeBlockBc = try $ do
string "bc."
extended <- option False (True <$ char '.')
@@ -179,11 +174,10 @@ trimTrailingNewlines :: String -> String
trimTrailingNewlines = reverse . dropWhile (=='\n') . reverse
-- | Code Blocks in Textile are between <pre> and </pre>
-codeBlockPre :: Parser [Char] ParserState Blocks
+codeBlockPre :: PandocMonad m => ParserT [Char] ParserState m Blocks
codeBlockPre = try $ do
(t@(TagOpen _ attrs),_) <- htmlTag (tagOpen (=="pre") (const True))
result' <- manyTill anyChar (htmlTag (tagClose (=="pre")))
- optional blanklines
-- drop leading newline if any
let result'' = case result' of
'\n':xs -> xs
@@ -198,7 +192,7 @@ codeBlockPre = try $ do
return $ B.codeBlockWith (ident,classes,kvs) result'''
-- | Header of the form "hN. content" with N in 1..6
-header :: Parser [Char] ParserState Blocks
+header :: PandocMonad m => ParserT [Char] ParserState m Blocks
header = try $ do
char 'h'
level <- digitToInt <$> oneOf "123456"
@@ -210,14 +204,14 @@ header = try $ do
return $ B.headerWith attr' level name
-- | Blockquote of the form "bq. content"
-blockQuote :: Parser [Char] ParserState Blocks
+blockQuote :: PandocMonad m => ParserT [Char] ParserState m Blocks
blockQuote = try $ do
string "bq" >> attributes >> char '.' >> whitespace
B.blockQuote <$> para
-- Horizontal rule
-hrule :: Parser [Char] st Blocks
+hrule :: PandocMonad m => ParserT [Char] st m Blocks
hrule = try $ do
skipSpaces
start <- oneOf "-*"
@@ -232,66 +226,67 @@ hrule = try $ do
-- | Can be a bullet list or an ordered list. This implementation is
-- strict in the nesting, sublist must start at exactly "parent depth
-- plus one"
-anyList :: Parser [Char] ParserState Blocks
+anyList :: PandocMonad m => ParserT [Char] ParserState m Blocks
anyList = try $ anyListAtDepth 1 <* blanklines
-- | This allow one type of list to be nested into an other type,
-- provided correct nesting
-anyListAtDepth :: Int -> Parser [Char] ParserState Blocks
+anyListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
anyListAtDepth depth = choice [ bulletListAtDepth depth,
orderedListAtDepth depth,
definitionList ]
-- | Bullet List of given depth, depth being the number of leading '*'
-bulletListAtDepth :: Int -> Parser [Char] ParserState Blocks
+bulletListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
bulletListAtDepth depth = try $ B.bulletList <$> many1 (bulletListItemAtDepth depth)
-- | Bullet List Item of given depth, depth being the number of
-- leading '*'
-bulletListItemAtDepth :: Int -> Parser [Char] ParserState Blocks
+bulletListItemAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
bulletListItemAtDepth = genericListItemAtDepth '*'
-- | Ordered List of given depth, depth being the number of
-- leading '#'
-orderedListAtDepth :: Int -> Parser [Char] ParserState Blocks
+orderedListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
orderedListAtDepth depth = try $ do
items <- many1 (orderedListItemAtDepth depth)
return $ B.orderedList items
-- | Ordered List Item of given depth, depth being the number of
-- leading '#'
-orderedListItemAtDepth :: Int -> Parser [Char] ParserState Blocks
+orderedListItemAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
orderedListItemAtDepth = genericListItemAtDepth '#'
-- | Common implementation of list items
-genericListItemAtDepth :: Char -> Int -> Parser [Char] ParserState Blocks
+genericListItemAtDepth :: PandocMonad m => Char -> Int -> ParserT [Char] ParserState m Blocks
genericListItemAtDepth c depth = try $ do
count depth (char c) >> attributes >> whitespace
- p <- mconcat <$> many listInline
+ contents <- mconcat <$> many ((B.plain . mconcat <$> many1 inline) <|>
+ try (newline >> codeBlockPre))
newline
sublist <- option mempty (anyListAtDepth (depth + 1))
- return $ (B.plain p) <> sublist
+ return $ contents <> sublist
-- | A definition list is a set of consecutive definition items
-definitionList :: Parser [Char] ParserState Blocks
+definitionList :: PandocMonad m => ParserT [Char] ParserState m Blocks
definitionList = try $ B.definitionList <$> many1 definitionListItem
-- | List start character.
-listStart :: Parser [Char] ParserState ()
+listStart :: PandocMonad m => ParserT [Char] ParserState m ()
listStart = genericListStart '*'
<|> () <$ genericListStart '#'
<|> () <$ definitionListStart
-genericListStart :: Char -> Parser [Char] st ()
+genericListStart :: PandocMonad m => Char -> ParserT [Char] st m ()
genericListStart c = () <$ try (many1 (char c) >> whitespace)
-basicDLStart :: Parser [Char] ParserState ()
+basicDLStart :: PandocMonad m => ParserT [Char] ParserState m ()
basicDLStart = do
char '-'
whitespace
notFollowedBy newline
-definitionListStart :: Parser [Char] ParserState Inlines
+definitionListStart :: PandocMonad m => ParserT [Char] ParserState m Inlines
definitionListStart = try $ do
basicDLStart
trimInlines . mconcat <$>
@@ -300,34 +295,30 @@ definitionListStart = try $ do
<|> try (lookAhead (() <$ string ":="))
)
-listInline :: Parser [Char] ParserState Inlines
-listInline = try (notFollowedBy newline >> inline)
- <|> try (endline <* notFollowedBy listStart)
-
-- | A definition list item in textile begins with '- ', followed by
-- the term defined, then spaces and ":=". The definition follows, on
-- the same single line, or spaned on multiple line, after a line
-- break.
-definitionListItem :: Parser [Char] ParserState (Inlines, [Blocks])
+definitionListItem :: PandocMonad m => ParserT [Char] ParserState m (Inlines, [Blocks])
definitionListItem = try $ do
term <- (mconcat . intersperse B.linebreak) <$> many1 definitionListStart
def' <- string ":=" *> optional whitespace *> (multilineDef <|> inlineDef)
return (term, def')
- where inlineDef :: Parser [Char] ParserState [Blocks]
+ where inlineDef :: PandocMonad m => ParserT [Char] ParserState m [Blocks]
inlineDef = liftM (\d -> [B.plain d])
- $ optional whitespace >> (trimInlines . mconcat <$> many listInline) <* newline
- multilineDef :: Parser [Char] ParserState [Blocks]
+ $ optional whitespace >> (trimInlines . mconcat <$> many inline) <* newline
+ multilineDef :: PandocMonad m => ParserT [Char] ParserState m [Blocks]
multilineDef = try $ do
optional whitespace >> newline
s <- many1Till anyChar (try (string "=:" >> newline))
-- this ++ "\n\n" does not look very good
- ds <- parseFromString parseBlocks (s ++ "\n\n")
+ ds <- parseFromString' parseBlocks (s ++ "\n\n")
return [ds]
-- raw content
-- | A raw Html Block, optionally followed by blanklines
-rawHtmlBlock :: Parser [Char] ParserState Blocks
+rawHtmlBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
rawHtmlBlock = try $ do
skipMany spaceChar
(_,b) <- htmlTag isBlockTag
@@ -335,14 +326,14 @@ rawHtmlBlock = try $ do
return $ B.rawBlock "html" b
-- | Raw block of LaTeX content
-rawLaTeXBlock' :: Parser [Char] ParserState Blocks
+rawLaTeXBlock' :: PandocMonad m => ParserT [Char] ParserState m Blocks
rawLaTeXBlock' = do
guardEnabled Ext_raw_tex
B.rawBlock "latex" <$> (rawLaTeXBlock <* spaces)
-- | In textile, paragraphs are separated by blank lines.
-para :: Parser [Char] ParserState Blocks
+para :: PandocMonad m => ParserT [Char] ParserState m Blocks
para = B.para . trimInlines . mconcat <$> many1 inline
-- Tables
@@ -353,7 +344,7 @@ toAlignment '>' = AlignRight
toAlignment '=' = AlignCenter
toAlignment _ = AlignDefault
-cellAttributes :: Parser [Char] ParserState (Bool, Alignment)
+cellAttributes :: PandocMonad m => ParserT [Char] ParserState m (Bool, Alignment)
cellAttributes = try $ do
isHeader <- option False (True <$ char '_')
-- we just ignore colspan and rowspan markers:
@@ -366,18 +357,18 @@ cellAttributes = try $ do
return (isHeader, alignment)
-- | A table cell spans until a pipe |
-tableCell :: Parser [Char] ParserState ((Bool, Alignment), Blocks)
+tableCell :: PandocMonad m => ParserT [Char] ParserState m ((Bool, Alignment), Blocks)
tableCell = try $ do
char '|'
- (isHeader, alignment) <- option (False, AlignDefault) $ cellAttributes
+ (isHeader, alignment) <- option (False, AlignDefault) cellAttributes
notFollowedBy blankline
raw <- trim <$>
many (noneOf "|\n" <|> try (char '\n' <* notFollowedBy blankline))
- content <- mconcat <$> parseFromString (many inline) raw
+ content <- mconcat <$> parseFromString' (many inline) raw
return ((isHeader, alignment), B.plain content)
-- | A table row is made of many table cells
-tableRow :: Parser [Char] ParserState [((Bool, Alignment), Blocks)]
+tableRow :: PandocMonad m => ParserT [Char] ParserState m [((Bool, Alignment), Blocks)]
tableRow = try $ do
-- skip optional row attributes
optional $ try $ do
@@ -387,7 +378,7 @@ tableRow = try $ do
many1 tableCell <* char '|' <* blankline
-- | A table with an optional header.
-table :: Parser [Char] ParserState Blocks
+table :: PandocMonad m => ParserT [Char] ParserState m Blocks
table = try $ do
-- ignore table attributes
caption <- option mempty $ try $ do
@@ -395,8 +386,8 @@ table = try $ do
_ <- attributes
char '.'
rawcapt <- trim <$> anyLine
- parseFromString (mconcat <$> many inline) rawcapt
- rawrows <- many1 $ (skipMany ignorableRow) >> tableRow
+ parseFromString' (mconcat <$> many inline) rawcapt
+ rawrows <- many1 $ skipMany ignorableRow >> tableRow
skipMany ignorableRow
blanklines
let (headers, rows) = case rawrows of
@@ -411,7 +402,7 @@ table = try $ do
(map (map snd) rows)
-- | Ignore markers for cols, thead, tfoot.
-ignorableRow :: Parser [Char] ParserState ()
+ignorableRow :: PandocMonad m => ParserT [Char] ParserState m ()
ignorableRow = try $ do
char '|'
oneOf ":^-~"
@@ -420,7 +411,7 @@ ignorableRow = try $ do
_ <- anyLine
return ()
-explicitBlockStart :: String -> Parser [Char] ParserState ()
+explicitBlockStart :: PandocMonad m => String -> ParserT [Char] ParserState m ()
explicitBlockStart name = try $ do
string name
attributes
@@ -430,9 +421,10 @@ explicitBlockStart name = try $ do
-- | Blocks like 'p' and 'table' do not need explicit block tag.
-- However, they can be used to set HTML/CSS attributes when needed.
-maybeExplicitBlock :: String -- ^ block tag name
- -> Parser [Char] ParserState Blocks -- ^ implicit block
- -> Parser [Char] ParserState Blocks
+maybeExplicitBlock :: PandocMonad m
+ => String -- ^ block tag name
+ -> ParserT [Char] ParserState m Blocks -- ^ implicit block
+ -> ParserT [Char] ParserState m Blocks
maybeExplicitBlock name blk = try $ do
optional $ explicitBlockStart name
blk
@@ -445,12 +437,11 @@ maybeExplicitBlock name blk = try $ do
-- | Any inline element
-inline :: Parser [Char] ParserState Inlines
-inline = do
- choice inlineParsers <?> "inline"
+inline :: PandocMonad m => ParserT [Char] ParserState m Inlines
+inline = choice inlineParsers <?> "inline"
-- | Inline parsers tried in order
-inlineParsers :: [Parser [Char] ParserState Inlines]
+inlineParsers :: PandocMonad m => [ParserT [Char] ParserState m Inlines]
inlineParsers = [ str
, whitespace
, endline
@@ -470,13 +461,13 @@ inlineParsers = [ str
]
-- | Inline markups
-inlineMarkup :: Parser [Char] ParserState Inlines
+inlineMarkup :: PandocMonad m => ParserT [Char] ParserState m Inlines
inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
, simpleInline (string "**") B.strong
, simpleInline (string "__") B.emph
, simpleInline (char '*') B.strong
, simpleInline (char '_') B.emph
- , simpleInline (char '+') B.emph -- approximates underline
+ , simpleInline (char '+') underlineSpan
, simpleInline (char '-' <* notFollowedBy (char '-')) B.strikeout
, simpleInline (char '^') B.superscript
, simpleInline (char '~') B.subscript
@@ -484,35 +475,35 @@ inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
]
-- | Trademark, registered, copyright
-mark :: Parser [Char] st Inlines
+mark :: PandocMonad m => ParserT [Char] st m Inlines
mark = try $ char '(' >> (try tm <|> try reg <|> copy)
-reg :: Parser [Char] st Inlines
+reg :: PandocMonad m => ParserT [Char] st m Inlines
reg = do
oneOf "Rr"
char ')'
return $ B.str "\174"
-tm :: Parser [Char] st Inlines
+tm :: PandocMonad m => ParserT [Char] st m Inlines
tm = do
oneOf "Tt"
oneOf "Mm"
char ')'
return $ B.str "\8482"
-copy :: Parser [Char] st Inlines
+copy :: PandocMonad m => ParserT [Char] st m Inlines
copy = do
oneOf "Cc"
char ')'
return $ B.str "\169"
-note :: Parser [Char] ParserState Inlines
+note :: PandocMonad m => ParserT [Char] ParserState m Inlines
note = try $ do
- ref <- (char '[' *> many1 digit <* char ']')
+ ref <- char '[' *> many1 digit <* char ']'
notes <- stateNotes <$> getState
case lookup ref notes of
- Nothing -> fail "note not found"
- Just raw -> B.note <$> parseFromString parseBlocks raw
+ Nothing -> fail "note not found"
+ Just raw -> B.note <$> parseFromString' parseBlocks raw
-- | Special chars
markupChars :: [Char]
@@ -530,22 +521,22 @@ wordBoundaries :: [Char]
wordBoundaries = markupChars ++ stringBreakers
-- | Parse a hyphened sequence of words
-hyphenedWords :: Parser [Char] ParserState String
+hyphenedWords :: PandocMonad m => ParserT [Char] ParserState m String
hyphenedWords = do
x <- wordChunk
xs <- many (try $ char '-' >> wordChunk)
return $ intercalate "-" (x:xs)
-wordChunk :: Parser [Char] ParserState String
+wordChunk :: PandocMonad m => ParserT [Char] ParserState m String
wordChunk = try $ do
hd <- noneOf wordBoundaries
- tl <- many ( (noneOf wordBoundaries) <|>
+ tl <- many ( noneOf wordBoundaries <|>
try (notFollowedBy' note *> oneOf markupChars
<* lookAhead (noneOf wordBoundaries) ) )
return $ hd:tl
-- | Any string
-str :: Parser [Char] ParserState Inlines
+str :: PandocMonad m => ParserT [Char] ParserState m Inlines
str = do
baseStr <- hyphenedWords
-- RedCloth compliance : if parsed word is uppercase and immediatly
@@ -558,11 +549,11 @@ str = do
return $ B.str fullStr
-- | Some number of space chars
-whitespace :: Parser [Char] st Inlines
+whitespace :: PandocMonad m => ParserT [Char] st m Inlines
whitespace = many1 spaceChar >> return B.space <?> "whitespace"
-- | In Textile, an isolated endline character is a line break
-endline :: Parser [Char] ParserState Inlines
+endline :: PandocMonad m => ParserT [Char] ParserState m Inlines
endline = try $ do
newline
notFollowedBy blankline
@@ -570,18 +561,18 @@ endline = try $ do
notFollowedBy rawHtmlBlock
return B.linebreak
-rawHtmlInline :: Parser [Char] ParserState Inlines
+rawHtmlInline :: PandocMonad m => ParserT [Char] ParserState m Inlines
rawHtmlInline = B.rawInline "html" . snd <$> htmlTag isInlineTag
-- | Raw LaTeX Inline
-rawLaTeXInline' :: Parser [Char] ParserState Inlines
+rawLaTeXInline' :: PandocMonad m => ParserT [Char] ParserState m Inlines
rawLaTeXInline' = try $ do
guardEnabled Ext_raw_tex
- B.singleton <$> rawLaTeXInline
+ B.rawInline "latex" <$> rawLaTeXInline
-- | Textile standard link syntax is "label":target. But we
-- can also have ["label":target].
-link :: Parser [Char] ParserState Inlines
+link :: PandocMonad m => ParserT [Char] ParserState m Inlines
link = try $ do
bracketed <- (True <$ char '[') <|> return False
char '"' *> notFollowedBy (oneOf " \t\n\r")
@@ -591,8 +582,9 @@ link = try $ do
char ':'
let stop = if bracketed
then char ']'
- else lookAhead $ space <|>
- try (oneOf "!.,;:" *> (space <|> newline))
+ else lookAhead $ space <|> eof' <|>
+ try (oneOf "!.,;:" *>
+ (space <|> newline <|> eof'))
url <- many1Till nonspaceChar stop
let name' = if B.toList name == [Str "$"] then B.str url else name
return $ if attr == nullAttr
@@ -600,7 +592,7 @@ link = try $ do
else B.spanWith attr $ B.link url "" name'
-- | image embedding
-image :: Parser [Char] ParserState Inlines
+image :: PandocMonad m => ParserT [Char] ParserState m Inlines
image = try $ do
char '!' >> notFollowedBy space
(ident, cls, kvs) <- attributes
@@ -612,50 +604,51 @@ image = try $ do
char '!'
return $ B.imageWith attr src alt (B.str alt)
-escapedInline :: Parser [Char] ParserState Inlines
+escapedInline :: PandocMonad m => ParserT [Char] ParserState m Inlines
escapedInline = escapedEqs <|> escapedTag
-escapedEqs :: Parser [Char] ParserState Inlines
+escapedEqs :: PandocMonad m => ParserT [Char] ParserState m Inlines
escapedEqs = B.str <$>
- (try $ string "==" *> manyTill anyChar' (try $ string "=="))
+ try (string "==" *> manyTill anyChar' (try $ string "=="))
-- | literal text escaped btw <notextile> tags
-escapedTag :: Parser [Char] ParserState Inlines
+escapedTag :: PandocMonad m => ParserT [Char] ParserState m Inlines
escapedTag = B.str <$>
- (try $ string "<notextile>" *>
+ try (string "<notextile>" *>
manyTill anyChar' (try $ string "</notextile>"))
-- | Any special symbol defined in wordBoundaries
-symbol :: Parser [Char] ParserState Inlines
+symbol :: PandocMonad m => ParserT [Char] ParserState m Inlines
symbol = B.str . singleton <$> (notFollowedBy newline *>
notFollowedBy rawHtmlBlock *>
oneOf wordBoundaries)
-- | Inline code
-code :: Parser [Char] ParserState Inlines
+code :: PandocMonad m => ParserT [Char] ParserState m Inlines
code = code1 <|> code2
-- any character except a newline before a blank line
-anyChar' :: Parser [Char] ParserState Char
+anyChar' :: PandocMonad m => ParserT [Char] ParserState m Char
anyChar' =
- satisfy (/='\n') <|> (try $ char '\n' <* notFollowedBy blankline)
+ satisfy (/='\n') <|>
+ try (char '\n' <* notFollowedBy blankline)
-code1 :: Parser [Char] ParserState Inlines
+code1 :: PandocMonad m => ParserT [Char] ParserState m Inlines
code1 = B.code <$> surrounded (char '@') anyChar'
-code2 :: Parser [Char] ParserState Inlines
+code2 :: PandocMonad m => ParserT [Char] ParserState m Inlines
code2 = do
htmlTag (tagOpen (=="tt") null)
B.code <$> manyTill anyChar' (try $ htmlTag $ tagClose (=="tt"))
-- | Html / CSS attributes
-attributes :: Parser [Char] ParserState Attr
-attributes = (foldl (flip ($)) ("",[],[])) <$>
+attributes :: PandocMonad m => ParserT [Char] ParserState m Attr
+attributes = foldl (flip ($)) ("",[],[]) <$>
try (do special <- option id specialAttribute
attrs <- many attribute
return (special : attrs))
-specialAttribute :: Parser [Char] ParserState (Attr -> Attr)
+specialAttribute :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
specialAttribute = do
alignStr <- ("center" <$ char '=') <|>
("justify" <$ try (string "<>")) <|>
@@ -664,11 +657,11 @@ specialAttribute = do
notFollowedBy spaceChar
return $ addStyle ("text-align:" ++ alignStr)
-attribute :: Parser [Char] ParserState (Attr -> Attr)
+attribute :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
attribute = try $
(classIdAttr <|> styleAttr <|> langAttr) <* notFollowedBy spaceChar
-classIdAttr :: Parser [Char] ParserState (Attr -> Attr)
+classIdAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
classIdAttr = try $ do -- (class class #id)
char '('
ws <- words `fmap` manyTill anyChar' (char ')')
@@ -679,7 +672,7 @@ classIdAttr = try $ do -- (class class #id)
classes' -> return $ \(_,_,keyvals) ->
("",classes',keyvals)
-styleAttr :: Parser [Char] ParserState (Attr -> Attr)
+styleAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
styleAttr = do
style <- try $ enclosed (char '{') (char '}') anyChar'
return $ addStyle style
@@ -690,21 +683,23 @@ addStyle style (id',classes,keyvals) =
where keyvals' = ("style", style') : [(k,v) | (k,v) <- keyvals, k /= "style"]
style' = style ++ ";" ++ concat [v | ("style",v) <- keyvals]
-langAttr :: Parser [Char] ParserState (Attr -> Attr)
+langAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
langAttr = do
lang <- try $ enclosed (char '[') (char ']') alphaNum
return $ \(id',classes,keyvals) -> (id',classes,("lang",lang):keyvals)
-- | Parses material surrounded by a parser.
-surrounded :: Parser [Char] st t -- ^ surrounding parser
- -> Parser [Char] st a -- ^ content parser (to be used repeatedly)
- -> Parser [Char] st [a]
+surrounded :: (PandocMonad m, Show t)
+ => ParserT [Char] st m t -- ^ surrounding parser
+ -> ParserT [Char] st m a -- ^ content parser (to be used repeatedly)
+ -> ParserT [Char] st m [a]
surrounded border =
enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
-simpleInline :: Parser [Char] ParserState t -- ^ surrounding parser
- -> (Inlines -> Inlines) -- ^ Inline constructor
- -> Parser [Char] ParserState Inlines -- ^ content parser (to be used repeatedly)
+simpleInline :: PandocMonad m
+ => ParserT [Char] ParserState m t -- ^ surrounding parser
+ -> (Inlines -> Inlines) -- ^ Inline constructor
+ -> ParserT [Char] ParserState m Inlines -- ^ content parser (to be used repeatedly)
simpleInline border construct = try $ do
notAfterString
border *> notFollowedBy (oneOf " \t\n\r")
@@ -718,7 +713,7 @@ simpleInline border construct = try $ do
then body
else B.spanWith attr body
-groupedInlineMarkup :: Parser [Char] ParserState Inlines
+groupedInlineMarkup :: PandocMonad m => ParserT [Char] ParserState m Inlines
groupedInlineMarkup = try $ do
char '['
sp1 <- option mempty $ B.space <$ whitespace
@@ -731,3 +726,5 @@ groupedInlineMarkup = try $ do
singleton :: a -> [a]
singleton x = [x]
+eof' :: Monad m => ParserT [Char] s m Char
+eof' = '\n' <$ eof
diff --git a/src/Text/Pandoc/Readers/TikiWiki.hs b/src/Text/Pandoc/Readers/TikiWiki.hs
new file mode 100644
index 000000000..a92f7bed2
--- /dev/null
+++ b/src/Text/Pandoc/Readers/TikiWiki.hs
@@ -0,0 +1,654 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RelaxedPolyRec #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{- |
+ Module : Text.Pandoc.Readers.TikiWiki
+ Copyright : Copyright (C) 2017 Robin Lee Powell
+ License : GPLv2
+
+ Maintainer : Robin Lee Powell <robinleepowell@gmail.com>
+ Stability : alpha
+ Portability : portable
+
+Conversion of TikiWiki text to 'Pandoc' document.
+-}
+
+module Text.Pandoc.Readers.TikiWiki ( readTikiWiki
+ ) where
+
+import Control.Monad
+import Control.Monad.Except (throwError)
+import qualified Data.Foldable as F
+import Data.Maybe (fromMaybe)
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (CommonState (..), PandocMonad (..))
+import Text.Pandoc.Definition
+import Text.Pandoc.Logging (Verbosity (..))
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (enclosed, nested)
+import Text.Pandoc.Shared (crFilter)
+import Text.Pandoc.XML (fromEntities)
+import Text.Printf (printf)
+
+-- | Read TikiWiki from an input string and return a Pandoc document.
+readTikiWiki :: PandocMonad m
+ => ReaderOptions
+ -> Text
+ -> m Pandoc
+readTikiWiki opts s = do
+ res <- readWithM parseTikiWiki def{ stateOptions = opts }
+ (T.unpack (crFilter s) ++ "\n\n")
+ case res of
+ Left e -> throwError e
+ Right d -> return d
+
+type TikiWikiParser = ParserT [Char] ParserState
+
+--
+-- utility functions
+--
+
+tryMsg :: PandocMonad m => String -> TikiWikiParser m a -> TikiWikiParser m a
+tryMsg msg p = try p <?> msg
+
+skip :: PandocMonad m => TikiWikiParser m a -> TikiWikiParser m ()
+skip parser = Control.Monad.void parser
+
+nested :: PandocMonad m => TikiWikiParser m a -> TikiWikiParser m a
+nested p = do
+ nestlevel <- stateMaxNestingLevel <$> getState
+ guard $ nestlevel > 0
+ updateState $ \st -> st{ stateMaxNestingLevel = stateMaxNestingLevel st - 1 }
+ res <- p
+ updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
+ return res
+
+--
+-- main parser
+--
+
+parseTikiWiki :: PandocMonad m => TikiWikiParser m Pandoc
+parseTikiWiki = do
+ bs <- mconcat <$> many block
+ spaces
+ eof
+ return $ B.doc bs
+
+block :: PandocMonad m => TikiWikiParser m B.Blocks
+block = do
+ verbosity <- getsCommonState stVerbosity
+ pos <- getPosition
+ res <- mempty <$ skipMany1 blankline
+ <|> blockElements
+ <|> para
+ skipMany blankline
+ when (verbosity >= INFO) $
+ trace (printf "line %d: %s" (sourceLine pos) (take 60 $ show $ B.toList res))
+ return res
+
+blockElements :: PandocMonad m => TikiWikiParser m B.Blocks
+blockElements = choice [ table
+ , hr
+ , header
+ , mixedList
+ , definitionList
+ , codeMacro
+ ]
+
+-- top
+-- ----
+-- bottom
+--
+-- ----
+--
+hr :: PandocMonad m => TikiWikiParser m B.Blocks
+hr = try $ do
+ string "----"
+ many (char '-')
+ newline
+ return B.horizontalRule
+
+-- ! header
+--
+-- !! header level two
+--
+-- !!! header level 3
+--
+header :: PandocMonad m => TikiWikiParser m B.Blocks
+header = tryMsg "header" $ do
+ level <- fmap length (many1 (char '!'))
+ guard $ level <= 6
+ skipSpaces
+ content <- B.trimInlines . mconcat <$> manyTill inline newline
+ attr <- registerHeader nullAttr content
+ return $B.headerWith attr level content
+
+tableRow :: PandocMonad m => TikiWikiParser m [B.Blocks]
+tableRow = try $ do
+-- row <- sepBy1 (many1Till inline $ oneOf "\n|") (try $ string "|" <* notFollowedBy (oneOf "|\n"))
+-- return $ map (B.plain . mconcat) row
+ row <- sepBy1 (many1 (noneOf "\n|") >>= parseColumn) (try $ string "|" <* notFollowedBy (oneOf "|\n"))
+ return $ map B.plain row
+ where
+ parseColumn x = do
+ parsed <- parseFromString (many1 inline) x
+ return $ mconcat parsed
+
+
+
+-- Tables:
+--
+-- ||foo||
+--
+-- ||row1-column1|row1-column2||row2-column1|row2-column2||
+--
+-- ||row1-column1|row1-column2
+-- row2-column1|row2-column2||
+--
+-- ||row1-column1|row1-column2
+-- row2-column1|row2-column2||row3-column1|row3-column2||
+--
+-- || Orange | Apple | more
+-- Bread | Pie | more
+-- Butter | Ice cream | and more ||
+--
+table :: PandocMonad m => TikiWikiParser m B.Blocks
+table = try $ do
+ string "||"
+ rows <- sepBy1 tableRow (try $ string "\n" <|> (string "||" <* notFollowedBy (string "\n")))
+ string "||"
+ newline
+ -- return $ B.simpleTable (headers rows) $ trace ("rows: " ++ (show rows)) rows
+ return $B.simpleTable (headers rows) rows
+ where
+ -- The headers are as many empty srings as the number of columns
+ -- in the first row
+ headers rows = map (B.plain . B.str) $replicate (length $ head rows) ""
+
+para :: PandocMonad m => TikiWikiParser m B.Blocks
+para = fmap (result . mconcat) ( many1Till inline endOfParaElement)
+ where
+ endOfParaElement = lookAhead $ endOfInput <|> endOfPara <|> newBlockElement
+ endOfInput = try $ skipMany blankline >> skipSpaces >> eof
+ endOfPara = try $ blankline >> skipMany1 blankline
+ newBlockElement = try $ blankline >> skip blockElements
+ result content = if F.all (==Space) content
+ then mempty
+ else B.para $ B.trimInlines content
+
+-- ;item 1: definition 1
+-- ;item 2: definition 2-1
+-- + definition 2-2
+-- ;item ''3'': definition ''3''
+--
+definitionList :: PandocMonad m => TikiWikiParser m B.Blocks
+definitionList = tryMsg "definitionList" $ do
+ elements <-many1 parseDefinitionListItem
+ return $ B.definitionList elements
+ where
+ parseDefinitionListItem :: PandocMonad m => TikiWikiParser m (B.Inlines, [B.Blocks])
+ parseDefinitionListItem = do
+ skipSpaces >> char ';' <* skipSpaces
+ term <- many1Till inline $ char ':' <* skipSpaces
+ line <- listItemLine 1
+ return (mconcat term, [B.plain line])
+
+data ListType = None | Numbered | Bullet deriving (Ord, Eq, Show)
+
+data ListNesting = LN { lntype :: ListType, lnnest :: Int } deriving (Ord, Eq, Show)
+
+-- The first argument is a stack (most recent == head) of our list
+-- nesting status; the list type and the nesting level; if we're in
+-- a number list in a bullet list it'd be
+-- [LN Numbered 2, LN Bullet 1]
+--
+-- Mixed list example:
+--
+-- # one
+-- # two
+-- ** two point one
+-- ** two point two
+-- # three
+-- # four
+--
+mixedList :: PandocMonad m => TikiWikiParser m B.Blocks
+mixedList = try $ do
+ items <- try $ many1 listItem
+ return $ mconcat $ fixListNesting $ spanFoldUpList (LN None 0) items
+
+-- See the "Handling Lists" section of DESIGN-CODE for why this
+-- function exists. It's to post-process the lists and do some
+-- mappends.
+--
+-- We need to walk the tree two items at a time, so we can see what
+-- we're going to join *to* before we get there.
+--
+-- Because of that, it seemed easier to do it by hand than to try to
+-- figre out a fold or something.
+fixListNesting :: [B.Blocks] -> [B.Blocks]
+fixListNesting [] = []
+fixListNesting [first] = [recurseOnList first]
+-- fixListNesting nestall | trace ("\n\nfixListNesting: " ++ (show nestall)) False = undefined
+-- fixListNesting nestall@(first:second:rest) =
+fixListNesting (first:second:rest) =
+ let secondBlock = head $ B.toList second in
+ case secondBlock of
+ BulletList _ -> fixListNesting $ mappend (recurseOnList first) (recurseOnList second) : rest
+ OrderedList _ _ -> fixListNesting $ mappend (recurseOnList first) (recurseOnList second) : rest
+ _ -> recurseOnList first : fixListNesting (second:rest)
+
+-- This function walks the Block structure for fixListNesting,
+-- because it's a bit complicated, what with converting to and from
+-- lists and so on.
+recurseOnList :: B.Blocks -> B.Blocks
+-- recurseOnList item | trace ("rOL: " ++ (show $ length $ B.toList item) ++ ", " ++ (show $ B.toList item)) False = undefined
+recurseOnList items
+ | length (B.toList items) == 1 =
+ let itemBlock = head $ B.toList items in
+ case itemBlock of
+ BulletList listItems -> B.bulletList $ fixListNesting $ map B.fromList listItems
+ OrderedList _ listItems -> B.orderedList $ fixListNesting $ map B.fromList listItems
+ _ -> items
+
+ -- The otherwise works because we constructed the blocks, and we
+ -- know for a fact that no mappends have been run on them; each
+ -- Blocks consists of exactly one Block.
+ --
+ -- Anything that's not like that has already been processed by
+ -- fixListNesting; don't bother to process it again.
+ | otherwise = items
+
+
+-- Turn the list if list items into a tree by breaking off the first
+-- item, splitting the remainder of the list into items that are in
+-- the tree of the first item and those that aren't, wrapping the
+-- tree of the first item in its list time, and recursing on both
+-- sections.
+spanFoldUpList :: ListNesting -> [(ListNesting, B.Blocks)] -> [B.Blocks]
+spanFoldUpList _ [] = []
+spanFoldUpList ln [first] =
+ listWrap ln (fst first) [snd first]
+spanFoldUpList ln (first:rest) =
+ let (span1, span2) = span (splitListNesting (fst first)) rest
+ newTree1 = listWrap ln (fst first) $ snd first : spanFoldUpList (fst first) span1
+ newTree2 = spanFoldUpList ln span2
+ in
+ newTree1 ++ newTree2
+
+-- Decide if the second item should be in the tree of the first
+-- item, which is true if the second item is at a deeper nesting
+-- level and of the same type.
+splitListNesting :: ListNesting -> (ListNesting, B.Blocks) -> Bool
+splitListNesting ln1 (ln2, _)
+ | lnnest ln1 < lnnest ln2 =
+ True
+ | ln1 == ln2 =
+ True
+ | otherwise =
+ False
+
+-- If we've moved to a deeper nesting level, wrap the new level in
+-- the appropriate type of list.
+listWrap :: ListNesting -> ListNesting -> [B.Blocks] -> [B.Blocks]
+listWrap upperLN curLN retTree =
+ if upperLN == curLN then
+ retTree
+ else
+ case lntype curLN of
+ None -> []
+ Bullet -> [B.bulletList retTree]
+ Numbered -> [B.orderedList retTree]
+
+listItem :: PandocMonad m => TikiWikiParser m (ListNesting, B.Blocks)
+listItem = choice [
+ bulletItem
+ , numberedItem
+ ]
+
+
+-- * Start each line
+-- * with an asterisk (*).
+-- ** More asterisks gives deeper
+-- *** and deeper levels.
+--
+bulletItem :: PandocMonad m => TikiWikiParser m (ListNesting, B.Blocks)
+bulletItem = try $ do
+ prefix <- many1 $ char '*'
+ many1 $ char ' '
+ content <- listItemLine (length prefix)
+ return (LN Bullet (length prefix), B.plain content)
+
+-- # Start each line
+-- # with a number (1.).
+-- ## More number signs gives deeper
+-- ### and deeper
+--
+numberedItem :: PandocMonad m => TikiWikiParser m (ListNesting, B.Blocks)
+numberedItem = try $ do
+ prefix <- many1 $ char '#'
+ many1 $ char ' '
+ content <- listItemLine (length prefix)
+ return (LN Numbered (length prefix), B.plain content)
+
+listItemLine :: PandocMonad m => Int -> TikiWikiParser m B.Inlines
+listItemLine nest = lineContent >>= parseContent
+ where
+ lineContent = do
+ content <- anyLine
+ continuation <- optionMaybe listContinuation
+ return $ filterSpaces content ++ "\n" ++ Data.Maybe.fromMaybe "" continuation
+ filterSpaces = reverse . dropWhile (== ' ') . reverse
+ listContinuation = string (replicate nest '+') >> lineContent
+ parseContent x = do
+ parsed <- parseFromString (many1 inline) x
+ return $ mconcat parsed
+
+-- Turn the CODE macro attributes into Pandoc code block attributes.
+mungeAttrs :: [(String, String)] -> (String, [String], [(String, String)])
+mungeAttrs rawAttrs = ("", classes, rawAttrs)
+ where
+ -- "colors" is TikiWiki CODE macro for "name of language to do
+ -- highlighting for"; turn the value into a class
+ color = fromMaybe "" $ lookup "colors" rawAttrs
+ -- ln = 1 means line numbering. It's also the default. So we
+ -- emit numberLines as a class unless ln = 0
+ lnRaw = fromMaybe "1" $ lookup "ln" rawAttrs
+ ln = if lnRaw == "0" then
+ ""
+ else
+ "numberLines"
+ classes = filter (/= "") [color, ln]
+
+codeMacro :: PandocMonad m => TikiWikiParser m B.Blocks
+codeMacro = try $ do
+ string "{CODE("
+ rawAttrs <- macroAttrs
+ string ")}"
+ body <- manyTill anyChar (try (string "{CODE}"))
+ newline
+ if not (null rawAttrs)
+ then
+ return $ B.codeBlockWith (mungeAttrs rawAttrs) body
+ else
+ return $ B.codeBlock body
+
+
+--
+-- inline parsers
+--
+
+inline :: PandocMonad m => TikiWikiParser m B.Inlines
+inline = choice [ whitespace
+ , noparse
+ , strong
+ , emph
+ , nbsp
+ , image
+ , htmlComment
+ , strikeout
+ , code
+ , wikiLink
+ , notExternalLink
+ , externalLink
+ , superTag
+ , superMacro
+ , subTag
+ , subMacro
+ , escapedChar
+ , colored
+ , centered
+ , underlined
+ , boxed
+ , breakChars
+ , str
+ , symbol
+ ] <?> "inline"
+
+whitespace :: PandocMonad m => TikiWikiParser m B.Inlines
+whitespace = lb <|> regsp
+ where lb = try $ skipMany spaceChar >> linebreak >> return B.space
+ regsp = try $ skipMany1 spaceChar >> return B.space
+
+-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
+-- for this
+nbsp :: PandocMonad m => TikiWikiParser m B.Inlines
+nbsp = try $ do
+ string "~hs~"
+ return $ B.str " NOT SUPPORTED BEGIN: ~hs~ (non-breaking space) :END "
+
+-- UNSUPPORTED, as the desired behaviour (that the data be
+-- *retained* and stored as a comment) doesn't exist in calibre, and
+-- silently throwing data out seemed bad.
+htmlComment :: PandocMonad m => TikiWikiParser m B.Inlines
+htmlComment = try $ do
+ string "~hc~"
+ inner <- many1 $ noneOf "~"
+ string "~/hc~"
+ return $ B.str $ " NOT SUPPORTED: ~hc~ (html comment opener) BEGIN: " ++ inner ++ " ~/hc~ :END "
+
+linebreak :: PandocMonad m => TikiWikiParser m B.Inlines
+linebreak = newline >> notFollowedBy newline >> (lastNewline <|> innerNewline)
+ where lastNewline = eof >> return mempty
+ innerNewline = return B.space
+
+between :: (Monoid c, PandocMonad m, Show b) => TikiWikiParser m a -> TikiWikiParser m b -> (TikiWikiParser m b -> TikiWikiParser m c) -> TikiWikiParser m c
+between start end p =
+ mconcat <$> try (start >> notFollowedBy whitespace >> many1Till (p end) end)
+
+enclosed :: (Monoid b, PandocMonad m, Show a) => TikiWikiParser m a -> (TikiWikiParser m a -> TikiWikiParser m b) -> TikiWikiParser m b
+enclosed sep p = between sep (try $ sep <* endMarker) p
+ where
+ endMarker = lookAhead $ skip endSpace <|> skip (oneOf ".,!?:)|'_") <|> eof
+ endSpace = (spaceChar <|> newline) >> return B.space
+
+
+nestedInlines :: (Show a, PandocMonad m) => TikiWikiParser m a -> TikiWikiParser m B.Inlines
+nestedInlines end = innerSpace <|> nestedInline
+ where
+ innerSpace = try $ whitespace <* notFollowedBy end
+ nestedInline = notFollowedBy whitespace >> nested inline
+
+-- {img attId="39" imalign="right" link="http://info.tikiwiki.org" alt="Panama Hat"}
+--
+-- {img attId="37", thumb="mouseover", styleimage="border", desc="150"}
+--
+-- {img src="img/wiki_up/393px-Pears.jpg" thumb="y" imalign="center" stylebox="border" button="y" desc="Pretty pears" max="200" rel="box"}
+--
+image :: PandocMonad m => TikiWikiParser m B.Inlines
+image = try $ do
+ string "{img "
+ rawAttrs <- sepEndBy1 imageAttr spaces
+ string "}"
+ let src = fromMaybe "" $ lookup "src" rawAttrs
+ let title = fromMaybe src $ lookup "desc" rawAttrs
+ let alt = fromMaybe title $ lookup "alt" rawAttrs
+ let classes = map fst $ filter (\(_,b) -> b == "" || b == "y") rawAttrs
+ if not (null src)
+ then
+ return $ B.imageWith ("", classes, rawAttrs) src title (B.str alt)
+ else
+ return $ B.str $ " NOT SUPPORTED: image without src attribute BEGIN: {img " ++ printAttrs rawAttrs ++ "} :END "
+ where
+ printAttrs attrs = unwords $ map (\(a, b) -> a ++ "=\"" ++ b ++ "\"") attrs
+
+imageAttr :: PandocMonad m => TikiWikiParser m (String, String)
+imageAttr = try $ do
+ key <- many1 (noneOf "=} \t\n")
+ char '='
+ optional $ char '"'
+ value <- many1 (noneOf "}\"\n")
+ optional $ char '"'
+ optional $ char ','
+ return (key, value)
+
+
+-- __strong__
+strong :: PandocMonad m => TikiWikiParser m B.Inlines
+strong = try $ fmap B.strong (enclosed (string "__") nestedInlines)
+
+-- ''emph''
+emph :: PandocMonad m => TikiWikiParser m B.Inlines
+emph = try $ fmap B.emph (enclosed (string "''") nestedInlines)
+
+-- ~246~
+escapedChar :: PandocMonad m => TikiWikiParser m B.Inlines
+escapedChar = try $ do
+ string "~"
+ inner <- many1 $ oneOf "0123456789"
+ string "~"
+ return $B.str [toEnum (read inner :: Int) :: Char]
+
+-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
+-- for this
+centered :: PandocMonad m => TikiWikiParser m B.Inlines
+centered = try $ do
+ string "::"
+ inner <- many1 $ noneOf ":\n"
+ string "::"
+ return $ B.str $ " NOT SUPPORTED: :: (centered) BEGIN: ::" ++ inner ++ ":: :END "
+
+-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
+-- for this
+colored :: PandocMonad m => TikiWikiParser m B.Inlines
+colored = try $ do
+ string "~~"
+ inner <- many1 $ noneOf "~\n"
+ string "~~"
+ return $ B.str $ " NOT SUPPORTED: ~~ (colored) BEGIN: ~~" ++ inner ++ "~~ :END "
+
+-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
+-- for this
+underlined :: PandocMonad m => TikiWikiParser m B.Inlines
+underlined = try $ do
+ string "==="
+ inner <- many1 $ noneOf "=\n"
+ string "==="
+ return $ B.str $ " NOT SUPPORTED: ==== (underlined) BEGIN: ===" ++ inner ++ "=== :END "
+
+-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
+-- for this
+boxed :: PandocMonad m => TikiWikiParser m B.Inlines
+boxed = try $ do
+ string "^"
+ inner <- many1 $ noneOf "^\n"
+ string "^"
+ return $ B.str $ " NOT SUPPORTED: ^ (boxed) BEGIN: ^" ++ inner ++ "^ :END "
+
+-- --text--
+strikeout :: PandocMonad m => TikiWikiParser m B.Inlines
+strikeout = try $ fmap B.strikeout (enclosed (string "--") nestedInlines)
+
+nestedString :: (Show a, PandocMonad m) => TikiWikiParser m a -> TikiWikiParser m String
+nestedString end = innerSpace <|> count 1 nonspaceChar
+ where
+ innerSpace = try $ many1 spaceChar <* notFollowedBy end
+
+breakChars :: PandocMonad m => TikiWikiParser m B.Inlines
+breakChars = try $ string "%%%" >> return B.linebreak
+
+-- superscript: foo{TAG(tag=>sup)}super{TAG}foo / bar{SUP()}super2{SUP}bar
+superTag :: PandocMonad m => TikiWikiParser m B.Inlines
+superTag = try $ fmap (B.superscript . B.text . fromEntities) ( between (string "{TAG(tag=>sup)}") (string "{TAG}") nestedString)
+
+superMacro :: PandocMonad m => TikiWikiParser m B.Inlines
+superMacro = try $ do
+ string "{SUP("
+ manyTill anyChar (string ")}")
+ body <- manyTill anyChar (string "{SUP}")
+ return $ B.superscript $ B.text body
+
+-- subscript: baz{TAG(tag=>sub)}sub{TAG}qux / qux{SUB()}sub2{SUB}qux
+subTag :: PandocMonad m => TikiWikiParser m B.Inlines
+subTag = try $ fmap (B.subscript . B.text . fromEntities) ( between (string "{TAG(tag=>sub)}") (string "{TAG}") nestedString)
+
+subMacro :: PandocMonad m => TikiWikiParser m B.Inlines
+subMacro = try $ do
+ string "{SUB("
+ manyTill anyChar (string ")}")
+ body <- manyTill anyChar (string "{SUB}")
+ return $ B.subscript $ B.text body
+
+-- -+text+-
+code :: PandocMonad m => TikiWikiParser m B.Inlines
+code = try $ fmap (B.code . fromEntities) ( between (string "-+") (string "+-") nestedString)
+
+macroAttr :: PandocMonad m => TikiWikiParser m (String, String)
+macroAttr = try $ do
+ key <- many1 (noneOf "=)")
+ char '='
+ optional $ char '"'
+ value <- many1 (noneOf " )\"")
+ optional $ char '"'
+ return (key, value)
+
+macroAttrs :: PandocMonad m => TikiWikiParser m [(String, String)]
+macroAttrs = try $ sepEndBy macroAttr spaces
+
+-- ~np~ __not bold__ ~/np~
+noparse :: PandocMonad m => TikiWikiParser m B.Inlines
+noparse = try $ do
+ string "~np~"
+ body <- manyTill anyChar (string "~/np~")
+ return $ B.str body
+
+str :: PandocMonad m => TikiWikiParser m B.Inlines
+str = fmap B.str (many1 alphaNum <|> count 1 characterReference)
+
+symbol :: PandocMonad m => TikiWikiParser m B.Inlines
+symbol = fmap B.str (count 1 nonspaceChar)
+
+-- [[not a link]
+notExternalLink :: PandocMonad m => TikiWikiParser m B.Inlines
+notExternalLink = try $ do
+ start <- string "[["
+ body <- many (noneOf "\n[]")
+ end <- string "]"
+ return $ B.text (start ++ body ++ end)
+
+-- [http://www.somesite.org url|Some Site title]
+-- ((internal link))
+--
+-- The ((...)) wiki links and [...] external links are handled
+-- exactly the same; this abstracts that out
+makeLink :: PandocMonad m => String -> String -> String -> TikiWikiParser m B.Inlines
+makeLink start middle end = try $ do
+ st <- getState
+ guard $ stateAllowLinks st
+ setState $ st{ stateAllowLinks = False }
+ (url, title, anchor) <- wikiLinkText start middle end
+ parsedTitle <- parseFromString (many1 inline) title
+ setState $ st{ stateAllowLinks = True }
+ return $ B.link (url++anchor) "" $mconcat parsedTitle
+
+wikiLinkText :: PandocMonad m => String -> String -> String -> TikiWikiParser m (String, String, String)
+wikiLinkText start middle end = do
+ string start
+ url <- many1 (noneOf $ middle ++ "\n")
+ seg1 <- option url linkContent
+ seg2 <- option "" linkContent
+ string end
+ if seg2 /= ""
+ then
+ return (url, seg2, seg1)
+ else
+ return (url, seg1, "")
+ where
+ linkContent = do
+ char '|'
+ many (noneOf middle)
+
+externalLink :: PandocMonad m => TikiWikiParser m B.Inlines
+externalLink = makeLink "[" "]|" "]"
+
+-- NB: this wiki linking is unlikely to work for anyone besides me
+-- (rlpowell); it happens to work for me because my Hakyll code has
+-- post-processing that treats pandoc .md titles as valid link
+-- targets, so something like
+-- [see also this other post](My Other Page) is perfectly valid.
+wikiLink :: PandocMonad m => TikiWikiParser m B.Inlines
+wikiLink = makeLink "((" ")|" "))"
diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs
index 0aafc83c7..f4dda7a11 100644
--- a/src/Text/Pandoc/Readers/Txt2Tags.hs
+++ b/src/Text/Pandoc/Readers/Txt2Tags.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE ViewPatterns #-}
{-
Copyright (C) 2014 Matthew Pickering <matthewtpickering@gmail.com>
@@ -29,39 +28,39 @@ Conversion of txt2tags formatted plain text to 'Pandoc' document.
module Text.Pandoc.Readers.Txt2Tags ( readTxt2Tags
, getT2TMeta
, T2TMeta (..)
- , readTxt2TagsNoMacros)
+ )
where
-import qualified Text.Pandoc.Builder as B
-import Text.Pandoc.Builder ( Inlines, Blocks, trimInlines )
-import Data.Monoid ((<>))
-import Text.Pandoc.Definition
-import Text.Pandoc.Options
-import Text.Pandoc.Shared (escapeURI,compactify', compactify'DL)
-import Text.Pandoc.Parsing hiding (space, spaces, uri, macro)
+import Control.Monad (guard, void, when)
+import Control.Monad.Except (catchError, throwError)
+import Control.Monad.Reader (Reader, asks, runReader)
import Data.Char (toLower)
-import Data.List (transpose, intersperse, intercalate)
-import Data.Maybe (fromMaybe)
---import Network.URI (isURI) -- Not sure whether to use this function
-import Control.Monad (void, guard, when)
import Data.Default
-import Control.Monad.Reader (Reader, runReader, asks)
-import Text.Pandoc.Error
-
-import Data.Time.LocalTime (getZonedTime)
-import System.Directory(getModificationTime)
+import Data.List (intercalate, transpose)
+import Data.Maybe (fromMaybe)
+import Data.Monoid ((<>))
+import Data.Text (Text)
+import qualified Data.Text as T
import Data.Time.Format (formatTime)
+import Text.Pandoc.Builder (Blocks, Inlines, trimInlines)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad)
+import qualified Text.Pandoc.Class as P
import Text.Pandoc.Compat.Time (defaultTimeLocale)
-import System.IO.Error (catchIOError)
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (space, spaces, uri)
+import Text.Pandoc.Shared (compactify, compactifyDL, crFilter, escapeURI,
+ underlineSpan)
type T2T = ParserT String ParserState (Reader T2TMeta)
-- | An object for the T2T macros meta information
-- the contents of each field is simply substituted verbatim into the file
data T2TMeta = T2TMeta {
- date :: String -- ^ Current date
- , mtime :: String -- ^ Last modification time of infile
- , infile :: FilePath -- ^ Input file
+ date :: String -- ^ Current date
+ , mtime :: String -- ^ Last modification time of infile
+ , infile :: FilePath -- ^ Input file
, outfile :: FilePath -- ^ Output file
} deriving Show
@@ -69,26 +68,38 @@ instance Default T2TMeta where
def = T2TMeta "" "" "" ""
-- | Get the meta information required by Txt2Tags macros
-getT2TMeta :: [FilePath] -> FilePath -> IO T2TMeta
-getT2TMeta inps out = do
- curDate <- formatTime defaultTimeLocale "%F" <$> getZonedTime
+getT2TMeta :: PandocMonad m => m T2TMeta
+getT2TMeta = do
+ inps <- P.getInputFiles
+ outp <- fromMaybe "" <$> P.getOutputFile
+ curDate <- formatTime defaultTimeLocale "%F" <$> P.getZonedTime
let getModTime = fmap (formatTime defaultTimeLocale "%T") .
- getModificationTime
+ P.getModificationTime
curMtime <- case inps of
- [] -> formatTime defaultTimeLocale "%T" <$> getZonedTime
- _ -> catchIOError
+ [] -> formatTime defaultTimeLocale "%T" <$> P.getZonedTime
+ _ -> catchError
(maximum <$> mapM getModTime inps)
(const (return ""))
- return $ T2TMeta curDate curMtime (intercalate ", " inps) out
+ return $ T2TMeta curDate curMtime (intercalate ", " inps) outp
-- | Read Txt2Tags from an input string returning a Pandoc document
-readTxt2Tags :: T2TMeta -> ReaderOptions -> String -> Either PandocError Pandoc
-readTxt2Tags t opts s = flip runReader t $ readWithM parseT2T (def {stateOptions = opts}) (s ++ "\n\n")
+readTxt2Tags :: PandocMonad m
+ => ReaderOptions
+ -> Text
+ -> m Pandoc
+readTxt2Tags opts s = do
+ meta <- getT2TMeta
+ let parsed = flip runReader meta $
+ readWithM parseT2T (def {stateOptions = opts}) $
+ T.unpack (crFilter s) ++ "\n\n"
+ case parsed of
+ Right result -> return result
+ Left e -> throwError e
-- | Read Txt2Tags (ignoring all macros) from an input string returning
-- a Pandoc document
-readTxt2TagsNoMacros :: ReaderOptions -> String -> Either PandocError Pandoc
-readTxt2TagsNoMacros = readTxt2Tags def
+-- readTxt2TagsNoMacros :: PandocMonad m => ReaderOptions -> String -> m Pandoc
+-- readTxt2TagsNoMacros = readTxt2Tags
parseT2T :: T2T Pandoc
parseT2T = do
@@ -137,7 +148,7 @@ setting = do
string "%!"
keyword <- ignoreSpacesCap (many1 alphaNum)
char ':'
- value <- ignoreSpacesCap (manyTill anyChar (newline))
+ value <- ignoreSpacesCap (manyTill anyChar newline)
return (keyword, value)
-- Blocks
@@ -146,7 +157,7 @@ parseBlocks :: T2T Blocks
parseBlocks = mconcat <$> manyTill block eof
block :: T2T Blocks
-block = do
+block =
choice
[ mempty <$ blanklines
, quote
@@ -184,7 +195,7 @@ para = try $ do
listStart = try bulletListStart <|> orderedListStart
commentBlock :: T2T Blocks
-commentBlock = try (blockMarkupArea (anyLine) (const mempty) "%%%") <|> comment
+commentBlock = try (blockMarkupArea anyLine (const mempty) "%%%") <|> comment
-- Seperator and Strong line treated the same
hrule :: T2T Blocks
@@ -198,7 +209,7 @@ quote :: T2T Blocks
quote = try $ do
lookAhead tab
rawQuote <- many1 (tab *> optional spaces *> anyLine)
- contents <- parseFromString parseBlocks (intercalate "\n" rawQuote ++ "\n\n")
+ contents <- parseFromString' parseBlocks (intercalate "\n" rawQuote ++ "\n\n")
return $ B.blockQuote contents
commentLine :: T2T Inlines
@@ -210,16 +221,16 @@ list :: T2T Blocks
list = choice [bulletList, orderedList, definitionList]
bulletList :: T2T Blocks
-bulletList = B.bulletList . compactify'
+bulletList = B.bulletList . compactify
<$> many1 (listItem bulletListStart parseBlocks)
orderedList :: T2T Blocks
-orderedList = B.orderedList . compactify'
+orderedList = B.orderedList . compactify
<$> many1 (listItem orderedListStart parseBlocks)
definitionList :: T2T Blocks
-definitionList = try $ do
- B.definitionList . compactify'DL <$>
+definitionList = try $
+ B.definitionList . compactifyDL <$>
many1 (listItem definitionListStart definitionListEnd)
definitionListEnd :: T2T (Inlines, [Blocks])
@@ -250,7 +261,7 @@ listItem start end = try $ do
firstLine <- anyLineNewline
blank <- option "" ("\n" <$ blankline)
rest <- concat <$> many (listContinuation markerLength)
- parseFromString end $ firstLine ++ blank ++ rest
+ parseFromString' end $ firstLine ++ blank ++ rest
-- continuation of a list item - indented and separated by blankline or endline.
-- Note: nested lists are parsed as continuations.
@@ -262,12 +273,6 @@ listContinuation markerLength = try $
<*> many blankline)
where listLine = try $ indentWith markerLength *> anyLineNewline
-anyLineNewline :: T2T String
-anyLineNewline = (++ "\n") <$> anyLine
-
-indentWith :: Int -> T2T String
-indentWith n = count n space
-
-- Table
table :: T2T Blocks
@@ -276,17 +281,17 @@ table = try $ do
rows <- many1 (many commentLine *> tableRow)
let columns = transpose rows
let ncolumns = length columns
- let aligns = map (foldr1 findAlign) (map (map fst) columns)
+ let aligns = map (foldr1 findAlign . map fst) columns
let rows' = map (map snd) rows
let size = maximum (map length rows')
let rowsPadded = map (pad size) rows'
- let headerPadded = if (not (null tableHeader)) then pad size tableHeader else mempty
+ let headerPadded = if null tableHeader then mempty else pad size tableHeader
return $ B.table mempty
(zip aligns (replicate ncolumns 0.0))
headerPadded rowsPadded
pad :: (Monoid a) => Int -> [a] -> [a]
-pad n xs = xs ++ (replicate (n - length xs) mempty)
+pad n xs = xs ++ replicate (n - length xs) mempty
findAlign :: Alignment -> Alignment -> Alignment
@@ -309,7 +314,7 @@ genericRow start = try $ do
tableCell :: T2T (Alignment, Blocks)
tableCell = try $ do
leftSpaces <- length <$> lookAhead (many1 space) -- Case of empty cell means we must lookAhead
- content <- (manyTill inline (try $ lookAhead (cellEnd)))
+ content <- manyTill inline (try $ lookAhead cellEnd)
rightSpaces <- length <$> many space
let align =
case compare leftSpaces rightSpaces of
@@ -317,9 +322,9 @@ tableCell = try $ do
EQ -> AlignCenter
GT -> AlignRight
endOfCell
- return $ (align, B.plain (B.trimInlines $ mconcat content))
+ return (align, B.plain (B.trimInlines $ mconcat content))
where
- cellEnd = (void newline <|> (many1 space *> endOfCell))
+ cellEnd = void newline <|> (many1 space *> endOfCell)
endOfCell :: T2T ()
endOfCell = try (skipMany1 $ char '|') <|> ( () <$ lookAhead newline)
@@ -342,10 +347,10 @@ taggedBlock = do
genericBlock :: Monoid a => T2T a -> (a -> Blocks) -> String -> T2T Blocks
genericBlock p f s = blockMarkupArea p f s <|> blockMarkupLine p f s
-blockMarkupArea :: Monoid a => (T2T a) -> (a -> Blocks) -> String -> T2T Blocks
-blockMarkupArea p f s = try $ (do
+blockMarkupArea :: Monoid a => T2T a -> (a -> Blocks) -> String -> T2T Blocks
+blockMarkupArea p f s = try (do
string s *> blankline
- f . mconcat <$> (manyTill p (eof <|> void (string s *> blankline))))
+ f . mconcat <$> manyTill p (eof <|> void (string s *> blankline)))
blockMarkupLine :: T2T a -> (a -> Blocks) -> String -> T2T Blocks
blockMarkupLine p f s = try (f <$> (string s *> space *> p))
@@ -363,7 +368,7 @@ parseInlines :: T2T Inlines
parseInlines = trimInlines . mconcat <$> many1 inline
inline :: T2T Inlines
-inline = do
+inline =
choice
[ endline
, macro
@@ -385,16 +390,16 @@ inline = do
]
bold :: T2T Inlines
-bold = inlineMarkup inline B.strong '*' (B.str)
+bold = inlineMarkup inline B.strong '*' B.str
underline :: T2T Inlines
-underline = inlineMarkup inline B.emph '_' (B.str)
+underline = inlineMarkup inline underlineSpan '_' B.str
strike :: T2T Inlines
-strike = inlineMarkup inline B.strikeout '-' (B.str)
+strike = inlineMarkup inline B.strikeout '-' B.str
italic :: T2T Inlines
-italic = inlineMarkup inline B.emph '/' (B.str)
+italic = inlineMarkup inline B.emph '/' B.str
code :: T2T Inlines
code = inlineMarkup ((:[]) <$> anyChar) B.code '`' id
@@ -413,7 +418,7 @@ tagged = do
-- Glued meaning that markup must be tight to content
-- Markup can't pass newlines
inlineMarkup :: Monoid a
- => (T2T a) -- Content parser
+ => T2T a -- Content parser
-> (a -> Inlines) -- Constructor
-> Char -- Fence
-> (String -> a) -- Special Case to handle ******
@@ -425,20 +430,24 @@ inlineMarkup p f c special = try $ do
when (l == 2) (void $ notFollowedBy space)
-- We must make sure that there is no space before the start of the
-- closing tags
- body <- optionMaybe (try $ manyTill (noneOf "\n\r") $
+ body <- optionMaybe (try $ manyTill (noneOf "\n\r")
(try $ lookAhead (noneOf " " >> string [c,c] )))
case body of
Just middle -> do
lastChar <- anyChar
end <- many1 (char c)
- let parser inp = parseFromString (mconcat <$> many p) inp
- let start' = special (drop 2 start)
+ let parser inp = parseFromString' (mconcat <$> many p) inp
+ let start' = case drop 2 start of
+ "" -> mempty
+ xs -> special xs
body' <- parser (middle ++ [lastChar])
- let end' = special (drop 2 end)
+ let end' = case drop 2 end of
+ "" -> mempty
+ xs -> special xs
return $ f (start' <> body' <> end')
Nothing -> do -- Either bad or case such as *****
guard (l >= 5)
- let body' = (replicate (l - 4) c)
+ let body' = replicate (l - 4) c
return $ f (special body')
link :: T2T Inlines
@@ -453,8 +462,8 @@ titleLink = try $ do
guard (length tokens >= 2)
char ']'
let link' = last tokens
- guard (length link' > 0)
- let tit = concat (intersperse " " (init tokens))
+ guard $ not $ null link'
+ let tit = unwords (init tokens)
return $ B.link link' "" (B.text tit)
-- Link with image
@@ -479,7 +488,7 @@ macro = try $ do
-- raw URLs in text are automatically linked
url :: T2T Inlines
url = try $ do
- (rawUrl, escapedUrl) <- (try uri <|> emailAddress)
+ (rawUrl, escapedUrl) <- try uri <|> emailAddress
return $ B.link rawUrl "" (B.str escapedUrl)
uri :: T2T (String, String)
@@ -520,8 +529,7 @@ image = try $ do
-- List taken from txt2tags source
let extensions = [".jpg", ".jpeg", ".gif", ".png", ".eps", ".bmp"]
char '['
- path <- manyTill (noneOf "\n\t\r ") (try $ lookAhead (oneOfStrings extensions))
- ext <- oneOfStrings extensions
+ (path, ext) <- manyUntil (noneOf "\n\t\r ") (oneOfStrings extensions)
char ']'
return $ B.image (path ++ ext) "" mempty
@@ -550,11 +558,10 @@ endline = try $ do
notFollowedBy quote
notFollowedBy list
notFollowedBy table
- return $ B.softbreak
+ return B.softbreak
str :: T2T Inlines
-str = try $ do
- B.str <$> many1 (noneOf $ specialChars ++ "\n\r ")
+str = try $ B.str <$> many1 (noneOf $ specialChars ++ "\n\r ")
whitespace :: T2T Inlines
whitespace = try $ B.space <$ spaceChar
diff --git a/src/Text/Pandoc/Readers/Vimwiki.hs b/src/Text/Pandoc/Readers/Vimwiki.hs
new file mode 100644
index 000000000..d717a1ba8
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Vimwiki.hs
@@ -0,0 +1,673 @@
+{-
+ Copyright (C) 2017-2018 Yuchen Pei <me@ypei.me>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Vimwiki
+ Copyright : Copyright (C) 2017-2018 Yuchen Pei
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Yuchen Pei <me@ypei.me>
+ Stability : alpha
+ Portability : portable
+
+Conversion of vimwiki text to 'Pandoc' document.
+-}
+{--
+[X]: implemented
+[O]: not implemented
+* block parsers:
+ * [X] header
+ * [X] hrule
+ * [X] comment
+ * [X] blockquote
+ * [X] preformatted -- using codeblock
+ * [X] displaymath
+ * [X] bulletlist / orderedlist
+ * [X] todo lists -- using span.
+ * [X] table
+ * [X] centered table -- using div
+ * [O] colspan and rowspan -- see issue #1024
+ * [X] paragraph
+ * [X] definition list
+* inline parsers:
+ * [X] bareURL
+ * [X] strong
+ * [X] emph
+ * [X] strikeout
+ * [X] code
+ * [X] link
+ * [X] image
+ * [X] inline math
+ * [X] tag
+ * [X] sub- and super-scripts
+* misc:
+ * [X] `TODO:` mark
+ * [X] metadata placeholders: %title and %date
+ * [O] control placeholders: %template and %nohtml -- ignored
+--}
+
+module Text.Pandoc.Readers.Vimwiki ( readVimwiki
+ ) where
+import Control.Monad (guard)
+import Control.Monad.Except (throwError)
+import Data.Default
+import Data.List (isInfixOf, isPrefixOf)
+import Data.Maybe
+import Data.Monoid ((<>))
+import Data.Text (Text, unpack)
+import Text.Pandoc.Builder (Blocks, Inlines, fromList, toList, trimInlines)
+import qualified Text.Pandoc.Builder as B (blockQuote, bulletList, code,
+ codeBlockWith, definitionList,
+ displayMath, divWith, emph,
+ headerWith, horizontalRule, image,
+ imageWith, link, math, orderedList,
+ para, plain, setMeta, simpleTable,
+ softbreak, space, spanWith, str,
+ strikeout, strong, subscript,
+ superscript)
+import Text.Pandoc.Class (PandocMonad (..))
+import Text.Pandoc.Definition (Attr, Block (BulletList, OrderedList),
+ Inline (Space), ListNumberDelim (..),
+ ListNumberStyle (..), Meta, Pandoc (..),
+ nullMeta)
+import Text.Pandoc.Options (ReaderOptions)
+import Text.Pandoc.Parsing (F, ParserState, ParserT, blanklines, emailAddress,
+ many1Till, orderedListMarker, readWithM,
+ registerHeader, runF, spaceChar, stateMeta',
+ stateOptions, uri)
+import Text.Pandoc.Shared (crFilter, splitBy, stringify, stripFirstAndLast)
+import Text.Parsec.Char (alphaNum, anyChar, char, newline, noneOf, oneOf, space,
+ spaces, string)
+import Text.Parsec.Combinator (between, choice, count, eof, lookAhead, many1,
+ manyTill, notFollowedBy, option, skipMany1)
+import Text.Parsec.Prim (getState, many, try, updateState, (<|>))
+
+readVimwiki :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
+readVimwiki opts s = do
+ res <- readWithM parseVimwiki def{ stateOptions = opts }
+ (unpack (crFilter s))
+ case res of
+ Left e -> throwError e
+ Right result -> return result
+
+type VwParser = ParserT [Char] ParserState
+
+
+-- constants
+
+specialChars :: [Char]
+specialChars = "=*-#[]_~{}`$|:%^,"
+
+spaceChars :: [Char]
+spaceChars = " \t\n"
+
+-- main parser
+
+parseVimwiki :: PandocMonad m => VwParser m Pandoc
+parseVimwiki = do
+ bs <- mconcat <$> many block
+ spaces
+ eof
+ st <- getState
+ let meta = runF (stateMeta' st) st
+ return $ Pandoc meta (toList bs)
+
+-- block parser
+
+block :: PandocMonad m => VwParser m Blocks
+block = do
+ res <- choice [ mempty <$ blanklines
+ , header
+ , hrule
+ , mempty <$ comment
+ , mixedList
+ , preformatted
+ , displayMath
+ , table
+ , mempty <$ placeholder
+ , blockQuote
+ , definitionList
+ , para
+ ]
+ trace (take 60 $ show $ toList res)
+ return res
+
+blockML :: PandocMonad m => VwParser m Blocks
+blockML = choice [preformatted, displayMath, table]
+
+header :: PandocMonad m => VwParser m Blocks
+header = try $ do
+ sp <- many spaceChar
+ eqs <- many1 (char '=')
+ spaceChar
+ let lev = length eqs
+ guard $ lev <= 6
+ contents <- trimInlines . mconcat <$> manyTill inline (try $ spaceChar
+ >> string eqs >> many spaceChar >> newline)
+ attr <- registerHeader (makeId contents,
+ if sp == "" then [] else ["justcenter"], []) contents
+ return $ B.headerWith attr lev contents
+
+para :: PandocMonad m => VwParser m Blocks
+para = try $ do
+ contents <- trimInlines . mconcat <$> many1 inline
+ if all (==Space) (toList contents)
+ then return mempty
+ else return $ B.para contents
+
+hrule :: PandocMonad m => VwParser m Blocks
+hrule = try $ B.horizontalRule <$ (string "----" >> many (char '-') >> newline)
+
+comment :: PandocMonad m => VwParser m ()
+comment = try $ do
+ many spaceChar >> string "%%" >> many (noneOf "\n")
+ return ()
+
+blockQuote :: PandocMonad m => VwParser m Blocks
+blockQuote = try $ do
+ string " "
+ contents <- trimInlines . mconcat <$> many1 inlineBQ
+ if all (==Space) (toList contents)
+ then return mempty
+ else return $ B.blockQuote $ B.plain contents
+
+definitionList :: PandocMonad m => VwParser m Blocks
+definitionList = try $
+ B.definitionList <$> many1 (dlItemWithDT <|> dlItemWithoutDT)
+
+dlItemWithDT :: PandocMonad m => VwParser m (Inlines, [Blocks])
+dlItemWithDT = do
+ dt <- definitionTerm
+ dds <- many definitionDef
+ return (dt, dds)
+
+dlItemWithoutDT :: PandocMonad m => VwParser m (Inlines, [Blocks])
+dlItemWithoutDT = do
+ dds <- many1 definitionDef
+ return (mempty, dds)
+
+definitionDef :: PandocMonad m => VwParser m Blocks
+definitionDef = try $
+ notFollowedBy definitionTerm >> many spaceChar
+ >> (definitionDef1 <|> definitionDef2)
+
+definitionDef1 :: PandocMonad m => VwParser m Blocks
+definitionDef1 = try $ mempty <$ defMarkerE
+
+definitionDef2 :: PandocMonad m => VwParser m Blocks
+definitionDef2 = try $ B.plain <$>
+ (defMarkerM >> (trimInlines . mconcat <$> many inline') <* newline)
+
+
+definitionTerm :: PandocMonad m => VwParser m Inlines
+definitionTerm = try $ do
+ x <- definitionTerm1 <|> definitionTerm2
+ guard (stringify x /= "")
+ return x
+
+definitionTerm1 :: PandocMonad m => VwParser m Inlines
+definitionTerm1 = try $
+ trimInlines . mconcat <$> manyTill inline' (try defMarkerE)
+
+definitionTerm2 :: PandocMonad m => VwParser m Inlines
+definitionTerm2 = try $ trimInlines . mconcat <$> manyTill inline'
+ (try $lookAhead (defMarkerM >> notFollowedBy hasDefMarkerM))
+
+defMarkerM :: PandocMonad m => VwParser m Char
+defMarkerM = string "::" >> spaceChar
+
+defMarkerE :: PandocMonad m => VwParser m Char
+defMarkerE = string "::" >> newline
+
+hasDefMarkerM :: PandocMonad m => VwParser m String
+hasDefMarkerM = manyTill (noneOf "\n") (try defMarkerM)
+
+preformatted :: PandocMonad m => VwParser m Blocks
+preformatted = try $ do
+ many spaceChar >> string "{{{"
+ attrText <- many (noneOf "\n")
+ lookAhead newline
+ contents <- manyTill anyChar (try (char '\n' >> many spaceChar >> string "}}}"
+ >> many spaceChar >> newline))
+ if (contents /= "") && (head contents == '\n')
+ then return $ B.codeBlockWith (makeAttr attrText) (tail contents)
+ else return $ B.codeBlockWith (makeAttr attrText) contents
+
+makeAttr :: String -> Attr
+makeAttr s =
+ let xs = splitBy (`elem` " \t") s in
+ ("", [], mapMaybe nameValue xs)
+
+nameValue :: String -> Maybe (String, String)
+nameValue s =
+ let t = splitBy (== '=') s in
+ if length t /= 2
+ then Nothing
+ else let (a, b) = (head t, last t) in
+ if (length b < 2) || ((head b, last b) /= ('"', '"'))
+ then Nothing
+ else Just (a, stripFirstAndLast b)
+
+
+displayMath :: PandocMonad m => VwParser m Blocks
+displayMath = try $ do
+ many spaceChar >> string "{{$"
+ mathTag <- option "" mathTagParser
+ many space
+ contents <- manyTill anyChar (try (char '\n' >> many spaceChar >> string "}}$"
+ >> many spaceChar >> newline))
+ let contentsWithTags
+ | mathTag == "" = contents
+ | otherwise = "\\begin{" ++ mathTag ++ "}\n" ++ contents
+ ++ "\n\\end{" ++ mathTag ++ "}"
+ return $ B.para $ B.displayMath contentsWithTags
+
+
+mathTagLaTeX :: String -> String
+mathTagLaTeX s = case s of
+ "equation" -> ""
+ "equation*" -> ""
+ "gather" -> "gathered"
+ "gather*" -> "gathered"
+ "multline" -> "gathered"
+ "multline*" -> "gathered"
+ "eqnarray" -> "aligned"
+ "eqnarray*" -> "aligned"
+ "align" -> "aligned"
+ "align*" -> "aligned"
+ "alignat" -> "aligned"
+ "alignat*" -> "aligned"
+ _ -> s
+
+
+mixedList :: PandocMonad m => VwParser m Blocks
+mixedList = try $ do
+ (bl, _) <- mixedList' (-1)
+ return $ head bl
+
+mixedList' :: PandocMonad m => Int -> VwParser m ([Blocks], Int)
+mixedList' prevInd = do
+ (curInd, builder) <- option (-1, "na") (lookAhead listStart)
+ if curInd < prevInd
+ then return ([], curInd)
+ else do
+ listStart
+ curLine <- listItemContent
+ let listBuilder =
+ if builder == "ul" then B.bulletList else B.orderedList
+ (subList, lowInd) <- mixedList' curInd
+ if lowInd >= curInd
+ then do
+ (sameIndList, endInd) <- mixedList' lowInd
+ let curList = combineList curLine subList ++ sameIndList
+ if curInd > prevInd
+ then return ([listBuilder curList], endInd)
+ else return (curList, endInd)
+ else do
+ let (curList, endInd) = (combineList curLine subList,
+ lowInd)
+ if curInd > prevInd
+ then return ([listBuilder curList], endInd)
+ else return (curList, endInd)
+
+plainInlineML' :: PandocMonad m => Inlines -> VwParser m Blocks
+plainInlineML' w = do
+ xs <- many inlineML
+ newline
+ return $ B.plain $ trimInlines $ mconcat $ w:xs
+
+plainInlineML :: PandocMonad m => VwParser m Blocks
+plainInlineML = notFollowedBy listStart >> spaceChar >> plainInlineML' mempty
+
+
+listItemContent :: PandocMonad m => VwParser m Blocks
+listItemContent = try $ do
+ w <- option mempty listTodoMarker
+ x <- plainInlineML' w
+ y <- many blocksThenInline
+ z <- many blockML
+ return $ mconcat $ x:y ++ z
+
+blocksThenInline :: PandocMonad m => VwParser m Blocks
+blocksThenInline = try $ do
+ y <- many1 blockML
+ x <- plainInlineML
+ return $ mconcat $ y ++ [x]
+
+listTodoMarker :: PandocMonad m => VwParser m Inlines
+listTodoMarker = try $ do
+ x <- between (many spaceChar >> char '[') (char ']' >> spaceChar)
+ (oneOf " .oOX")
+ return $ makeListMarkerSpan x
+
+makeListMarkerSpan :: Char -> Inlines
+makeListMarkerSpan x =
+ let cl = case x of
+ ' ' -> "done0"
+ '.' -> "done1"
+ 'o' -> "done2"
+ 'O' -> "done3"
+ 'X' -> "done4"
+ _ -> ""
+ in
+ B.spanWith ("", [cl], []) mempty
+
+combineList :: Blocks -> [Blocks] -> [Blocks]
+combineList x [y] = case toList y of
+ [BulletList z] -> [fromList $ toList x
+ ++ [BulletList z]]
+ [OrderedList attr z] -> [fromList $ toList x
+ ++ [OrderedList attr z]]
+ _ -> x:[y]
+combineList x xs = x:xs
+
+listStart :: PandocMonad m => VwParser m (Int, String)
+listStart = try $ do
+ s <- many spaceChar
+ listType <- bulletListMarkers <|> orderedListMarkers
+ spaceChar
+ return (length s, listType)
+
+bulletListMarkers :: PandocMonad m => VwParser m String
+bulletListMarkers = "ul" <$ (char '*' <|> char '-')
+
+orderedListMarkers :: PandocMonad m => VwParser m String
+orderedListMarkers =
+ ("ol" <$choice (orderedListMarker Decimal Period:(($OneParen) . orderedListMarker <$> [Decimal, LowerRoman, UpperRoman, LowerAlpha, UpperAlpha])))
+ <|> ("ol" <$ char '#')
+
+--many need trimInlines
+table :: PandocMonad m => VwParser m Blocks
+table = try $ do
+ indent <- lookAhead (many spaceChar)
+ (th, trs) <- table1 <|> table2
+ let tab = B.simpleTable th trs
+ if indent == ""
+ then return tab
+ else return $ B.divWith ("", ["center"], []) tab
+
+-- table with header
+table1 :: PandocMonad m => VwParser m ([Blocks], [[Blocks]])
+table1 = try $ do
+ th <- tableRow
+ many1 tableHeaderSeparator
+ trs <- many tableRow
+ return (th, trs)
+
+-- headerless table
+table2 :: PandocMonad m => VwParser m ([Blocks], [[Blocks]])
+table2 = try $ do
+ trs <- many1 tableRow
+ return (replicate (length $ head trs) mempty, trs)
+
+tableHeaderSeparator :: PandocMonad m => VwParser m ()
+tableHeaderSeparator = try $ do
+ many spaceChar >> char '|' >> many1 (many1 (char '-') >> char '|')
+ >> many spaceChar >> newline
+ return ()
+
+tableRow :: PandocMonad m => VwParser m [Blocks]
+tableRow = try $ do
+ many spaceChar >> char '|'
+ s <- lookAhead $ manyTill anyChar (try (char '|' >> many spaceChar
+ >> newline))
+ guard $ not $ "||" `isInfixOf` ("|" ++ s ++ "|")
+ tr <- many tableCell
+ many spaceChar >> char '\n'
+ return tr
+
+tableCell :: PandocMonad m => VwParser m Blocks
+tableCell = try $
+ B.plain . trimInlines . mconcat <$> manyTill inline' (char '|')
+
+placeholder :: PandocMonad m => VwParser m ()
+placeholder = try $
+ choice (ph <$> ["title", "date"]) <|> noHtmlPh <|> templatePh
+
+ph :: PandocMonad m => String -> VwParser m ()
+ph s = try $ do
+ many spaceChar >>string ('%':s) >> spaceChar
+ contents <- trimInlines . mconcat <$> manyTill inline (lookAhead newline)
+ --use lookAhead because of placeholder in the whitespace parser
+ let meta' = return $ B.setMeta s contents nullMeta :: F Meta
+ updateState $ \st -> st { stateMeta' = stateMeta' st <> meta' }
+
+noHtmlPh :: PandocMonad m => VwParser m ()
+noHtmlPh = try $
+ () <$ (many spaceChar >> string "%nohtml" >> many spaceChar
+ >> lookAhead newline)
+
+templatePh :: PandocMonad m => VwParser m ()
+templatePh = try $
+ () <$ (many spaceChar >> string "%template" >>many (noneOf "\n")
+ >> lookAhead newline)
+
+-- inline parser
+
+inline :: PandocMonad m => VwParser m Inlines
+inline = choice $ whitespace endlineP:inlineList
+
+inlineList :: PandocMonad m => [VwParser m Inlines]
+inlineList = [ bareURL
+ , todoMark
+ , str
+ , strong
+ , emph
+ , strikeout
+ , code
+ , link
+ , image
+ , inlineMath
+ , tag
+ , superscript
+ , subscript
+ , special
+ ]
+
+-- inline parser without softbreaks or comment breaks
+inline' :: PandocMonad m => VwParser m Inlines
+inline' = choice $ whitespace':inlineList
+
+-- inline parser for blockquotes
+inlineBQ :: PandocMonad m => VwParser m Inlines
+inlineBQ = choice $ whitespace endlineBQ:inlineList
+
+-- inline parser for mixedlists
+inlineML :: PandocMonad m => VwParser m Inlines
+inlineML = choice $ whitespace endlineML:inlineList
+
+str :: PandocMonad m => VwParser m Inlines
+str = B.str <$>many1 (noneOf $ spaceChars ++ specialChars)
+
+whitespace :: PandocMonad m => VwParser m () -> VwParser m Inlines
+whitespace endline = B.space <$ (skipMany1 spaceChar <|>
+ try (newline >> (comment <|> placeholder)))
+ <|> B.softbreak <$ endline
+
+whitespace' :: PandocMonad m => VwParser m Inlines
+whitespace' = B.space <$ skipMany1 spaceChar
+
+special :: PandocMonad m => VwParser m Inlines
+special = B.str <$> count 1 (oneOf specialChars)
+
+bareURL :: PandocMonad m => VwParser m Inlines
+bareURL = try $ do
+ (orig, src) <- uri <|> emailAddress
+ return $ B.link src "" (B.str orig)
+
+strong :: PandocMonad m => VwParser m Inlines
+strong = try $ do
+ s <- lookAhead $ between (char '*') (char '*') (many1 $ noneOf "*")
+ guard $ (head s `notElem` spaceChars)
+ && (last s `notElem` spaceChars)
+ char '*'
+ contents <- mconcat <$>manyTill inline' (char '*'
+ >> notFollowedBy alphaNum)
+ return $ B.spanWith (makeId contents, [], []) mempty
+ <> B.strong contents
+
+makeId :: Inlines -> String
+makeId i = concat (stringify <$> toList i)
+
+emph :: PandocMonad m => VwParser m Inlines
+emph = try $ do
+ s <- lookAhead $ between (char '_') (char '_') (many1 $ noneOf "_")
+ guard $ (head s `notElem` spaceChars)
+ && (last s `notElem` spaceChars)
+ char '_'
+ contents <- mconcat <$>manyTill inline' (char '_'
+ >> notFollowedBy alphaNum)
+ return $ B.emph contents
+
+strikeout :: PandocMonad m => VwParser m Inlines
+strikeout = try $ do
+ string "~~"
+ contents <- mconcat <$>many1Till inline' (string "~~")
+ return $ B.strikeout contents
+
+code :: PandocMonad m => VwParser m Inlines
+code = try $ do
+ char '`'
+ contents <- many1Till (noneOf "\n") (char '`')
+ return $ B.code contents
+
+superscript :: PandocMonad m => VwParser m Inlines
+superscript = try $
+ B.superscript . mconcat <$> (char '^' >> many1Till inline' (char '^'))
+
+subscript :: PandocMonad m => VwParser m Inlines
+subscript = try $
+ B.subscript . mconcat <$> (string ",,"
+ >> many1Till inline' (try $ string ",,"))
+
+link :: PandocMonad m => VwParser m Inlines
+link = try $ do
+ string "[["
+ contents <- lookAhead $ manyTill anyChar (string "]]")
+ case '|' `elem` contents of
+ False -> do
+ manyTill anyChar (string "]]")
+-- not using try here because [[hell]o]] is not rendered as a link in vimwiki
+ return $ B.link (procLink contents) "" (B.str contents)
+ True -> do
+ url <- manyTill anyChar $ char '|'
+ lab <- mconcat <$> manyTill inline (string "]]")
+ return $ B.link (procLink url) "" lab
+
+image :: PandocMonad m => VwParser m Inlines
+image = try $ do
+ string "{{"
+ contentText <- lookAhead $ manyTill (noneOf "\n") (try $ string "}}")
+ images $ length $ filter (== '|') contentText
+
+images :: PandocMonad m => Int -> VwParser m Inlines
+images k
+ | k == 0 = do
+ imgurl <- manyTill anyChar (try $ string "}}")
+ return $ B.image (procImgurl imgurl) "" (B.str "")
+ | k == 1 = do
+ imgurl <- manyTill anyChar (char '|')
+ alt <- mconcat <$> manyTill inline (try $ string "}}")
+ return $ B.image (procImgurl imgurl) "" alt
+ | k == 2 = do
+ imgurl <- manyTill anyChar (char '|')
+ alt <- mconcat <$>manyTill inline (char '|')
+ attrText <- manyTill anyChar (try $ string "}}")
+ return $ B.imageWith (makeAttr attrText) (procImgurl imgurl) "" alt
+ | otherwise = do
+ imgurl <- manyTill anyChar (char '|')
+ alt <- mconcat <$>manyTill inline (char '|')
+ attrText <- manyTill anyChar (char '|')
+ manyTill anyChar (try $ string "}}")
+ return $ B.imageWith (makeAttr attrText) (procImgurl imgurl) "" alt
+
+procLink' :: String -> String
+procLink' s
+ | take 6 s == "local:" = "file" ++ drop 5 s
+ | take 6 s == "diary:" = "diary/" ++ drop 6 s ++ ".html"
+ | or ((`isPrefixOf` s) <$> [ "http:", "https:", "ftp:", "file:", "mailto:",
+ "news:", "telnet:" ])
+ = s
+ | s == "" = ""
+ | last s == '/' = s
+ | otherwise = s ++ ".html"
+
+procLink :: String -> String
+procLink s = procLink' x ++ y
+ where (x, y) = break (=='#') s
+
+procImgurl :: String -> String
+procImgurl s = if take 6 s == "local:" then "file" ++ drop 5 s else s
+
+inlineMath :: PandocMonad m => VwParser m Inlines
+inlineMath = try $ do
+ char '$'
+ contents <- many1Till (noneOf "\n") (char '$')
+ return $ B.math contents
+
+tag :: PandocMonad m => VwParser m Inlines
+tag = try $ do
+ char ':'
+ s <- manyTill (noneOf spaceChars) (try (char ':' >> lookAhead space))
+ guard $ not $ "::" `isInfixOf` (":" ++ s ++ ":")
+ let ss = splitBy (==':') s
+ return $ mconcat $ makeTagSpan' (head ss):(makeTagSpan <$> tail ss)
+
+todoMark :: PandocMonad m => VwParser m Inlines
+todoMark = try $ do
+ string "TODO:"
+ return $ B.spanWith ("", ["todo"], []) (B.str "TODO:")
+
+-- helper functions and parsers
+endlineP :: PandocMonad m => VwParser m ()
+endlineP = () <$ try (newline <* nFBTTBSB <* notFollowedBy blockQuote)
+
+endlineBQ :: PandocMonad m => VwParser m ()
+endlineBQ = () <$ try (newline <* nFBTTBSB <* string " ")
+
+endlineML :: PandocMonad m => VwParser m ()
+endlineML = () <$ try (newline <* nFBTTBSB <* many1 spaceChar)
+
+--- nFBTTBSB is short for notFollowedByThingsThatBreakSoftBreaks
+nFBTTBSB :: PandocMonad m => VwParser m ()
+nFBTTBSB =
+ notFollowedBy newline <*
+ notFollowedBy hrule <*
+ notFollowedBy tableRow <*
+ notFollowedBy header <*
+ notFollowedBy listStart <*
+ notFollowedBy preformatted <*
+ notFollowedBy displayMath <*
+ notFollowedBy hasDefMarker
+
+hasDefMarker :: PandocMonad m => VwParser m ()
+hasDefMarker = () <$ manyTill (noneOf "\n") (string "::" >> oneOf spaceChars)
+
+makeTagSpan' :: String -> Inlines
+makeTagSpan' s = B.spanWith ('-' : s, [], []) (B.str "") <>
+ B.spanWith (s, ["tag"], []) (B.str s)
+
+makeTagSpan :: String -> Inlines
+makeTagSpan s = B.space <> makeTagSpan' s
+
+mathTagParser :: PandocMonad m => VwParser m String
+mathTagParser = do
+ s <- try $ lookAhead (char '%' >> manyTill (noneOf spaceChars)
+ (try $ char '%' >> many (noneOf $ '%':spaceChars) >> space))
+ char '%' >> string s >> char '%'
+ return $ mathTagLaTeX s
diff --git a/src/Text/Pandoc/SelfContained.hs b/src/Text/Pandoc/SelfContained.hs
index d08d636df..a1c5c919e 100644
--- a/src/Text/Pandoc/SelfContained.hs
+++ b/src/Text/Pandoc/SelfContained.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2011-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.SelfContained
- Copyright : Copyright (C) 2011-2016 John MacFarlane
+ Copyright : Copyright (C) 2011-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,32 +30,36 @@ Functions for converting an HTML file into one that can be viewed
offline, by incorporating linked images, CSS, and scripts into
the HTML using data URIs.
-}
-module Text.Pandoc.SelfContained ( makeSelfContained ) where
-import Text.HTML.TagSoup
-import Network.URI (isURI, escapeURIString, URI(..), parseURI)
+module Text.Pandoc.SelfContained ( makeDataURI, makeSelfContained ) where
+import Codec.Compression.GZip as Gzip
+import Control.Applicative ((<|>))
+import Control.Monad.Except (throwError)
+import Control.Monad.Trans (lift)
+import Data.ByteString (ByteString)
import Data.ByteString.Base64
import qualified Data.ByteString.Char8 as B
-import Data.ByteString (ByteString)
-import System.FilePath (takeExtension, takeDirectory, (</>))
-import Data.Char (toLower, isAscii, isAlphaNum)
-import Codec.Compression.GZip as Gzip
import qualified Data.ByteString.Lazy as L
-import Text.Pandoc.Shared (renderTags', err, fetchItem', warn, trim)
-import Text.Pandoc.MediaBag (MediaBag)
+import Data.Char (isAlphaNum, isAscii, toLower)
+import Data.List (isPrefixOf)
+import Data.Monoid ((<>))
+import Network.URI (escapeURIString)
+import System.FilePath (takeDirectory, takeExtension, (</>))
+import Text.HTML.TagSoup
+import Text.Pandoc.Class (PandocMonad (..), fetchItem, getInputFiles, report,
+ setInputFiles)
+import Text.Pandoc.Error
+import Text.Pandoc.Logging
import Text.Pandoc.MIME (MimeType)
+import Text.Pandoc.Shared (isURI, renderTags', trim)
import Text.Pandoc.UTF8 (toString)
-import Text.Pandoc.Options (WriterOptions(..))
-import Data.List (isPrefixOf)
-import Control.Applicative ((<|>))
-import Text.Parsec (runParserT, ParsecT)
+import Text.Parsec (ParsecT, runParserT)
import qualified Text.Parsec as P
-import Control.Monad.Trans (lift)
isOk :: Char -> Bool
isOk c = isAscii c && isAlphaNum c
-makeDataURI :: String -> ByteString -> String
-makeDataURI mime raw =
+makeDataURI :: (MimeType, ByteString) -> String
+makeDataURI (mime, raw) =
if textual
then "data:" ++ mime' ++ "," ++ escapeURIString isOk (toString raw)
else "data:" ++ mime' ++ ";base64," ++ toString (encode raw)
@@ -64,64 +68,143 @@ makeDataURI mime raw =
then mime ++ ";charset=utf-8"
else mime -- mime type already has charset
-convertTag :: MediaBag -> Maybe String -> Tag String -> IO (Tag String)
-convertTag media sourceURL t@(TagOpen tagname as)
+convertTags :: PandocMonad m => [Tag String] -> m [Tag String]
+convertTags [] = return []
+convertTags (t@TagOpen{}:ts)
+ | fromAttrib "data-external" t == "1" = (t:) <$> convertTags ts
+convertTags (t@(TagOpen tagname as):ts)
| tagname `elem`
- ["img", "embed", "video", "input", "audio", "source", "track"] = do
+ ["img", "embed", "video", "input", "audio", "source", "track",
+ "section"] = do
as' <- mapM processAttribute as
- return $ TagOpen tagname as'
+ rest <- convertTags ts
+ return $ TagOpen tagname as' : rest
where processAttribute (x,y) =
- if x == "src" || x == "href" || x == "poster"
+ if x `elem` ["src", "data-src", "href", "poster", "data-background-image"]
then do
- enc <- getDataURI media sourceURL (fromAttrib "type" t) y
+ enc <- getDataURI (fromAttrib "type" t) y
return (x, enc)
else return (x,y)
-convertTag media sourceURL t@(TagOpen "script" as) =
+convertTags (t@(TagOpen "script" as):TagClose "script":ts) =
case fromAttrib "src" t of
- [] -> return t
+ [] -> (t:) <$> convertTags ts
src -> do
- enc <- getDataURI media sourceURL (fromAttrib "type" t) src
- return $ TagOpen "script" (("src",enc) : [(x,y) | (x,y) <- as, x /= "src"])
-convertTag media sourceURL t@(TagOpen "link" as) =
+ let typeAttr = fromAttrib "type" t
+ res <- getData typeAttr src
+ rest <- convertTags ts
+ case res of
+ Left dataUri -> return $ TagOpen "script"
+ (("src",dataUri) : [(x,y) | (x,y) <- as, x /= "src"]) :
+ TagClose "script" : rest
+ Right (mime, bs)
+ | ("text/javascript" `isPrefixOf` mime ||
+ "application/javascript" `isPrefixOf` mime ||
+ "application/x-javascript" `isPrefixOf` mime) &&
+ not ("</script" `B.isInfixOf` bs) ->
+ return $
+ TagOpen "script" [("type", typeAttr)|not (null typeAttr)]
+ : TagText (toString bs)
+ : TagClose "script"
+ : rest
+ | otherwise ->
+ return $ TagOpen "script"
+ (("src",makeDataURI (mime, bs)) :
+ [(x,y) | (x,y) <- as, x /= "src"]) :
+ TagClose "script" : rest
+convertTags (t@(TagOpen "link" as):ts) =
case fromAttrib "href" t of
- [] -> return t
+ [] -> (t:) <$> convertTags ts
src -> do
- enc <- getDataURI media sourceURL (fromAttrib "type" t) src
- return $ TagOpen "link" (("href",enc) : [(x,y) | (x,y) <- as, x /= "href"])
-convertTag _ _ t = return t
-
-cssURLs :: MediaBag -> Maybe String -> FilePath -> ByteString
- -> IO ByteString
-cssURLs media sourceURL d orig = do
- res <- runParserT (parseCSSUrls media sourceURL d) () "css" orig
+ res <- getData (fromAttrib "type" t) src
+ case res of
+ Left dataUri -> do
+ rest <- convertTags ts
+ return $ TagOpen "link"
+ (("href",dataUri) : [(x,y) | (x,y) <- as, x /= "href"]) :
+ rest
+ Right (mime, bs)
+ | "text/css" `isPrefixOf` mime
+ && null (fromAttrib "media" t)
+ && not ("</" `B.isInfixOf` bs) -> do
+ rest <- convertTags $
+ dropWhile (==TagClose "link") ts
+ return $
+ TagOpen "style" [("type", mime)]
+ : TagText (toString bs)
+ : TagClose "style"
+ : rest
+ | otherwise -> do
+ rest <- convertTags ts
+ return $ TagOpen "link"
+ (("href",makeDataURI (mime, bs)) :
+ [(x,y) | (x,y) <- as, x /= "href"]) : rest
+convertTags (t:ts) = (t:) <$> convertTags ts
+
+cssURLs :: PandocMonad m
+ => FilePath -> ByteString -> m ByteString
+cssURLs d orig = do
+ res <- runParserT (parseCSSUrls d) () "css" orig
case res of
- Left e -> warn ("Could not parse CSS: " ++ show e) >> return orig
+ Left e -> do
+ report $ CouldNotParseCSS (show e)
+ return orig
Right bs -> return bs
-parseCSSUrls :: MediaBag -> Maybe String -> FilePath
- -> ParsecT ByteString () IO ByteString
-parseCSSUrls media sourceURL d = B.concat <$> P.many
- (pCSSWhite <|> pCSSComment <|> pCSSUrl media sourceURL d <|> pCSSOther)
+parseCSSUrls :: PandocMonad m
+ => FilePath -> ParsecT ByteString () m ByteString
+parseCSSUrls d = B.concat <$> P.many
+ (pCSSWhite <|> pCSSComment <|> pCSSImport d <|> pCSSUrl d <|> pCSSOther)
+
+pCSSImport :: PandocMonad m
+ => FilePath -> ParsecT ByteString () m ByteString
+pCSSImport d = P.try $ do
+ P.string "@import"
+ P.spaces
+ res <- (pQuoted <|> pUrl) >>= handleCSSUrl d
+ P.spaces
+ P.char ';'
+ P.spaces
+ case res of
+ Left b -> return $ B.pack "@import " <> b
+ Right (_, b) -> return b
-- Note: some whitespace in CSS is significant, so we can't collapse it!
-pCSSWhite :: ParsecT ByteString () IO ByteString
+pCSSWhite :: PandocMonad m => ParsecT ByteString () m ByteString
pCSSWhite = B.singleton <$> P.space <* P.spaces
-pCSSComment :: ParsecT ByteString () IO ByteString
+pCSSComment :: PandocMonad m => ParsecT ByteString () m ByteString
pCSSComment = P.try $ do
P.string "/*"
P.manyTill P.anyChar (P.try (P.string "*/"))
return B.empty
-pCSSOther :: ParsecT ByteString () IO ByteString
-pCSSOther = do
+pCSSOther :: PandocMonad m => ParsecT ByteString () m ByteString
+pCSSOther =
(B.pack <$> P.many1 (P.noneOf "u/ \n\r\t")) <|>
- (B.singleton <$> P.char 'u') <|>
- (B.singleton <$> P.char '/')
+ (B.singleton <$> P.char 'u') <|>
+ (B.singleton <$> P.char '/')
+
+pCSSUrl :: PandocMonad m
+ => FilePath -> ParsecT ByteString () m ByteString
+pCSSUrl d = P.try $ do
+ res <- pUrl >>= handleCSSUrl d
+ case res of
+ Left b -> return b
+ Right (mt,b) -> do
+ let enc = makeDataURI (mt, b)
+ return (B.pack $ "url(" ++ enc ++ ")")
+
+pQuoted :: PandocMonad m
+ => ParsecT ByteString () m (String, ByteString)
+pQuoted = P.try $ do
+ quote <- P.oneOf "\"'"
+ url <- P.manyTill P.anyChar (P.char quote)
+ let fallback = B.pack ([quote] ++ trim url ++ [quote])
+ return (url, fallback)
-pCSSUrl :: MediaBag -> Maybe String -> FilePath
- -> ParsecT ByteString () IO ByteString
-pCSSUrl media sourceURL d = P.try $ do
+pUrl :: PandocMonad m
+ => ParsecT ByteString () m (String, ByteString)
+pUrl = P.try $ do
P.string "url("
P.spaces
quote <- P.option Nothing (Just <$> P.oneOf "\"'")
@@ -130,49 +213,66 @@ pCSSUrl media sourceURL d = P.try $ do
P.char ')'
let fallback = B.pack ("url(" ++ maybe "" (:[]) quote ++ trim url ++
maybe "" (:[]) quote ++ ")")
- case trim url of
- '#':_ -> return fallback
- 'd':'a':'t':'a':':':_ -> return fallback
+ return (url, fallback)
+
+handleCSSUrl :: PandocMonad m
+ => FilePath -> (String, ByteString)
+ -> ParsecT ByteString () m
+ (Either ByteString (MimeType, ByteString))
+handleCSSUrl d (url, fallback) =
+ case escapeURIString (/='|') (trim url) of
+ '#':_ -> return $ Left fallback
+ 'd':'a':'t':'a':':':_ -> return $ Left fallback
u -> do let url' = if isURI u then u else d </> u
- enc <- lift $ getDataURI media sourceURL "" url'
- return (B.pack $ "url(" ++ enc ++ ")")
+ res <- lift $ getData "" url'
+ case res of
+ Left uri -> return $ Left (B.pack $ "url(" ++ uri ++ ")")
+ Right (mt, raw) -> do
+ -- note that the downloaded CSS may
+ -- itself contain url(...).
+ b <- if "text/css" `isPrefixOf` mt
+ then cssURLs d raw
+ else return raw
+ return $ Right (mt, b)
+getDataURI :: PandocMonad m => MimeType -> String -> m String
+getDataURI mimetype src = do
+ res <- getData mimetype src
+ case res of
+ Left uri -> return uri
+ Right x -> return $ makeDataURI x
-getDataURI :: MediaBag -> Maybe String -> MimeType -> String
- -> IO String
-getDataURI _ _ _ src@('d':'a':'t':'a':':':_) = return src -- already data: uri
-getDataURI media sourceURL mimetype src = do
+getData :: PandocMonad m
+ => MimeType -> String
+ -> m (Either String (MimeType, ByteString))
+getData _ src@('d':'a':'t':'a':':':_) = return $ Left src-- already data: uri
+getData mimetype src = do
let ext = map toLower $ takeExtension src
- fetchResult <- fetchItem' media sourceURL src
- (raw, respMime) <- case fetchResult of
- Left msg -> err 67 $ "Could not fetch " ++ src ++
- "\n" ++ show msg
- Right x -> return x
+ (raw, respMime) <- fetchItem src
let raw' = if ext == ".gz"
- then B.concat $ L.toChunks $ Gzip.decompress $ L.fromChunks
- $ [raw]
+ then B.concat $ L.toChunks $ Gzip.decompress $ L.fromChunks [raw]
else raw
- let mime = case (mimetype, respMime) of
- ("",Nothing) -> error
+ mime <- case (mimetype, respMime) of
+ ("",Nothing) -> throwError $ PandocSomeError
$ "Could not determine mime type for `" ++ src ++ "'"
- (x, Nothing) -> x
- (_, Just x ) -> x
- let cssSourceURL = case parseURI src of
- Just u
- | uriScheme u `elem` ["http:","https:"] ->
- Just $ show u{ uriPath = "",
- uriQuery = "",
- uriFragment = "" }
- _ -> Nothing
- result <- if mime == "text/css"
- then cssURLs media cssSourceURL (takeDirectory src) raw'
+ (x, Nothing) -> return x
+ (_, Just x ) -> return x
+ result <- if "text/css" `isPrefixOf` mime
+ then do
+ oldInputs <- getInputFiles
+ setInputFiles [src]
+ res <- cssURLs (takeDirectory src) raw'
+ setInputFiles oldInputs
+ return res
else return raw'
- return $ makeDataURI mime result
+ return $ Right (mime, result)
+
+
-- | Convert HTML into self-contained HTML, incorporating images,
-- scripts, and CSS using data: URIs.
-makeSelfContained :: WriterOptions -> String -> IO String
-makeSelfContained opts inp = do
+makeSelfContained :: PandocMonad m => String -> m String
+makeSelfContained inp = do
let tags = parseTags inp
- out' <- mapM (convertTag (writerMediaBag opts) (writerSourceURL opts)) tags
+ out' <- convertTags tags
return $ renderTags' out'
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
index bd2da945e..52e1447db 100644
--- a/src/Text/Pandoc/Shared.hs
+++ b/src/Text/Pandoc/Shared.hs
@@ -1,8 +1,12 @@
-{-# LANGUAGE DeriveDataTypeable, CPP, MultiParamTypeClasses,
- FlexibleContexts, ScopedTypeVariables, PatternGuards,
- ViewPatterns #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Shared
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -49,21 +53,18 @@ module Text.Pandoc.Shared (
toRomanNumeral,
escapeURI,
tabFilter,
+ crFilter,
-- * Date/time
normalizeDate,
-- * Pandoc block and inline list processing
orderedListMarkers,
- normalizeSpaces,
extractSpaces,
- normalize,
- normalizeInlines,
- normalizeBlocks,
removeFormatting,
+ deNote,
stringify,
capitalize,
compactify,
- compactify',
- compactify'DL,
+ compactifyDL,
linesToPara,
Element (..),
hierarchicalize,
@@ -71,29 +72,26 @@ module Text.Pandoc.Shared (
inlineListToIdentifier,
isHeaderBlock,
headerShift,
+ stripEmptyParagraphs,
isTightList,
addMetaField,
makeMeta,
+ eastAsianLineBreakFilter,
+ underlineSpan,
-- * TagSoup HTML handling
renderTags',
-- * File handling
inDirectory,
- getDefaultReferenceDocx,
- getDefaultReferenceODT,
- readDataFile,
- readDataFileUTF8,
- fetchItem,
- fetchItem',
- openURL,
collapseFilePath,
filteredFilesFromArchive,
+ -- * URI handling
+ schemes,
+ isURI,
-- * Error handling
- err,
- warn,
mapLeft,
- hush,
-- * for squashing blocks
blocksToInlines,
+ blocksToInlines',
-- * Safe read
safeRead,
-- * Temp directory
@@ -102,74 +100,37 @@ module Text.Pandoc.Shared (
pandocVersion
) where
-import Text.Pandoc.Definition
-import Text.Pandoc.Walk
-import Text.Pandoc.MediaBag (MediaBag, lookupMedia)
-import Text.Pandoc.Builder (Inlines, Blocks, ToMetaValue(..))
-import qualified Text.Pandoc.Builder as B
-import qualified Text.Pandoc.UTF8 as UTF8
-import System.Environment (getProgName)
-import System.Exit (exitWith, ExitCode(..))
-import Data.Char ( toLower, isLower, isUpper, isAlpha,
- isLetter, isDigit, isSpace )
-import Data.List ( find, stripPrefix, intercalate )
-import Data.Maybe (mapMaybe)
-import Data.Version ( showVersion )
+import Codec.Archive.Zip
+import qualified Control.Exception as E
+import Control.Monad (MonadPlus (..), msum, unless)
+import qualified Control.Monad.State.Strict as S
+import qualified Data.ByteString.Lazy as BL
+import Data.Char (isAlpha, isDigit, isLetter, isLower, isSpace, isUpper,
+ toLower)
+import Data.Data (Data, Typeable)
+import Data.List (find, intercalate, intersperse, stripPrefix)
import qualified Data.Map as M
-import Network.URI ( escapeURIString, nonStrictRelativeTo,
- unEscapeString, parseURIReference, isAllowedInURI,
- parseURI, URI(..) )
+import Data.Maybe (mapMaybe)
+import Data.Monoid ((<>))
+import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr)
import qualified Data.Set as Set
+import qualified Data.Text as T
+import Data.Version (showVersion)
+import Network.URI (URI (uriScheme), escapeURIString, parseURI)
+import Paths_pandoc (version)
import System.Directory
-import System.FilePath (splitDirectories, isPathSeparator)
+import System.FilePath (isPathSeparator, splitDirectories)
import qualified System.FilePath.Posix as Posix
-import Text.Pandoc.MIME (MimeType, getMimeType)
-import System.FilePath ( (</>), takeExtension, dropExtension)
-import Data.Generics (Typeable, Data)
-import qualified Control.Monad.State as S
-import Control.Monad.Trans (MonadIO (..))
-import qualified Control.Exception as E
-import Control.Monad (msum, unless, MonadPlus(..))
-import Text.Pandoc.Pretty (charWidth)
-import Text.Pandoc.Compat.Time
-import Data.Time.Clock.POSIX
-import System.IO (stderr)
import System.IO.Temp
-import Text.HTML.TagSoup (renderTagsOptions, RenderOptions(..), Tag(..),
- renderOptions)
-import Data.Monoid ((<>))
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Char8 as B8
-import Data.ByteString.Base64 (decodeLenient)
-import Data.Sequence (ViewR(..), ViewL(..), viewl, viewr)
-import qualified Data.Text as T (toUpper, pack, unpack)
-import Data.ByteString.Lazy (toChunks, fromChunks)
-import qualified Data.ByteString.Lazy as BL
-import Paths_pandoc (version)
-
-import Codec.Archive.Zip
-
-#ifdef EMBED_DATA_FILES
-import Text.Pandoc.Data (dataFiles)
-#else
-import Paths_pandoc (getDataFileName)
-#endif
-#ifdef HTTP_CLIENT
-import Network.HTTP.Client (httpLbs, responseBody, responseHeaders,
- Request(port,host))
-import Network.HTTP.Client (parseRequest)
-import Network.HTTP.Client (newManager)
-import Network.HTTP.Client.Internal (addProxy)
-import Network.HTTP.Client.TLS (tlsManagerSettings)
-import System.Environment (getEnv)
-import Network.HTTP.Types.Header ( hContentType)
-import Network (withSocketsDo)
-#else
-import Network.URI (parseURI)
-import Network.HTTP (findHeader, rspBody,
- RequestMethod(..), HeaderName(..), mkRequest)
-import Network.Browser (browse, setAllowRedirects, setOutHandler, request)
-#endif
+import Text.HTML.TagSoup (RenderOptions (..), Tag (..), renderOptions,
+ renderTagsOptions)
+import Text.Pandoc.Builder (Blocks, Inlines, ToMetaValue (..))
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Compat.Time
+import Text.Pandoc.Definition
+import Text.Pandoc.Generic (bottomUp)
+import Text.Pandoc.Pretty (charWidth)
+import Text.Pandoc.Walk
-- | Version number of pandoc library.
pandocVersion :: String
@@ -185,11 +146,11 @@ splitBy _ [] = []
splitBy isSep lst =
let (first, rest) = break isSep lst
rest' = dropWhile isSep rest
- in first:(splitBy isSep rest')
+ in first:splitBy isSep rest'
splitByIndices :: [Int] -> [a] -> [[a]]
splitByIndices [] lst = [lst]
-splitByIndices (x:xs) lst = first:(splitByIndices (map (\y -> y - x) xs) rest)
+splitByIndices (x:xs) lst = first:splitByIndices (map (\y -> y - x) xs) rest
where (first, rest) = splitAt x lst
-- | Split string into chunks divided at specified indices.
@@ -197,7 +158,7 @@ splitStringByIndices :: [Int] -> [Char] -> [[Char]]
splitStringByIndices [] lst = [lst]
splitStringByIndices (x:xs) lst =
let (first, rest) = splitAt' x lst in
- first : (splitStringByIndices (map (\y -> y - x) xs) rest)
+ first : splitStringByIndices (map (\y -> y - x) xs) rest
splitAt' :: Int -> [Char] -> ([Char],[Char])
splitAt' _ [] = ([],[])
@@ -236,9 +197,9 @@ backslashEscapes = map (\ch -> (ch, ['\\',ch]))
escapeStringUsing :: [(Char, String)] -> String -> String
escapeStringUsing _ [] = ""
escapeStringUsing escapeTable (x:xs) =
- case (lookup x escapeTable) of
- Just str -> str ++ rest
- Nothing -> x:rest
+ case lookup x escapeTable of
+ Just str -> str ++ rest
+ Nothing -> x:rest
where rest = escapeStringUsing escapeTable xs
-- | Strip trailing newlines from string.
@@ -260,35 +221,33 @@ trimr = reverse . triml . reverse
-- | Strip leading and trailing characters from string
stripFirstAndLast :: String -> String
stripFirstAndLast str =
- drop 1 $ take ((length str) - 1) str
+ drop 1 $ take (length str - 1) str
-- | Change CamelCase word to hyphenated lowercase (e.g., camel-case).
camelCaseToHyphenated :: String -> String
camelCaseToHyphenated [] = ""
camelCaseToHyphenated (a:b:rest) | isLower a && isUpper b =
- a:'-':(toLower b):(camelCaseToHyphenated rest)
-camelCaseToHyphenated (a:rest) = (toLower a):(camelCaseToHyphenated rest)
+ a:'-':toLower b:camelCaseToHyphenated rest
+camelCaseToHyphenated (a:rest) = toLower a:camelCaseToHyphenated rest
-- | Convert number < 4000 to uppercase roman numeral.
toRomanNumeral :: Int -> String
-toRomanNumeral x =
- if x >= 4000 || x < 0
- then "?"
- else case x of
- _ | x >= 1000 -> "M" ++ toRomanNumeral (x - 1000)
- _ | x >= 900 -> "CM" ++ toRomanNumeral (x - 900)
- _ | x >= 500 -> "D" ++ toRomanNumeral (x - 500)
- _ | x >= 400 -> "CD" ++ toRomanNumeral (x - 400)
- _ | x >= 100 -> "C" ++ toRomanNumeral (x - 100)
- _ | x >= 90 -> "XC" ++ toRomanNumeral (x - 90)
- _ | x >= 50 -> "L" ++ toRomanNumeral (x - 50)
- _ | x >= 40 -> "XL" ++ toRomanNumeral (x - 40)
- _ | x >= 10 -> "X" ++ toRomanNumeral (x - 10)
- _ | x == 9 -> "IX"
- _ | x >= 5 -> "V" ++ toRomanNumeral (x - 5)
- _ | x == 4 -> "IV"
- _ | x >= 1 -> "I" ++ toRomanNumeral (x - 1)
- _ -> ""
+toRomanNumeral x
+ | x >= 4000 || x < 0 = "?"
+ | x >= 1000 = "M" ++ toRomanNumeral (x - 1000)
+ | x >= 900 = "CM" ++ toRomanNumeral (x - 900)
+ | x >= 500 = "D" ++ toRomanNumeral (x - 500)
+ | x >= 400 = "CD" ++ toRomanNumeral (x - 400)
+ | x >= 100 = "C" ++ toRomanNumeral (x - 100)
+ | x >= 90 = "XC" ++ toRomanNumeral (x - 90)
+ | x >= 50 = "L" ++ toRomanNumeral (x - 50)
+ | x >= 40 = "XL" ++ toRomanNumeral (x - 40)
+ | x >= 10 = "X" ++ toRomanNumeral (x - 10)
+ | x == 9 = "IX"
+ | x >= 5 = "V" ++ toRomanNumeral (x - 5)
+ | x == 4 = "IV"
+ | x >= 1 = "I" ++ toRomanNumeral (x - 1)
+ | otherwise = ""
-- | Escape whitespace and some punctuation characters in URI.
escapeURI :: String -> String
@@ -296,26 +255,23 @@ escapeURI = escapeURIString (not . needsEscaping)
where needsEscaping c = isSpace c || c `elem`
['<','>','|','"','{','}','[',']','^', '`']
-
--- | Convert tabs to spaces and filter out DOS line endings.
--- Tabs will be preserved if tab stop is set to 0.
+-- | Convert tabs to spaces. Tabs will be preserved if tab stop is set to 0.
tabFilter :: Int -- ^ Tab stop
- -> String -- ^ Input
- -> String
-tabFilter tabStop =
- let go _ [] = ""
- go _ ('\n':xs) = '\n' : go tabStop xs
- go _ ('\r':'\n':xs) = '\n' : go tabStop xs
- go _ ('\r':xs) = '\n' : go tabStop xs
- go spsToNextStop ('\t':xs) =
- if tabStop == 0
- then '\t' : go tabStop xs
- else replicate spsToNextStop ' ' ++ go tabStop xs
- go 1 (x:xs) =
- x : go tabStop xs
- go spsToNextStop (x:xs) =
- x : go (spsToNextStop - 1) xs
- in go tabStop
+ -> T.Text -- ^ Input
+ -> T.Text
+tabFilter 0 = id
+tabFilter tabStop = T.unlines . map go . T.lines
+ where go s =
+ let (s1, s2) = T.break (== '\t') s
+ in if T.null s2
+ then s1
+ else s1 <> T.replicate
+ (tabStop - (T.length s1 `mod` tabStop)) (T.pack " ")
+ <> go (T.drop 1 s2)
+
+-- | Strip out DOS line endings.
+crFilter :: T.Text -> T.Text
+crFilter = T.filter (/= '\r')
--
-- Date/time
@@ -329,7 +285,7 @@ normalizeDate s = fmap (formatTime defaultTimeLocale "%F")
(msum $ map (\fs -> parsetimeWith fs s >>= rejectBadYear) formats :: Maybe Day)
where rejectBadYear day = case toGregorian day of
(y, _, _) | y >= 1601 && y <= 9999 -> Just day
- _ -> Nothing
+ _ -> Nothing
parsetimeWith =
#if MIN_VERSION_time(1,5,0)
parseTimeM True defaultTimeLocale
@@ -337,7 +293,7 @@ normalizeDate s = fmap (formatTime defaultTimeLocale "%F")
parseTime defaultTimeLocale
#endif
formats = ["%x","%m/%d/%Y", "%D","%F", "%d %b %Y",
- "%d %B %Y", "%b. %d, %Y", "%B %d, %Y",
+ "%e %B %Y", "%b. %e, %Y", "%B %e, %Y",
"%Y%m%d", "%Y%m", "%Y"]
--
@@ -366,23 +322,6 @@ orderedListMarkers (start, numstyle, numdelim) =
TwoParens -> "(" ++ str ++ ")"
in map inDelim nums
--- | Normalize a list of inline elements: remove leading and trailing
--- @Space@ elements, collapse double @Space@s into singles, and
--- remove empty Str elements.
-normalizeSpaces :: [Inline] -> [Inline]
-normalizeSpaces = cleanup . dropWhile isSpaceOrEmpty
- where cleanup [] = []
- cleanup (Space:rest) = case dropWhile isSpaceOrEmpty rest of
- [] -> []
- (x:xs) -> Space : x : cleanup xs
- cleanup ((Str ""):rest) = cleanup rest
- cleanup (x:rest) = x : cleanup rest
-
-isSpaceOrEmpty :: Inline -> Bool
-isSpaceOrEmpty Space = True
-isSpaceOrEmpty (Str "") = True
-isSpaceOrEmpty _ = False
-
-- | Extract the leading and trailing spaces from inside an inline element
-- and place them outside the element. SoftBreaks count as Spaces for
-- these purposes.
@@ -399,183 +338,43 @@ extractSpaces f is =
_ -> mempty in
(left <> f (B.trimInlines . B.Many $ contents) <> right)
--- | Normalize @Pandoc@ document, consolidating doubled 'Space's,
--- combining adjacent 'Str's and 'Emph's, remove 'Null's and
--- empty elements, etc.
-normalize :: Pandoc -> Pandoc
-normalize (Pandoc (Meta meta) blocks) =
- Pandoc (Meta $ M.map go meta) (normalizeBlocks blocks)
- where go (MetaInlines xs) = MetaInlines $ normalizeInlines xs
- go (MetaBlocks xs) = MetaBlocks $ normalizeBlocks xs
- go (MetaList ms) = MetaList $ map go ms
- go (MetaMap m) = MetaMap $ M.map go m
- go x = x
-
-normalizeBlocks :: [Block] -> [Block]
-normalizeBlocks (Null : xs) = normalizeBlocks xs
-normalizeBlocks (Div attr bs : xs) =
- Div attr (normalizeBlocks bs) : normalizeBlocks xs
-normalizeBlocks (BlockQuote bs : xs) =
- case normalizeBlocks bs of
- [] -> normalizeBlocks xs
- bs' -> BlockQuote bs' : normalizeBlocks xs
-normalizeBlocks (BulletList [] : xs) = normalizeBlocks xs
-normalizeBlocks (BulletList items : xs) =
- BulletList (map normalizeBlocks items) : normalizeBlocks xs
-normalizeBlocks (OrderedList _ [] : xs) = normalizeBlocks xs
-normalizeBlocks (OrderedList attr items : xs) =
- OrderedList attr (map normalizeBlocks items) : normalizeBlocks xs
-normalizeBlocks (DefinitionList [] : xs) = normalizeBlocks xs
-normalizeBlocks (DefinitionList items : xs) =
- DefinitionList (map go items) : normalizeBlocks xs
- where go (ils, bs) = (normalizeInlines ils, map normalizeBlocks bs)
-normalizeBlocks (RawBlock _ "" : xs) = normalizeBlocks xs
-normalizeBlocks (RawBlock f x : xs) =
- case normalizeBlocks xs of
- (RawBlock f' x' : rest) | f' == f ->
- RawBlock f (x ++ ('\n':x')) : rest
- rest -> RawBlock f x : rest
-normalizeBlocks (Para ils : xs) =
- case normalizeInlines ils of
- [] -> normalizeBlocks xs
- ils' -> Para ils' : normalizeBlocks xs
-normalizeBlocks (Plain ils : xs) =
- case normalizeInlines ils of
- [] -> normalizeBlocks xs
- ils' -> Plain ils' : normalizeBlocks xs
-normalizeBlocks (Header lev attr ils : xs) =
- Header lev attr (normalizeInlines ils) : normalizeBlocks xs
-normalizeBlocks (Table capt aligns widths hdrs rows : xs) =
- Table (normalizeInlines capt) aligns widths
- (map normalizeBlocks hdrs) (map (map normalizeBlocks) rows)
- : normalizeBlocks xs
-normalizeBlocks (x:xs) = x : normalizeBlocks xs
-normalizeBlocks [] = []
-
-normalizeInlines :: [Inline] -> [Inline]
-normalizeInlines (Str x : ys) =
- case concat (x : map fromStr strs) of
- "" -> rest
- n -> Str n : rest
- where
- (strs, rest) = span isStr $ normalizeInlines ys
- isStr (Str _) = True
- isStr _ = False
- fromStr (Str z) = z
- fromStr _ = error "normalizeInlines - fromStr - not a Str"
-normalizeInlines (Space : SoftBreak : ys) =
- SoftBreak : normalizeInlines ys
-normalizeInlines (Space : ys) =
- if null rest
- then []
- else Space : rest
- where isSp Space = True
- isSp _ = False
- rest = dropWhile isSp $ normalizeInlines ys
-normalizeInlines (Emph xs : zs) =
- case normalizeInlines zs of
- (Emph ys : rest) -> normalizeInlines $
- Emph (normalizeInlines $ xs ++ ys) : rest
- rest -> case normalizeInlines xs of
- [] -> rest
- xs' -> Emph xs' : rest
-normalizeInlines (Strong xs : zs) =
- case normalizeInlines zs of
- (Strong ys : rest) -> normalizeInlines $
- Strong (normalizeInlines $ xs ++ ys) : rest
- rest -> case normalizeInlines xs of
- [] -> rest
- xs' -> Strong xs' : rest
-normalizeInlines (Subscript xs : zs) =
- case normalizeInlines zs of
- (Subscript ys : rest) -> normalizeInlines $
- Subscript (normalizeInlines $ xs ++ ys) : rest
- rest -> case normalizeInlines xs of
- [] -> rest
- xs' -> Subscript xs' : rest
-normalizeInlines (Superscript xs : zs) =
- case normalizeInlines zs of
- (Superscript ys : rest) -> normalizeInlines $
- Superscript (normalizeInlines $ xs ++ ys) : rest
- rest -> case normalizeInlines xs of
- [] -> rest
- xs' -> Superscript xs' : rest
-normalizeInlines (SmallCaps xs : zs) =
- case normalizeInlines zs of
- (SmallCaps ys : rest) -> normalizeInlines $
- SmallCaps (normalizeInlines $ xs ++ ys) : rest
- rest -> case normalizeInlines xs of
- [] -> rest
- xs' -> SmallCaps xs' : rest
-normalizeInlines (Strikeout xs : zs) =
- case normalizeInlines zs of
- (Strikeout ys : rest) -> normalizeInlines $
- Strikeout (normalizeInlines $ xs ++ ys) : rest
- rest -> case normalizeInlines xs of
- [] -> rest
- xs' -> Strikeout xs' : rest
-normalizeInlines (RawInline _ [] : ys) = normalizeInlines ys
-normalizeInlines (RawInline f xs : zs) =
- case normalizeInlines zs of
- (RawInline f' ys : rest) | f == f' -> normalizeInlines $
- RawInline f (xs ++ ys) : rest
- rest -> RawInline f xs : rest
-normalizeInlines (Code _ "" : ys) = normalizeInlines ys
-normalizeInlines (Code attr xs : zs) =
- case normalizeInlines zs of
- (Code attr' ys : rest) | attr == attr' -> normalizeInlines $
- Code attr (xs ++ ys) : rest
- rest -> Code attr xs : rest
--- allow empty spans, they may carry identifiers etc.
--- normalizeInlines (Span _ [] : ys) = normalizeInlines ys
-normalizeInlines (Span attr xs : zs) =
- case normalizeInlines zs of
- (Span attr' ys : rest) | attr == attr' -> normalizeInlines $
- Span attr (normalizeInlines $ xs ++ ys) : rest
- rest -> Span attr (normalizeInlines xs) : rest
-normalizeInlines (Note bs : ys) = Note (normalizeBlocks bs) :
- normalizeInlines ys
-normalizeInlines (Quoted qt ils : ys) =
- Quoted qt (normalizeInlines ils) : normalizeInlines ys
-normalizeInlines (Link attr ils t : ys) =
- Link attr (normalizeInlines ils) t : normalizeInlines ys
-normalizeInlines (Image attr ils t : ys) =
- Image attr (normalizeInlines ils) t : normalizeInlines ys
-normalizeInlines (Cite cs ils : ys) =
- Cite cs (normalizeInlines ils) : normalizeInlines ys
-normalizeInlines (x : xs) = x : normalizeInlines xs
-normalizeInlines [] = []
-
-- | Extract inlines, removing formatting.
removeFormatting :: Walkable Inline a => a -> [Inline]
-removeFormatting = query go . walk deNote
+removeFormatting = query go . walk (deNote . deQuote)
where go :: Inline -> [Inline]
- go (Str xs) = [Str xs]
- go Space = [Space]
- go SoftBreak = [SoftBreak]
- go (Code _ x) = [Str x]
- go (Math _ x) = [Str x]
- go LineBreak = [Space]
- go _ = []
- deNote (Note _) = Str ""
- deNote x = x
+ go (Str xs) = [Str xs]
+ go Space = [Space]
+ go SoftBreak = [SoftBreak]
+ go (Code _ x) = [Str x]
+ go (Math _ x) = [Str x]
+ go LineBreak = [Space]
+ go _ = []
+
+deNote :: Inline -> Inline
+deNote (Note _) = Str ""
+deNote x = x
+
+deQuote :: Inline -> Inline
+deQuote (Quoted SingleQuote xs) =
+ Span ("",[],[]) (Str "\8216" : xs ++ [Str "\8217"])
+deQuote (Quoted DoubleQuote xs) =
+ Span ("",[],[]) (Str "\8220" : xs ++ [Str "\8221"])
+deQuote x = x
-- | Convert pandoc structure to a string with formatting removed.
-- Footnotes are skipped (since we don't want their contents in link
-- labels).
stringify :: Walkable Inline a => a -> String
-stringify = query go . walk deNote
+stringify = query go . walk (deNote . deQuote)
where go :: Inline -> [Char]
- go Space = " "
- go SoftBreak = " "
- go (Str x) = x
- go (Code _ x) = x
- go (Math _ x) = x
+ go Space = " "
+ go SoftBreak = " "
+ go (Str x) = x
+ go (Code _ x) = x
+ go (Math _ x) = x
go (RawInline (Format "html") ('<':'b':'r':_)) = " " -- see #2105
- go LineBreak = " "
- go _ = ""
- deNote (Note _) = Str ""
- deNote x = x
+ go LineBreak = " "
+ go _ = ""
-- | Bring all regular text in a pandoc structure to uppercase.
--
@@ -589,28 +388,12 @@ capitalize = walk go
go x = x
-- | Change final list item from @Para@ to @Plain@ if the list contains
--- no other @Para@ blocks.
-compactify :: [[Block]] -- ^ List of list items (each a list of blocks)
- -> [[Block]]
-compactify [] = []
-compactify items =
- case (init items, last items) of
- (_,[]) -> items
- (others, final) ->
- case last final of
- Para a -> case (filter isPara $ concat items) of
- -- if this is only Para, change to Plain
- [_] -> others ++ [init final ++ [Plain a]]
- _ -> items
- _ -> items
-
--- | Change final list item from @Para@ to @Plain@ if the list contains
-- no other @Para@ blocks. Like compactify, but operates on @Blocks@ rather
-- than @[Block]@.
-compactify' :: [Blocks] -- ^ List of list items (each a list of blocks)
+compactify :: [Blocks] -- ^ List of list items (each a list of blocks)
-> [Blocks]
-compactify' [] = []
-compactify' items =
+compactify [] = []
+compactify items =
let (others, final) = (init items, last items)
in case reverse (B.toList final) of
(Para a:xs) -> case [Para x | Para x <- concatMap B.toList items] of
@@ -619,9 +402,9 @@ compactify' items =
_ -> items
_ -> items
--- | Like @compactify'@, but acts on items of definition lists.
-compactify'DL :: [(Inlines, [Blocks])] -> [(Inlines, [Blocks])]
-compactify'DL items =
+-- | Like @compactify@, but acts on items of definition lists.
+compactifyDL :: [(Inlines, [Blocks])] -> [(Inlines, [Blocks])]
+compactifyDL items =
let defs = concatMap snd items
in case reverse (concatMap B.toList defs) of
(Para x:xs)
@@ -663,7 +446,7 @@ instance Walkable Inline Element where
ils' <- walkM f ils
elts' <- walkM f elts
return $ Sec lev nums attr ils' elts'
- query f (Blk x) = query f x
+ query f (Blk x) = query f x
query f (Sec _ _ _ ils elts) = query f ils <> query f elts
instance Walkable Block Element where
@@ -674,7 +457,7 @@ instance Walkable Block Element where
ils' <- walkM f ils
elts' <- walkM f elts
return $ Sec lev nums attr ils' elts'
- query f (Blk x) = query f x
+ query f (Blk x) = query f x
query f (Sec _ _ _ ils elts) = query f ils <> query f elts
@@ -687,8 +470,8 @@ inlineListToIdentifier =
map (nbspToSp . toLower) .
filter (\c -> isLetter c || isDigit c || c `elem` "_-. ") .
stringify
- where nbspToSp '\160' = ' '
- nbspToSp x = x
+ where nbspToSp '\160' = ' '
+ nbspToSp x = x
-- | Convert list of Pandoc blocks into (hierarchical) list of Elements
hierarchicalize :: [Block] -> [Element]
@@ -696,7 +479,7 @@ hierarchicalize blocks = S.evalState (hierarchicalizeWithIds blocks) []
hierarchicalizeWithIds :: [Block] -> S.State [Int] [Element]
hierarchicalizeWithIds [] = return []
-hierarchicalizeWithIds ((Header level attr@(_,classes,_) title'):xs) = do
+hierarchicalizeWithIds (Header level attr@(_,classes,_) title':xs) = do
lastnum <- S.get
let lastnum' = take level lastnum
let newnum = case length lastnum' of
@@ -709,26 +492,26 @@ hierarchicalizeWithIds ((Header level attr@(_,classes,_) title'):xs) = do
sectionContents' <- hierarchicalizeWithIds sectionContents
rest' <- hierarchicalizeWithIds rest
return $ Sec level newnum attr title' sectionContents' : rest'
-hierarchicalizeWithIds ((Div ("",["references"],[])
- (Header level (ident,classes,kvs) title' : xs)):ys) =
- hierarchicalizeWithIds ((Header level (ident,("references":classes),kvs)
- title') : (xs ++ ys))
+hierarchicalizeWithIds (Div ("",["references"],[])
+ (Header level (ident,classes,kvs) title' : xs):ys) =
+ hierarchicalizeWithIds (Header level (ident,"references":classes,kvs)
+ title' : (xs ++ ys))
hierarchicalizeWithIds (x:rest) = do
rest' <- hierarchicalizeWithIds rest
- return $ (Blk x) : rest'
+ return $ Blk x : rest'
headerLtEq :: Int -> Block -> Bool
-headerLtEq level (Header l _ _) = l <= level
-headerLtEq level (Div ("",["references"],[]) (Header l _ _ : _)) = l <= level
-headerLtEq _ _ = False
+headerLtEq level (Header l _ _) = l <= level
+headerLtEq level (Div ("",["references"],[]) (Header l _ _ : _)) = l <= level
+headerLtEq _ _ = False
-- | Generate a unique identifier from a list of inlines.
-- Second argument is a list of already used identifiers.
uniqueIdent :: [Inline] -> Set.Set String -> String
uniqueIdent title' usedIdents
= let baseIdent = case inlineListToIdentifier title' of
- "" -> "section"
- x -> x
+ "" -> "section"
+ x -> x
numIdent n = baseIdent ++ "-" ++ show n
in if baseIdent `Set.member` usedIdents
then case find (\x -> not $ numIdent x `Set.member` usedIdents) ([1..60000] :: [Int]) of
@@ -738,8 +521,8 @@ uniqueIdent title' usedIdents
-- | True if block is a Header block.
isHeaderBlock :: Block -> Bool
-isHeaderBlock (Header _ _ _) = True
-isHeaderBlock _ = False
+isHeaderBlock Header{} = True
+isHeaderBlock _ = False
-- | Shift header levels up or down.
headerShift :: Int -> Pandoc -> Pandoc
@@ -748,6 +531,14 @@ headerShift n = walk shift
shift (Header level attr inner) = Header (level + n) attr inner
shift x = x
+-- | Remove empty paragraphs.
+stripEmptyParagraphs :: Pandoc -> Pandoc
+stripEmptyParagraphs = walk go
+ where go :: [Block] -> [Block]
+ go = filter (not . isEmptyParagraph)
+ isEmptyParagraph (Para []) = True
+ isEmptyParagraph _ = False
+
-- | Detect if a list is tight.
isTightList :: [[Block]] -> Bool
isTightList = all firstIsPlain
@@ -765,8 +556,8 @@ addMetaField key val (Meta meta) =
Meta $ M.insertWith combine key (toMetaValue val) meta
where combine newval (MetaList xs) = MetaList (xs ++ tolist newval)
combine newval x = MetaList [x, newval]
- tolist (MetaList ys) = ys
- tolist y = [y]
+ tolist (MetaList ys) = ys
+ tolist y = [y]
-- | Create 'Meta' from old-style title, authors, date. This is
-- provided to ease the transition from the old API.
@@ -774,8 +565,24 @@ makeMeta :: [Inline] -> [[Inline]] -> [Inline] -> Meta
makeMeta title authors date =
addMetaField "title" (B.fromList title)
$ addMetaField "author" (map B.fromList authors)
- $ addMetaField "date" (B.fromList date)
- $ nullMeta
+ $ addMetaField "date" (B.fromList date) nullMeta
+
+-- | Remove soft breaks between East Asian characters.
+eastAsianLineBreakFilter :: Pandoc -> Pandoc
+eastAsianLineBreakFilter = bottomUp go
+ where go (x:SoftBreak:y:zs) =
+ case (stringify x, stringify y) of
+ (xs@(_:_), c:_)
+ | charWidth (last xs) == 2 && charWidth c == 2 -> x:y:zs
+ _ -> x:SoftBreak:y:zs
+ go xs = xs
+
+-- | Builder for underline.
+-- This probably belongs in Builder.hs in pandoc-types.
+-- Will be replaced once Underline is an element.
+underlineSpan :: Inlines -> Inlines
+underlineSpan = B.spanWith ("", ["underline"], [])
+
--
-- TagSoup HTML handling
@@ -787,7 +594,7 @@ renderTags' = renderTagsOptions
renderOptions{ optMinimize = matchTags ["hr", "br", "img",
"meta", "link"]
, optRawTag = matchTags ["script", "style"] }
- where matchTags = \tags -> flip elem tags . map toLower
+ where matchTags tags = flip elem tags . map toLower
--
-- File handling
@@ -800,226 +607,14 @@ inDirectory path action = E.bracket
setCurrentDirectory
(const $ setCurrentDirectory path >> action)
-getDefaultReferenceDocx :: Maybe FilePath -> IO Archive
-getDefaultReferenceDocx datadir = do
- let paths = ["[Content_Types].xml",
- "_rels/.rels",
- "docProps/app.xml",
- "docProps/core.xml",
- "word/document.xml",
- "word/fontTable.xml",
- "word/footnotes.xml",
- "word/numbering.xml",
- "word/settings.xml",
- "word/webSettings.xml",
- "word/styles.xml",
- "word/_rels/document.xml.rels",
- "word/_rels/footnotes.xml.rels",
- "word/theme/theme1.xml"]
- let toLazy = fromChunks . (:[])
- let pathToEntry path = do epochtime <- (floor . utcTimeToPOSIXSeconds) <$>
- getCurrentTime
- contents <- toLazy <$> readDataFile datadir
- ("docx/" ++ path)
- return $ toEntry path epochtime contents
- mbArchive <- case datadir of
- Nothing -> return Nothing
- Just d -> do
- exists <- doesFileExist (d </> "reference.docx")
- if exists
- then return (Just (d </> "reference.docx"))
- else return Nothing
- case mbArchive of
- Just arch -> toArchive <$> BL.readFile arch
- Nothing -> foldr addEntryToArchive emptyArchive <$>
- mapM pathToEntry paths
-
-getDefaultReferenceODT :: Maybe FilePath -> IO Archive
-getDefaultReferenceODT datadir = do
- let paths = ["mimetype",
- "manifest.rdf",
- "styles.xml",
- "content.xml",
- "meta.xml",
- "settings.xml",
- "Configurations2/accelerator/current.xml",
- "Thumbnails/thumbnail.png",
- "META-INF/manifest.xml"]
- let pathToEntry path = do epochtime <- floor `fmap` getPOSIXTime
- contents <- (fromChunks . (:[])) `fmap`
- readDataFile datadir ("odt/" ++ path)
- return $ toEntry path epochtime contents
- mbArchive <- case datadir of
- Nothing -> return Nothing
- Just d -> do
- exists <- doesFileExist (d </> "reference.odt")
- if exists
- then return (Just (d </> "reference.odt"))
- else return Nothing
- case mbArchive of
- Just arch -> toArchive <$> BL.readFile arch
- Nothing -> foldr addEntryToArchive emptyArchive <$>
- mapM pathToEntry paths
-
-
-readDefaultDataFile :: FilePath -> IO BS.ByteString
-readDefaultDataFile "reference.docx" =
- (BS.concat . toChunks . fromArchive) <$> getDefaultReferenceDocx Nothing
-readDefaultDataFile "reference.odt" =
- (BS.concat . toChunks . fromArchive) <$> getDefaultReferenceODT Nothing
-readDefaultDataFile fname =
-#ifdef EMBED_DATA_FILES
- case lookup (makeCanonical fname) dataFiles of
- Nothing -> err 97 $ "Could not find data file " ++ fname
- Just contents -> return contents
- where makeCanonical = Posix.joinPath . transformPathParts . splitDirectories
- transformPathParts = reverse . foldl go []
- go as "." = as
- go (_:as) ".." = as
- go as x = x : as
-#else
- getDataFileName fname' >>= checkExistence >>= BS.readFile
- where fname' = if fname == "MANUAL.txt" then fname else "data" </> fname
-
-checkExistence :: FilePath -> IO FilePath
-checkExistence fn = do
- exists <- doesFileExist fn
- if exists
- then return fn
- else err 97 ("Could not find data file " ++ fn)
-#endif
-
--- | Read file from specified user data directory or, if not found there, from
--- Cabal data directory.
-readDataFile :: Maybe FilePath -> FilePath -> IO BS.ByteString
-readDataFile Nothing fname = readDefaultDataFile fname
-readDataFile (Just userDir) fname = do
- exists <- doesFileExist (userDir </> fname)
- if exists
- then BS.readFile (userDir </> fname)
- else readDefaultDataFile fname
-
--- | Same as 'readDataFile' but returns a String instead of a ByteString.
-readDataFileUTF8 :: Maybe FilePath -> FilePath -> IO String
-readDataFileUTF8 userDir fname =
- UTF8.toString `fmap` readDataFile userDir fname
-
--- | Specialized version of parseURIReference that disallows
--- single-letter schemes. Reason: these are usually windows absolute
--- paths.
-parseURIReference' :: String -> Maybe URI
-parseURIReference' s =
- case parseURIReference s of
- Just u
- | length (uriScheme u) > 2 -> Just u
- | null (uriScheme u) -> Just u -- protocol-relative
- _ -> Nothing
-
--- | Fetch an image or other item from the local filesystem or the net.
--- Returns raw content and maybe mime type.
-fetchItem :: Maybe String -> String
- -> IO (Either E.SomeException (BS.ByteString, Maybe MimeType))
-fetchItem sourceURL s =
- case (sourceURL >>= parseURIReference' . ensureEscaped, ensureEscaped s) of
- (Just u, s') -> -- try fetching from relative path at source
- case parseURIReference' s' of
- Just u' -> openURL $ show $ u' `nonStrictRelativeTo` u
- Nothing -> openURL s' -- will throw error
- (Nothing, s'@('/':'/':_)) -> -- protocol-relative URI
- case parseURIReference' s' of
- Just u' -> openURL $ show $ u' `nonStrictRelativeTo` httpcolon
- Nothing -> openURL s' -- will throw error
- (Nothing, s') ->
- case parseURI s' of -- requires absolute URI
- -- We don't want to treat C:/ as a scheme:
- Just u' | length (uriScheme u') > 2 -> openURL (show u')
- Just u' | uriScheme u' == "file:" ->
- E.try $ readLocalFile $ dropWhile (=='/') (uriPath u')
- _ -> E.try $ readLocalFile fp -- get from local file system
- where readLocalFile f = do
- cont <- BS.readFile f
- return (cont, mime)
- httpcolon = URI{ uriScheme = "http:",
- uriAuthority = Nothing,
- uriPath = "",
- uriQuery = "",
- uriFragment = "" }
- dropFragmentAndQuery = takeWhile (\c -> c /= '?' && c /= '#')
- fp = unEscapeString $ dropFragmentAndQuery s
- mime = case takeExtension fp of
- ".gz" -> getMimeType $ dropExtension fp
- ".svgz" -> getMimeType $ dropExtension fp ++ ".svg"
- x -> getMimeType x
- ensureEscaped = escapeURIString isAllowedInURI . map convertSlash
- convertSlash '\\' = '/'
- convertSlash x = x
-
--- | Like 'fetchItem', but also looks for items in a 'MediaBag'.
-fetchItem' :: MediaBag -> Maybe String -> String
- -> IO (Either E.SomeException (BS.ByteString, Maybe MimeType))
-fetchItem' media sourceURL s = do
- case lookupMedia s media of
- Nothing -> fetchItem sourceURL s
- Just (mime, bs) -> return $ Right (BS.concat $ toChunks bs, Just mime)
-
--- | Read from a URL and return raw data and maybe mime type.
-openURL :: String -> IO (Either E.SomeException (BS.ByteString, Maybe MimeType))
-openURL u
- | Just u'' <- stripPrefix "data:" u =
- let mime = takeWhile (/=',') u''
- contents = B8.pack $ unEscapeString $ drop 1 $ dropWhile (/=',') u''
- in return $ Right (decodeLenient contents, Just mime)
-#ifdef HTTP_CLIENT
- | otherwise = withSocketsDo $ E.try $ do
- let parseReq = parseRequest
- (proxy :: Either E.SomeException String) <- E.try $ getEnv "http_proxy"
- req <- parseReq u
- req' <- case proxy of
- Left _ -> return req
- Right pr -> (parseReq pr >>= \r ->
- return $ addProxy (host r) (port r) req)
- `mplus` return req
- resp <- newManager tlsManagerSettings >>= httpLbs req'
- return (BS.concat $ toChunks $ responseBody resp,
- UTF8.toString `fmap` lookup hContentType (responseHeaders resp))
-#else
- | otherwise = E.try $ getBodyAndMimeType `fmap` browse
- (do liftIO $ UTF8.hPutStrLn stderr $ "Fetching " ++ u ++ "..."
- setOutHandler $ const (return ())
- setAllowRedirects True
- request (getRequest' u'))
- where getBodyAndMimeType (_, r) = (rspBody r, findHeader HdrContentType r)
- getRequest' uriString = case parseURI uriString of
- Nothing -> error ("Not a valid URL: " ++
- uriString)
- Just v -> mkRequest GET v
- u' = escapeURIString (/= '|') u -- pipes are rejected by Network.URI
-#endif
-
--
-- Error reporting
--
-err :: Int -> String -> IO a
-err exitCode msg = do
- name <- getProgName
- UTF8.hPutStrLn stderr $ name ++ ": " ++ msg
- exitWith $ ExitFailure exitCode
- return undefined
-
-warn :: MonadIO m => String -> m ()
-warn msg = liftIO $ do
- name <- getProgName
- UTF8.hPutStrLn stderr $ "[" ++ name ++ " warning] " ++ msg
-
mapLeft :: (a -> b) -> Either a c -> Either b c
-mapLeft f (Left x) = Left (f x)
+mapLeft f (Left x) = Left (f x)
mapLeft _ (Right x) = Right x
-hush :: Either a b -> Maybe b
-hush (Left _) = Nothing
-hush (Right x) = Just x
-
-- | Remove intermediate "." and ".." directories from a path.
--
-- > collapseFilePath "./foo" == "foo"
@@ -1034,14 +629,14 @@ collapseFilePath = Posix.joinPath . reverse . foldl go [] . splitDirectories
where
go rs "." = rs
go r@(p:rs) ".." = case p of
- ".." -> ("..":r)
- (checkPathSeperator -> Just True) -> ("..":r)
- _ -> rs
+ ".." -> "..":r
+ (checkPathSeperator -> Just True) -> "..":r
+ _ -> rs
go _ (checkPathSeperator -> Just True) = [[Posix.pathSeparator]]
go rs x = x:rs
- isSingleton [] = Nothing
+ isSingleton [] = Nothing
isSingleton [x] = Just x
- isSingleton _ = Nothing
+ isSingleton _ = Nothing
checkPathSeperator = fmap isPathSeparator . isSingleton
--
@@ -1054,41 +649,109 @@ filteredFilesFromArchive zf f =
fileAndBinary :: Archive -> FilePath -> Maybe (FilePath, BL.ByteString)
fileAndBinary a fp = findEntryByPath fp a >>= \e -> Just (fp, fromEntry e)
+
+--
+-- IANA URIs
+--
+
+-- | Schemes from http://www.iana.org/assignments/uri-schemes.html plus
+-- the unofficial schemes doi, javascript, isbn, pmid.
+schemes :: Set.Set String
+schemes = Set.fromList
+ -- Official IANA schemes
+ [ "aaa", "aaas", "about", "acap", "acct", "acr", "adiumxtra", "afp", "afs"
+ , "aim", "appdata", "apt", "attachment", "aw", "barion", "beshare", "bitcoin"
+ , "blob", "bolo", "browserext", "callto", "cap", "chrome", "chrome-extension"
+ , "cid", "coap", "coaps", "com-eventbrite-attendee", "content", "crid", "cvs"
+ , "data", "dav", "dict", "dis", "dlna-playcontainer", "dlna-playsingle"
+ , "dns", "dntp", "dtn", "dvb", "ed2k", "example", "facetime", "fax", "feed"
+ , "feedready", "file", "filesystem", "finger", "fish", "ftp", "geo", "gg"
+ , "git", "gizmoproject", "go", "gopher", "graph", "gtalk", "h323", "ham"
+ , "hcp", "http", "https", "hxxp", "hxxps", "hydrazone", "iax", "icap", "icon"
+ , "im", "imap", "info", "iotdisco", "ipn", "ipp", "ipps", "irc", "irc6"
+ , "ircs", "iris", "iris.beep", "iris.lwz", "iris.xpc", "iris.xpcs"
+ , "isostore", "itms", "jabber", "jar", "jms", "keyparc", "lastfm", "ldap"
+ , "ldaps", "lvlt", "magnet", "mailserver", "mailto", "maps", "market"
+ , "message", "mid", "mms", "modem", "mongodb", "moz", "ms-access"
+ , "ms-browser-extension", "ms-drive-to", "ms-enrollment", "ms-excel"
+ , "ms-gamebarservices", "ms-getoffice", "ms-help", "ms-infopath"
+ , "ms-media-stream-id", "ms-officeapp", "ms-project", "ms-powerpoint"
+ , "ms-publisher", "ms-search-repair", "ms-secondary-screen-controller"
+ , "ms-secondary-screen-setup", "ms-settings", "ms-settings-airplanemode"
+ , "ms-settings-bluetooth", "ms-settings-camera", "ms-settings-cellular"
+ , "ms-settings-cloudstorage", "ms-settings-connectabledevices"
+ , "ms-settings-displays-topology", "ms-settings-emailandaccounts"
+ , "ms-settings-language", "ms-settings-location", "ms-settings-lock"
+ , "ms-settings-nfctransactions", "ms-settings-notifications"
+ , "ms-settings-power", "ms-settings-privacy", "ms-settings-proximity"
+ , "ms-settings-screenrotation", "ms-settings-wifi", "ms-settings-workplace"
+ , "ms-spd", "ms-sttoverlay", "ms-transit-to", "ms-virtualtouchpad"
+ , "ms-visio", "ms-walk-to", "ms-whiteboard", "ms-whiteboard-cmd", "ms-word"
+ , "msnim", "msrp", "msrps", "mtqp", "mumble", "mupdate", "mvn", "news", "nfs"
+ , "ni", "nih", "nntp", "notes", "ocf", "oid", "onenote", "onenote-cmd"
+ , "opaquelocktoken", "pack", "palm", "paparazzi", "pkcs11", "platform", "pop"
+ , "pres", "prospero", "proxy", "pwid", "psyc", "qb", "query", "redis"
+ , "rediss", "reload", "res", "resource", "rmi", "rsync", "rtmfp", "rtmp"
+ , "rtsp", "rtsps", "rtspu", "secondlife", "service", "session", "sftp", "sgn"
+ , "shttp", "sieve", "sip", "sips", "skype", "smb", "sms", "smtp", "snews"
+ , "snmp", "soap.beep", "soap.beeps", "soldat", "spotify", "ssh", "steam"
+ , "stun", "stuns", "submit", "svn", "tag", "teamspeak", "tel", "teliaeid"
+ , "telnet", "tftp", "things", "thismessage", "tip", "tn3270", "tool", "turn"
+ , "turns", "tv", "udp", "unreal", "urn", "ut2004", "v-event", "vemmi"
+ , "ventrilo", "videotex", "vnc", "view-source", "wais", "webcal", "wpid"
+ , "ws", "wss", "wtai", "wyciwyg", "xcon", "xcon-userid", "xfire"
+ , "xmlrpc.beep", "xmlrpc.beeps", "xmpp", "xri", "ymsgr", "z39.50", "z39.50r"
+ , "z39.50s"
+ -- Inofficial schemes
+ , "doi", "isbn", "javascript", "pmid"
+ ]
+
+-- | Check if the string is a valid URL with a IANA or frequently used but
+-- unofficial scheme (see @schemes@).
+isURI :: String -> Bool
+isURI = maybe False hasKnownScheme . parseURI
+ where
+ hasKnownScheme = (`Set.member` schemes) . map toLower .
+ filter (/= ':') . uriScheme
+
---
--- Squash blocks into inlines
---
-blockToInlines :: Block -> [Inline]
-blockToInlines (Plain ils) = ils
-blockToInlines (Para ils) = ils
-blockToInlines (LineBlock lns) = combineLines lns
-blockToInlines (CodeBlock attr str) = [Code attr str]
-blockToInlines (RawBlock fmt str) = [RawInline fmt str]
-blockToInlines (BlockQuote blks) = blocksToInlines blks
+blockToInlines :: Block -> Inlines
+blockToInlines (Plain ils) = B.fromList ils
+blockToInlines (Para ils) = B.fromList ils
+blockToInlines (LineBlock lns) = B.fromList $ combineLines lns
+blockToInlines (CodeBlock attr str) = B.codeWith attr str
+blockToInlines (RawBlock (Format fmt) str) = B.rawInline fmt str
+blockToInlines (BlockQuote blks) = blocksToInlines' blks
blockToInlines (OrderedList _ blkslst) =
- concatMap blocksToInlines blkslst
+ mconcat $ map blocksToInlines' blkslst
blockToInlines (BulletList blkslst) =
- concatMap blocksToInlines blkslst
+ mconcat $ map blocksToInlines' blkslst
blockToInlines (DefinitionList pairslst) =
- concatMap f pairslst
+ mconcat $ map f pairslst
where
- f (ils, blkslst) = ils ++
- [Str ":", Space] ++
- (concatMap blocksToInlines blkslst)
-blockToInlines (Header _ _ ils) = ils
-blockToInlines (HorizontalRule) = []
+ f (ils, blkslst) = B.fromList ils <> B.str ":" <> B.space <>
+ mconcat (map blocksToInlines' blkslst)
+blockToInlines (Header _ _ ils) = B.fromList ils
+blockToInlines HorizontalRule = mempty
blockToInlines (Table _ _ _ headers rows) =
- intercalate [LineBreak] $ map (concatMap blocksToInlines) tbl
- where
- tbl = headers : rows
-blockToInlines (Div _ blks) = blocksToInlines blks
-blockToInlines Null = []
+ mconcat $ intersperse B.linebreak $
+ map (mconcat . map blocksToInlines') (headers:rows)
+blockToInlines (Div _ blks) = blocksToInlines' blks
+blockToInlines Null = mempty
+
+blocksToInlinesWithSep :: Inlines -> [Block] -> Inlines
+blocksToInlinesWithSep sep =
+ mconcat . intersperse sep . map blockToInlines
-blocksToInlinesWithSep :: [Inline] -> [Block] -> [Inline]
-blocksToInlinesWithSep sep blks = intercalate sep $ map blockToInlines blks
+blocksToInlines' :: [Block] -> Inlines
+blocksToInlines' = blocksToInlinesWithSep parSep
+ where parSep = B.space <> B.str "¶" <> B.space
blocksToInlines :: [Block] -> [Inline]
-blocksToInlines = blocksToInlinesWithSep [Space, Str "¶", Space]
+blocksToInlines = B.toList . blocksToInlines'
--
diff --git a/src/Text/Pandoc/Slides.hs b/src/Text/Pandoc/Slides.hs
index e19dba3e2..9d63555c2 100644
--- a/src/Text/Pandoc/Slides.hs
+++ b/src/Text/Pandoc/Slides.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2012-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Slides
- Copyright : Copyright (C) 2012-2016 John MacFarlane
+ Copyright : Copyright (C) 2012-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -40,9 +40,9 @@ getSlideLevel = go 6
| otherwise = go least (x:xs)
go least (_ : xs) = go least xs
go least [] = least
- nonHOrHR (Header{}) = False
- nonHOrHR (HorizontalRule) = False
- nonHOrHR _ = True
+ nonHOrHR Header{} = False
+ nonHOrHR HorizontalRule = False
+ nonHOrHR _ = True
-- | Prepare a block list to be passed to hierarchicalize.
prepSlides :: Int -> [Block] -> [Block]
diff --git a/src/Text/Pandoc/Templates.hs b/src/Text/Pandoc/Templates.hs
index d15d27438..4be0d081c 100644
--- a/src/Text/Pandoc/Templates.hs
+++ b/src/Text/Pandoc/Templates.hs
@@ -1,7 +1,9 @@
-{-# LANGUAGE TypeSynonymInstances, FlexibleInstances,
- OverloadedStrings, GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeSynonymInstances #-}
{-
-Copyright (C) 2009-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2009-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Templates
- Copyright : Copyright (C) 2009-2016 John MacFarlane
+ Copyright : Copyright (C) 2009-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,44 +33,52 @@ A simple templating system with variable substitution and conditionals.
-}
-module Text.Pandoc.Templates ( renderTemplate
+module Text.Pandoc.Templates ( module Text.DocTemplates
, renderTemplate'
- , TemplateTarget
- , varListToJSON
- , compileTemplate
- , Template
- , getDefaultTemplate ) where
+ , getDefaultTemplate
+ ) where
-import Text.DocTemplates (Template, TemplateTarget, compileTemplate,
- renderTemplate, applyTemplate,
- varListToJSON)
-import Data.Aeson (ToJSON(..))
+import Control.Monad.Except (throwError)
+import Data.Aeson (ToJSON (..))
import qualified Data.Text as T
-import System.FilePath ((</>), (<.>))
-import qualified Control.Exception.Extensible as E (try, IOException)
-import Text.Pandoc.Shared (readDataFileUTF8)
+import System.FilePath ((<.>), (</>))
+import Text.DocTemplates (Template, TemplateTarget, applyTemplate,
+ compileTemplate, renderTemplate, varListToJSON)
+import Text.Pandoc.Class (PandocMonad, readDataFile)
+import Text.Pandoc.Error
+import qualified Text.Pandoc.UTF8 as UTF8
-- | Get default template for the specified writer.
-getDefaultTemplate :: (Maybe FilePath) -- ^ User data directory to search first
- -> String -- ^ Name of writer
- -> IO (Either E.IOException String)
-getDefaultTemplate user writer = do
+getDefaultTemplate :: PandocMonad m
+ => String -- ^ Name of writer
+ -> m String
+getDefaultTemplate writer = do
let format = takeWhile (`notElem` ("+-" :: String)) writer -- strip off extensions
case format of
- "native" -> return $ Right ""
- "json" -> return $ Right ""
- "docx" -> return $ Right ""
- "fb2" -> return $ Right ""
- "odt" -> getDefaultTemplate user "opendocument"
- "markdown_strict" -> getDefaultTemplate user "markdown"
- "multimarkdown" -> getDefaultTemplate user "markdown"
- "markdown_github" -> getDefaultTemplate user "markdown"
- "markdown_mmd" -> getDefaultTemplate user "markdown"
- "markdown_phpextra" -> getDefaultTemplate user "markdown"
+ "native" -> return ""
+ "json" -> return ""
+ "docx" -> return ""
+ "fb2" -> return ""
+ "pptx" -> return ""
+ "odt" -> getDefaultTemplate "opendocument"
+ "html" -> getDefaultTemplate "html5"
+ "docbook" -> getDefaultTemplate "docbook5"
+ "epub" -> getDefaultTemplate "epub3"
+ "beamer" -> getDefaultTemplate "latex"
+ "markdown_strict" -> getDefaultTemplate "markdown"
+ "multimarkdown" -> getDefaultTemplate "markdown"
+ "markdown_github" -> getDefaultTemplate "markdown"
+ "markdown_mmd" -> getDefaultTemplate "markdown"
+ "markdown_phpextra" -> getDefaultTemplate "markdown"
+ "gfm" -> getDefaultTemplate "commonmark"
_ -> let fname = "templates" </> "default" <.> format
- in E.try $ readDataFileUTF8 user fname
-
--- | Like 'applyTemplate', but raising an error if compilation fails.
-renderTemplate' :: (ToJSON a, TemplateTarget b) => String -> a -> b
-renderTemplate' template = either error id . applyTemplate (T.pack template)
+ in UTF8.toString <$> readDataFile fname
+-- | Like 'applyTemplate', but runs in PandocMonad and
+-- raises an error if compilation fails.
+renderTemplate' :: (PandocMonad m, ToJSON a, TemplateTarget b)
+ => String -> a -> m b
+renderTemplate' template context =
+ case applyTemplate (T.pack template) context of
+ Left e -> throwError (PandocTemplateError e)
+ Right r -> return r
diff --git a/src/Text/Pandoc/Translations.hs b/src/Text/Pandoc/Translations.hs
new file mode 100644
index 000000000..949618178
--- /dev/null
+++ b/src/Text/Pandoc/Translations.hs
@@ -0,0 +1,112 @@
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-
+Copyright (C) 2017-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Translations
+ Copyright : Copyright (C) 2017-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Data types for localization.
+
+Translations are stored in @data/translations/langname.trans@,
+where langname can be the full BCP47 language specifier, or
+just the language part. File format is:
+
+> # A comment, ignored
+> Figure: Figura
+> Index: Indeksi
+
+-}
+module Text.Pandoc.Translations (
+ Term(..)
+ , Translations
+ , lookupTerm
+ , readTranslations
+ )
+where
+import Data.Aeson.Types (typeMismatch)
+import qualified Data.HashMap.Strict as HM
+import qualified Data.Map as M
+import Data.Text as T
+import Data.Yaml as Yaml
+import GHC.Generics (Generic)
+import Text.Pandoc.Shared (safeRead)
+import qualified Text.Pandoc.UTF8 as UTF8
+
+data Term =
+ Preface
+ | References
+ | Abstract
+ | Bibliography
+ | Chapter
+ | Appendix
+ | Contents
+ | ListOfFigures
+ | ListOfTables
+ | Index
+ | Figure
+ | Table
+ | Part
+ | Page
+ | See
+ | SeeAlso
+ | Encl
+ | Cc
+ | To
+ | Proof
+ | Glossary
+ | Listing
+ deriving (Show, Eq, Ord, Generic, Enum, Read)
+
+newtype Translations = Translations (M.Map Term String)
+ deriving (Show, Generic, Monoid)
+
+instance FromJSON Term where
+ parseJSON (String t) = case safeRead (T.unpack t) of
+ Just t' -> pure t'
+ Nothing -> fail $ "Invalid Term name " ++
+ show t
+ parseJSON invalid = typeMismatch "Term" invalid
+
+instance FromJSON Translations where
+ parseJSON (Object hm) = do
+ xs <- mapM addItem (HM.toList hm)
+ return $ Translations (M.fromList xs)
+ where addItem (k,v) =
+ case safeRead (T.unpack k) of
+ Nothing -> fail $ "Invalid Term name " ++ show k
+ Just t ->
+ case v of
+ (String s) -> return (t, T.unpack $ T.strip s)
+ inv -> typeMismatch "String" inv
+ parseJSON invalid = typeMismatch "Translations" invalid
+
+lookupTerm :: Term -> Translations -> Maybe String
+lookupTerm t (Translations tm) = M.lookup t tm
+
+readTranslations :: String -> Either String Translations
+readTranslations s =
+ case Yaml.decodeEither' $ UTF8.fromString s of
+ Left err' -> Left $ prettyPrintParseException err'
+ Right t -> Right t
diff --git a/src/Text/Pandoc/UTF8.hs b/src/Text/Pandoc/UTF8.hs
index 62a662029..3f759958f 100644
--- a/src/Text/Pandoc/UTF8.hs
+++ b/src/Text/Pandoc/UTF8.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2010-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.UTF8
- Copyright : Copyright (C) 2010-2016 John MacFarlane
+ Copyright : Copyright (C) 2010-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -28,16 +29,25 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
UTF-8 aware string IO functions that will work with GHC 6.10, 6.12, or 7.
-}
module Text.Pandoc.UTF8 ( readFile
- , writeFile
, getContents
+ , writeFileWith
+ , writeFile
+ , putStrWith
, putStr
+ , putStrLnWith
, putStrLn
+ , hPutStrWith
, hPutStr
+ , hPutStrLnWith
, hPutStrLn
, hGetContents
, toString
+ , toText
, fromString
+ , fromText
, toStringLazy
+ , fromTextLazy
+ , toTextLazy
, fromStringLazy
, encodePath
, decodeArg
@@ -45,39 +55,59 @@ module Text.Pandoc.UTF8 ( readFile
where
-import System.IO hiding (readFile, writeFile, getContents,
- putStr, putStrLn, hPutStr, hPutStrLn, hGetContents)
-import Prelude hiding (readFile, writeFile, getContents, putStr, putStrLn)
-import qualified System.IO as IO
import qualified Data.ByteString.Char8 as B
-import qualified Data.ByteString.Lazy as BL
-import qualified Data.Text.Encoding as T
+import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TL
+import Prelude hiding (getContents, putStr, putStrLn, readFile, writeFile)
+import System.IO hiding (getContents, hGetContents, hPutStr, hPutStrLn, putStr,
+ putStrLn, readFile, writeFile)
+import qualified System.IO as IO
readFile :: FilePath -> IO String
readFile f = do
h <- openFile (encodePath f) ReadMode
hGetContents h
-writeFile :: FilePath -> String -> IO ()
-writeFile f s = withFile (encodePath f) WriteMode $ \h -> hPutStr h s
-
getContents :: IO String
getContents = hGetContents stdin
+writeFileWith :: Newline -> FilePath -> String -> IO ()
+writeFileWith eol f s =
+ withFile (encodePath f) WriteMode $ \h -> hPutStrWith eol h s
+
+writeFile :: FilePath -> String -> IO ()
+writeFile = writeFileWith nativeNewline
+
+putStrWith :: Newline -> String -> IO ()
+putStrWith eol s = hPutStrWith eol stdout s
+
putStr :: String -> IO ()
-putStr s = hPutStr stdout s
+putStr = putStrWith nativeNewline
+
+putStrLnWith :: Newline -> String -> IO ()
+putStrLnWith eol s = hPutStrLnWith eol stdout s
putStrLn :: String -> IO ()
-putStrLn s = hPutStrLn stdout s
+putStrLn = putStrLnWith nativeNewline
+
+hPutStrWith :: Newline -> Handle -> String -> IO ()
+hPutStrWith eol h s =
+ hSetNewlineMode h (NewlineMode eol eol) >>
+ hSetEncoding h utf8 >> IO.hPutStr h s
hPutStr :: Handle -> String -> IO ()
-hPutStr h s = hSetEncoding h utf8 >> IO.hPutStr h s
+hPutStr = hPutStrWith nativeNewline
+
+hPutStrLnWith :: Newline -> Handle -> String -> IO ()
+hPutStrLnWith eol h s =
+ hSetNewlineMode h (NewlineMode eol eol) >>
+ hSetEncoding h utf8 >> IO.hPutStrLn h s
hPutStrLn :: Handle -> String -> IO ()
-hPutStrLn h s = hSetEncoding h utf8 >> IO.hPutStrLn h s
+hPutStrLn = hPutStrLnWith nativeNewline
hGetContents :: Handle -> IO String
hGetContents = fmap toString . B.hGetContents
@@ -85,34 +115,47 @@ hGetContents = fmap toString . B.hGetContents
-- >> hSetNewlineMode h universalNewlineMode
-- >> IO.hGetContents h
--- | Drop BOM (byte order marker) if present at beginning of string.
--- Note that Data.Text converts the BOM to code point FEFF, zero-width
--- no-break space, so if the string begins with this we strip it off.
-dropBOM :: String -> String
-dropBOM ('\xFEFF':xs) = xs
-dropBOM xs = xs
-
-filterCRs :: String -> String
-filterCRs ('\r':'\n':xs) = '\n': filterCRs xs
-filterCRs ('\r':xs) = '\n' : filterCRs xs
-filterCRs (x:xs) = x : filterCRs xs
-filterCRs [] = []
+-- | Convert UTF8-encoded ByteString to Text, also
+-- removing '\r' characters.
+toText :: B.ByteString -> T.Text
+toText = T.decodeUtf8 . filterCRs . dropBOM
+ where dropBOM bs =
+ if "\xEF\xBB\xBF" `B.isPrefixOf` bs
+ then B.drop 3 bs
+ else bs
+ filterCRs = B.filter (/='\r')
-- | Convert UTF8-encoded ByteString to String, also
-- removing '\r' characters.
toString :: B.ByteString -> String
-toString = filterCRs . dropBOM . T.unpack . T.decodeUtf8
+toString = T.unpack . toText
-fromString :: String -> B.ByteString
-fromString = T.encodeUtf8 . T.pack
+-- | Convert UTF8-encoded ByteString to Text, also
+-- removing '\r' characters.
+toTextLazy :: BL.ByteString -> TL.Text
+toTextLazy = TL.decodeUtf8 . filterCRs . dropBOM
+ where dropBOM bs =
+ if "\xEF\xBB\xBF" `BL.isPrefixOf` bs
+ then BL.drop 3 bs
+ else bs
+ filterCRs = BL.filter (/='\r')
-- | Convert UTF8-encoded ByteString to String, also
-- removing '\r' characters.
toStringLazy :: BL.ByteString -> String
-toStringLazy = filterCRs . dropBOM . TL.unpack . TL.decodeUtf8
+toStringLazy = TL.unpack . toTextLazy
+
+fromText :: T.Text -> B.ByteString
+fromText = T.encodeUtf8
+
+fromTextLazy :: TL.Text -> BL.ByteString
+fromTextLazy = TL.encodeUtf8
+
+fromString :: String -> B.ByteString
+fromString = fromText . T.pack
fromStringLazy :: String -> BL.ByteString
-fromStringLazy = TL.encodeUtf8 . TL.pack
+fromStringLazy = fromTextLazy . TL.pack
encodePath :: FilePath -> FilePath
encodePath = id
diff --git a/src/Text/Pandoc/UUID.hs b/src/Text/Pandoc/UUID.hs
index 5d05fa303..4d99324db 100644
--- a/src/Text/Pandoc/UUID.hs
+++ b/src/Text/Pandoc/UUID.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2010-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.UUID
- Copyright : Copyright (C) 2010-2016 John MacFarlane
+ Copyright : Copyright (C) 2010-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,13 +29,12 @@ UUID generation using Version 4 (random method) described
in RFC4122. See http://tools.ietf.org/html/rfc4122
-}
-module Text.Pandoc.UUID ( UUID, getRandomUUID ) where
+module Text.Pandoc.UUID ( UUID(..), getRandomUUID, getUUID ) where
-import Text.Printf ( printf )
-import System.Random ( randomIO )
+import Data.Bits (clearBit, setBit)
import Data.Word
-import Data.Bits ( setBit, clearBit )
-import Control.Monad ( liftM )
+import System.Random (RandomGen, getStdGen, randoms)
+import Text.Printf (printf)
data UUID = UUID Word8 Word8 Word8 Word8 Word8 Word8 Word8 Word8
Word8 Word8 Word8 Word8 Word8 Word8 Word8 Word8
@@ -64,14 +63,15 @@ instance Show UUID where
printf "%02x" o ++
printf "%02x" p
-getRandomUUID :: IO UUID
-getRandomUUID = do
- let getRN :: a -> IO Word8
- getRN _ = liftM fromIntegral (randomIO :: IO Int)
- [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] <- mapM getRN ([1..16] :: [Int])
+getUUID :: RandomGen g => g -> UUID
+getUUID gen =
+ let [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] = take 16 $ randoms gen :: [Word8]
-- set variant
- let i' = i `setBit` 7 `clearBit` 6
+ i' = i `setBit` 7 `clearBit` 6
-- set version (0100 for random)
- let g' = g `clearBit` 7 `setBit` 6 `clearBit` 5 `clearBit` 4
- return $ UUID a b c d e f g' h i' j k l m n o p
+ g' = g `clearBit` 7 `setBit` 6 `clearBit` 5 `clearBit` 4
+ in
+ UUID a b c d e f g' h i' j k l m n o p
+getRandomUUID :: IO UUID
+getRandomUUID = getUUID <$> getStdGen
diff --git a/src/Text/Pandoc/Writers.hs b/src/Text/Pandoc/Writers.hs
new file mode 100644
index 000000000..596a8680e
--- /dev/null
+++ b/src/Text/Pandoc/Writers.hs
@@ -0,0 +1,195 @@
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+{- |
+ Module : Text.Pandoc
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+This helper module exports all writers functions.
+-}
+module Text.Pandoc.Writers
+ (
+ -- * Writers: converting /from/ Pandoc format
+ Writer(..)
+ , writers
+ , writeAsciiDoc
+ , writeBeamer
+ , writeCommonMark
+ , writeConTeXt
+ , writeCustom
+ , writeDZSlides
+ , writeDocbook4
+ , writeDocbook5
+ , writeDocx
+ , writeDokuWiki
+ , writeEPUB2
+ , writeEPUB3
+ , writeFB2
+ , writeHaddock
+ , writeHtml4
+ , writeHtml4String
+ , writeHtml5
+ , writeHtml5String
+ , writeICML
+ , writeJATS
+ , writeJSON
+ , writeLaTeX
+ , writeMan
+ , writeMarkdown
+ , writeMediaWiki
+ , writeMs
+ , writeMuse
+ , writeNative
+ , writeODT
+ , writeOPML
+ , writeOpenDocument
+ , writeOrg
+ , writePlain
+ , writePowerpoint
+ , writeRST
+ , writeRTF
+ , writeRevealJs
+ , writeS5
+ , writeSlideous
+ , writeSlidy
+ , writeTEI
+ , writeTexinfo
+ , writeTextile
+ , writeZimWiki
+ , getWriter
+ ) where
+
+import Data.Aeson
+import qualified Data.ByteString.Lazy as BL
+import Data.List (intercalate)
+import Data.Text (Text)
+import Text.Pandoc.Class
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.Pandoc.Writers.AsciiDoc
+import Text.Pandoc.Writers.CommonMark
+import Text.Pandoc.Writers.ConTeXt
+import Text.Pandoc.Writers.Custom
+import Text.Pandoc.Writers.Docbook
+import Text.Pandoc.Writers.Docx
+import Text.Pandoc.Writers.DokuWiki
+import Text.Pandoc.Writers.EPUB
+import Text.Pandoc.Writers.FB2
+import Text.Pandoc.Writers.Haddock
+import Text.Pandoc.Writers.HTML
+import Text.Pandoc.Writers.ICML
+import Text.Pandoc.Writers.JATS
+import Text.Pandoc.Writers.LaTeX
+import Text.Pandoc.Writers.Man
+import Text.Pandoc.Writers.Markdown
+import Text.Pandoc.Writers.MediaWiki
+import Text.Pandoc.Writers.Ms
+import Text.Pandoc.Writers.Muse
+import Text.Pandoc.Writers.Native
+import Text.Pandoc.Writers.ODT
+import Text.Pandoc.Writers.OpenDocument
+import Text.Pandoc.Writers.OPML
+import Text.Pandoc.Writers.Org
+import Text.Pandoc.Writers.Powerpoint
+import Text.Pandoc.Writers.RST
+import Text.Pandoc.Writers.RTF
+import Text.Pandoc.Writers.TEI
+import Text.Pandoc.Writers.Texinfo
+import Text.Pandoc.Writers.Textile
+import Text.Pandoc.Writers.ZimWiki
+import Text.Parsec.Error
+
+data Writer m = TextWriter (WriterOptions -> Pandoc -> m Text)
+ | ByteStringWriter (WriterOptions -> Pandoc -> m BL.ByteString)
+
+-- | Association list of formats and writers.
+writers :: PandocMonad m => [ ( String, Writer m) ]
+writers = [
+ ("native" , TextWriter writeNative)
+ ,("json" , TextWriter $ \o d -> return $ writeJSON o d)
+ ,("docx" , ByteStringWriter writeDocx)
+ ,("odt" , ByteStringWriter writeODT)
+ ,("pptx" , ByteStringWriter writePowerpoint)
+ ,("epub" , ByteStringWriter writeEPUB3)
+ ,("epub2" , ByteStringWriter writeEPUB2)
+ ,("epub3" , ByteStringWriter writeEPUB3)
+ ,("fb2" , TextWriter writeFB2)
+ ,("html" , TextWriter writeHtml5String)
+ ,("html4" , TextWriter writeHtml4String)
+ ,("html5" , TextWriter writeHtml5String)
+ ,("icml" , TextWriter writeICML)
+ ,("s5" , TextWriter writeS5)
+ ,("slidy" , TextWriter writeSlidy)
+ ,("slideous" , TextWriter writeSlideous)
+ ,("dzslides" , TextWriter writeDZSlides)
+ ,("revealjs" , TextWriter writeRevealJs)
+ ,("docbook" , TextWriter writeDocbook5)
+ ,("docbook4" , TextWriter writeDocbook4)
+ ,("docbook5" , TextWriter writeDocbook5)
+ ,("jats" , TextWriter writeJATS)
+ ,("opml" , TextWriter writeOPML)
+ ,("opendocument" , TextWriter writeOpenDocument)
+ ,("latex" , TextWriter writeLaTeX)
+ ,("beamer" , TextWriter writeBeamer)
+ ,("context" , TextWriter writeConTeXt)
+ ,("texinfo" , TextWriter writeTexinfo)
+ ,("man" , TextWriter writeMan)
+ ,("ms" , TextWriter writeMs)
+ ,("markdown" , TextWriter writeMarkdown)
+ ,("markdown_strict" , TextWriter writeMarkdown)
+ ,("markdown_phpextra" , TextWriter writeMarkdown)
+ ,("markdown_github" , TextWriter writeMarkdown)
+ ,("markdown_mmd" , TextWriter writeMarkdown)
+ ,("plain" , TextWriter writePlain)
+ ,("rst" , TextWriter writeRST)
+ ,("mediawiki" , TextWriter writeMediaWiki)
+ ,("dokuwiki" , TextWriter writeDokuWiki)
+ ,("zimwiki" , TextWriter writeZimWiki)
+ ,("textile" , TextWriter writeTextile)
+ ,("rtf" , TextWriter writeRTF)
+ ,("org" , TextWriter writeOrg)
+ ,("asciidoc" , TextWriter writeAsciiDoc)
+ ,("haddock" , TextWriter writeHaddock)
+ ,("commonmark" , TextWriter writeCommonMark)
+ ,("gfm" , TextWriter writeCommonMark)
+ ,("tei" , TextWriter writeTEI)
+ ,("muse" , TextWriter writeMuse)
+ ]
+
+-- | Retrieve writer, extensions based on formatSpec (format+extensions).
+getWriter :: PandocMonad m => String -> Either String (Writer m, Extensions)
+getWriter s
+ = case parseFormatSpec s of
+ Left e -> Left $ intercalate "\n" [m | Message m <- errorMessages e]
+ Right (writerName, setExts) ->
+ case lookup writerName writers of
+ Nothing -> Left $ "Unknown writer: " ++ writerName
+ Just r -> Right (r, setExts $
+ getDefaultExtensions writerName)
+
+writeJSON :: WriterOptions -> Pandoc -> Text
+writeJSON _ = UTF8.toText . BL.toStrict . encode
diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index e9d3dccf1..f91fa8fa0 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.AsciiDoc
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -37,49 +37,59 @@ that it has omitted the construct.
AsciiDoc: <http://www.methods.co.nz/asciidoc/>
-}
module Text.Pandoc.Writers.AsciiDoc (writeAsciiDoc) where
+import Control.Monad.State.Strict
+import Data.Aeson (Result (..), Value (String), fromJSON, toJSON)
+import Data.Char (isPunctuation, isSpace)
+import Data.List (intercalate, intersperse, stripPrefix)
+import qualified Data.Map as M
+import Data.Maybe (fromMaybe, isJust)
+import qualified Data.Set as Set
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
-import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (blankline, space)
-import Data.Maybe (fromMaybe)
-import Data.List ( stripPrefix, intersperse, intercalate )
import Text.Pandoc.Pretty
-import Text.Pandoc.ImageSize
-import Control.Monad.State
-import qualified Data.Map as M
-import Data.Aeson (Value(String), fromJSON, toJSON, Result(..))
-import qualified Data.Text as T
-import Data.Char (isSpace, isPunctuation)
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Shared
-data WriterState = WriterState { defListMarker :: String
+data WriterState = WriterState { defListMarker :: String
, orderedListLevel :: Int
, bulletListLevel :: Int
, intraword :: Bool
+ , autoIds :: Set.Set String
}
-- | Convert Pandoc to AsciiDoc.
-writeAsciiDoc :: WriterOptions -> Pandoc -> String
+writeAsciiDoc :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeAsciiDoc opts document =
- evalState (pandocToAsciiDoc opts document) WriterState{
+ evalStateT (pandocToAsciiDoc opts document) WriterState{
defListMarker = "::"
, orderedListLevel = 1
, bulletListLevel = 1
, intraword = False
+ , autoIds = Set.empty
}
+type ADW = StateT WriterState
+
-- | Return asciidoc representation of document.
-pandocToAsciiDoc :: WriterOptions -> Pandoc -> State WriterState String
+pandocToAsciiDoc :: PandocMonad m => WriterOptions -> Pandoc -> ADW m Text
pandocToAsciiDoc opts (Pandoc meta blocks) = do
let titleblock = not $ null (docTitle meta) && null (docAuthors meta) &&
null (docDate meta)
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToAsciiDoc opts)
- (fmap (render colwidth) . inlineListToAsciiDoc opts)
+ (fmap render' . blockListToAsciiDoc opts)
+ (fmap render' . inlineListToAsciiDoc opts)
meta
let addTitleLine (String t) = String $
t <> "\n" <> T.replicate (T.length t) "="
@@ -93,12 +103,11 @@ pandocToAsciiDoc opts (Pandoc meta blocks) = do
let context = defField "body" main
$ defField "toc"
(writerTableOfContents opts &&
- writerTemplate opts /= Nothing)
- $ defField "titleblock" titleblock
- $ metadata'
+ isJust (writerTemplate opts))
+ $defField "titleblock" titleblock metadata'
case writerTemplate opts of
Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
-- | Escape special characters for AsciiDoc.
escapeString :: String -> String
@@ -118,18 +127,19 @@ olMarker = do (start, style', delim) <- anyOrderedListMarker
beginsWithOrderedListMarker :: String -> Bool
beginsWithOrderedListMarker str =
case runParser olMarker defaultParserState "para start" (take 10 str) of
- Left _ -> False
- Right _ -> True
+ Left _ -> False
+ Right _ -> True
-- | Convert Pandoc block element to asciidoc.
-blockToAsciiDoc :: WriterOptions -- ^ Options
+blockToAsciiDoc :: PandocMonad m
+ => WriterOptions -- ^ Options
-> Block -- ^ Block element
- -> State WriterState Doc
+ -> ADW m Doc
blockToAsciiDoc _ Null = return empty
blockToAsciiDoc opts (Plain inlines) = do
contents <- inlineListToAsciiDoc opts inlines
return $ contents <> blankline
-blockToAsciiDoc opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) = do
+blockToAsciiDoc opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) =
blockToAsciiDoc opts (Para [Image attr alt (src,tit)])
blockToAsciiDoc opts (Para inlines) = do
contents <- inlineListToAsciiDoc opts inlines
@@ -145,9 +155,11 @@ blockToAsciiDoc opts (LineBlock lns) = do
let joinWithLinefeeds = nowrap . mconcat . intersperse cr
contents <- joinWithLinefeeds <$> mapM docify lns
return $ "[verse]" $$ text "--" $$ contents $$ text "--" $$ blankline
-blockToAsciiDoc _ (RawBlock f s)
+blockToAsciiDoc _ b@(RawBlock f s)
| f == "asciidoc" = return $ text s
- | otherwise = return empty
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
blockToAsciiDoc _ HorizontalRule =
return $ blankline <> text "'''''" <> blankline
blockToAsciiDoc opts (Header level (ident,_,_) inlines) = do
@@ -155,21 +167,25 @@ blockToAsciiDoc opts (Header level (ident,_,_) inlines) = do
let len = offset contents
-- ident seem to be empty most of the time and asciidoc will generate them automatically
-- so lets make them not show up when null
- let identifier = if (null ident) then empty else ("[[" <> text ident <> "]]")
+ ids <- gets autoIds
+ let autoId = uniqueIdent inlines ids
+ modify $ \st -> st{ autoIds = Set.insert autoId ids }
+ let identifier = if null ident || (isEnabled Ext_auto_identifiers opts && ident == autoId)
+ then empty else "[[" <> text ident <> "]]"
let setext = writerSetextHeaders opts
- return $
+ return
(if setext
then
identifier $$ contents $$
(case level of
- 1 -> text $ replicate len '-'
- 2 -> text $ replicate len '~'
- 3 -> text $ replicate len '^'
- 4 -> text $ replicate len '+'
- _ -> empty) <> blankline
+ 1 -> text $ replicate len '-'
+ 2 -> text $ replicate len '~'
+ 3 -> text $ replicate len '^'
+ 4 -> text $ replicate len '+'
+ _ -> empty) <> blankline
else
identifier $$ text (replicate level '=') <> space <> contents <> blankline)
-blockToAsciiDoc _ (CodeBlock (_,classes,_) str) = return $ (flush $
+blockToAsciiDoc _ (CodeBlock (_,classes,_) str) = return $ flush (
if null classes
then "...." $$ text str $$ "...."
else attrs $$ "----" $$ text str $$ "----")
@@ -194,7 +210,7 @@ blockToAsciiDoc opts (Table caption aligns widths headers rows) = do
let isSimple = all (== 0) widths
let relativePercentWidths = if isSimple
then widths
- else map (/ (sum widths)) widths
+ else map (/ sum widths) widths
let widths'' :: [Integer]
widths'' = map (floor . (* 100)) relativePercentWidths
-- ensure that the widths sum to 100
@@ -210,7 +226,7 @@ blockToAsciiDoc opts (Table caption aligns widths headers rows) = do
AlignCenter -> "^"
AlignRight -> ">"
AlignDefault -> "") ++
- if wi == 0 then "" else (show wi ++ "%")
+ if wi == 0 then "" else show wi ++ "%"
let headerspec = if all null headers
then empty
else text "options=\"header\","
@@ -256,21 +272,21 @@ blockToAsciiDoc opts (OrderedList (_start, sty, _delim) items) = do
let markers' = map (\m -> if length m < 3
then m ++ replicate (3 - length m) ' '
else m) markers
- contents <- mapM (\(item, num) -> orderedListItemToAsciiDoc opts item num) $
- zip markers' items
+ contents <- zipWithM (orderedListItemToAsciiDoc opts) markers' items
return $ cat contents <> blankline
blockToAsciiDoc opts (DefinitionList items) = do
contents <- mapM (definitionListItemToAsciiDoc opts) items
return $ cat contents <> blankline
blockToAsciiDoc opts (Div (ident,_,_) bs) = do
- let identifier = if (null ident) then empty else ("[[" <> text ident <> "]]")
+ let identifier = if null ident then empty else ("[[" <> text ident <> "]]")
contents <- blockListToAsciiDoc opts bs
return $ identifier $$ contents
-- | Convert bullet list item (list of blocks) to asciidoc.
-bulletListItemToAsciiDoc :: WriterOptions -> [Block] -> State WriterState Doc
+bulletListItemToAsciiDoc :: PandocMonad m
+ => WriterOptions -> [Block] -> ADW m Doc
bulletListItemToAsciiDoc opts blocks = do
- let addBlock :: Doc -> Block -> State WriterState Doc
+ let addBlock :: PandocMonad m => Doc -> Block -> ADW m Doc
addBlock d b | isEmpty d = chomp `fmap` blockToAsciiDoc opts b
addBlock d b@(BulletList _) = do x <- blockToAsciiDoc opts b
return $ d <> cr <> chomp x
@@ -278,7 +294,7 @@ bulletListItemToAsciiDoc opts blocks = do
return $ d <> cr <> chomp x
addBlock d b = do x <- blockToAsciiDoc opts b
return $ d <> cr <> text "+" <> cr <> chomp x
- lev <- bulletListLevel `fmap` get
+ lev <- gets bulletListLevel
modify $ \s -> s{ bulletListLevel = lev + 1 }
contents <- foldM addBlock empty blocks
modify $ \s -> s{ bulletListLevel = lev }
@@ -286,37 +302,38 @@ bulletListItemToAsciiDoc opts blocks = do
return $ marker <> text " " <> contents <> cr
-- | Convert ordered list item (a list of blocks) to asciidoc.
-orderedListItemToAsciiDoc :: WriterOptions -- ^ options
+orderedListItemToAsciiDoc :: PandocMonad m
+ => WriterOptions -- ^ options
-> String -- ^ list item marker
-> [Block] -- ^ list item (list of blocks)
- -> State WriterState Doc
+ -> ADW m Doc
orderedListItemToAsciiDoc opts marker blocks = do
- let addBlock :: Doc -> Block -> State WriterState Doc
- addBlock d b | isEmpty d = chomp `fmap` blockToAsciiDoc opts b
+ let addBlock d b | isEmpty d = chomp `fmap` blockToAsciiDoc opts b
addBlock d b@(BulletList _) = do x <- blockToAsciiDoc opts b
return $ d <> cr <> chomp x
addBlock d b@(OrderedList _ _) = do x <- blockToAsciiDoc opts b
return $ d <> cr <> chomp x
addBlock d b = do x <- blockToAsciiDoc opts b
return $ d <> cr <> text "+" <> cr <> chomp x
- lev <- orderedListLevel `fmap` get
+ lev <- gets orderedListLevel
modify $ \s -> s{ orderedListLevel = lev + 1 }
contents <- foldM addBlock empty blocks
modify $ \s -> s{ orderedListLevel = lev }
return $ text marker <> text " " <> contents <> cr
-- | Convert definition list item (label, list of blocks) to asciidoc.
-definitionListItemToAsciiDoc :: WriterOptions
+definitionListItemToAsciiDoc :: PandocMonad m
+ => WriterOptions
-> ([Inline],[[Block]])
- -> State WriterState Doc
+ -> ADW m Doc
definitionListItemToAsciiDoc opts (label, defs) = do
labelText <- inlineListToAsciiDoc opts label
- marker <- defListMarker `fmap` get
+ marker <- gets defListMarker
if marker == "::"
then modify (\st -> st{ defListMarker = ";;"})
else modify (\st -> st{ defListMarker = "::"})
let divider = cr <> text "+" <> cr
- let defsToAsciiDoc :: [Block] -> State WriterState Doc
+ let defsToAsciiDoc :: PandocMonad m => [Block] -> ADW m Doc
defsToAsciiDoc ds = (vcat . intersperse divider . map chomp)
`fmap` mapM (blockToAsciiDoc opts) ds
defs' <- mapM defsToAsciiDoc defs
@@ -325,15 +342,16 @@ definitionListItemToAsciiDoc opts (label, defs) = do
return $ labelText <> text marker <> cr <> contents <> cr
-- | Convert list of Pandoc block elements to asciidoc.
-blockListToAsciiDoc :: WriterOptions -- ^ Options
+blockListToAsciiDoc :: PandocMonad m
+ => WriterOptions -- ^ Options
-> [Block] -- ^ List of block elements
- -> State WriterState Doc
+ -> ADW m Doc
blockListToAsciiDoc opts blocks = cat `fmap` mapM (blockToAsciiDoc opts) blocks
data SpacyLocation = End | Start
-- | Convert list of Pandoc inline elements to asciidoc.
-inlineListToAsciiDoc :: WriterOptions -> [Inline] -> State WriterState Doc
+inlineListToAsciiDoc :: PandocMonad m => WriterOptions -> [Inline] -> ADW m Doc
inlineListToAsciiDoc opts lst = do
oldIntraword <- gets intraword
setIntraword False
@@ -369,14 +387,14 @@ inlineListToAsciiDoc opts lst = do
isSpacy Start (Str (c:_)) = isPunctuation c || isSpace c
isSpacy _ _ = False
-setIntraword :: Bool -> State WriterState ()
+setIntraword :: PandocMonad m => Bool -> ADW m ()
setIntraword b = modify $ \st -> st{ intraword = b }
-withIntraword :: State WriterState a -> State WriterState a
+withIntraword :: PandocMonad m => ADW m a -> ADW m a
withIntraword p = setIntraword True *> p <* setIntraword False
-- | Convert Pandoc inline element to asciidoc.
-inlineToAsciiDoc :: WriterOptions -> Inline -> State WriterState Doc
+inlineToAsciiDoc :: PandocMonad m => WriterOptions -> Inline -> ADW m Doc
inlineToAsciiDoc opts (Emph lst) = do
contents <- inlineListToAsciiDoc opts lst
isIntraword <- gets intraword
@@ -408,16 +426,19 @@ inlineToAsciiDoc _ (Math InlineMath str) =
return $ "latexmath:[$" <> text str <> "$]"
inlineToAsciiDoc _ (Math DisplayMath str) =
return $ "latexmath:[\\[" <> text str <> "\\]]"
-inlineToAsciiDoc _ (RawInline f s)
+inlineToAsciiDoc _ il@(RawInline f s)
| f == "asciidoc" = return $ text s
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
| otherwise = return empty
-inlineToAsciiDoc _ (LineBreak) = return $ " +" <> cr
+inlineToAsciiDoc _ LineBreak = return $ " +" <> cr
inlineToAsciiDoc _ Space = return space
inlineToAsciiDoc opts SoftBreak =
case writerWrapText opts of
- WrapAuto -> return space
+ WrapAuto -> return space
WrapPreserve -> return cr
- WrapNone -> return space
+ WrapNone -> return space
inlineToAsciiDoc opts (Cite _ lst) = inlineListToAsciiDoc opts lst
inlineToAsciiDoc opts (Link _ txt (src, _tit)) = do
-- relative: link:downloads/foo.zip[download foo.zip]
@@ -431,20 +452,20 @@ inlineToAsciiDoc opts (Link _ txt (src, _tit)) = do
let srcSuffix = fromMaybe src (stripPrefix "mailto:" src)
let useAuto = case txt of
[Str s] | escapeURI s == srcSuffix -> True
- _ -> False
+ _ -> False
return $ if useAuto
then text srcSuffix
else prefix <> text src <> "[" <> linktext <> "]"
inlineToAsciiDoc opts (Image attr alternate (src, tit)) = do
-- image:images/logo.png[Company logo, title="blah"]
- let txt = if (null alternate) || (alternate == [Str ""])
+ let txt = if null alternate || (alternate == [Str ""])
then [Str "image"]
else alternate
linktext <- inlineListToAsciiDoc opts txt
let linktitle = if null tit
then empty
else ",title=\"" <> text tit <> "\""
- showDim dir = case (dimension dir attr) of
+ showDim dir = case dimension dir attr of
Just (Percent a) ->
["scaledwidth=" <> text (show (Percent a))]
Just dim ->
@@ -464,6 +485,6 @@ inlineToAsciiDoc opts (Note [Plain inlines]) = do
-- asciidoc can't handle blank lines in notes
inlineToAsciiDoc _ (Note _) = return "[multiblock footnote omitted]"
inlineToAsciiDoc opts (Span (ident,_,_) ils) = do
- let identifier = if (null ident) then empty else ("[[" <> text ident <> "]]")
+ let identifier = if null ident then empty else ("[[" <> text ident <> "]]")
contents <- inlineListToAsciiDoc opts ils
return $ identifier <> contents
diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs
index 88a92eb47..7a6eb2948 100644
--- a/src/Text/Pandoc/Writers/CommonMark.hs
+++ b/src/Text/Pandoc/Writers/CommonMark.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2015-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.CommonMark
- Copyright : Copyright (C) 2015 John MacFarlane
+ Copyright : Copyright (C) 2015-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,34 +32,43 @@ CommonMark: <http://commonmark.org>
-}
module Text.Pandoc.Writers.CommonMark (writeCommonMark) where
-import Text.Pandoc.Writers.HTML (writeHtmlString)
+import CMarkGFM
+import Control.Monad.State.Strict (State, get, modify, runState)
+import Data.Foldable (foldrM)
+import Data.List (transpose)
+import Data.Monoid (Any (..), (<>))
+import Data.Text (Text)
+import qualified Data.Text as T
+import Network.HTTP (urlEncode)
+import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
-import Text.Pandoc.Shared (isTightList, linesToPara)
+import Text.Pandoc.Options
+import Text.Pandoc.Shared (isTightList, linesToPara, substitute)
import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Walk (query, walk, walkM)
+import Text.Pandoc.Writers.HTML (writeHtml5String, tagWithAttributes)
import Text.Pandoc.Writers.Shared
-import Text.Pandoc.Options
-import CMark
-import qualified Data.Text as T
-import Control.Monad.Identity (runIdentity, Identity)
-import Control.Monad.State (runState, State, modify, get)
-import Text.Pandoc.Walk (walkM)
-- | Convert Pandoc to CommonMark.
-writeCommonMark :: WriterOptions -> Pandoc -> String
-writeCommonMark opts (Pandoc meta blocks) = rendered
- where main = runIdentity $ blocksToCommonMark opts (blocks' ++ notes')
- (blocks', notes) = runState (walkM processNotes blocks) []
- notes' = if null notes
- then []
- else [OrderedList (1, Decimal, Period) $ reverse notes]
- metadata = runIdentity $ metaToJSON opts
- (blocksToCommonMark opts)
- (inlinesToCommonMark opts)
- meta
- context = defField "body" main $ metadata
- rendered = case writerTemplate opts of
- Nothing -> main
- Just tpl -> renderTemplate' tpl context
+writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeCommonMark opts (Pandoc meta blocks) = do
+ let (blocks', notes) = runState (walkM processNotes blocks) []
+ notes' = if null notes
+ then []
+ else [OrderedList (1, Decimal, Period) $ reverse notes]
+ main <- blocksToCommonMark opts (blocks' ++ notes')
+ metadata <- metaToJSON opts
+ (blocksToCommonMark opts)
+ (inlinesToCommonMark opts)
+ meta
+ let context = defField "body" main metadata
+ case writerTemplate opts of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
+
+softBreakToSpace :: Inline -> Inline
+softBreakToSpace SoftBreak = Space
+softBreakToSpace x = x
processNotes :: Inline -> State [[Block]] Inline
processNotes (Note bs) = do
@@ -70,111 +80,235 @@ processNotes x = return x
node :: NodeType -> [Node] -> Node
node = Node Nothing
-blocksToCommonMark :: WriterOptions -> [Block] -> Identity String
-blocksToCommonMark opts bs = return $
- T.unpack $ nodeToCommonmark cmarkOpts colwidth
- $ node DOCUMENT (blocksToNodes bs)
- where cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
- colwidth = if writerWrapText opts == WrapAuto
- then Just $ writerColumns opts
- else Nothing
+blocksToCommonMark :: PandocMonad m => WriterOptions -> [Block] -> m Text
+blocksToCommonMark opts bs = do
+ let cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
+ colwidth = if writerWrapText opts == WrapAuto
+ then Just $ writerColumns opts
+ else Nothing
+ nodes <- blocksToNodes opts bs
+ return $ T.stripEnd $
+ nodeToCommonmark cmarkOpts colwidth $
+ node DOCUMENT nodes
-inlinesToCommonMark :: WriterOptions -> [Inline] -> Identity String
+inlinesToCommonMark :: PandocMonad m => WriterOptions -> [Inline] -> m Text
inlinesToCommonMark opts ils = return $
- T.unpack $ nodeToCommonmark cmarkOpts colwidth
- $ node PARAGRAPH (inlinesToNodes ils)
+ nodeToCommonmark cmarkOpts colwidth $
+ node PARAGRAPH (inlinesToNodes opts ils)
where cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
-blocksToNodes :: [Block] -> [Node]
-blocksToNodes = foldr blockToNodes []
-
-blockToNodes :: Block -> [Node] -> [Node]
-blockToNodes (Plain xs) = (node PARAGRAPH (inlinesToNodes xs) :)
-blockToNodes (Para xs) = (node PARAGRAPH (inlinesToNodes xs) :)
-blockToNodes (LineBlock lns) = blockToNodes $ linesToPara lns
-blockToNodes (CodeBlock (_,classes,_) xs) =
- (node (CODE_BLOCK (T.pack (unwords classes)) (T.pack xs)) [] :)
-blockToNodes (RawBlock fmt xs)
- | fmt == Format "html" = (node (HTML_BLOCK (T.pack xs)) [] :)
- | otherwise = (node (CUSTOM_BLOCK (T.pack xs) (T.empty)) [] :)
-blockToNodes (BlockQuote bs) =
- (node BLOCK_QUOTE (blocksToNodes bs) :)
-blockToNodes (BulletList items) =
- (node (LIST ListAttributes{
- listType = BULLET_LIST,
- listDelim = PERIOD_DELIM,
- listTight = isTightList items,
- listStart = 1 }) (map (node ITEM . blocksToNodes) items) :)
-blockToNodes (OrderedList (start, _sty, delim) items) =
- (node (LIST ListAttributes{
- listType = ORDERED_LIST,
- listDelim = case delim of
- OneParen -> PAREN_DELIM
- TwoParens -> PAREN_DELIM
- _ -> PERIOD_DELIM,
- listTight = isTightList items,
- listStart = start }) (map (node ITEM . blocksToNodes) items) :)
-blockToNodes HorizontalRule = (node THEMATIC_BREAK [] :)
-blockToNodes (Header lev _ ils) = (node (HEADING lev) (inlinesToNodes ils) :)
-blockToNodes (Div _ bs) = (blocksToNodes bs ++)
-blockToNodes (DefinitionList items) = blockToNodes (BulletList items')
+blocksToNodes :: PandocMonad m => WriterOptions -> [Block] -> m [Node]
+blocksToNodes opts = foldrM (blockToNodes opts) []
+
+blockToNodes :: PandocMonad m => WriterOptions -> Block -> [Node] -> m [Node]
+blockToNodes opts (Plain xs) ns =
+ return (node PARAGRAPH (inlinesToNodes opts xs) : ns)
+blockToNodes opts (Para xs) ns =
+ return (node PARAGRAPH (inlinesToNodes opts xs) : ns)
+blockToNodes opts (LineBlock lns) ns = blockToNodes opts (linesToPara lns) ns
+blockToNodes _ (CodeBlock (_,classes,_) xs) ns = return
+ (node (CODE_BLOCK (T.pack (unwords classes)) (T.pack xs)) [] : ns)
+blockToNodes opts (RawBlock fmt xs) ns
+ | fmt == Format "html" && isEnabled Ext_raw_html opts
+ = return (node (HTML_BLOCK (T.pack xs)) [] : ns)
+ | fmt == Format "latex" || fmt == Format "tex" && isEnabled Ext_raw_tex opts
+ = return (node (CUSTOM_BLOCK (T.pack xs) T.empty) [] : ns)
+ | otherwise = return ns
+blockToNodes opts (BlockQuote bs) ns = do
+ nodes <- blocksToNodes opts bs
+ return (node BLOCK_QUOTE nodes : ns)
+blockToNodes opts (BulletList items) ns = do
+ nodes <- mapM (blocksToNodes opts) items
+ return (node (LIST ListAttributes{
+ listType = BULLET_LIST,
+ listDelim = PERIOD_DELIM,
+ listTight = isTightList items,
+ listStart = 1 }) (map (node ITEM) nodes) : ns)
+blockToNodes opts (OrderedList (start, _sty, delim) items) ns = do
+ nodes <- mapM (blocksToNodes opts) items
+ return (node (LIST ListAttributes{
+ listType = ORDERED_LIST,
+ listDelim = case delim of
+ OneParen -> PAREN_DELIM
+ TwoParens -> PAREN_DELIM
+ _ -> PERIOD_DELIM,
+ listTight = isTightList items,
+ listStart = start }) (map (node ITEM) nodes) : ns)
+blockToNodes _ HorizontalRule ns = return (node THEMATIC_BREAK [] : ns)
+blockToNodes opts (Header lev _ ils) ns =
+ return (node (HEADING lev) (inlinesToNodes opts ils) : ns)
+blockToNodes opts (Div attr bs) ns = do
+ nodes <- blocksToNodes opts bs
+ let op = tagWithAttributes opts True False "div" attr
+ if isEnabled Ext_raw_html opts
+ then return (node (HTML_BLOCK op) [] : nodes ++
+ [node (HTML_BLOCK (T.pack "</div>")) []] ++ ns)
+ else return (nodes ++ ns)
+blockToNodes opts (DefinitionList items) ns =
+ blockToNodes opts (BulletList items') ns
where items' = map dlToBullet items
- dlToBullet (term, ((Para xs : ys) : zs)) =
+ dlToBullet (term, (Para xs : ys) : zs) =
Para (term ++ [LineBreak] ++ xs) : ys ++ concat zs
- dlToBullet (term, ((Plain xs : ys) : zs)) =
+ dlToBullet (term, (Plain xs : ys) : zs) =
Plain (term ++ [LineBreak] ++ xs) : ys ++ concat zs
dlToBullet (term, xs) =
Para term : concat xs
-blockToNodes t@(Table _ _ _ _ _) =
- (node (HTML_BLOCK (T.pack $! writeHtmlString def $! Pandoc nullMeta [t])) [] :)
-blockToNodes Null = id
-
-inlinesToNodes :: [Inline] -> [Node]
-inlinesToNodes = foldr inlineToNodes []
-
-inlineToNodes :: Inline -> [Node] -> [Node]
-inlineToNodes (Str s) = (node (TEXT (T.pack s)) [] :)
-inlineToNodes Space = (node (TEXT (T.pack " ")) [] :)
-inlineToNodes LineBreak = (node LINEBREAK [] :)
-inlineToNodes SoftBreak = (node SOFTBREAK [] :)
-inlineToNodes (Emph xs) = (node EMPH (inlinesToNodes xs) :)
-inlineToNodes (Strong xs) = (node STRONG (inlinesToNodes xs) :)
-inlineToNodes (Strikeout xs) =
- ((node (HTML_INLINE (T.pack "<s>")) [] : inlinesToNodes xs ++
- [node (HTML_INLINE (T.pack "</s>")) []]) ++ )
-inlineToNodes (Superscript xs) =
- ((node (HTML_INLINE (T.pack "<sup>")) [] : inlinesToNodes xs ++
+blockToNodes opts t@(Table capt aligns _widths headers rows) ns = do
+ let allcells = concat (headers:rows)
+ let isLineBreak LineBreak = Any True
+ isLineBreak _ = Any False
+ let isPlainOrPara [Para _] = True
+ isPlainOrPara [Plain _] = True
+ isPlainOrPara [] = True
+ isPlainOrPara _ = False
+ let isSimple = all isPlainOrPara allcells &&
+ not ( getAny (query isLineBreak allcells) )
+ if isEnabled Ext_pipe_tables opts && isSimple
+ then do
+ -- We construct a table manually as a CUSTOM_BLOCK, for
+ -- two reasons: (1) cmark-gfm currently doesn't support
+ -- rendering TABLE nodes; (2) we can align the column sides;
+ -- (3) we can render the caption as a regular paragraph.
+ let capt' = node PARAGRAPH (inlinesToNodes opts capt)
+ -- backslash | in code and raw:
+ let fixPipe (Code attr xs) =
+ Code attr (substitute "|" "\\|" xs)
+ fixPipe (RawInline format xs) =
+ RawInline format (substitute "|" "\\|" xs)
+ fixPipe x = x
+ let toCell [Plain ils] = T.strip
+ $ nodeToCommonmark [] Nothing
+ $ node (CUSTOM_INLINE mempty mempty)
+ $ inlinesToNodes opts
+ $ walk (fixPipe . softBreakToSpace) ils
+ toCell [Para ils] = T.strip
+ $ nodeToCommonmark [] Nothing
+ $ node (CUSTOM_INLINE mempty mempty)
+ $ inlinesToNodes opts
+ $ walk (fixPipe . softBreakToSpace) ils
+ toCell [] = ""
+ toCell xs = error $ "toCell encountered " ++ show xs
+ let separator = " | "
+ let starter = "| "
+ let ender = " |"
+ let rawheaders = map toCell headers
+ let rawrows = map (map toCell) rows
+ let maximum' [] = 0
+ maximum' xs = maximum xs
+ let colwidths = map (maximum' . map T.length) $
+ transpose (rawheaders:rawrows)
+ let toHeaderLine len AlignDefault = T.replicate len "-"
+ toHeaderLine len AlignLeft = ":" <>
+ T.replicate (max (len - 1) 1) "-"
+ toHeaderLine len AlignRight =
+ T.replicate (max (len - 1) 1) "-" <> ":"
+ toHeaderLine len AlignCenter = ":" <>
+ T.replicate (max (len - 2) 1) (T.pack "-") <> ":"
+ let rawheaderlines = zipWith toHeaderLine colwidths aligns
+ let headerlines = starter <> T.intercalate separator rawheaderlines <>
+ ender
+ let padContent (align, w) t' =
+ let padding = w - T.length t'
+ halfpadding = padding `div` 2
+ in case align of
+ AlignRight -> T.replicate padding " " <> t'
+ AlignCenter -> T.replicate halfpadding " " <> t' <>
+ T.replicate (padding - halfpadding) " "
+ _ -> t' <> T.replicate padding " "
+ let toRow xs = starter <> T.intercalate separator
+ (zipWith padContent (zip aligns colwidths) xs) <>
+ ender
+ let table' = toRow rawheaders <> "\n" <> headerlines <> "\n" <>
+ T.intercalate "\n" (map toRow rawrows)
+ return (node (CUSTOM_BLOCK table' mempty) [] :
+ if null capt
+ then ns
+ else capt' : ns)
+ else do -- fall back to raw HTML
+ s <- writeHtml5String def $! Pandoc nullMeta [t]
+ return (node (HTML_BLOCK s) [] : ns)
+blockToNodes _ Null ns = return ns
+
+inlinesToNodes :: WriterOptions -> [Inline] -> [Node]
+inlinesToNodes opts = foldr (inlineToNodes opts) []
+
+inlineToNodes :: WriterOptions -> Inline -> [Node] -> [Node]
+inlineToNodes opts (Str s) = (node (TEXT (T.pack s')) [] :)
+ where s' = if isEnabled Ext_smart opts
+ then unsmartify opts s
+ else s
+inlineToNodes _ Space = (node (TEXT (T.pack " ")) [] :)
+inlineToNodes _ LineBreak = (node LINEBREAK [] :)
+inlineToNodes opts SoftBreak
+ | isEnabled Ext_hard_line_breaks opts = (node LINEBREAK [] :)
+ | writerWrapText opts == WrapNone = (node (TEXT " ") [] :)
+ | otherwise = (node SOFTBREAK [] :)
+inlineToNodes opts (Emph xs) = (node EMPH (inlinesToNodes opts xs) :)
+inlineToNodes opts (Strong xs) = (node STRONG (inlinesToNodes opts xs) :)
+inlineToNodes opts (Strikeout xs) =
+ if isEnabled Ext_strikeout opts
+ then (node (CUSTOM_INLINE "~~" "~~") (inlinesToNodes opts xs) :)
+ else ((node (HTML_INLINE (T.pack "<s>")) [] : inlinesToNodes opts xs ++
+ [node (HTML_INLINE (T.pack "</s>")) []]) ++ )
+inlineToNodes opts (Superscript xs) =
+ ((node (HTML_INLINE (T.pack "<sup>")) [] : inlinesToNodes opts xs ++
[node (HTML_INLINE (T.pack "</sup>")) []]) ++ )
-inlineToNodes (Subscript xs) =
- ((node (HTML_INLINE (T.pack "<sub>")) [] : inlinesToNodes xs ++
+inlineToNodes opts (Subscript xs) =
+ ((node (HTML_INLINE (T.pack "<sub>")) [] : inlinesToNodes opts xs ++
[node (HTML_INLINE (T.pack "</sub>")) []]) ++ )
-inlineToNodes (SmallCaps xs) =
- ((node (HTML_INLINE (T.pack "<span style=\"font-variant:small-caps;\">")) []
- : inlinesToNodes xs ++
+inlineToNodes opts (SmallCaps xs) =
+ ((node (HTML_INLINE (T.pack "<span class=\"smallcaps\">")) []
+ : inlinesToNodes opts xs ++
[node (HTML_INLINE (T.pack "</span>")) []]) ++ )
-inlineToNodes (Link _ ils (url,tit)) =
- (node (LINK (T.pack url) (T.pack tit)) (inlinesToNodes ils) :)
-inlineToNodes (Image _ ils (url,tit)) =
- (node (IMAGE (T.pack url) (T.pack tit)) (inlinesToNodes ils) :)
-inlineToNodes (RawInline fmt xs)
- | fmt == Format "html" = (node (HTML_INLINE (T.pack xs)) [] :)
- | otherwise = (node (CUSTOM_INLINE (T.pack xs) (T.empty)) [] :)
-inlineToNodes (Quoted qt ils) =
- ((node (TEXT start) [] : inlinesToNodes ils ++ [node (TEXT end) []]) ++)
+inlineToNodes opts (Link _ ils (url,tit)) =
+ (node (LINK (T.pack url) (T.pack tit)) (inlinesToNodes opts ils) :)
+-- title beginning with fig: indicates implicit figure
+inlineToNodes opts (Image alt ils (url,'f':'i':'g':':':tit)) =
+ inlineToNodes opts (Image alt ils (url,tit))
+inlineToNodes opts (Image _ ils (url,tit)) =
+ (node (IMAGE (T.pack url) (T.pack tit)) (inlinesToNodes opts ils) :)
+inlineToNodes opts (RawInline fmt xs)
+ | fmt == Format "html" && isEnabled Ext_raw_html opts
+ = (node (HTML_INLINE (T.pack xs)) [] :)
+ | (fmt == Format "latex" || fmt == Format "tex") && isEnabled Ext_raw_tex opts
+ = (node (CUSTOM_INLINE (T.pack xs) T.empty) [] :)
+ | otherwise = id
+inlineToNodes opts (Quoted qt ils) =
+ ((node (TEXT start) [] :
+ inlinesToNodes opts ils ++ [node (TEXT end) []]) ++)
where (start, end) = case qt of
- SingleQuote -> (T.pack "‘", T.pack "’")
- DoubleQuote -> (T.pack "“", T.pack "”")
-inlineToNodes (Code _ str) = (node (CODE (T.pack str)) [] :)
-inlineToNodes (Math mt str) =
- case mt of
- InlineMath ->
- (node (HTML_INLINE (T.pack ("\\(" ++ str ++ "\\)"))) [] :)
- DisplayMath ->
- (node (HTML_INLINE (T.pack ("\\[" ++ str ++ "\\]"))) [] :)
-inlineToNodes (Span _ ils) = (inlinesToNodes ils ++)
-inlineToNodes (Cite _ ils) = (inlinesToNodes ils ++)
-inlineToNodes (Note _) = id -- should not occur
+ SingleQuote
+ | isEnabled Ext_smart opts -> ("'","'")
+ | otherwise -> ("‘", "’")
+ DoubleQuote
+ | isEnabled Ext_smart opts -> ("\"", "\"")
+ | otherwise -> ("“", "”")
+inlineToNodes _ (Code _ str) = (node (CODE (T.pack str)) [] :)
+inlineToNodes opts (Math mt str) =
+ case writerHTMLMathMethod opts of
+ WebTeX url ->
+ let core = inlineToNodes opts
+ (Image nullAttr [Str str] (url ++ urlEncode str, str))
+ sep = if mt == DisplayMath
+ then (node LINEBREAK [] :)
+ else id
+ in (sep . core . sep)
+ _ ->
+ case mt of
+ InlineMath ->
+ (node (HTML_INLINE (T.pack ("\\(" ++ str ++ "\\)"))) [] :)
+ DisplayMath ->
+ (node (HTML_INLINE (T.pack ("\\[" ++ str ++ "\\]"))) [] :)
+inlineToNodes opts (Span attr ils) =
+ let nodes = inlinesToNodes opts ils
+ op = tagWithAttributes opts True False "span" attr
+ in if isEnabled Ext_raw_html opts
+ then ((node (HTML_INLINE op) [] : nodes ++
+ [node (HTML_INLINE (T.pack "</span>")) []]) ++)
+ else (nodes ++)
+inlineToNodes opts (Cite _ ils) = (inlinesToNodes opts ils ++)
+inlineToNodes _ (Note _) = id -- should not occur
-- we remove Note elements in preprocessing
diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
index c663c75ce..f94c12d89 100644
--- a/src/Text/Pandoc/Writers/ConTeXt.hs
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.ConTeXt
- Copyright : Copyright (C) 2007-2015 John MacFarlane
+ Copyright : Copyright (C) 2007-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,20 +30,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' format into ConTeXt.
-}
module Text.Pandoc.Writers.ConTeXt ( writeConTeXt ) where
+import Control.Monad.State.Strict
+import Data.Char (ord, isDigit)
+import Data.List (intercalate, intersperse)
+import Data.Maybe (mapMaybe)
+import Data.Text (Text)
+import Network.URI (unEscapeString)
+import Text.Pandoc.BCP47
+import Text.Pandoc.Class (PandocMonad, report, toLang)
import Text.Pandoc.Definition
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Walk (query)
-import Text.Printf ( printf )
-import Data.List ( intercalate, intersperse )
-import Data.Char ( ord )
-import Data.Maybe ( catMaybes )
-import Control.Monad.State
import Text.Pandoc.Pretty
-import Text.Pandoc.ImageSize
-import Text.Pandoc.Templates ( renderTemplate' )
-import Network.URI ( isURI, unEscapeString )
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Walk (query)
+import Text.Pandoc.Writers.Shared
+import Text.Printf (printf)
data WriterState =
WriterState { stNextRef :: Int -- number of next URL reference
@@ -50,37 +55,43 @@ data WriterState =
, stOptions :: WriterOptions -- writer options
}
+data Tabl = Xtb | Ntb deriving (Show, Eq)
+
orderedListStyles :: [Char]
orderedListStyles = cycle "narg"
-- | Convert Pandoc to ConTeXt.
-writeConTeXt :: WriterOptions -> Pandoc -> String
+writeConTeXt :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeConTeXt options document =
let defaultWriterState = WriterState { stNextRef = 1
, stOrderedListLevel = 0
, stOptions = options
}
- in evalState (pandocToConTeXt options document) defaultWriterState
+ in evalStateT (pandocToConTeXt options document) defaultWriterState
-pandocToConTeXt :: WriterOptions -> Pandoc -> State WriterState String
+type WM = StateT WriterState
+
+pandocToConTeXt :: PandocMonad m => WriterOptions -> Pandoc -> WM m Text
pandocToConTeXt options (Pandoc meta blocks) = do
let colwidth = if writerWrapText options == WrapAuto
then Just $ writerColumns options
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON options
- (fmap (render colwidth) . blockListToConTeXt)
- (fmap (render colwidth) . inlineListToConTeXt)
+ (fmap render' . blockListToConTeXt)
+ (fmap render' . inlineListToConTeXt)
meta
body <- mapM (elementToConTeXt options) $ hierarchicalize blocks
- let main = (render colwidth . vcat) body
- let layoutFromMargins = intercalate [','] $ catMaybes $
- map (\(x,y) ->
+ let main = (render' . vcat) body
+ let layoutFromMargins = intercalate [','] $ mapMaybe (\(x,y) ->
((x ++ "=") ++) <$> getField y metadata)
[("leftmargin","margin-left")
,("rightmargin","margin-right")
,("top","margin-top")
,("bottom","margin-bottom")
]
+ mblang <- fromBCP47 (getLang options meta)
let context = defField "toc" (writerTableOfContents options)
$ defField "placelist" (intercalate ("," :: String) $
take (writerTOCDepth options +
@@ -93,14 +104,17 @@ pandocToConTeXt options (Pandoc meta blocks) = do
$ defField "body" main
$ defField "layout" layoutFromMargins
$ defField "number-sections" (writerNumberSections options)
- $ metadata
- let context' = defField "context-lang" (maybe "" (fromBcp47 . splitBy (=='-')) $
- getField "lang" context)
- $ defField "context-dir" (toContextDir $ getField "dir" context)
- $ context
- return $ case writerTemplate options of
- Nothing -> main
- Just tpl -> renderTemplate' tpl context'
+ $ maybe id (defField "context-lang") mblang
+ $ (case getField "papersize" metadata of
+ Just (('a':d:ds) :: String)
+ | all isDigit (d:ds) -> resetField "papersize"
+ (('A':d:ds) :: String)
+ _ -> id) metadata
+ let context' = defField "context-dir" (toContextDir
+ $ getField "dir" context) context
+ case writerTemplate options of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context'
toContextDir :: Maybe String -> String
toContextDir (Just "rtl") = "r2l"
@@ -110,24 +124,24 @@ toContextDir _ = ""
-- | escape things as needed for ConTeXt
escapeCharForConTeXt :: WriterOptions -> Char -> String
escapeCharForConTeXt opts ch =
- let ligatures = writerTeXLigatures opts in
+ let ligatures = isEnabled Ext_smart opts in
case ch of
- '{' -> "\\{"
- '}' -> "\\}"
- '\\' -> "\\letterbackslash{}"
- '$' -> "\\$"
- '|' -> "\\letterbar{}"
- '%' -> "\\letterpercent{}"
- '~' -> "\\lettertilde{}"
- '#' -> "\\#"
- '[' -> "{[}"
- ']' -> "{]}"
- '\160' -> "~"
+ '{' -> "\\{"
+ '}' -> "\\}"
+ '\\' -> "\\letterbackslash{}"
+ '$' -> "\\$"
+ '|' -> "\\letterbar{}"
+ '%' -> "\\letterpercent{}"
+ '~' -> "\\lettertilde{}"
+ '#' -> "\\#"
+ '[' -> "{[}"
+ ']' -> "{]}"
+ '\160' -> "~"
'\x2014' | ligatures -> "---"
'\x2013' | ligatures -> "--"
'\x2019' | ligatures -> "'"
'\x2026' -> "\\ldots{}"
- x -> [x]
+ x -> [x]
-- | Escape string for ConTeXt
stringToConTeXt :: WriterOptions -> String -> String
@@ -137,20 +151,20 @@ stringToConTeXt opts = concatMap (escapeCharForConTeXt opts)
toLabel :: String -> String
toLabel z = concatMap go z
where go x
- | elem x ("\\#[]\",{}%()|=" :: String) = "ux" ++ printf "%x" (ord x)
+ | x `elem` ("\\#[]\",{}%()|=" :: String) = "ux" ++ printf "%x" (ord x)
| otherwise = [x]
-- | Convert Elements to ConTeXt
-elementToConTeXt :: WriterOptions -> Element -> State WriterState Doc
+elementToConTeXt :: PandocMonad m => WriterOptions -> Element -> WM m Doc
elementToConTeXt _ (Blk block) = blockToConTeXt block
elementToConTeXt opts (Sec level _ attr title' elements) = do
header' <- sectionHeader attr level title'
+ footer' <- sectionFooter attr level
innerContents <- mapM (elementToConTeXt opts) elements
- return $ vcat (header' : innerContents)
+ return $ header' $$ vcat innerContents $$ footer'
-- | Convert Pandoc block element to ConTeXt.
-blockToConTeXt :: Block
- -> State WriterState Doc
+blockToConTeXt :: PandocMonad m => Block -> WM m Doc
blockToConTeXt Null = return empty
blockToConTeXt (Plain lst) = inlineListToConTeXt lst
-- title beginning with fig: indicates that the image is a figure
@@ -175,9 +189,12 @@ blockToConTeXt (CodeBlock _ str) =
return $ flush ("\\starttyping" <> cr <> text str <> cr <> "\\stoptyping") $$ blankline
-- blankline because \stoptyping can't have anything after it, inc. '}'
blockToConTeXt (RawBlock "context" str) = return $ text str <> blankline
-blockToConTeXt (RawBlock _ _ ) = return empty
+blockToConTeXt b@(RawBlock _ _ ) = do
+ report $ BlockNotRendered b
+ return empty
blockToConTeXt (Div (ident,_,kvs) bs) = do
let align dir txt = "\\startalignment[" <> dir <> "]" $$ txt $$ "\\stopalignment"
+ mblang <- fromBCP47 (lookup "lang" kvs)
let wrapRef txt = if null ident
then txt
else ("\\reference" <> brackets (text $ toLabel ident) <>
@@ -186,12 +203,12 @@ blockToConTeXt (Div (ident,_,kvs) bs) = do
Just "rtl" -> align "righttoleft"
Just "ltr" -> align "lefttoright"
_ -> id
- wrapLang txt = case lookup "lang" kvs of
+ wrapLang txt = case mblang of
Just lng -> "\\start\\language["
- <> text (fromBcp47' lng) <> "]" $$ txt $$ "\\stop"
+ <> text lng <> "]" $$ txt $$ "\\stop"
Nothing -> txt
wrapBlank txt = blankline <> txt <> blankline
- fmap (wrapBlank . wrapLang . wrapDir . wrapRef) $ blockListToConTeXt bs
+ (wrapBlank . wrapLang . wrapDir . wrapRef) <$> blockListToConTeXt bs
blockToConTeXt (BulletList lst) = do
contents <- mapM listItemToConTeXt lst
return $ ("\\startitemize" <> if isTightList lst
@@ -201,9 +218,9 @@ blockToConTeXt (BulletList lst) = do
blockToConTeXt (OrderedList (start, style', delim) lst) = do
st <- get
let level = stOrderedListLevel st
- put $ st {stOrderedListLevel = level + 1}
+ put st {stOrderedListLevel = level + 1}
contents <- mapM listItemToConTeXt lst
- put $ st {stOrderedListLevel = level}
+ put st {stOrderedListLevel = level}
let start' = if start == 1 then "" else "start=" ++ show start
let delim' = case delim of
DefaultDelim -> ""
@@ -238,39 +255,83 @@ blockToConTeXt HorizontalRule = return $ "\\thinrule" <> blankline
-- If this is ever executed, provide a default for the reference identifier.
blockToConTeXt (Header level attr lst) = sectionHeader attr level lst
blockToConTeXt (Table caption aligns widths heads rows) = do
- let colDescriptor colWidth alignment = (case alignment of
- AlignLeft -> 'l'
- AlignRight -> 'r'
- AlignCenter -> 'c'
- AlignDefault -> 'l'):
- if colWidth == 0
- then "|"
- else ("p(" ++ printf "%.2f" colWidth ++ "\\textwidth)|")
- let colDescriptors = "|" ++ (concat $
- zipWith colDescriptor widths aligns)
- headers <- if all null heads
- then return empty
- else liftM ($$ "\\HL") $ tableRowToConTeXt heads
+ opts <- gets stOptions
+ let tabl = if isEnabled Ext_ntb opts
+ then Ntb
+ else Xtb
captionText <- inlineListToConTeXt caption
- rows' <- mapM tableRowToConTeXt rows
- return $ "\\placetable" <> (if null caption
- then brackets "none"
- else empty)
- <> braces captionText $$
- "\\starttable" <> brackets (text colDescriptors) $$
- "\\HL" $$ headers $$
- vcat rows' $$ "\\HL" $$ "\\stoptable" <> blankline
-
-tableRowToConTeXt :: [[Block]] -> State WriterState Doc
-tableRowToConTeXt cols = do
- cols' <- mapM blockListToConTeXt cols
- return $ (vcat (map ("\\NC " <>) cols')) $$ "\\NC\\AR"
-
-listItemToConTeXt :: [Block] -> State WriterState Doc
+ headers <- if all null heads
+ then return empty
+ else tableRowToConTeXt tabl aligns widths heads
+ rows' <- mapM (tableRowToConTeXt tabl aligns widths) rows
+ body <- tableToConTeXt tabl headers rows'
+ return $ "\\startplacetable" <> brackets (
+ if null caption
+ then "location=none"
+ else "title=" <> braces captionText
+ ) $$ body $$ "\\stopplacetable" <> blankline
+
+tableToConTeXt :: PandocMonad m => Tabl -> Doc -> [Doc] -> WM m Doc
+tableToConTeXt Xtb heads rows =
+ return $ "\\startxtable" $$
+ (if isEmpty heads
+ then empty
+ else "\\startxtablehead[head]" $$ heads $$ "\\stopxtablehead") $$
+ (if null rows
+ then empty
+ else "\\startxtablebody[body]" $$ vcat (init rows) $$ "\\stopxtablebody" $$
+ "\\startxtablefoot[foot]" $$ last rows $$ "\\stopxtablefoot") $$
+ "\\stopxtable"
+tableToConTeXt Ntb heads rows =
+ return $ "\\startTABLE" $$
+ (if isEmpty heads
+ then empty
+ else "\\startTABLEhead" $$ heads $$ "\\stopTABLEhead") $$
+ (if null rows
+ then empty
+ else "\\startTABLEbody" $$ vcat (init rows) $$ "\\stopTABLEbody" $$
+ "\\startTABLEfoot" $$ last rows $$ "\\stopTABLEfoot") $$
+ "\\stopTABLE"
+
+tableRowToConTeXt :: PandocMonad m => Tabl -> [Alignment] -> [Double] -> [[Block]] -> WM m Doc
+tableRowToConTeXt Xtb aligns widths cols = do
+ cells <- mapM (tableColToConTeXt Xtb) $ zip3 aligns widths cols
+ return $ "\\startxrow" $$ vcat cells $$ "\\stopxrow"
+tableRowToConTeXt Ntb aligns widths cols = do
+ cells <- mapM (tableColToConTeXt Ntb) $ zip3 aligns widths cols
+ return $ vcat cells $$ "\\NC\\NR"
+
+tableColToConTeXt :: PandocMonad m => Tabl -> (Alignment, Double, [Block]) -> WM m Doc
+tableColToConTeXt tabl (align, width, blocks) = do
+ cellContents <- blockListToConTeXt blocks
+ let colwidth = if width == 0
+ then empty
+ else "width=" <> braces (text (printf "%.2f\\textwidth" width))
+ let halign = alignToConTeXt align
+ let options = (if keys == empty
+ then empty
+ else brackets keys) <> space
+ where keys = hcat $ intersperse "," $ filter (empty /=) [halign, colwidth]
+ tableCellToConTeXt tabl options cellContents
+
+tableCellToConTeXt :: PandocMonad m => Tabl -> Doc -> Doc -> WM m Doc
+tableCellToConTeXt Xtb options cellContents =
+ return $ "\\startxcell" <> options <> cellContents <> " \\stopxcell"
+tableCellToConTeXt Ntb options cellContents =
+ return $ "\\NC" <> options <> cellContents
+
+alignToConTeXt :: Alignment -> Doc
+alignToConTeXt align = case align of
+ AlignLeft -> "align=right"
+ AlignRight -> "align=left"
+ AlignCenter -> "align=middle"
+ AlignDefault -> empty
+
+listItemToConTeXt :: PandocMonad m => [Block] -> WM m Doc
listItemToConTeXt list = blockListToConTeXt list >>=
- return . ("\\item" $$) . (nest 2)
+ return . ("\\item" $$) . nest 2
-defListItemToConTeXt :: ([Inline], [[Block]]) -> State WriterState Doc
+defListItemToConTeXt :: PandocMonad m => ([Inline], [[Block]]) -> WM m Doc
defListItemToConTeXt (term, defs) = do
term' <- inlineListToConTeXt term
def' <- liftM vsep $ mapM blockListToConTeXt defs
@@ -278,12 +339,13 @@ defListItemToConTeXt (term, defs) = do
"\\stopdescription" <> blankline
-- | Convert list of block elements to ConTeXt.
-blockListToConTeXt :: [Block] -> State WriterState Doc
+blockListToConTeXt :: PandocMonad m => [Block] -> WM m Doc
blockListToConTeXt lst = liftM vcat $ mapM blockToConTeXt lst
-- | Convert list of inline elements to ConTeXt.
-inlineListToConTeXt :: [Inline] -- ^ Inlines to convert
- -> State WriterState Doc
+inlineListToConTeXt :: PandocMonad m
+ => [Inline] -- ^ Inlines to convert
+ -> WM m Doc
inlineListToConTeXt lst = liftM hcat $ mapM inlineToConTeXt $ addStruts lst
-- We add a \strut after a line break that precedes a space,
-- or the space gets swallowed
@@ -292,13 +354,14 @@ inlineListToConTeXt lst = liftM hcat $ mapM inlineToConTeXt $ addStruts lst
addStruts xs
addStruts (x:xs) = x : addStruts xs
addStruts [] = []
- isSpacey Space = True
+ isSpacey Space = True
isSpacey (Str ('\160':_)) = True
- isSpacey _ = False
+ isSpacey _ = False
-- | Convert inline element to ConTeXt
-inlineToConTeXt :: Inline -- ^ Inline to convert
- -> State WriterState Doc
+inlineToConTeXt :: PandocMonad m
+ => Inline -- ^ Inline to convert
+ -> WM m Doc
inlineToConTeXt (Emph lst) = do
contents <- inlineListToConTeXt lst
return $ braces $ "\\em " <> contents
@@ -338,8 +401,10 @@ inlineToConTeXt (Math DisplayMath str) =
return $ text "\\startformula " <> text str <> text " \\stopformula" <> space
inlineToConTeXt (RawInline "context" str) = return $ text str
inlineToConTeXt (RawInline "tex" str) = return $ text str
-inlineToConTeXt (RawInline _ _) = return empty
-inlineToConTeXt (LineBreak) = return $ text "\\crlf" <> cr
+inlineToConTeXt il@(RawInline _ _) = do
+ report $ InlineNotRendered il
+ return empty
+inlineToConTeXt LineBreak = return $ text "\\crlf" <> cr
inlineToConTeXt SoftBreak = do
wrapText <- gets (writerWrapText . stOptions)
return $ case wrapText of
@@ -348,7 +413,7 @@ inlineToConTeXt SoftBreak = do
WrapPreserve -> cr
inlineToConTeXt Space = return space
-- Handle HTML-like internal document references to sections
-inlineToConTeXt (Link _ txt (('#' : ref), _)) = do
+inlineToConTeXt (Link _ txt ('#' : ref, _)) = do
opts <- gets stOptions
contents <- inlineListToConTeXt txt
let ref' = toLabel $ stringToConTeXt opts ref
@@ -374,7 +439,7 @@ inlineToConTeXt (Link _ txt (src, _)) = do
inlineToConTeXt (Image attr@(_,cls,_) _ (src, _)) = do
opts <- gets stOptions
let showDim dir = let d = text (show dir) <> "="
- in case (dimension dir attr) of
+ in case dimension dir attr of
Just (Pixel a) ->
[d <> text (showInInch opts (Pixel a)) <> "in"]
Just (Percent a) ->
@@ -397,84 +462,104 @@ inlineToConTeXt (Image attr@(_,cls,_) _ (src, _)) = do
inlineToConTeXt (Note contents) = do
contents' <- blockListToConTeXt contents
let codeBlock x@(CodeBlock _ _) = [x]
- codeBlock _ = []
+ codeBlock _ = []
let codeBlocks = query codeBlock contents
return $ if null codeBlocks
then text "\\footnote{" <> nest 2 contents' <> char '}'
else text "\\startbuffer " <> nest 2 contents' <>
text "\\stopbuffer\\footnote{\\getbuffer}"
inlineToConTeXt (Span (_,_,kvs) ils) = do
+ mblang <- fromBCP47 (lookup "lang" kvs)
let wrapDir txt = case lookup "dir" kvs of
Just "rtl" -> braces $ "\\righttoleft " <> txt
Just "ltr" -> braces $ "\\lefttoright " <> txt
_ -> txt
- wrapLang txt = case lookup "lang" kvs of
- Just lng -> "\\start\\language[" <> text (fromBcp47' lng)
+ wrapLang txt = case mblang of
+ Just lng -> "\\start\\language[" <> text lng
<> "]" <> txt <> "\\stop "
Nothing -> txt
- fmap (wrapLang . wrapDir) $ inlineListToConTeXt ils
+ (wrapLang . wrapDir) <$> inlineListToConTeXt ils
-- | Craft the section header, inserting the section reference, if supplied.
-sectionHeader :: Attr
+sectionHeader :: PandocMonad m
+ => Attr
-> Int
-> [Inline]
- -> State WriterState Doc
-sectionHeader (ident,classes,_) hdrLevel lst = do
+ -> WM m Doc
+sectionHeader (ident,classes,kvs) hdrLevel lst = do
+ opts <- gets stOptions
contents <- inlineListToConTeXt lst
- st <- get
- let opts = stOptions st
+ levelText <- sectionLevelToText opts (ident,classes,kvs) hdrLevel
+ let ident' = if null ident
+ then empty
+ else "reference=" <> braces (text (toLabel ident))
+ let contents' = if contents == empty
+ then empty
+ else "title=" <> braces contents
+ let options = if keys == empty || levelText == empty
+ then empty
+ else brackets keys
+ where keys = hcat $ intersperse "," $ filter (empty /=) [contents', ident']
+ let starter = if writerSectionDivs opts
+ then "\\start"
+ else "\\"
+ return $ starter <> levelText <> options <> blankline
+
+-- | Craft the section footer
+sectionFooter :: PandocMonad m => Attr -> Int -> WM m Doc
+sectionFooter attr hdrLevel = do
+ opts <- gets stOptions
+ levelText <- sectionLevelToText opts attr hdrLevel
+ return $ if writerSectionDivs opts
+ then "\\stop" <> levelText <> blankline
+ else empty
+
+-- | Generate a textual representation of the section level
+sectionLevelToText :: PandocMonad m => WriterOptions -> Attr -> Int -> WM m Doc
+sectionLevelToText opts (_,classes,_) hdrLevel = do
let level' = case writerTopLevelDivision opts of
TopLevelPart -> hdrLevel - 2
TopLevelChapter -> hdrLevel - 1
TopLevelSection -> hdrLevel
TopLevelDefault -> hdrLevel
- let ident' = toLabel ident
let (section, chapter) = if "unnumbered" `elem` classes
then (text "subject", text "title")
else (text "section", text "chapter")
return $ case level' of
- -1 -> text "\\part" <> braces contents
- 0 -> char '\\' <> chapter <> braces contents
- n | n >= 1 && n <= 5 -> char '\\'
- <> text (concat (replicate (n - 1) "sub"))
- <> section
- <> (if (not . null) ident'
- then brackets (text ident')
- else empty)
- <> braces contents
- <> blankline
- _ -> contents <> blankline
-
-fromBcp47' :: String -> String
-fromBcp47' = fromBcp47 . splitBy (=='-')
+ -1 -> text "part"
+ 0 -> chapter
+ n | n >= 1 -> text (concat (replicate (n - 1) "sub"))
+ <> section
+ _ -> empty -- cannot happen
+
+fromBCP47 :: PandocMonad m => Maybe String -> WM m (Maybe String)
+fromBCP47 mbs = fromBCP47' <$> toLang mbs
-- Takes a list of the constituents of a BCP 47 language code
-- and irons out ConTeXt's exceptions
-- https://tools.ietf.org/html/bcp47#section-2.1
-- http://wiki.contextgarden.net/Language_Codes
-fromBcp47 :: [String] -> String
-fromBcp47 [] = ""
-fromBcp47 ("ar":"SY":_) = "ar-sy"
-fromBcp47 ("ar":"IQ":_) = "ar-iq"
-fromBcp47 ("ar":"JO":_) = "ar-jo"
-fromBcp47 ("ar":"LB":_) = "ar-lb"
-fromBcp47 ("ar":"DZ":_) = "ar-dz"
-fromBcp47 ("ar":"MA":_) = "ar-ma"
-fromBcp47 ("de":"1901":_) = "deo"
-fromBcp47 ("de":"DE":_) = "de-de"
-fromBcp47 ("de":"AT":_) = "de-at"
-fromBcp47 ("de":"CH":_) = "de-ch"
-fromBcp47 ("el":"poly":_) = "agr"
-fromBcp47 ("en":"US":_) = "en-us"
-fromBcp47 ("en":"GB":_) = "en-gb"
-fromBcp47 ("grc":_) = "agr"
-fromBcp47 x = fromIso $ head x
- where
- fromIso "el" = "gr"
- fromIso "eu" = "ba"
- fromIso "he" = "il"
- fromIso "jp" = "ja"
- fromIso "uk" = "ua"
- fromIso "vi" = "vn"
- fromIso "zh" = "cn"
- fromIso l = l
+fromBCP47' :: Maybe Lang -> Maybe String
+fromBCP47' (Just (Lang "ar" _ "SY" _) ) = Just "ar-sy"
+fromBCP47' (Just (Lang "ar" _ "IQ" _) ) = Just "ar-iq"
+fromBCP47' (Just (Lang "ar" _ "JO" _) ) = Just "ar-jo"
+fromBCP47' (Just (Lang "ar" _ "LB" _) ) = Just "ar-lb"
+fromBCP47' (Just (Lang "ar" _ "DZ" _) ) = Just "ar-dz"
+fromBCP47' (Just (Lang "ar" _ "MA" _) ) = Just "ar-ma"
+fromBCP47' (Just (Lang "de" _ _ ["1901"]) ) = Just "deo"
+fromBCP47' (Just (Lang "de" _ "DE" _) ) = Just "de-de"
+fromBCP47' (Just (Lang "de" _ "AT" _) ) = Just "de-at"
+fromBCP47' (Just (Lang "de" _ "CH" _) ) = Just "de-ch"
+fromBCP47' (Just (Lang "el" _ _ ["poly"]) ) = Just "agr"
+fromBCP47' (Just (Lang "en" _ "US" _) ) = Just "en-us"
+fromBCP47' (Just (Lang "en" _ "GB" _) ) = Just "en-gb"
+fromBCP47' (Just (Lang "grc"_ _ _) ) = Just "agr"
+fromBCP47' (Just (Lang "el" _ _ _) ) = Just "gr"
+fromBCP47' (Just (Lang "eu" _ _ _) ) = Just "ba"
+fromBCP47' (Just (Lang "he" _ _ _) ) = Just "il"
+fromBCP47' (Just (Lang "jp" _ _ _) ) = Just "ja"
+fromBCP47' (Just (Lang "uk" _ _ _) ) = Just "ua"
+fromBCP47' (Just (Lang "vi" _ _ _) ) = Just "vn"
+fromBCP47' (Just (Lang "zh" _ _ _) ) = Just "cn"
+fromBCP47' (Just (Lang l _ _ _) ) = Just l
+fromBCP47' Nothing = Nothing
diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs
index cf641dcd6..3daa8d0cf 100644
--- a/src/Text/Pandoc/Writers/Custom.hs
+++ b/src/Text/Pandoc/Writers/Custom.hs
@@ -1,11 +1,6 @@
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-{-# LANGUAGE FlexibleInstances, OverloadedStrings,
- ScopedTypeVariables, DeriveDataTypeable, CPP #-}
-#if MIN_VERSION_base(4,8,0)
-#else
-{-# LANGUAGE OverlappingInstances #-}
-#endif
-{- Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE FlexibleInstances #-}
+{- Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Custom
- Copyright : Copyright (C) 2012-2015 John MacFarlane
+ Copyright : Copyright (C) 2012-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,20 +30,27 @@ Conversion of 'Pandoc' documents to custom markup using
a lua writer.
-}
module Text.Pandoc.Writers.Custom ( writeCustom ) where
-import Text.Pandoc.Definition
-import Text.Pandoc.Options
-import Data.List ( intersperse )
-import Data.Char ( toLower )
-import Data.Typeable
-import Scripting.Lua (LuaState, StackValue, callfunc)
-import Text.Pandoc.Writers.Shared
-import qualified Scripting.Lua as Lua
-import qualified Text.Pandoc.UTF8 as UTF8
-import Control.Monad (when)
+import Control.Arrow ((***))
import Control.Exception
+import Control.Monad (when)
+import Control.Monad.Trans (MonadIO (liftIO))
+import Data.Char (toLower)
+import Data.List (intersperse)
import qualified Data.Map as M
+import Data.Text (Text, pack)
+import Data.Typeable
+import Foreign.Lua (Lua, ToLuaStack (..), callFunc)
+import Foreign.Lua.Api
+import Text.Pandoc.Class (PandocIO)
+import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath)
+import Text.Pandoc.Lua.StackInstances ()
+import Text.Pandoc.Lua.Util (addValue, dostring')
+import Text.Pandoc.Options
import Text.Pandoc.Templates
-import GHC.IO.Encoding (getForeignEncoding,setForeignEncoding, utf8)
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.Pandoc.Writers.Shared
attrToMap :: Attr -> M.Map String String
attrToMap (id',classes,keyvals) = M.fromList
@@ -56,119 +58,43 @@ attrToMap (id',classes,keyvals) = M.fromList
: ("class", unwords classes)
: keyvals
-#if MIN_VERSION_hslua(0,4,0)
-#if MIN_VERSION_base(4,8,0)
-instance {-# OVERLAPS #-} StackValue [Char] where
-#else
-instance StackValue [Char] where
-#endif
- push lua cs = Lua.push lua (UTF8.fromString cs)
- peek lua i = do
- res <- Lua.peek lua i
- return $ UTF8.toString `fmap` res
- valuetype _ = Lua.TSTRING
-#else
-#if MIN_VERSION_base(4,8,0)
-instance {-# OVERLAPS #-} StackValue a => StackValue [a] where
-#else
-instance StackValue a => StackValue [a] where
-#endif
- push lua xs = do
- Lua.createtable lua (length xs + 1) 0
- let addValue (i, x) = Lua.push lua x >> Lua.rawseti lua (-2) i
- mapM_ addValue $ zip [1..] xs
- peek lua i = do
- top <- Lua.gettop lua
- let i' = if i < 0 then top + i + 1 else i
- Lua.pushnil lua
- lst <- getList lua i'
- Lua.pop lua 1
- return (Just lst)
- valuetype _ = Lua.TTABLE
-
-getList :: StackValue a => LuaState -> Int -> IO [a]
-getList lua i' = do
- continue <- Lua.next lua i'
- if continue
- then do
- next <- Lua.peek lua (-1)
- Lua.pop lua 1
- x <- maybe (fail "peek returned Nothing") return next
- rest <- getList lua i'
- return (x : rest)
- else return []
-#endif
-
-instance StackValue Format where
- push lua (Format f) = Lua.push lua (map toLower f)
- peek l n = fmap Format `fmap` Lua.peek l n
- valuetype _ = Lua.TSTRING
-
-instance (StackValue a, StackValue b) => StackValue (M.Map a b) where
- push lua m = do
- let xs = M.toList m
- Lua.createtable lua (length xs + 1) 0
- let addValue (k, v) = Lua.push lua k >> Lua.push lua v >>
- Lua.rawset lua (-3)
- mapM_ addValue xs
- peek _ _ = undefined -- not needed for our purposes
- valuetype _ = Lua.TTABLE
-
-instance (StackValue a, StackValue b) => StackValue (a,b) where
- push lua (k,v) = do
- Lua.createtable lua 2 0
- Lua.push lua k
- Lua.push lua v
- Lua.rawset lua (-3)
- peek _ _ = undefined -- not needed for our purposes
- valuetype _ = Lua.TTABLE
-
-#if MIN_VERSION_base(4,8,0)
-instance {-# OVERLAPS #-} StackValue [Inline] where
-#else
-instance StackValue [Inline] where
-#endif
- push l ils = Lua.push l =<< inlineListToCustom l ils
- peek _ _ = undefined
- valuetype _ = Lua.TSTRING
-
-#if MIN_VERSION_base(4,8,0)
-instance {-# OVERLAPS #-} StackValue [Block] where
-#else
-instance StackValue [Block] where
-#endif
- push l ils = Lua.push l =<< blockListToCustom l ils
- peek _ _ = undefined
- valuetype _ = Lua.TSTRING
-
-instance StackValue MetaValue where
- push l (MetaMap m) = Lua.push l m
- push l (MetaList xs) = Lua.push l xs
- push l (MetaBool x) = Lua.push l x
- push l (MetaString s) = Lua.push l s
- push l (MetaInlines ils) = Lua.push l ils
- push l (MetaBlocks bs) = Lua.push l bs
- peek _ _ = undefined
- valuetype (MetaMap _) = Lua.TTABLE
- valuetype (MetaList _) = Lua.TTABLE
- valuetype (MetaBool _) = Lua.TBOOLEAN
- valuetype (MetaString _) = Lua.TSTRING
- valuetype (MetaInlines _) = Lua.TSTRING
- valuetype (MetaBlocks _) = Lua.TSTRING
-
-instance StackValue Citation where
- push lua cit = do
- Lua.createtable lua 6 0
- let addValue (k :: String, v) = Lua.push lua k >> Lua.push lua v >>
- Lua.rawset lua (-3)
- addValue ("citationId", citationId cit)
- addValue ("citationPrefix", citationPrefix cit)
- addValue ("citationSuffix", citationSuffix cit)
- addValue ("citationMode", show (citationMode cit))
- addValue ("citationNoteNum", citationNoteNum cit)
- addValue ("citationHash", citationHash cit)
- peek = undefined
- valuetype _ = Lua.TTABLE
+newtype Stringify a = Stringify a
+
+instance ToLuaStack (Stringify Format) where
+ push (Stringify (Format f)) = push (map toLower f)
+
+instance ToLuaStack (Stringify [Inline]) where
+ push (Stringify ils) = push =<< inlineListToCustom ils
+
+instance ToLuaStack (Stringify [Block]) where
+ push (Stringify blks) = push =<< blockListToCustom blks
+
+instance ToLuaStack (Stringify MetaValue) where
+ push (Stringify (MetaMap m)) = push (fmap Stringify m)
+ push (Stringify (MetaList xs)) = push (map Stringify xs)
+ push (Stringify (MetaBool x)) = push x
+ push (Stringify (MetaString s)) = push s
+ push (Stringify (MetaInlines ils)) = push (Stringify ils)
+ push (Stringify (MetaBlocks bs)) = push (Stringify bs)
+
+instance ToLuaStack (Stringify Citation) where
+ push (Stringify cit) = do
+ createtable 6 0
+ addValue "citationId" $ citationId cit
+ addValue "citationPrefix" . Stringify $ citationPrefix cit
+ addValue "citationSuffix" . Stringify $ citationSuffix cit
+ addValue "citationMode" $ show (citationMode cit)
+ addValue "citationNoteNum" $ citationNoteNum cit
+ addValue "citationHash" $ citationHash cit
+
+-- | Key-value pair, pushed as a table with @a@ as the only key and @v@ as the
+-- associated value.
+newtype KeyValue a b = KeyValue (a, b)
+
+instance (ToLuaStack a, ToLuaStack b) => ToLuaStack (KeyValue a b) where
+ push (KeyValue (k, v)) = do
+ newtable
+ addValue k v
data PandocLuaException = PandocLuaException String
deriving (Show, Typeable)
@@ -176,147 +102,147 @@ data PandocLuaException = PandocLuaException String
instance Exception PandocLuaException
-- | Convert Pandoc to custom markup.
-writeCustom :: FilePath -> WriterOptions -> Pandoc -> IO String
+writeCustom :: FilePath -> WriterOptions -> Pandoc -> PandocIO Text
writeCustom luaFile opts doc@(Pandoc meta _) = do
- luaScript <- UTF8.readFile luaFile
- enc <- getForeignEncoding
- setForeignEncoding utf8
- lua <- Lua.newstate
- Lua.openlibs lua
- status <- Lua.loadstring lua luaScript luaFile
- -- check for error in lua script (later we'll change the return type
- -- to handle this more gracefully):
- when (status /= 0) $
-#if MIN_VERSION_hslua(0,4,0)
- Lua.tostring lua 1 >>= throw . PandocLuaException . UTF8.toString
-#else
- Lua.tostring lua 1 >>= throw . PandocLuaException
-#endif
- Lua.call lua 0 0
- -- TODO - call hierarchicalize, so we have that info
- rendered <- docToCustom lua opts doc
- context <- metaToJSON opts
- (blockListToCustom lua)
- (inlineListToCustom lua)
- meta
- Lua.close lua
- setForeignEncoding enc
- let body = rendered
+ luaScript <- liftIO $ UTF8.readFile luaFile
+ res <- runPandocLua $ do
+ registerScriptPath luaFile
+ stat <- dostring' luaScript
+ -- check for error in lua script (later we'll change the return type
+ -- to handle this more gracefully):
+ when (stat /= OK) $
+ tostring 1 >>= throw . PandocLuaException . UTF8.toString
+ -- TODO - call hierarchicalize, so we have that info
+ rendered <- docToCustom opts doc
+ context <- metaToJSON opts
+ blockListToCustom
+ inlineListToCustom
+ meta
+ return (rendered, context)
+ let (body, context) = case res of
+ Left e -> throw (PandocLuaException (show e))
+ Right x -> x
case writerTemplate opts of
- Nothing -> return body
- Just tpl -> return $ renderTemplate' tpl $ setField "body" body context
+ Nothing -> return $ pack body
+ Just tpl ->
+ case applyTemplate (pack tpl) $ setField "body" body context of
+ Left e -> throw (PandocTemplateError e)
+ Right r -> return (pack r)
-docToCustom :: LuaState -> WriterOptions -> Pandoc -> IO String
-docToCustom lua opts (Pandoc (Meta metamap) blocks) = do
- body <- blockListToCustom lua blocks
- callfunc lua "Doc" body metamap (writerVariables opts)
+docToCustom :: WriterOptions -> Pandoc -> Lua String
+docToCustom opts (Pandoc (Meta metamap) blocks) = do
+ body <- blockListToCustom blocks
+ callFunc "Doc" body (fmap Stringify metamap) (writerVariables opts)
-- | Convert Pandoc block element to Custom.
-blockToCustom :: LuaState -- ^ Lua state
- -> Block -- ^ Block element
- -> IO String
+blockToCustom :: Block -- ^ Block element
+ -> Lua String
-blockToCustom _ Null = return ""
+blockToCustom Null = return ""
-blockToCustom lua (Plain inlines) = callfunc lua "Plain" inlines
+blockToCustom (Plain inlines) = callFunc "Plain" (Stringify inlines)
-blockToCustom lua (Para [Image attr txt (src,tit)]) =
- callfunc lua "CaptionedImage" src tit txt (attrToMap attr)
+blockToCustom (Para [Image attr txt (src,tit)]) =
+ callFunc "CaptionedImage" src tit (Stringify txt) (attrToMap attr)
-blockToCustom lua (Para inlines) = callfunc lua "Para" inlines
+blockToCustom (Para inlines) = callFunc "Para" (Stringify inlines)
-blockToCustom lua (LineBlock linesList) = callfunc lua "LineBlock" linesList
+blockToCustom (LineBlock linesList) = callFunc "LineBlock" (map Stringify linesList)
-blockToCustom lua (RawBlock format str) =
- callfunc lua "RawBlock" format str
+blockToCustom (RawBlock format str) =
+ callFunc "RawBlock" (Stringify format) str
-blockToCustom lua HorizontalRule = callfunc lua "HorizontalRule"
+blockToCustom HorizontalRule = callFunc "HorizontalRule"
-blockToCustom lua (Header level attr inlines) =
- callfunc lua "Header" level inlines (attrToMap attr)
+blockToCustom (Header level attr inlines) =
+ callFunc "Header" level (Stringify inlines) (attrToMap attr)
-blockToCustom lua (CodeBlock attr str) =
- callfunc lua "CodeBlock" str (attrToMap attr)
+blockToCustom (CodeBlock attr str) =
+ callFunc "CodeBlock" str (attrToMap attr)
-blockToCustom lua (BlockQuote blocks) = callfunc lua "BlockQuote" blocks
+blockToCustom (BlockQuote blocks) = callFunc "BlockQuote" (Stringify blocks)
-blockToCustom lua (Table capt aligns widths headers rows') =
- callfunc lua "Table" capt (map show aligns) widths headers rows'
+blockToCustom (Table capt aligns widths headers rows) =
+ let aligns' = map show aligns
+ capt' = Stringify capt
+ headers' = map Stringify headers
+ rows' = map (map Stringify) rows
+ in callFunc "Table" capt' aligns' widths headers' rows'
-blockToCustom lua (BulletList items) = callfunc lua "BulletList" items
+blockToCustom (BulletList items) = callFunc "BulletList" (map Stringify items)
-blockToCustom lua (OrderedList (num,sty,delim) items) =
- callfunc lua "OrderedList" items num (show sty) (show delim)
+blockToCustom (OrderedList (num,sty,delim) items) =
+ callFunc "OrderedList" (map Stringify items) num (show sty) (show delim)
-blockToCustom lua (DefinitionList items) =
- callfunc lua "DefinitionList" items
+blockToCustom (DefinitionList items) =
+ callFunc "DefinitionList"
+ (map (KeyValue . (Stringify *** map Stringify)) items)
-blockToCustom lua (Div attr items) =
- callfunc lua "Div" items (attrToMap attr)
+blockToCustom (Div attr items) =
+ callFunc "Div" (Stringify items) (attrToMap attr)
-- | Convert list of Pandoc block elements to Custom.
-blockListToCustom :: LuaState -- ^ Options
- -> [Block] -- ^ List of block elements
- -> IO String
-blockListToCustom lua xs = do
- blocksep <- callfunc lua "Blocksep"
- bs <- mapM (blockToCustom lua) xs
+blockListToCustom :: [Block] -- ^ List of block elements
+ -> Lua String
+blockListToCustom xs = do
+ blocksep <- callFunc "Blocksep"
+ bs <- mapM blockToCustom xs
return $ mconcat $ intersperse blocksep bs
-- | Convert list of Pandoc inline elements to Custom.
-inlineListToCustom :: LuaState -> [Inline] -> IO String
-inlineListToCustom lua lst = do
- xs <- mapM (inlineToCustom lua) lst
- return $ concat xs
+inlineListToCustom :: [Inline] -> Lua String
+inlineListToCustom lst = do
+ xs <- mapM inlineToCustom lst
+ return $ mconcat xs
-- | Convert Pandoc inline element to Custom.
-inlineToCustom :: LuaState -> Inline -> IO String
+inlineToCustom :: Inline -> Lua String
-inlineToCustom lua (Str str) = callfunc lua "Str" str
+inlineToCustom (Str str) = callFunc "Str" str
-inlineToCustom lua Space = callfunc lua "Space"
+inlineToCustom Space = callFunc "Space"
-inlineToCustom lua SoftBreak = callfunc lua "SoftBreak"
+inlineToCustom SoftBreak = callFunc "SoftBreak"
-inlineToCustom lua (Emph lst) = callfunc lua "Emph" lst
+inlineToCustom (Emph lst) = callFunc "Emph" (Stringify lst)
-inlineToCustom lua (Strong lst) = callfunc lua "Strong" lst
+inlineToCustom (Strong lst) = callFunc "Strong" (Stringify lst)
-inlineToCustom lua (Strikeout lst) = callfunc lua "Strikeout" lst
+inlineToCustom (Strikeout lst) = callFunc "Strikeout" (Stringify lst)
-inlineToCustom lua (Superscript lst) = callfunc lua "Superscript" lst
+inlineToCustom (Superscript lst) = callFunc "Superscript" (Stringify lst)
-inlineToCustom lua (Subscript lst) = callfunc lua "Subscript" lst
+inlineToCustom (Subscript lst) = callFunc "Subscript" (Stringify lst)
-inlineToCustom lua (SmallCaps lst) = callfunc lua "SmallCaps" lst
+inlineToCustom (SmallCaps lst) = callFunc "SmallCaps" (Stringify lst)
-inlineToCustom lua (Quoted SingleQuote lst) = callfunc lua "SingleQuoted" lst
+inlineToCustom (Quoted SingleQuote lst) = callFunc "SingleQuoted" (Stringify lst)
-inlineToCustom lua (Quoted DoubleQuote lst) = callfunc lua "DoubleQuoted" lst
+inlineToCustom (Quoted DoubleQuote lst) = callFunc "DoubleQuoted" (Stringify lst)
-inlineToCustom lua (Cite cs lst) = callfunc lua "Cite" lst cs
+inlineToCustom (Cite cs lst) = callFunc "Cite" (Stringify lst) (map Stringify cs)
-inlineToCustom lua (Code attr str) =
- callfunc lua "Code" str (attrToMap attr)
+inlineToCustom (Code attr str) =
+ callFunc "Code" str (attrToMap attr)
-inlineToCustom lua (Math DisplayMath str) =
- callfunc lua "DisplayMath" str
+inlineToCustom (Math DisplayMath str) =
+ callFunc "DisplayMath" str
-inlineToCustom lua (Math InlineMath str) =
- callfunc lua "InlineMath" str
+inlineToCustom (Math InlineMath str) =
+ callFunc "InlineMath" str
-inlineToCustom lua (RawInline format str) =
- callfunc lua "RawInline" format str
+inlineToCustom (RawInline format str) =
+ callFunc "RawInline" (Stringify format) str
-inlineToCustom lua (LineBreak) = callfunc lua "LineBreak"
+inlineToCustom LineBreak = callFunc "LineBreak"
-inlineToCustom lua (Link attr txt (src,tit)) =
- callfunc lua "Link" txt src tit (attrToMap attr)
+inlineToCustom (Link attr txt (src,tit)) =
+ callFunc "Link" (Stringify txt) src tit (attrToMap attr)
-inlineToCustom lua (Image attr alt (src,tit)) =
- callfunc lua "Image" alt src tit (attrToMap attr)
+inlineToCustom (Image attr alt (src,tit)) =
+ callFunc "Image" (Stringify alt) src tit (attrToMap attr)
-inlineToCustom lua (Note contents) = callfunc lua "Note" contents
+inlineToCustom (Note contents) = callFunc "Note" (Stringify contents)
-inlineToCustom lua (Span attr items) =
- callfunc lua "Span" items (attrToMap attr)
+inlineToCustom (Span attr items) =
+ callFunc "Span" (Stringify items) (attrToMap attr)
diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs
index 44f96d700..3034fade5 100644
--- a/src/Text/Pandoc/Writers/Docbook.hs
+++ b/src/Text/Pandoc/Writers/Docbook.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE OverloadedStrings, PatternGuards #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Docbook
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -28,34 +29,43 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to Docbook XML.
-}
-module Text.Pandoc.Writers.Docbook ( writeDocbook) where
+module Text.Pandoc.Writers.Docbook ( writeDocbook4, writeDocbook5 ) where
+import Control.Monad.Reader
+import Data.Char (toLower)
+import Data.Generics (everywhere, mkT)
+import Data.List (isPrefixOf, isSuffixOf, stripPrefix)
+import Data.Monoid (Any (..))
+import Data.Text (Text)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
-import Text.Pandoc.XML
+import Text.Pandoc.Highlighting (languages, languagesByExtension)
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
+import Text.Pandoc.Options
+import Text.Pandoc.Pretty
import Text.Pandoc.Shared
+import Text.Pandoc.Templates (renderTemplate')
import Text.Pandoc.Walk
+import Text.Pandoc.Writers.Math
import Text.Pandoc.Writers.Shared
-import Text.Pandoc.Options
-import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.Readers.TeXMath
-import Data.List ( stripPrefix, isPrefixOf, intercalate, isSuffixOf )
-import Data.Char ( toLower )
-import Data.Monoid ( Any(..) )
-import Text.Pandoc.Highlighting ( languages, languagesByExtension )
-import Text.Pandoc.Pretty
-import Text.Pandoc.ImageSize
-import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.XML
import Text.TeXMath
import qualified Text.XML.Light as Xml
-import Data.Generics (everywhere, mkT)
+
+data DocBookVersion = DocBook4 | DocBook5
+ deriving (Eq, Show)
+
+type DB = ReaderT DocBookVersion
-- | Convert list of authors to a docbook <author> section
-authorToDocbook :: WriterOptions -> [Inline] -> B.Inlines
-authorToDocbook opts name' =
- let name = render Nothing $ inlinesToDocbook opts name'
- colwidth = if writerWrapText opts == WrapAuto
+authorToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> DB m B.Inlines
+authorToDocbook opts name' = do
+ name <- render Nothing <$> inlinesToDocbook opts name'
+ let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- in B.rawInline "docbook" $ render colwidth $
+ return $ B.rawInline "docbook" $ render colwidth $
if ',' `elem` name
then -- last name first
let (lastname, rest) = break (==',') name
@@ -66,52 +76,63 @@ authorToDocbook opts name' =
let namewords = words name
lengthname = length namewords
(firstname, lastname) = case lengthname of
- 0 -> ("","")
- 1 -> ("", name)
- n -> (intercalate " " (take (n-1) namewords), last namewords)
+ 0 -> ("","")
+ 1 -> ("", name)
+ n -> (unwords (take (n-1) namewords), last namewords)
in inTagsSimple "firstname" (text $ escapeStringForXML firstname) $$
inTagsSimple "surname" (text $ escapeStringForXML lastname)
+writeDocbook4 :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeDocbook4 opts d =
+ runReaderT (writeDocbook opts d) DocBook4
+
+writeDocbook5 :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeDocbook5 opts d =
+ runReaderT (writeDocbook opts d) DocBook5
+
-- | Convert Pandoc document to string in Docbook format.
-writeDocbook :: WriterOptions -> Pandoc -> String
-writeDocbook opts (Pandoc meta blocks) =
+writeDocbook :: PandocMonad m => WriterOptions -> Pandoc -> DB m Text
+writeDocbook opts (Pandoc meta blocks) = do
let elements = hierarchicalize blocks
- colwidth = if writerWrapText opts == WrapAuto
+ let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- render' = render colwidth
- opts' = if (maybe False (("/book>" `isSuffixOf`) . trimr)
+ let render' :: Doc -> Text
+ render' = render colwidth
+ let opts' = if maybe False (("/book>" `isSuffixOf`) . trimr)
(writerTemplate opts) &&
- TopLevelDefault == writerTopLevelDivision opts)
+ TopLevelDefault == writerTopLevelDivision opts
then opts{ writerTopLevelDivision = TopLevelChapter }
else opts
- -- The numbering here follows LaTeX's internal numbering
- startLvl = case writerTopLevelDivision opts' of
+ -- The numbering here follows LaTeX's internal numbering
+ let startLvl = case writerTopLevelDivision opts' of
TopLevelPart -> -1
TopLevelChapter -> 0
TopLevelSection -> 1
TopLevelDefault -> 1
- auths' = map (authorToDocbook opts) $ docAuthors meta
- meta' = B.setMeta "author" auths' meta
- Just metadata = metaToJSON opts
- (Just . render colwidth . (vcat .
- (map (elementToDocbook opts' startLvl)) . hierarchicalize))
- (Just . render colwidth . inlinesToDocbook opts')
+ auths' <- mapM (authorToDocbook opts) $ docAuthors meta
+ let meta' = B.setMeta "author" auths' meta
+ metadata <- metaToJSON opts
+ (fmap (render' . vcat) .
+ mapM (elementToDocbook opts' startLvl) .
+ hierarchicalize)
+ (fmap render' . inlinesToDocbook opts')
meta'
- main = render' $ vcat (map (elementToDocbook opts' startLvl) elements)
- context = defField "body" main
- $ defField "mathml" (case writerHTMLMathMethod opts of
- MathML _ -> True
- _ -> False)
- $ metadata
- in case writerTemplate opts of
- Nothing -> main
- Just tpl -> renderTemplate' tpl context
+ main <- (render' . vcat) <$> mapM (elementToDocbook opts' startLvl) elements
+ let context = defField "body" main
+ $
+ defField "mathml" (case writerHTMLMathMethod opts of
+ MathML -> True
+ _ -> False) metadata
+ case writerTemplate opts of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
-- | Convert an Element to Docbook.
-elementToDocbook :: WriterOptions -> Int -> Element -> Doc
+elementToDocbook :: PandocMonad m => WriterOptions -> Int -> Element -> DB m Doc
elementToDocbook opts _ (Blk block) = blockToDocbook opts block
-elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) =
+elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) = do
+ version <- ask
-- Docbook doesn't allow sections with no content, so insert some if needed
let elements' = if null elements
then [Blk (Para [])]
@@ -119,24 +140,25 @@ elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) =
tag = case lvl of
-1 -> "part"
0 -> "chapter"
- n | n >= 1 && n <= 5 -> if writerDocbook5 opts
+ n | n >= 1 && n <= 5 -> if version == DocBook5
then "section"
else "sect" ++ show n
_ -> "simplesect"
- idName = if writerDocbook5 opts
+ idName = if version == DocBook5
then "xml:id"
else "id"
idAttr = [(idName, writerIdentifierPrefix opts ++ id') | not (null id')]
- nsAttr = if writerDocbook5 opts && lvl == 0 then [("xmlns", "http://docbook.org/ns/docbook"),("xmlns:xlink", "http://www.w3.org/1999/xlink")]
+ nsAttr = if version == DocBook5 && lvl == 0 then [("xmlns", "http://docbook.org/ns/docbook"),("xmlns:xlink", "http://www.w3.org/1999/xlink")]
else []
attribs = nsAttr ++ idAttr
- in inTags True tag attribs $
- inTagsSimple "title" (inlinesToDocbook opts title) $$
- vcat (map (elementToDocbook opts (lvl + 1)) elements')
+ contents <- mapM (elementToDocbook opts (lvl + 1)) elements'
+ title' <- inlinesToDocbook opts title
+ return $ inTags True tag attribs $
+ inTagsSimple "title" title' $$ vcat contents
-- | Convert a list of Pandoc blocks to Docbook.
-blocksToDocbook :: WriterOptions -> [Block] -> Doc
-blocksToDocbook opts = vcat . map (blockToDocbook opts)
+blocksToDocbook :: PandocMonad m => WriterOptions -> [Block] -> DB m Doc
+blocksToDocbook opts = fmap vcat . mapM (blockToDocbook opts)
-- | Auxiliary function to convert Plain block to Para.
plainToPara :: Block -> Block
@@ -145,74 +167,82 @@ plainToPara x = x
-- | Convert a list of pairs of terms and definitions into a list of
-- Docbook varlistentrys.
-deflistItemsToDocbook :: WriterOptions -> [([Inline],[[Block]])] -> Doc
+deflistItemsToDocbook :: PandocMonad m
+ => WriterOptions -> [([Inline],[[Block]])] -> DB m Doc
deflistItemsToDocbook opts items =
- vcat $ map (\(term, defs) -> deflistItemToDocbook opts term defs) items
+ vcat <$> mapM (uncurry (deflistItemToDocbook opts)) items
-- | Convert a term and a list of blocks into a Docbook varlistentry.
-deflistItemToDocbook :: WriterOptions -> [Inline] -> [[Block]] -> Doc
-deflistItemToDocbook opts term defs =
- let def' = concatMap (map plainToPara) defs
- in inTagsIndented "varlistentry" $
- inTagsIndented "term" (inlinesToDocbook opts term) $$
- inTagsIndented "listitem" (blocksToDocbook opts def')
+deflistItemToDocbook :: PandocMonad m
+ => WriterOptions -> [Inline] -> [[Block]] -> DB m Doc
+deflistItemToDocbook opts term defs = do
+ term' <- inlinesToDocbook opts term
+ def' <- blocksToDocbook opts $ concatMap (map plainToPara) defs
+ return $ inTagsIndented "varlistentry" $
+ inTagsIndented "term" term' $$
+ inTagsIndented "listitem" def'
-- | Convert a list of lists of blocks to a list of Docbook list items.
-listItemsToDocbook :: WriterOptions -> [[Block]] -> Doc
-listItemsToDocbook opts items = vcat $ map (listItemToDocbook opts) items
+listItemsToDocbook :: PandocMonad m => WriterOptions -> [[Block]] -> DB m Doc
+listItemsToDocbook opts items = vcat <$> mapM (listItemToDocbook opts) items
-- | Convert a list of blocks into a Docbook list item.
-listItemToDocbook :: WriterOptions -> [Block] -> Doc
+listItemToDocbook :: PandocMonad m => WriterOptions -> [Block] -> DB m Doc
listItemToDocbook opts item =
- inTagsIndented "listitem" $ blocksToDocbook opts $ map plainToPara item
+ inTagsIndented "listitem" <$> blocksToDocbook opts (map plainToPara item)
imageToDocbook :: WriterOptions -> Attr -> String -> Doc
imageToDocbook _ attr src = selfClosingTag "imagedata" $
("fileref", src) : idAndRole attr ++ dims
where
dims = go Width "width" ++ go Height "depth"
- go dir dstr = case (dimension dir attr) of
+ go dir dstr = case dimension dir attr of
Just a -> [(dstr, show a)]
Nothing -> []
-- | Convert a Pandoc block element to Docbook.
-blockToDocbook :: WriterOptions -> Block -> Doc
-blockToDocbook _ Null = empty
+blockToDocbook :: PandocMonad m => WriterOptions -> Block -> DB m Doc
+blockToDocbook _ Null = return empty
-- Add ids to paragraphs in divs with ids - this is needed for
-- pandoc-citeproc to get link anchors in bibliographies:
blockToDocbook opts (Div (ident,_,_) [Para lst]) =
let attribs = [("id", ident) | not (null ident)] in
if hasLineBreaks lst
- then flush $ nowrap $ inTags False "literallayout" attribs
- $ inlinesToDocbook opts lst
- else inTags True "para" attribs $ inlinesToDocbook opts lst
-blockToDocbook opts (Div (ident,_,_) bs) =
- (if null ident
- then mempty
- else selfClosingTag "anchor" [("id", ident)]) $$
- blocksToDocbook opts (map plainToPara bs)
-blockToDocbook _ (Header _ _ _) = empty -- should not occur after hierarchicalize
+ then (flush . nowrap . inTags False "literallayout" attribs)
+ <$> inlinesToDocbook opts lst
+ else inTags True "para" attribs <$> inlinesToDocbook opts lst
+blockToDocbook opts (Div (ident,_,_) bs) = do
+ contents <- blocksToDocbook opts (map plainToPara bs)
+ return $
+ (if null ident
+ then mempty
+ else selfClosingTag "anchor" [("id", ident)]) $$ contents
+blockToDocbook _ h@Header{} = do
+ -- should not occur after hierarchicalize, except inside lists/blockquotes
+ report $ BlockNotRendered h
+ return empty
blockToDocbook opts (Plain lst) = inlinesToDocbook opts lst
-- title beginning with fig: indicates that the image is a figure
-blockToDocbook opts (Para [Image attr txt (src,'f':'i':'g':':':_)]) =
- let alt = inlinesToDocbook opts txt
- capt = if null txt
+blockToDocbook opts (Para [Image attr txt (src,'f':'i':'g':':':_)]) = do
+ alt <- inlinesToDocbook opts txt
+ let capt = if null txt
then empty
else inTagsSimple "title" alt
- in inTagsIndented "figure" $
+ return $ inTagsIndented "figure" $
capt $$
- (inTagsIndented "mediaobject" $
- (inTagsIndented "imageobject"
- (imageToDocbook opts attr src)) $$
+ inTagsIndented "mediaobject" (
+ inTagsIndented "imageobject"
+ (imageToDocbook opts attr src) $$
inTagsSimple "textobject" (inTagsSimple "phrase" alt))
blockToDocbook opts (Para lst)
- | hasLineBreaks lst = flush $ nowrap $ inTagsSimple "literallayout" $ inlinesToDocbook opts lst
- | otherwise = inTagsIndented "para" $ inlinesToDocbook opts lst
+ | hasLineBreaks lst = (flush . nowrap . inTagsSimple "literallayout")
+ <$> inlinesToDocbook opts lst
+ | otherwise = inTagsIndented "para" <$> inlinesToDocbook opts lst
blockToDocbook opts (LineBlock lns) =
blockToDocbook opts $ linesToPara lns
blockToDocbook opts (BlockQuote blocks) =
- inTagsIndented "blockquote" $ blocksToDocbook opts blocks
-blockToDocbook _ (CodeBlock (_,classes,_) str) =
+ inTagsIndented "blockquote" <$> blocksToDocbook opts blocks
+blockToDocbook _ (CodeBlock (_,classes,_) str) = return $
text ("<programlisting" ++ lang ++ ">") <> cr <>
flush (text (escapeStringForXML str) <> cr <> text "</programlisting>")
where lang = if null langs
@@ -224,11 +254,11 @@ blockToDocbook _ (CodeBlock (_,classes,_) str) =
then [s]
else languagesByExtension . map toLower $ s
langs = concatMap langsFrom classes
-blockToDocbook opts (BulletList lst) =
+blockToDocbook opts (BulletList lst) = do
let attribs = [("spacing", "compact") | isTightList lst]
- in inTags True "itemizedlist" attribs $ listItemsToDocbook opts lst
-blockToDocbook _ (OrderedList _ []) = empty
-blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) =
+ inTags True "itemizedlist" attribs <$> listItemsToDocbook opts lst
+blockToDocbook _ (OrderedList _ []) = return empty
+blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) = do
let numeration = case numstyle of
DefaultStyle -> []
Decimal -> [("numeration", "arabic")]
@@ -239,40 +269,46 @@ blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) =
LowerRoman -> [("numeration", "lowerroman")]
spacing = [("spacing", "compact") | isTightList (first:rest)]
attribs = numeration ++ spacing
- items = if start == 1
- then listItemsToDocbook opts (first:rest)
- else (inTags True "listitem" [("override",show start)]
- (blocksToDocbook opts $ map plainToPara first)) $$
- listItemsToDocbook opts rest
- in inTags True "orderedlist" attribs items
-blockToDocbook opts (DefinitionList lst) =
+ items <- if start == 1
+ then listItemsToDocbook opts (first:rest)
+ else do
+ first' <- blocksToDocbook opts (map plainToPara first)
+ rest' <- listItemsToDocbook opts rest
+ return $
+ inTags True "listitem" [("override",show start)] first' $$
+ rest'
+ return $ inTags True "orderedlist" attribs items
+blockToDocbook opts (DefinitionList lst) = do
let attribs = [("spacing", "compact") | isTightList $ concatMap snd lst]
- in inTags True "variablelist" attribs $ deflistItemsToDocbook opts lst
-blockToDocbook opts (RawBlock f str)
- | f == "docbook" = text str -- raw XML block
- | f == "html" = if writerDocbook5 opts
- then empty -- No html in Docbook5
- else text str -- allow html for backwards compatibility
- | otherwise = empty
-blockToDocbook _ HorizontalRule = empty -- not semantic
-blockToDocbook opts (Table caption aligns widths headers rows) =
- let captionDoc = if null caption
- then empty
- else inTagsIndented "title"
- (inlinesToDocbook opts caption)
- tableType = if isEmpty captionDoc then "informaltable" else "table"
+ inTags True "variablelist" attribs <$> deflistItemsToDocbook opts lst
+blockToDocbook _ b@(RawBlock f str)
+ | f == "docbook" = return $ text str -- raw XML block
+ | f == "html" = do
+ version <- ask
+ if version == DocBook5
+ then return empty -- No html in Docbook5
+ else return $ text str -- allow html for backwards compatibility
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
+blockToDocbook _ HorizontalRule = return empty -- not semantic
+blockToDocbook opts (Table caption aligns widths headers rows) = do
+ captionDoc <- if null caption
+ then return empty
+ else inTagsIndented "title" <$>
+ inlinesToDocbook opts caption
+ let tableType = if isEmpty captionDoc then "informaltable" else "table"
percent w = show (truncate (100*w) :: Integer) ++ "*"
coltags = vcat $ zipWith (\w al -> selfClosingTag "colspec"
([("colwidth", percent w) | w > 0] ++
[("align", alignmentToString al)])) widths aligns
- head' = if all null headers
- then empty
- else inTagsIndented "thead" $
- tableRowToDocbook opts headers
- body' = inTagsIndented "tbody" $
- vcat $ map (tableRowToDocbook opts) rows
- in inTagsIndented tableType $ captionDoc $$
- (inTags True "tgroup" [("cols", show (length headers))] $
+ head' <- if all null headers
+ then return empty
+ else inTagsIndented "thead" <$> tableRowToDocbook opts headers
+ body' <- (inTagsIndented "tbody" . vcat) <$>
+ mapM (tableRowToDocbook opts) rows
+ return $ inTagsIndented tableType $ captionDoc $$
+ inTags True "tgroup" [("cols", show (length headers))] (
coltags $$ head' $$ body')
hasLineBreaks :: [Inline] -> Bool
@@ -280,101 +316,111 @@ hasLineBreaks = getAny . query isLineBreak . walk removeNote
where
removeNote :: Inline -> Inline
removeNote (Note _) = Str ""
- removeNote x = x
+ removeNote x = x
isLineBreak :: Inline -> Any
isLineBreak LineBreak = Any True
- isLineBreak _ = Any False
+ isLineBreak _ = Any False
alignmentToString :: Alignment -> [Char]
alignmentToString alignment = case alignment of
- AlignLeft -> "left"
- AlignRight -> "right"
- AlignCenter -> "center"
+ AlignLeft -> "left"
+ AlignRight -> "right"
+ AlignCenter -> "center"
AlignDefault -> "left"
-tableRowToDocbook :: WriterOptions
+tableRowToDocbook :: PandocMonad m
+ => WriterOptions
-> [[Block]]
- -> Doc
+ -> DB m Doc
tableRowToDocbook opts cols =
- inTagsIndented "row" $ vcat $ map (tableItemToDocbook opts) cols
+ (inTagsIndented "row" . vcat) <$> mapM (tableItemToDocbook opts) cols
-tableItemToDocbook :: WriterOptions
+tableItemToDocbook :: PandocMonad m
+ => WriterOptions
-> [Block]
- -> Doc
+ -> DB m Doc
tableItemToDocbook opts item =
- inTags True "entry" [] $ vcat $ map (blockToDocbook opts) item
+ (inTags True "entry" [] . vcat) <$> mapM (blockToDocbook opts) item
-- | Convert a list of inline elements to Docbook.
-inlinesToDocbook :: WriterOptions -> [Inline] -> Doc
-inlinesToDocbook opts lst = hcat $ map (inlineToDocbook opts) lst
+inlinesToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> DB m Doc
+inlinesToDocbook opts lst = hcat <$> mapM (inlineToDocbook opts) lst
-- | Convert an inline element to Docbook.
-inlineToDocbook :: WriterOptions -> Inline -> Doc
-inlineToDocbook _ (Str str) = text $ escapeStringForXML str
+inlineToDocbook :: PandocMonad m => WriterOptions -> Inline -> DB m Doc
+inlineToDocbook _ (Str str) = return $ text $ escapeStringForXML str
inlineToDocbook opts (Emph lst) =
- inTagsSimple "emphasis" $ inlinesToDocbook opts lst
+ inTagsSimple "emphasis" <$> inlinesToDocbook opts lst
inlineToDocbook opts (Strong lst) =
- inTags False "emphasis" [("role", "strong")] $ inlinesToDocbook opts lst
+ inTags False "emphasis" [("role", "strong")] <$> inlinesToDocbook opts lst
inlineToDocbook opts (Strikeout lst) =
- inTags False "emphasis" [("role", "strikethrough")] $
+ inTags False "emphasis" [("role", "strikethrough")] <$>
inlinesToDocbook opts lst
inlineToDocbook opts (Superscript lst) =
- inTagsSimple "superscript" $ inlinesToDocbook opts lst
+ inTagsSimple "superscript" <$> inlinesToDocbook opts lst
inlineToDocbook opts (Subscript lst) =
- inTagsSimple "subscript" $ inlinesToDocbook opts lst
+ inTagsSimple "subscript" <$> inlinesToDocbook opts lst
inlineToDocbook opts (SmallCaps lst) =
- inTags False "emphasis" [("role", "smallcaps")] $
+ inTags False "emphasis" [("role", "smallcaps")] <$>
inlinesToDocbook opts lst
inlineToDocbook opts (Quoted _ lst) =
- inTagsSimple "quote" $ inlinesToDocbook opts lst
+ inTagsSimple "quote" <$> inlinesToDocbook opts lst
inlineToDocbook opts (Cite _ lst) =
inlinesToDocbook opts lst
inlineToDocbook opts (Span (ident,_,_) ils) =
- (if null ident
- then mempty
- else selfClosingTag "anchor" [("id", ident)]) <>
+ ((if null ident
+ then mempty
+ else selfClosingTag "anchor" [("id", ident)]) <>) <$>
inlinesToDocbook opts ils
inlineToDocbook _ (Code _ str) =
- inTagsSimple "literal" $ text (escapeStringForXML str)
+ return $ inTagsSimple "literal" $ text (escapeStringForXML str)
inlineToDocbook opts (Math t str)
- | isMathML (writerHTMLMathMethod opts) =
- case writeMathML dt <$> readTeX str of
- Right r -> inTagsSimple tagtype
- $ text $ Xml.ppcElement conf
- $ fixNS
- $ removeAttr r
- Left _ -> inlinesToDocbook opts
- $ texMathToInlines t str
- | otherwise = inlinesToDocbook opts $ texMathToInlines t str
- where (dt, tagtype) = case t of
- InlineMath -> (DisplayInline,"inlineequation")
- DisplayMath -> (DisplayBlock,"informalequation")
+ | isMathML (writerHTMLMathMethod opts) = do
+ res <- convertMath writeMathML t str
+ case res of
+ Right r -> return $ inTagsSimple tagtype
+ $ text $ Xml.ppcElement conf
+ $ fixNS
+ $ removeAttr r
+ Left il -> inlineToDocbook opts il
+ | otherwise =
+ texMathToInlines t str >>= inlinesToDocbook opts
+ where tagtype = case t of
+ InlineMath -> "inlineequation"
+ DisplayMath -> "informalequation"
conf = Xml.useShortEmptyTags (const False) Xml.defaultConfigPP
removeAttr e = e{ Xml.elAttribs = [] }
fixNS' qname = qname{ Xml.qPrefix = Just "mml" }
fixNS = everywhere (mkT fixNS')
-inlineToDocbook _ (RawInline f x) | f == "html" || f == "docbook" = text x
- | otherwise = empty
-inlineToDocbook _ LineBreak = text "\n"
-inlineToDocbook _ Space = space
+inlineToDocbook _ il@(RawInline f x)
+ | f == "html" || f == "docbook" = return $ text x
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
+inlineToDocbook _ LineBreak = return $ text "\n"
+-- currently ignore, would require the option to add custom
+-- styles to the document
+inlineToDocbook _ Space = return space
-- because we use \n for LineBreak, we can't do soft breaks:
-inlineToDocbook _ SoftBreak = space
+inlineToDocbook _ SoftBreak = return space
inlineToDocbook opts (Link attr txt (src, _))
| Just email <- stripPrefix "mailto:" src =
let emailLink = inTagsSimple "email" $ text $
- escapeStringForXML $ email
+ escapeStringForXML email
in case txt of
- [Str s] | escapeURI s == email -> emailLink
- _ -> inlinesToDocbook opts txt <+>
- char '(' <> emailLink <> char ')'
- | otherwise =
- (if isPrefixOf "#" src
- then inTags False "link" $ ("linkend", drop 1 src) : idAndRole attr
- else if writerDocbook5 opts
+ [Str s] | escapeURI s == email -> return emailLink
+ _ -> do contents <- inlinesToDocbook opts txt
+ return $ contents <+>
+ char '(' <> emailLink <> char ')'
+ | otherwise = do
+ version <- ask
+ (if "#" `isPrefixOf` src
+ then inTags False "link" $ ("linkend", writerIdentifierPrefix opts ++ drop 1 src) : idAndRole attr
+ else if version == DocBook5
then inTags False "link" $ ("xlink:href", src) : idAndRole attr
- else inTags False "ulink" $ ("url", src) : idAndRole attr ) $
- inlinesToDocbook opts txt
-inlineToDocbook opts (Image attr _ (src, tit)) =
+ else inTags False "ulink" $ ("url", src) : idAndRole attr )
+ <$> inlinesToDocbook opts txt
+inlineToDocbook opts (Image attr _ (src, tit)) = return $
let titleDoc = if null tit
then empty
else inTagsIndented "objectinfo" $
@@ -382,11 +428,11 @@ inlineToDocbook opts (Image attr _ (src, tit)) =
in inTagsIndented "inlinemediaobject" $ inTagsIndented "imageobject" $
titleDoc $$ imageToDocbook opts attr src
inlineToDocbook opts (Note contents) =
- inTagsIndented "footnote" $ blocksToDocbook opts contents
+ inTagsIndented "footnote" <$> blocksToDocbook opts contents
isMathML :: HTMLMathMethod -> Bool
-isMathML (MathML _) = True
-isMathML _ = False
+isMathML MathML = True
+isMathML _ = False
idAndRole :: Attr -> [(String, String)]
idAndRole (id',cls,_) = ident ++ role
diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs
index 3fc5d22a2..4542389a2 100644
--- a/src/Text/Pandoc/Writers/Docx.hs
+++ b/src/Text/Pandoc/Writers/Docx.hs
@@ -1,6 +1,9 @@
-{-# LANGUAGE ScopedTypeVariables, PatternGuards, ViewPatterns #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
{-
-Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Docx
- Copyright : Copyright (C) 2012-2015 John MacFarlane
+ Copyright : Copyright (C) 2012-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,44 +32,44 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to docx.
-}
module Text.Pandoc.Writers.Docx ( writeDocx ) where
-import Data.List ( intercalate, isPrefixOf, isSuffixOf )
+import Codec.Archive.Zip
+import Control.Applicative ((<|>))
+import Control.Monad.Except (catchError)
+import Control.Monad.Reader
+import Control.Monad.State.Strict
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
-import qualified Data.ByteString.Lazy.Char8 as BL8
+import Data.Char (isSpace, ord, toLower)
+import Data.List (intercalate, isPrefixOf, isSuffixOf)
import qualified Data.Map as M
+import Data.Maybe (fromMaybe, isNothing, mapMaybe, maybeToList)
import qualified Data.Set as Set
-import qualified Text.Pandoc.UTF8 as UTF8
-import Codec.Archive.Zip
+import qualified Data.Text as T
import Data.Time.Clock.POSIX
-import System.Environment
+import Skylighting
+import System.Random (randomR, StdGen, mkStdGen)
+import Text.Pandoc.BCP47 (getLang, renderLang)
+import Text.Pandoc.Class (PandocMonad, report, toLang)
+import qualified Text.Pandoc.Class as P
import Text.Pandoc.Compat.Time
import Text.Pandoc.Definition
import Text.Pandoc.Generic
+import Text.Pandoc.Highlighting (highlight)
import Text.Pandoc.ImageSize
-import Text.Pandoc.Shared hiding (Element)
-import Text.Pandoc.Writers.Shared (fixDisplayMath)
+import Text.Pandoc.Logging
+import Text.Pandoc.MIME (MimeType, extensionFromMimeType, getMimeType,
+ getMimeTypeDef)
import Text.Pandoc.Options
-import Text.Pandoc.Readers.TeXMath
-import Text.Pandoc.Highlighting ( highlight )
-import Text.Pandoc.Walk
-import Text.XML.Light as XML
-import Text.TeXMath
import Text.Pandoc.Readers.Docx.StyleMap
-import Text.Pandoc.Readers.Docx.Util (elemName)
-import Control.Monad.Reader
-import Control.Monad.State
-import Skylighting
-import Data.Unique (hashUnique, newUnique)
-import System.Random (randomRIO)
+import Text.Pandoc.Shared hiding (Element)
+import Text.Pandoc.Walk
+import Text.Pandoc.Writers.Math
+import Text.Pandoc.Writers.Shared (fixDisplayMath, metaValueToInlines)
import Text.Printf (printf)
-import qualified Control.Exception as E
-import Data.Monoid ((<>))
-import qualified Data.Text as T
-import Text.Pandoc.MIME (MimeType, getMimeType, getMimeTypeDef,
- extensionFromMimeType)
-import Control.Applicative ((<|>))
-import Data.Maybe (fromMaybe, mapMaybe, maybeToList, isNothing)
-import Data.Char (ord, isSpace, toLower)
+import Text.TeXMath
+import Text.XML.Light as XML
+import Text.XML.Light.Cursor as XMLC
+import Text.Pandoc.Writers.OOXML
data ListMarker = NoMarker
| BulletMarker
@@ -79,28 +82,28 @@ listMarkerToId BulletMarker = "991"
listMarkerToId (NumberMarker sty delim n) =
'9' : '9' : styNum : delimNum : show n
where styNum = case sty of
- DefaultStyle -> '2'
- Example -> '3'
- Decimal -> '4'
- LowerRoman -> '5'
- UpperRoman -> '6'
- LowerAlpha -> '7'
- UpperAlpha -> '8'
+ DefaultStyle -> '2'
+ Example -> '3'
+ Decimal -> '4'
+ LowerRoman -> '5'
+ UpperRoman -> '6'
+ LowerAlpha -> '7'
+ UpperAlpha -> '8'
delimNum = case delim of
- DefaultDelim -> '0'
- Period -> '1'
- OneParen -> '2'
- TwoParens -> '3'
+ DefaultDelim -> '0'
+ Period -> '1'
+ OneParen -> '2'
+ TwoParens -> '3'
data WriterEnv = WriterEnv{ envTextProperties :: [Element]
, envParaProperties :: [Element]
- , envRTL :: Bool
- , envListLevel :: Int
- , envListNumId :: Int
- , envInDel :: Bool
- , envChangesAuthor :: String
- , envChangesDate :: String
- , envPrintWidth :: Integer
+ , envRTL :: Bool
+ , envListLevel :: Int
+ , envListNumId :: Int
+ , envInDel :: Bool
+ , envChangesAuthor :: String
+ , envChangesDate :: String
+ , envPrintWidth :: Integer
}
defaultWriterEnv :: WriterEnv
@@ -117,22 +120,25 @@ defaultWriterEnv = WriterEnv{ envTextProperties = []
data WriterState = WriterState{
stFootnotes :: [Element]
+ , stComments :: [([(String,String)], [Inline])]
, stSectionIds :: Set.Set String
, stExternalLinks :: M.Map String String
- , stImages :: M.Map FilePath (String, String, Maybe MimeType, Element, B.ByteString)
+ , stImages :: M.Map FilePath (String, String, Maybe MimeType, B.ByteString)
, stLists :: [ListMarker]
, stInsId :: Int
, stDelId :: Int
, stStyleMaps :: StyleMaps
, stFirstPara :: Bool
, stTocTitle :: [Inline]
- , stDynamicParaProps :: [String]
- , stDynamicTextProps :: [String]
+ , stDynamicParaProps :: Set.Set String
+ , stDynamicTextProps :: Set.Set String
+ , stCurId :: Int
}
defaultWriterState :: WriterState
defaultWriterState = WriterState{
stFootnotes = defaultFootnotes
+ , stComments = []
, stSectionIds = Set.empty
, stExternalLinks = M.empty
, stImages = M.empty
@@ -141,44 +147,29 @@ defaultWriterState = WriterState{
, stDelId = 1
, stStyleMaps = defaultStyleMaps
, stFirstPara = False
- , stTocTitle = normalizeInlines [Str "Table of Contents"]
- , stDynamicParaProps = []
- , stDynamicTextProps = []
+ , stTocTitle = [Str "Table of Contents"]
+ , stDynamicParaProps = Set.empty
+ , stDynamicTextProps = Set.empty
+ , stCurId = 20
}
-type WS = ReaderT WriterEnv (StateT WriterState IO)
-
-mknode :: Node t => String -> [(String,String)] -> t -> Element
-mknode s attrs =
- add_attrs (map (\(k,v) -> Attr (nodename k) v) attrs) . node (nodename s)
+type WS m = ReaderT WriterEnv (StateT WriterState m)
-nodename :: String -> QName
-nodename s = QName{ qName = name, qURI = Nothing, qPrefix = prefix }
- where (name, prefix) = case break (==':') s of
- (xs,[]) -> (xs, Nothing)
- (ys, _:zs) -> (zs, Just ys)
-
-toLazy :: B.ByteString -> BL.ByteString
-toLazy = BL.fromChunks . (:[])
-
-renderXml :: Element -> BL.ByteString
-renderXml elt = BL8.pack "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" <>
- UTF8.fromStringLazy (showElement elt)
renumIdMap :: Int -> [Element] -> M.Map String String
renumIdMap _ [] = M.empty
renumIdMap n (e:es)
| Just oldId <- findAttr (QName "Id" Nothing Nothing) e =
- M.insert oldId ("rId" ++ (show n)) (renumIdMap (n+1) es)
+ M.insert oldId ("rId" ++ show n) (renumIdMap (n+1) es)
| otherwise = renumIdMap n es
replaceAttr :: (QName -> Bool) -> String -> [XML.Attr] -> [XML.Attr]
replaceAttr _ _ [] = []
replaceAttr f val (a:as) | f (attrKey a) =
- (XML.Attr (attrKey a) val) : (replaceAttr f val as)
- | otherwise = a : (replaceAttr f val as)
+ XML.Attr (attrKey a) val : replaceAttr f val as
+ | otherwise = a : replaceAttr f val as
-renumId :: (QName -> Bool) -> (M.Map String String) -> Element -> Element
+renumId :: (QName -> Bool) -> M.Map String String -> Element -> Element
renumId f renumMap e
| Just oldId <- findAttrBy f e
, Just newId <- M.lookup oldId renumMap =
@@ -187,7 +178,7 @@ renumId f renumMap e
e { elAttribs = attrs' }
| otherwise = e
-renumIds :: (QName -> Bool) -> (M.Map String String) -> [Element] -> [Element]
+renumIds :: (QName -> Bool) -> M.Map String String -> [Element] -> [Element]
renumIds f renumMap = map (renumId f renumMap)
-- | Certain characters are invalid in XML even if escaped.
@@ -206,38 +197,36 @@ isValidChar (ord -> c)
| 0x10000 <= c && c <= 0x10FFFF = True
| otherwise = False
-metaValueToInlines :: MetaValue -> [Inline]
-metaValueToInlines (MetaString s) = normalizeInlines [Str s]
-metaValueToInlines (MetaInlines ils) = ils
-metaValueToInlines (MetaBlocks bs) = query return bs
-metaValueToInlines (MetaBool b) = [Str $ show b]
-metaValueToInlines _ = []
-
--- | Produce an Docx file from a Pandoc document.
-writeDocx :: WriterOptions -- ^ Writer options
+writeDocx :: (PandocMonad m)
+ => WriterOptions -- ^ Writer options
-> Pandoc -- ^ Document to convert
- -> IO BL.ByteString
+ -> m BL.ByteString
writeDocx opts doc@(Pandoc meta _) = do
- let datadir = writerUserDataDir opts
- let doc' = walk fixDisplayMath $ doc
- username <- lookup "USERNAME" <$> getEnvironment
- utctime <- getCurrentTime
- distArchive <- getDefaultReferenceDocx datadir
- refArchive <- case writerReferenceDocx opts of
- Just f -> liftM (toArchive . toLazy) $ B.readFile f
- Nothing -> getDefaultReferenceDocx datadir
+ let doc' = walk fixDisplayMath doc
+ username <- P.lookupEnv "USERNAME"
+ utctime <- P.getCurrentTime
+ distArchive <- (toArchive . BL.fromStrict) <$> do
+ oldUserDataDir <- P.getUserDataDir
+ P.setUserDataDir Nothing
+ res <- P.readDefaultDataFile "reference.docx"
+ P.setUserDataDir oldUserDataDir
+ return res
+ refArchive <- case writerReferenceDoc opts of
+ Just f -> toArchive <$> P.readFileLazy f
+ Nothing -> (toArchive . BL.fromStrict) <$>
+ P.readDataFile "reference.docx"
parsedDoc <- parseXml refArchive distArchive "word/document.xml"
let wname f qn = qPrefix qn == Just "w" && f (qName qn)
let mbsectpr = filterElementName (wname (=="sectPr")) parsedDoc
-- Gets the template size
- let mbpgsz = mbsectpr >>= (filterElementName (wname (=="pgSz")))
- let mbAttrSzWidth = (elAttribs <$> mbpgsz) >>= (lookupAttrBy ((=="w") . qName))
+ let mbpgsz = mbsectpr >>= filterElementName (wname (=="pgSz"))
+ let mbAttrSzWidth = (elAttribs <$> mbpgsz) >>= lookupAttrBy ((=="w") . qName)
- let mbpgmar = mbsectpr >>= (filterElementName (wname (=="pgMar")))
- let mbAttrMarLeft = (elAttribs <$> mbpgmar) >>= (lookupAttrBy ((=="left") . qName))
- let mbAttrMarRight = (elAttribs <$> mbpgmar) >>= (lookupAttrBy ((=="right") . qName))
+ let mbpgmar = mbsectpr >>= filterElementName (wname (=="pgMar"))
+ let mbAttrMarLeft = (elAttribs <$> mbpgmar) >>= lookupAttrBy ((=="left") . qName)
+ let mbAttrMarRight = (elAttribs <$> mbpgmar) >>= lookupAttrBy ((=="right") . qName)
-- Get the avaible area (converting the size and the margins to int and
-- doing the difference
@@ -248,8 +237,29 @@ writeDocx opts doc@(Pandoc meta _) = do
)
-- styles
+ mblang <- toLang $ getLang opts meta
+ let addLang :: Element -> Element
+ addLang e = case mblang >>= \l ->
+ (return . XMLC.toTree . go (renderLang l)
+ . XMLC.fromElement) e of
+ Just (Elem e') -> e'
+ _ -> e -- return original
+ where go :: String -> Cursor -> Cursor
+ go l cursor = case XMLC.findRec (isLangElt . current) cursor of
+ Nothing -> cursor
+ Just t -> XMLC.modifyContent (setval l) t
+ setval :: String -> Content -> Content
+ setval l (Elem e') = Elem $ e'{ elAttribs = map (setvalattr l) $
+ elAttribs e' }
+ setval _ x = x
+ setvalattr :: String -> XML.Attr -> XML.Attr
+ setvalattr l (XML.Attr qn@(QName "val" _ _) _) = XML.Attr qn l
+ setvalattr _ x = x
+ isLangElt (Elem e') = qName (elName e') == "lang"
+ isLangElt _ = False
+
let stylepath = "word/styles.xml"
- styledoc <- parseXml refArchive distArchive stylepath
+ styledoc <- addLang <$> parseXml refArchive distArchive stylepath
-- parse styledoc for heading styles
let styleMaps = getStyleMaps styledoc
@@ -271,20 +281,20 @@ writeDocx opts doc@(Pandoc meta _) = do
envRTL = isRTLmeta
, envChangesAuthor = fromMaybe "unknown" username
, envChangesDate = formatTime defaultTimeLocale "%FT%XZ" utctime
- , envPrintWidth = (maybe 420 (\x -> quot x 20) pgContentWidth)
+ , envPrintWidth = maybe 420 (\x -> quot x 20) pgContentWidth
}
- ((contents, footnotes), st) <- runStateT
- (runReaderT
- (writeOpenXML opts{writerWrapText = WrapNone} doc')
- env)
- initialSt
+ ((contents, footnotes, comments), st) <- runStateT
+ (runReaderT
+ (writeOpenXML opts{writerWrapText = WrapNone} doc')
+ env)
+ initialSt
let epochtime = floor $ utcTimeToPOSIXSeconds utctime
let imgs = M.elems $ stImages st
-- create entries for images in word/media/...
- let toImageEntry (_,path,_,_,img) = toEntry ("word/" ++ path) epochtime $ toLazy img
+ let toImageEntry (_,path,_,img) = toEntry ("word/" ++ path) epochtime $ toLazy img
let imageEntries = map toImageEntry imgs
let stdAttributes =
@@ -316,7 +326,7 @@ writeDocx opts doc@(Pandoc meta _) = do
-- [Content_Types].xml
let mkOverrideNode (part', contentType') = mknode "Override"
[("PartName",part'),("ContentType",contentType')] ()
- let mkImageOverride (_, imgpath, mbMimeType, _, _) =
+ let mkImageOverride (_, imgpath, mbMimeType, _) =
mkOverrideNode ("/word/" ++ imgpath,
fromMaybe "application/octet-stream" mbMimeType)
let mkMediaOverride imgpath =
@@ -340,6 +350,8 @@ writeDocx opts doc@(Pandoc meta _) = do
"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml")
,("/word/document.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")
+ ,("/word/comments.xml",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml")
,("/word/footnotes.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml")
] ++
@@ -386,13 +398,16 @@ writeDocx opts doc@(Pandoc meta _) = do
,("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
"rId7",
"footnotes.xml")
+ ,("http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
+ "rId8",
+ "comments.xml")
]
let idMap = renumIdMap (length baserels' + 1) (headers ++ footers)
let renumHeaders = renumIds (\q -> qName q == "Id") idMap headers
let renumFooters = renumIds (\q -> qName q == "Id") idMap footers
let baserels = baserels' ++ renumHeaders ++ renumFooters
- let toImgRel (ident,path,_,_,_) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"),("Id",ident),("Target",path)] ()
+ let toImgRel (ident,path,_,_) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"),("Id",ident),("Target",path)] ()
let imgrels = map toImgRel imgs
let toLinkRel (src,ident) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"),("Id",ident),("Target",src),("TargetMode","External") ] ()
let linkrels = map toLinkRel $ M.toList $ stExternalLinks st
@@ -409,7 +424,7 @@ writeDocx opts doc@(Pandoc meta _) = do
(elChildren sectpr')
in
add_attrs (elAttribs sectpr') $ mknode "w:sectPr" [] cs
- Nothing -> (mknode "w:sectPr" [] ())
+ Nothing -> mknode "w:sectPr" [] ()
-- let sectpr = fromMaybe (mknode "w:sectPr" [] ()) mbsectpr'
let contents' = contents ++ [sectpr]
@@ -431,6 +446,10 @@ writeDocx opts doc@(Pandoc meta _) = do
$ renderXml $ mknode "Relationships" [("xmlns","http://schemas.openxmlformats.org/package/2006/relationships")]
linkrels
+ -- comments
+ let commentsEntry = toEntry "word/comments.xml" epochtime
+ $ renderXml $ mknode "w:comments" stdAttributes comments
+
-- styles
-- We only want to inject paragraph and text properties that
@@ -438,26 +457,19 @@ writeDocx opts doc@(Pandoc meta _) = do
-- are normalized as lowercase.
let newDynamicParaProps = filter
(\sty -> isNothing $ M.lookup (toLower <$> sty) $ getMap $ sParaStyleMap styleMaps)
- (stDynamicParaProps st)
+ (Set.toList $ stDynamicParaProps st)
newDynamicTextProps = filter
(\sty -> isNothing $ M.lookup (toLower <$> sty) $ getMap $ sCharStyleMap styleMaps)
- (stDynamicTextProps st)
+ (Set.toList $ stDynamicTextProps st)
let newstyles = map newParaPropToOpenXml newDynamicParaProps ++
map newTextPropToOpenXml newDynamicTextProps ++
- (styleToOpenXml styleMaps $ writerHighlightStyle opts)
- let styledoc' = styledoc{ elContent = modifyContent (elContent styledoc) }
- where
- modifyContent
- | writerHighlight opts = (++ map Elem newstyles)
- | otherwise = filter notTokStyle
- notTokStyle (Elem el) = notStyle el || notTokId el
- notTokStyle _ = True
- notStyle = (/= elemName' "style") . elName
- notTokId = maybe True (`notElem` tokStys) . findAttr (elemName' "styleId")
- tokStys = "SourceCode" : map show (enumFromTo KeywordTok NormalTok)
- elemName' = elemName (sNameSpaces styleMaps) "w"
+ (case writerHighlightStyle opts of
+ Nothing -> []
+ Just sty -> styleToOpenXml styleMaps sty)
+ let styledoc' = styledoc{ elContent = elContent styledoc ++
+ map Elem newstyles }
let styleEntry = toEntry stylepath epochtime $ renderXml styledoc'
-- construct word/numbering.xml
@@ -472,6 +484,11 @@ writeDocx opts doc@(Pandoc meta _) = do
, qName (elName e) == "abstractNum" ] ++
[Elem e | e <- allElts
, qName (elName e) == "num" ] }
+
+ let keywords = case lookupMeta "keywords" meta of
+ Just (MetaList xs) -> map stringify xs
+ _ -> []
+
let docPropsPath = "docProps/core.xml"
let docProps = mknode "cp:coreProperties"
[("xmlns:cp","http://schemas.openxmlformats.org/package/2006/metadata/core-properties")
@@ -481,6 +498,7 @@ writeDocx opts doc@(Pandoc meta _) = do
,("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")]
$ mknode "dc:title" [] (stringify $ docTitle meta)
: mknode "dc:creator" [] (intercalate "; " (map stringify $ docAuthors meta))
+ : mknode "cp:keywords" [] (intercalate ", " keywords)
: (\x -> [ mknode "dcterms:created" [("xsi:type","dcterms:W3CDTF")] x
, mknode "dcterms:modified" [("xsi:type","dcterms:W3CDTF")] x
]) (formatTime defaultTimeLocale "%FT%XZ" utctime)
@@ -509,6 +527,7 @@ writeDocx opts doc@(Pandoc meta _) = do
, "w:consecutiveHyphenLimit"
, "w:hyphenationZone"
, "w:doNotHyphenateCap"
+ , "w:evenAndOddHeaders"
]
settingsEntry <- copyChildren refArchive distArchive settingsPath epochtime settingsList
@@ -535,6 +554,7 @@ writeDocx opts doc@(Pandoc meta _) = do
let archive = foldr addEntryToArchive emptyArchive $
contentTypesEntry : relsEntry : contentEntry : relEntry :
footnoteRelEntry : numEntry : styleEntry : footnotesEntry :
+ commentsEntry :
docPropsEntry : docPropsAppEntry : themeEntry :
fontTableEntry : settingsEntry : webSettingsEntry :
imageEntries ++ headerFooterEntries ++
@@ -583,12 +603,12 @@ styleToOpenXml sm style =
[ mknode "w:u" [] () | tokFeature tokenUnderline toktype ]
]
tokStyles = tokenStyles style
- tokFeature f toktype = maybe False f $ lookup toktype tokStyles
+ tokFeature f toktype = maybe False f $ M.lookup toktype tokStyles
tokCol toktype = maybe "auto" (drop 1 . fromColor)
- $ (tokenColor =<< lookup toktype tokStyles)
+ $ (tokenColor =<< M.lookup toktype tokStyles)
`mplus` defaultColor style
tokBg toktype = maybe "auto" (drop 1 . fromColor)
- $ (tokenBackground =<< lookup toktype tokStyles)
+ $ (tokenBackground =<< M.lookup toktype tokStyles)
`mplus` backgroundColor style
parStyle | hasStyleName "Source Code" (sParaStyleMap sm) = Nothing
| otherwise = Just $
@@ -599,11 +619,11 @@ styleToOpenXml sm style =
, mknode "w:link" [("w:val","VerbatimChar")] ()
, mknode "w:pPr" []
$ mknode "w:wordWrap" [("w:val","off")] ()
- : ( maybe [] (\col -> [mknode "w:shd" [("w:val","clear"),("w:fill",drop 1 $ fromColor col)] ()])
- $ backgroundColor style )
+ :
+ maybe [] (\col -> [mknode "w:shd" [("w:val","clear"),("w:fill",drop 1 $ fromColor col)] ()]) (backgroundColor style)
]
-copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> IO Entry
+copyChildren :: (PandocMonad m) => Archive -> Archive -> String -> Integer -> [String] -> m Entry
copyChildren refArchive distArchive path timestamp elNames = do
ref <- parseXml refArchive distArchive path
dist <- parseXml distArchive distArchive path
@@ -622,11 +642,14 @@ copyChildren refArchive distArchive path timestamp elNames = do
baseListId :: Int
baseListId = 1000
-mkNumbering :: [ListMarker] -> IO [Element]
+mkNumbering :: (PandocMonad m) => [ListMarker] -> m [Element]
mkNumbering lists = do
- elts <- mapM mkAbstractNum (ordNub lists)
+ elts <- evalStateT (mapM mkAbstractNum (ordNub lists)) (mkStdGen 1848)
return $ elts ++ zipWith mkNum lists [baseListId..(baseListId + length lists - 1)]
+maxListLevel :: Int
+maxListLevel = 8
+
mkNum :: ListMarker -> Int -> Element
mkNum marker numid =
mknode "w:num" [("w:numId",show numid)]
@@ -636,15 +659,19 @@ mkNum marker numid =
BulletMarker -> []
NumberMarker _ _ start ->
map (\lvl -> mknode "w:lvlOverride" [("w:ilvl",show (lvl :: Int))]
- $ mknode "w:startOverride" [("w:val",show start)] ()) [0..6]
+ $ mknode "w:startOverride" [("w:val",show start)] ())
+ [0..maxListLevel]
-mkAbstractNum :: ListMarker -> IO Element
+mkAbstractNum :: (PandocMonad m) => ListMarker -> StateT StdGen m Element
mkAbstractNum marker = do
- nsid <- randomRIO (0x10000000 :: Integer, 0xFFFFFFFF :: Integer)
+ gen <- get
+ let (nsid, gen') = randomR (0x10000000 :: Integer, 0xFFFFFFFF :: Integer) gen
+ put gen'
return $ mknode "w:abstractNum" [("w:abstractNumId",listMarkerToId marker)]
$ mknode "w:nsid" [("w:val", printf "%8x" nsid)] ()
: mknode "w:multiLevelType" [("w:val","multilevel")] ()
- : map (mkLvl marker) [0..6]
+ : map (mkLvl marker)
+ [0..maxListLevel]
mkLvl :: ListMarker -> Int -> Element
mkLvl marker lvl =
@@ -675,33 +702,35 @@ mkLvl marker lvl =
bulletFor 3 = "\x2013"
bulletFor 4 = "\x2022"
bulletFor 5 = "\x2013"
- bulletFor _ = "\x2022"
- styleFor UpperAlpha _ = "upperLetter"
- styleFor LowerAlpha _ = "lowerLetter"
- styleFor UpperRoman _ = "upperRoman"
- styleFor LowerRoman _ = "lowerRoman"
- styleFor Decimal _ = "decimal"
+ bulletFor x = bulletFor (x `mod` 6)
+ styleFor UpperAlpha _ = "upperLetter"
+ styleFor LowerAlpha _ = "lowerLetter"
+ styleFor UpperRoman _ = "upperRoman"
+ styleFor LowerRoman _ = "lowerRoman"
+ styleFor Decimal _ = "decimal"
styleFor DefaultStyle 1 = "decimal"
styleFor DefaultStyle 2 = "lowerLetter"
styleFor DefaultStyle 3 = "lowerRoman"
styleFor DefaultStyle 4 = "decimal"
styleFor DefaultStyle 5 = "lowerLetter"
- styleFor DefaultStyle 6 = "lowerRoman"
- styleFor _ _ = "decimal"
- patternFor OneParen s = s ++ ")"
+ styleFor DefaultStyle 0 = "lowerRoman"
+ styleFor DefaultStyle x = styleFor DefaultStyle (x `mod` 6)
+ styleFor _ _ = "decimal"
+ patternFor OneParen s = s ++ ")"
patternFor TwoParens s = "(" ++ s ++ ")"
- patternFor _ s = s ++ "."
+ patternFor _ s = s ++ "."
-getNumId :: WS Int
+getNumId :: (PandocMonad m) => WS m Int
getNumId = (((baseListId - 1) +) . length) `fmap` gets stLists
-makeTOC :: WriterOptions -> WS [Element]
+
+makeTOC :: (PandocMonad m) => WriterOptions -> WS m [Element]
makeTOC opts | writerTableOfContents opts = do
- let depth = "1-"++(show (writerTOCDepth opts))
+ let depth = "1-"++show (writerTOCDepth opts)
let tocCmd = "TOC \\o \""++depth++"\" \\h \\z \\u"
tocTitle <- gets stTocTitle
title <- withParaPropM (pStyleM "TOC Heading") (blocksToOpenXML opts [Para tocTitle])
- return $
+ return
[mknode "w:sdt" [] ([
mknode "w:sdtPr" [] (
mknode "w:docPartObj" [] (
@@ -725,22 +754,20 @@ makeTOC _ = return []
-- | Convert Pandoc document to two lists of
-- OpenXML elements (the main document and footnotes).
-writeOpenXML :: WriterOptions -> Pandoc -> WS ([Element], [Element])
+writeOpenXML :: (PandocMonad m) => WriterOptions -> Pandoc -> WS m ([Element], [Element],[Element])
writeOpenXML opts (Pandoc meta blocks) = do
- let tit = docTitle meta ++ case lookupMeta "subtitle" meta of
- Just (MetaBlocks [Plain xs]) -> LineBreak : xs
- _ -> []
+ let tit = docTitle meta
let auths = docAuthors meta
let dat = docDate meta
let abstract' = case lookupMeta "abstract" meta of
- Just (MetaBlocks bs) -> bs
+ Just (MetaBlocks bs) -> bs
Just (MetaInlines ils) -> [Plain ils]
- _ -> []
+ _ -> []
let subtitle' = case lookupMeta "subtitle" meta of
Just (MetaBlocks [Plain xs]) -> xs
Just (MetaBlocks [Para xs]) -> xs
Just (MetaInlines xs) -> xs
- _ -> []
+ _ -> []
title <- withParaPropM (pStyleM "Title") $ blocksToOpenXML opts [Para tit | not (null tit)]
subtitle <- withParaPropM (pStyleM "Subtitle") $ blocksToOpenXML opts [Para subtitle' | not (null subtitle')]
authors <- withParaProp (pCustomStyle "Author") $ blocksToOpenXML opts $
@@ -750,23 +777,40 @@ writeOpenXML opts (Pandoc meta blocks) = do
then return []
else withParaProp (pCustomStyle "Abstract") $ blocksToOpenXML opts abstract'
let convertSpace (Str x : Space : Str y : xs) = Str (x ++ " " ++ y) : xs
- convertSpace (Str x : Str y : xs) = Str (x ++ y) : xs
- convertSpace xs = xs
+ convertSpace (Str x : Str y : xs) = Str (x ++ y) : xs
+ convertSpace xs = xs
let blocks' = bottomUp convertSpace blocks
- doc' <- (setFirstPara >> blocksToOpenXML opts blocks')
- notes' <- reverse `fmap` gets stFootnotes
+ doc' <- setFirstPara >> blocksToOpenXML opts blocks'
+ notes' <- reverse <$> gets stFootnotes
+ comments <- reverse <$> gets stComments
+ let toComment (kvs, ils) = do
+ annotation <- inlinesToOpenXML opts ils
+ return $
+ mknode "w:comment" [('w':':':k,v) | (k,v) <- kvs]
+ [ mknode "w:p" [] $
+ [ mknode "w:pPr" []
+ [ mknode "w:pStyle" [("w:val", "CommentText")] () ]
+ , mknode "w:r" []
+ [ mknode "w:rPr" []
+ [ mknode "w:rStyle" [("w:val", "CommentReference")] ()
+ , mknode "w:annotationRef" [] ()
+ ]
+ ]
+ ] ++ annotation
+ ]
+ comments' <- mapM toComment comments
toc <- makeTOC opts
let meta' = title ++ subtitle ++ authors ++ date ++ abstract ++ toc
- return (meta' ++ doc', notes')
+ return (meta' ++ doc', notes', comments')
-- | Convert a list of Pandoc blocks to OpenXML.
-blocksToOpenXML :: WriterOptions -> [Block] -> WS [Element]
+blocksToOpenXML :: (PandocMonad m) => WriterOptions -> [Block] -> WS m [Element]
blocksToOpenXML opts bls = concat `fmap` mapM (blockToOpenXML opts) bls
pCustomStyle :: String -> Element
pCustomStyle sty = mknode "w:pStyle" [("w:val",sty)] ()
-pStyleM :: String -> WS XML.Element
+pStyleM :: (PandocMonad m) => String -> WS m XML.Element
pStyleM styleName = do
styleMaps <- gets stStyleMaps
let sty' = getStyleId styleName $ sParaStyleMap styleMaps
@@ -775,61 +819,75 @@ pStyleM styleName = do
rCustomStyle :: String -> Element
rCustomStyle sty = mknode "w:rStyle" [("w:val",sty)] ()
-rStyleM :: String -> WS XML.Element
+rStyleM :: (PandocMonad m) => String -> WS m XML.Element
rStyleM styleName = do
styleMaps <- gets stStyleMaps
let sty' = getStyleId styleName $ sCharStyleMap styleMaps
return $ mknode "w:rStyle" [("w:val",sty')] ()
-getUniqueId :: MonadIO m => m String
+getUniqueId :: (PandocMonad m) => WS m String
-- the + 20 is to ensure that there are no clashes with the rIds
-- already in word/document.xml.rel
-getUniqueId = liftIO $ (show . (+ 20) . hashUnique) `fmap` newUnique
+getUniqueId = do
+ n <- gets stCurId
+ modify $ \st -> st{stCurId = n + 1}
+ return $ show n
-- | Key for specifying user-defined docx styles.
dynamicStyleKey :: String
dynamicStyleKey = "custom-style"
-- | Convert a Pandoc block element to OpenXML.
-blockToOpenXML :: WriterOptions -> Block -> WS [Element]
+blockToOpenXML :: (PandocMonad m) => WriterOptions -> Block -> WS m [Element]
blockToOpenXML opts blk = withDirection $ blockToOpenXML' opts blk
-blockToOpenXML' :: WriterOptions -> Block -> WS [Element]
+blockToOpenXML' :: (PandocMonad m) => WriterOptions -> Block -> WS m [Element]
blockToOpenXML' _ Null = return []
-blockToOpenXML' opts (Div (ident,classes,kvs) bs)
- | Just sty <- lookup dynamicStyleKey kvs = do
- modify $ \s -> s{stDynamicParaProps = sty : (stDynamicParaProps s)}
- withParaPropM (pStyleM sty) $ blocksToOpenXML opts bs
- | Just "rtl" <- lookup "dir" kvs = do
- let kvs' = filter (("dir", "rtl")/=) kvs
- local (\env -> env { envRTL = True }) $
- blockToOpenXML opts (Div (ident,classes,kvs') bs)
- | Just "ltr" <- lookup "dir" kvs = do
- let kvs' = filter (("dir", "ltr")/=) kvs
- local (\env -> env { envRTL = False }) $
- blockToOpenXML opts (Div (ident,classes,kvs') bs)
-blockToOpenXML' opts (Div (_,["references"],_) bs) = do
- let (hs, bs') = span isHeaderBlock bs
- header <- blocksToOpenXML opts hs
- -- We put the Bibliography style on paragraphs after the header
- rest <- withParaPropM (pStyleM "Bibliography") $ blocksToOpenXML opts bs'
- return (header ++ rest)
-blockToOpenXML' opts (Div _ bs) = blocksToOpenXML opts bs
+blockToOpenXML' opts (Div (ident,classes,kvs) bs) = do
+ stylemod <- case lookup dynamicStyleKey kvs of
+ Just sty -> do
+ modify $ \s ->
+ s{stDynamicParaProps = Set.insert sty
+ (stDynamicParaProps s)}
+ return $ withParaPropM (pStyleM sty)
+ _ -> return id
+ dirmod <- case lookup "dir" kvs of
+ Just "rtl" -> return $ local (\env -> env { envRTL = True })
+ Just "ltr" -> return $ local (\env -> env { envRTL = False })
+ _ -> return id
+ let (hs, bs') = if "references" `elem` classes
+ then span isHeaderBlock bs
+ else ([], bs)
+ let bibmod = if "references" `elem` classes
+ then withParaPropM (pStyleM "Bibliography")
+ else id
+ header <- dirmod $ stylemod $ blocksToOpenXML opts hs
+ contents <- dirmod $ bibmod $ stylemod $ blocksToOpenXML opts bs'
+ if null ident
+ then return $ header ++ contents
+ else do
+ id' <- getUniqueId
+ let bookmarkStart = mknode "w:bookmarkStart" [("w:id", id')
+ ,("w:name",ident)] ()
+ let bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] ()
+ return $ bookmarkStart : header ++ contents ++ [bookmarkEnd]
blockToOpenXML' opts (Header lev (ident,_,_) lst) = do
setFirstPara
paraProps <- withParaPropM (pStyleM ("Heading "++show lev)) $
getParaProps False
contents <- inlinesToOpenXML opts lst
- usedIdents <- gets stSectionIds
- let bookmarkName = if null ident
- then uniqueIdent lst usedIdents
- else ident
- modify $ \s -> s{ stSectionIds = Set.insert bookmarkName $ stSectionIds s }
- id' <- getUniqueId
- let bookmarkStart = mknode "w:bookmarkStart" [("w:id", id')
+ if null ident
+ then return [mknode "w:p" [] (paraProps ++contents)]
+ else do
+ let bookmarkName = ident
+ modify $ \s -> s{ stSectionIds = Set.insert bookmarkName
+ $ stSectionIds s }
+ id' <- getUniqueId
+ let bookmarkStart = mknode "w:bookmarkStart" [("w:id", id')
,("w:name",bookmarkName)] ()
- let bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] ()
- return [mknode "w:p" [] (paraProps ++ [bookmarkStart, bookmarkEnd] ++ contents)]
+ let bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] ()
+ return [mknode "w:p" [] (paraProps ++
+ [bookmarkStart] ++ contents ++ [bookmarkEnd])]
blockToOpenXML' opts (Plain lst) = withParaProp (pCustomStyle "Compact")
$ blockToOpenXML opts (Para lst)
-- title beginning with fig: indicates that the image is a figure
@@ -838,31 +896,34 @@ blockToOpenXML' opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) = do
let prop = pCustomStyle $
if null alt
then "Figure"
- else "FigureWithCaption"
+ else "CaptionedFigure"
paraProps <- local (\env -> env { envParaProperties = prop : envParaProperties env }) (getParaProps False)
contents <- inlinesToOpenXML opts [Image attr alt (src,tit)]
captionNode <- withParaProp (pCustomStyle "ImageCaption")
$ blockToOpenXML opts (Para alt)
return $ mknode "w:p" [] (paraProps ++ contents) : captionNode
--- fixDisplayMath sometimes produces a Para [] as artifact
-blockToOpenXML' _ (Para []) = return []
-blockToOpenXML' opts (Para lst) = do
- isFirstPara <- gets stFirstPara
- paraProps <- getParaProps $ case lst of
- [Math DisplayMath _] -> True
- _ -> False
- bodyTextStyle <- pStyleM "Body Text"
- let paraProps' = case paraProps of
- [] | isFirstPara -> [mknode "w:pPr" [] [pCustomStyle "FirstParagraph"]]
- [] -> [mknode "w:pPr" [] [bodyTextStyle]]
- ps -> ps
- modify $ \s -> s { stFirstPara = False }
- contents <- inlinesToOpenXML opts lst
- return [mknode "w:p" [] (paraProps' ++ contents)]
+blockToOpenXML' opts (Para lst)
+ | null lst && not (isEnabled Ext_empty_paragraphs opts) = return []
+ | otherwise = do
+ isFirstPara <- gets stFirstPara
+ paraProps <- getParaProps $ case lst of
+ [Math DisplayMath _] -> True
+ _ -> False
+ bodyTextStyle <- pStyleM "Body Text"
+ let paraProps' = case paraProps of
+ [] | isFirstPara -> [mknode "w:pPr" []
+ [pCustomStyle "FirstParagraph"]]
+ [] -> [mknode "w:pPr" [] [bodyTextStyle]]
+ ps -> ps
+ modify $ \s -> s { stFirstPara = False }
+ contents <- inlinesToOpenXML opts lst
+ return [mknode "w:p" [] (paraProps' ++ contents)]
blockToOpenXML' opts (LineBlock lns) = blockToOpenXML opts $ linesToPara lns
-blockToOpenXML' _ (RawBlock format str)
+blockToOpenXML' _ b@(RawBlock format str)
| format == Format "openxml" = return [ x | Elem x <- parseXML str ]
- | otherwise = return []
+ | otherwise = do
+ report $ BlockNotRendered b
+ return []
blockToOpenXML' opts (BlockQuote blocks) = do
p <- withParaPropM (pStyleM "Block Text") $ blocksToOpenXML opts blocks
setFirstPara
@@ -914,9 +975,9 @@ blockToOpenXML' opts (Table caption aligns widths headers rows) = do
caption' ++
[mknode "w:tbl" []
( mknode "w:tblPr" []
- ( mknode "w:tblStyle" [("w:val","TableNormal")] () :
+ ( mknode "w:tblStyle" [("w:val","Table")] () :
mknode "w:tblW" [("w:type", "pct"), ("w:w", show rowwidth)] () :
- mknode "w:tblLook" [("w:firstRow","1") | hasHeader ] () :
+ mknode "w:tblLook" [("w:firstRow",if hasHeader then "1" else "0") ] () :
[ mknode "w:tblCaption" [("w:val", captionStr)] ()
| not (null caption) ] )
: mknode "w:tblGrid" []
@@ -945,7 +1006,7 @@ blockToOpenXML' opts (DefinitionList items) = do
setFirstPara
return l
-definitionListItemToOpenXML :: WriterOptions -> ([Inline],[[Block]]) -> WS [Element]
+definitionListItemToOpenXML :: (PandocMonad m) => WriterOptions -> ([Inline],[[Block]]) -> WS m [Element]
definitionListItemToOpenXML opts (term,defs) = do
term' <- withParaProp (pCustomStyle "DefinitionTerm")
$ blockToOpenXML opts (Para term)
@@ -953,12 +1014,12 @@ definitionListItemToOpenXML opts (term,defs) = do
$ concat `fmap` mapM (blocksToOpenXML opts) defs
return $ term' ++ defs'
-addList :: ListMarker -> WS ()
+addList :: (PandocMonad m) => ListMarker -> WS m ()
addList marker = do
lists <- gets stLists
modify $ \st -> st{ stLists = lists ++ [marker] }
-listItemToOpenXML :: WriterOptions -> Int -> [Block] -> WS [Element]
+listItemToOpenXML :: (PandocMonad m) => WriterOptions -> Int -> [Block] -> WS m [Element]
listItemToOpenXML _ _ [] = return []
listItemToOpenXML opts numid (first:rest) = do
first' <- withNumId numid $ blockToOpenXML opts first
@@ -968,121 +1029,162 @@ listItemToOpenXML opts numid (first:rest) = do
alignmentToString :: Alignment -> [Char]
alignmentToString alignment = case alignment of
- AlignLeft -> "left"
- AlignRight -> "right"
- AlignCenter -> "center"
+ AlignLeft -> "left"
+ AlignRight -> "right"
+ AlignCenter -> "center"
AlignDefault -> "left"
-- | Convert a list of inline elements to OpenXML.
-inlinesToOpenXML :: WriterOptions -> [Inline] -> WS [Element]
+inlinesToOpenXML :: (PandocMonad m) => WriterOptions -> [Inline] -> WS m [Element]
inlinesToOpenXML opts lst = concat `fmap` mapM (inlineToOpenXML opts) lst
-withNumId :: Int -> WS a -> WS a
+withNumId :: (PandocMonad m) => Int -> WS m a -> WS m a
withNumId numid = local $ \env -> env{ envListNumId = numid }
-asList :: WS a -> WS a
+asList :: (PandocMonad m) => WS m a -> WS m a
asList = local $ \env -> env{ envListLevel = envListLevel env + 1 }
-getTextProps :: WS [Element]
+getTextProps :: (PandocMonad m) => WS m [Element]
getTextProps = do
props <- asks envTextProperties
return $ if null props
then []
else [mknode "w:rPr" [] props]
-withTextProp :: Element -> WS a -> WS a
+withTextProp :: PandocMonad m => Element -> WS m a -> WS m a
withTextProp d p =
local (\env -> env {envTextProperties = d : envTextProperties env}) p
-withTextPropM :: WS Element -> WS a -> WS a
+withTextPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
withTextPropM = (. flip withTextProp) . (>>=)
-getParaProps :: Bool -> WS [Element]
+getParaProps :: PandocMonad m => Bool -> WS m [Element]
getParaProps displayMathPara = do
props <- asks envParaProperties
listLevel <- asks envListLevel
numid <- asks envListNumId
- let listPr = if listLevel >= 0 && not displayMathPara
- then [ mknode "w:numPr" []
- [ mknode "w:numId" [("w:val",show numid)] ()
- , mknode "w:ilvl" [("w:val",show listLevel)] () ]
- ]
- else []
+ let listPr = [mknode "w:numPr" []
+ [ mknode "w:numId" [("w:val",show numid)] ()
+ , mknode "w:ilvl" [("w:val",show listLevel)] () ] | listLevel >= 0 && not displayMathPara]
return $ case props ++ listPr of
[] -> []
ps -> [mknode "w:pPr" [] ps]
-withParaProp :: Element -> WS a -> WS a
+withParaProp :: PandocMonad m => Element -> WS m a -> WS m a
withParaProp d p =
local (\env -> env {envParaProperties = d : envParaProperties env}) p
-withParaPropM :: WS Element -> WS a -> WS a
+withParaPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
withParaPropM = (. flip withParaProp) . (>>=)
-formattedString :: String -> WS [Element]
-formattedString str = do
- props <- getTextProps
+formattedString :: PandocMonad m => String -> WS m [Element]
+formattedString str =
+ -- properly handle soft hyphens
+ case splitBy (=='\173') str of
+ [w] -> formattedString' w
+ ws -> do
+ sh <- formattedRun [mknode "w:softHyphen" [] ()]
+ intercalate sh <$> mapM formattedString' ws
+
+formattedString' :: PandocMonad m => String -> WS m [Element]
+formattedString' str = do
inDel <- asks envInDel
- return [ mknode "w:r" [] $
- props ++
- [ mknode (if inDel then "w:delText" else "w:t")
- [("xml:space","preserve")] (stripInvalidChars str) ] ]
+ formattedRun [ mknode (if inDel then "w:delText" else "w:t")
+ [("xml:space","preserve")] (stripInvalidChars str) ]
-setFirstPara :: WS ()
+formattedRun :: PandocMonad m => [Element] -> WS m [Element]
+formattedRun els = do
+ props <- getTextProps
+ return [ mknode "w:r" [] $ props ++ els ]
+
+setFirstPara :: PandocMonad m => WS m ()
setFirstPara = modify $ \s -> s { stFirstPara = True }
-- | Convert an inline element to OpenXML.
-inlineToOpenXML :: WriterOptions -> Inline -> WS [Element]
+inlineToOpenXML :: PandocMonad m => WriterOptions -> Inline -> WS m [Element]
inlineToOpenXML opts il = withDirection $ inlineToOpenXML' opts il
-inlineToOpenXML' :: WriterOptions -> Inline -> WS [Element]
-inlineToOpenXML' _ (Str str) = formattedString str
+inlineToOpenXML' :: PandocMonad m => WriterOptions -> Inline -> WS m [Element]
+inlineToOpenXML' _ (Str str) =
+ formattedString str
inlineToOpenXML' opts Space = inlineToOpenXML opts (Str " ")
inlineToOpenXML' opts SoftBreak = inlineToOpenXML opts (Str " ")
-inlineToOpenXML' opts (Span (ident,classes,kvs) ils)
- | Just sty <- lookup dynamicStyleKey kvs = do
- let kvs' = filter ((dynamicStyleKey, sty)/=) kvs
- modify $ \s -> s{stDynamicTextProps = sty : (stDynamicTextProps s)}
- withTextProp (rCustomStyle sty) $
- inlineToOpenXML opts (Span (ident,classes,kvs') ils)
- | Just "rtl" <- lookup "dir" kvs = do
- let kvs' = filter (("dir", "rtl")/=) kvs
- local (\env -> env { envRTL = True }) $
- inlineToOpenXML opts (Span (ident,classes,kvs') ils)
- | Just "ltr" <- lookup "dir" kvs = do
- let kvs' = filter (("dir", "ltr")/=) kvs
- local (\env -> env { envRTL = False }) $
- inlineToOpenXML opts (Span (ident,classes,kvs') ils)
- | "insertion" `elem` classes = do
- defaultAuthor <- asks envChangesAuthor
- defaultDate <- asks envChangesDate
- let author = fromMaybe defaultAuthor (lookup "author" kvs)
- date = fromMaybe defaultDate (lookup "date" kvs)
- insId <- gets stInsId
- modify $ \s -> s{stInsId = (insId + 1)}
- x <- inlinesToOpenXML opts ils
- return [ mknode "w:ins" [("w:id", (show insId)),
- ("w:author", author),
- ("w:date", date)]
- x ]
- | "deletion" `elem` classes = do
- defaultAuthor <- asks envChangesAuthor
- defaultDate <- asks envChangesDate
- let author = fromMaybe defaultAuthor (lookup "author" kvs)
- date = fromMaybe defaultDate (lookup "date" kvs)
- delId <- gets stDelId
- modify $ \s -> s{stDelId = (delId + 1)}
- x <- local (\env -> env {envInDel = True}) (inlinesToOpenXML opts ils)
- return [ mknode "w:del" [("w:id", (show delId)),
- ("w:author", author),
- ("w:date", date)]
- x ]
- | otherwise = do
- let off x = withTextProp (mknode x [("w:val","0")] ())
- ((if "csl-no-emph" `elem` classes then off "w:i" else id) .
- (if "csl-no-strong" `elem` classes then off "w:b" else id) .
- (if "csl-no-smallcaps" `elem` classes then off "w:smallCaps" else id))
- $ inlinesToOpenXML opts ils
+inlineToOpenXML' _ (Span (ident,["comment-start"],kvs) ils) = do
+ -- prefer the "id" in kvs, since that is the one produced by the docx
+ -- reader.
+ let ident' = fromMaybe ident (lookup "id" kvs)
+ kvs' = filter (("id" /=) . fst) kvs
+ modify $ \st -> st{ stComments = (("id",ident'):kvs', ils) : stComments st }
+ return [ mknode "w:commentRangeStart" [("w:id", ident')] () ]
+inlineToOpenXML' _ (Span (ident,["comment-end"],kvs) _) =
+ -- prefer the "id" in kvs, since that is the one produced by the docx
+ -- reader.
+ let ident' = fromMaybe ident (lookup "id" kvs)
+ in
+ return [ mknode "w:commentRangeEnd" [("w:id", ident')] ()
+ , mknode "w:r" []
+ [ mknode "w:rPr" []
+ [ mknode "w:rStyle" [("w:val", "CommentReference")] () ]
+ , mknode "w:commentReference" [("w:id", ident')] () ]
+ ]
+inlineToOpenXML' opts (Span (ident,classes,kvs) ils) = do
+ stylemod <- case lookup dynamicStyleKey kvs of
+ Just sty -> do
+ modify $ \s ->
+ s{stDynamicTextProps = Set.insert sty
+ (stDynamicTextProps s)}
+ return $ withTextPropM (rStyleM sty)
+ _ -> return id
+ let dirmod = case lookup "dir" kvs of
+ Just "rtl" -> local (\env -> env { envRTL = True })
+ Just "ltr" -> local (\env -> env { envRTL = False })
+ _ -> id
+ let off x = withTextProp (mknode x [("w:val","0")] ())
+ let pmod = (if "csl-no-emph" `elem` classes then off "w:i" else id) .
+ (if "csl-no-strong" `elem` classes then off "w:b" else id) .
+ (if "csl-no-smallcaps" `elem` classes
+ then off "w:smallCaps"
+ else id)
+ insmod <- if "insertion" `elem` classes
+ then do
+ defaultAuthor <- asks envChangesAuthor
+ defaultDate <- asks envChangesDate
+ let author = fromMaybe defaultAuthor (lookup "author" kvs)
+ date = fromMaybe defaultDate (lookup "date" kvs)
+ insId <- gets stInsId
+ modify $ \s -> s{stInsId = insId + 1}
+ return $ \f -> do
+ x <- f
+ return [ mknode "w:ins"
+ [("w:id", show insId),
+ ("w:author", author),
+ ("w:date", date)] x ]
+ else return id
+ delmod <- if "deletion" `elem` classes
+ then do
+ defaultAuthor <- asks envChangesAuthor
+ defaultDate <- asks envChangesDate
+ let author = fromMaybe defaultAuthor (lookup "author" kvs)
+ date = fromMaybe defaultDate (lookup "date" kvs)
+ delId <- gets stDelId
+ modify $ \s -> s{stDelId = delId + 1}
+ return $ \f -> local (\env->env{envInDel=True}) $ do
+ x <- f
+ return [mknode "w:del"
+ [("w:id", show delId),
+ ("w:author", author),
+ ("w:date", date)] x]
+ else return id
+ contents <- insmod $ delmod $ dirmod $ stylemod $ pmod
+ $ inlinesToOpenXML opts ils
+ if null ident
+ then return contents
+ else do
+ id' <- getUniqueId
+ let bookmarkStart = mknode "w:bookmarkStart" [("w:id", id')
+ ,("w:name",ident)] ()
+ let bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] ()
+ return $ bookmarkStart : contents ++ [bookmarkEnd]
inlineToOpenXML' opts (Strong lst) =
withTextProp (mknode "w:b" [] ()) $ inlinesToOpenXML opts lst
inlineToOpenXML' opts (Emph lst) =
@@ -1100,40 +1202,40 @@ inlineToOpenXML' opts (Strikeout lst) =
withTextProp (mknode "w:strike" [] ())
$ inlinesToOpenXML opts lst
inlineToOpenXML' _ LineBreak = return [br]
-inlineToOpenXML' _ (RawInline f str)
+inlineToOpenXML' _ il@(RawInline f str)
| f == Format "openxml" = return [ x | Elem x <- parseXML str ]
- | otherwise = return []
+ | otherwise = do
+ report $ InlineNotRendered il
+ return []
inlineToOpenXML' opts (Quoted quoteType lst) =
inlinesToOpenXML opts $ [Str open] ++ lst ++ [Str close]
where (open, close) = case quoteType of
SingleQuote -> ("\x2018", "\x2019")
DoubleQuote -> ("\x201C", "\x201D")
inlineToOpenXML' opts (Math mathType str) = do
- let displayType = if mathType == DisplayMath
- then DisplayBlock
- else DisplayInline
- when (displayType == DisplayBlock) setFirstPara
- case writeOMML displayType <$> readTeX str of
- Right r -> return [r]
- Left e -> do
- warn $ "Cannot convert the following TeX math, skipping:\n" ++ str ++
- "\n" ++ e
- inlinesToOpenXML opts (texMathToInlines mathType str)
+ when (mathType == DisplayMath) setFirstPara
+ res <- (lift . lift) (convertMath writeOMML mathType str)
+ case res of
+ Right r -> return [r]
+ Left il -> inlineToOpenXML' opts il
inlineToOpenXML' opts (Cite _ lst) = inlinesToOpenXML opts lst
inlineToOpenXML' opts (Code attrs str) = do
let unhighlighted = intercalate [br] `fmap`
- (mapM formattedString $ lines str)
+ mapM formattedString (lines str)
formatOpenXML _fmtOpts = intercalate [br] . map (map toHlTok)
toHlTok (toktype,tok) = mknode "w:r" []
[ mknode "w:rPr" []
[ rCustomStyle (show toktype) ]
, mknode "w:t" [("xml:space","preserve")] (T.unpack tok) ]
withTextProp (rCustomStyle "VerbatimChar")
- $ if writerHighlight opts
- then case highlight formatOpenXML attrs str of
- Nothing -> unhighlighted
- Just h -> return h
- else unhighlighted
+ $ if isNothing (writerHighlightStyle opts)
+ then unhighlighted
+ else case highlight (writerSyntaxMap opts)
+ formatOpenXML attrs str of
+ Right h -> return h
+ Left msg -> do
+ unless (null msg) $ report $ CouldNotHighlight msg
+ unhighlighted
inlineToOpenXML' opts (Note bs) = do
notes <- gets stFootnotes
notenum <- getUniqueId
@@ -1151,7 +1253,7 @@ inlineToOpenXML' opts (Note bs) = do
, envTextProperties = [] })
(withParaPropM (pStyleM "Footnote Text") $ blocksToOpenXML opts
$ insertNoteRef bs)
- let newnote = mknode "w:footnote" [("w:id", notenum)] $ contents
+ let newnote = mknode "w:footnote" [("w:id", notenum)] contents
modify $ \s -> s{ stFootnotes = newnote : notes }
return [ mknode "w:r" []
[ mknode "w:rPr" [] footnoteStyle
@@ -1173,81 +1275,109 @@ inlineToOpenXML' opts (Link _ txt (src,_)) = do
return i
return [ mknode "w:hyperlink" [("r:id",id')] contents ]
inlineToOpenXML' opts (Image attr alt (src, title)) = do
- -- first, check to see if we've already done this image
pageWidth <- asks envPrintWidth
imgs <- gets stImages
- case M.lookup src imgs of
- Just (_,_,_,elt,_) -> return [elt]
- Nothing -> do
- res <- liftIO $
- fetchItem' (writerMediaBag opts) (writerSourceURL opts) src
- case res of
- Left (_ :: E.SomeException) -> do
- warn $ "Could not find image `" ++ src ++ "', skipping..."
- -- emit alt text
- inlinesToOpenXML opts alt
- Right (img, mt) -> do
- ident <- ("rId"++) `fmap` getUniqueId
- let (xpt,ypt) = desiredSizeInPoints opts attr
- (either (const def) id (imageSize img))
- -- 12700 emu = 1 pt
- let (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700) (pageWidth * 12700)
- let cNvPicPr = mknode "pic:cNvPicPr" [] $
- mknode "a:picLocks" [("noChangeArrowheads","1"),("noChangeAspect","1")] ()
- let nvPicPr = mknode "pic:nvPicPr" []
- [ mknode "pic:cNvPr"
- [("descr",src),("id","0"),("name","Picture")] ()
- , cNvPicPr ]
- let blipFill = mknode "pic:blipFill" []
- [ mknode "a:blip" [("r:embed",ident)] ()
- , mknode "a:stretch" [] $ mknode "a:fillRect" [] () ]
- let xfrm = mknode "a:xfrm" []
- [ mknode "a:off" [("x","0"),("y","0")] ()
- , mknode "a:ext" [("cx",show xemu),("cy",show yemu)] () ]
- let prstGeom = mknode "a:prstGeom" [("prst","rect")] $
- mknode "a:avLst" [] ()
- let ln = mknode "a:ln" [("w","9525")]
- [ mknode "a:noFill" [] ()
- , mknode "a:headEnd" [] ()
- , mknode "a:tailEnd" [] () ]
- let spPr = mknode "pic:spPr" [("bwMode","auto")]
- [xfrm, prstGeom, mknode "a:noFill" [] (), ln]
- let graphic = mknode "a:graphic" [] $
- mknode "a:graphicData" [("uri","http://schemas.openxmlformats.org/drawingml/2006/picture")]
- [ mknode "pic:pic" []
- [ nvPicPr
- , blipFill
- , spPr ] ]
- let imgElt = mknode "w:r" [] $
- mknode "w:drawing" [] $
- mknode "wp:inline" []
- [ mknode "wp:extent" [("cx",show xemu),("cy",show yemu)] ()
- , mknode "wp:effectExtent" [("b","0"),("l","0"),("r","0"),("t","0")] ()
- , mknode "wp:docPr" [("descr",stringify alt), ("title", title), ("id","1"),("name","Picture")] ()
- , graphic ]
- let imgext = case mt >>= extensionFromMimeType of
- Just x -> '.':x
- Nothing -> case imageType img of
- Just Png -> ".png"
- Just Jpeg -> ".jpeg"
- Just Gif -> ".gif"
- Just Pdf -> ".pdf"
- Just Eps -> ".eps"
- Nothing -> ""
- if null imgext
- then -- without an extension there is no rule for content type
- inlinesToOpenXML opts alt -- return alt to avoid corrupted docx
- else do
- let imgpath = "media/" ++ ident ++ imgext
- let mbMimeType = mt <|> getMimeType imgpath
- -- insert mime type to use in constructing [Content_Types].xml
- modify $ \st -> st{ stImages =
- M.insert src (ident, imgpath, mbMimeType, imgElt, img)
- $ stImages st }
- return [imgElt]
+ let
+ stImage = M.lookup src imgs
+ generateImgElt (ident, _, _, img) =
+ let
+ (xpt,ypt) = desiredSizeInPoints opts attr
+ (either (const def) id (imageSize opts img))
+ -- 12700 emu = 1 pt
+ (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700)
+ (pageWidth * 12700)
+ cNvPicPr = mknode "pic:cNvPicPr" [] $
+ mknode "a:picLocks" [("noChangeArrowheads","1")
+ ,("noChangeAspect","1")] ()
+ nvPicPr = mknode "pic:nvPicPr" []
+ [ mknode "pic:cNvPr"
+ [("descr",src),("id","0"),("name","Picture")] ()
+ , cNvPicPr ]
+ blipFill = mknode "pic:blipFill" []
+ [ mknode "a:blip" [("r:embed",ident)] ()
+ , mknode "a:stretch" [] $
+ mknode "a:fillRect" [] ()
+ ]
+ xfrm = mknode "a:xfrm" []
+ [ mknode "a:off" [("x","0"),("y","0")] ()
+ , mknode "a:ext" [("cx",show xemu)
+ ,("cy",show yemu)] () ]
+ prstGeom = mknode "a:prstGeom" [("prst","rect")] $
+ mknode "a:avLst" [] ()
+ ln = mknode "a:ln" [("w","9525")]
+ [ mknode "a:noFill" [] ()
+ , mknode "a:headEnd" [] ()
+ , mknode "a:tailEnd" [] () ]
+ spPr = mknode "pic:spPr" [("bwMode","auto")]
+ [xfrm, prstGeom, mknode "a:noFill" [] (), ln]
+ graphic = mknode "a:graphic" [] $
+ mknode "a:graphicData"
+ [("uri","http://schemas.openxmlformats.org/drawingml/2006/picture")]
+ [ mknode "pic:pic" []
+ [ nvPicPr
+ , blipFill
+ , spPr
+ ]
+ ]
+ imgElt = mknode "w:r" [] $
+ mknode "w:drawing" [] $
+ mknode "wp:inline" []
+ [ mknode "wp:extent" [("cx",show xemu),("cy",show yemu)] ()
+ , mknode "wp:effectExtent"
+ [("b","0"),("l","0"),("r","0"),("t","0")] ()
+ , mknode "wp:docPr"
+ [ ("descr", stringify alt)
+ , ("title", title)
+ , ("id","1")
+ , ("name","Picture")
+ ] ()
+ , graphic
+ ]
+ in
+ imgElt
+
+ case stImage of
+ Just imgData -> return $ [generateImgElt imgData]
+ Nothing -> ( do --try
+ (img, mt) <- P.fetchItem src
+ ident <- ("rId"++) `fmap` getUniqueId
+
+ let
+ imgext = case mt >>= extensionFromMimeType of
+ Just x -> '.':x
+ Nothing -> case imageType img of
+ Just Png -> ".png"
+ Just Jpeg -> ".jpeg"
+ Just Gif -> ".gif"
+ Just Pdf -> ".pdf"
+ Just Eps -> ".eps"
+ Just Svg -> ".svg"
+ Just Emf -> ".emf"
+ Nothing -> ""
+ imgpath = "media/" ++ ident ++ imgext
+ mbMimeType = mt <|> getMimeType imgpath
+
+ imgData = (ident, imgpath, mbMimeType, img)
+
+ if null imgext
+ then -- without an extension there is no rule for content type
+ inlinesToOpenXML opts alt -- return alt to avoid corrupted docx
+ else do
+ -- insert mime type to use in constructing [Content_Types].xml
+ modify $ \st -> st { stImages = M.insert src imgData $ stImages st }
+ return [generateImgElt imgData]
+ )
+ `catchError` ( \e -> do
+ report $ CouldNotFetchResource src (show e)
+ -- emit alt text
+ inlinesToOpenXML opts alt
+ )
br :: Element
-br = mknode "w:r" [] [mknode "w:br" [("w:type","textWrapping")] () ]
+br = breakElement "textWrapping"
+
+breakElement :: String -> Element
+breakElement kind = mknode "w:r" [] [mknode "w:br" [("w:type",kind)] () ]
-- Word will insert these footnotes into the settings.xml file
-- (whether or not they're visible in the document). If they're in the
@@ -1255,35 +1385,18 @@ br = mknode "w:r" [] [mknode "w:br" [("w:type","textWrapping")] () ]
-- problems. So we want to make sure we insert them into our document.
defaultFootnotes :: [Element]
defaultFootnotes = [ mknode "w:footnote"
- [("w:type", "separator"), ("w:id", "-1")] $
+ [("w:type", "separator"), ("w:id", "-1")]
[ mknode "w:p" [] $
[mknode "w:r" [] $
[ mknode "w:separator" [] ()]]]
, mknode "w:footnote"
- [("w:type", "continuationSeparator"), ("w:id", "0")] $
+ [("w:type", "continuationSeparator"), ("w:id", "0")]
[ mknode "w:p" [] $
[ mknode "w:r" [] $
[ mknode "w:continuationSeparator" [] ()]]]]
-parseXml :: Archive -> Archive -> String -> IO Element
-parseXml refArchive distArchive relpath =
- case findEntryByPath relpath refArchive `mplus`
- findEntryByPath relpath distArchive of
- Nothing -> fail $ relpath ++ " missing in reference docx"
- Just e -> case parseXMLDoc . UTF8.toStringLazy . fromEntry $ e of
- Nothing -> fail $ relpath ++ " corrupt in reference docx"
- Just d -> return d
-
--- | Scales the image to fit the page
--- sizes are passed in emu
-fitToPage :: (Double, Double) -> Integer -> (Integer, Integer)
-fitToPage (x, y) pageWidth
- -- Fixes width to the page width and scales the height
- | x > fromIntegral pageWidth =
- (pageWidth, floor $ ((fromIntegral pageWidth) / x) * y)
- | otherwise = (floor x, floor y)
-
-withDirection :: WS a -> WS a
+
+withDirection :: PandocMonad m => WS m a -> WS m a
withDirection x = do
isRTL <- asks envRTL
paraProps <- asks envParaProperties
@@ -1296,8 +1409,8 @@ withDirection x = do
if isRTL
-- if we are going right-to-left, we (re?)add the properties.
then flip local x $
- \env -> env { envParaProperties = (mknode "w:bidi" [] ()) : paraProps'
- , envTextProperties = (mknode "w:rtl" [] ()) : textProps'
+ \env -> env { envParaProperties = mknode "w:bidi" [] () : paraProps'
+ , envTextProperties = mknode "w:rtl" [] () : textProps'
}
else flip local x $ \env -> env { envParaProperties = paraProps'
, envTextProperties = textProps'
diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs
index 7459f1b42..dda21d23d 100644
--- a/src/Text/Pandoc/Writers/DokuWiki.hs
+++ b/src/Text/Pandoc/Writers/DokuWiki.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.DokuWiki
- Copyright : Copyright (C) 2008-2015 John MacFarlane
+ Copyright : Copyright (C) 2008-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Clare Macrae <clare.macrae@googlemail.com>
@@ -39,71 +39,64 @@ DokuWiki: <https://www.dokuwiki.org/dokuwiki>
-}
module Text.Pandoc.Writers.DokuWiki ( writeDokuWiki ) where
+import Control.Monad (zipWithM)
+import Control.Monad.Reader (ReaderT, ask, local, runReaderT)
+import Control.Monad.State.Strict (StateT, evalStateT)
+import Data.Default (Default (..))
+import Data.List (intercalate, intersect, isPrefixOf, transpose)
+import Data.Text (Text, pack)
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
-import Text.Pandoc.Options ( WriterOptions(
- writerTableOfContents
- , writerTemplate
- , writerWrapText), WrapOption(..) )
-import Text.Pandoc.Shared ( escapeURI, linesToPara, removeFormatting
- , camelCaseToHyphenated, trimr, normalize, substitute )
-import Text.Pandoc.Writers.Shared ( defField, metaToJSON )
import Text.Pandoc.ImageSize
-import Text.Pandoc.Templates ( renderTemplate' )
-import Data.List ( intersect, intercalate, isPrefixOf, transpose )
-import Data.Default (Default(..))
-import Network.URI ( isURI )
-import Control.Monad ( zipWithM )
-import Control.Monad.State ( modify, State, get, evalState )
-import Control.Monad.Reader ( ReaderT, runReaderT, ask, local )
+import Text.Pandoc.Logging
+import Text.Pandoc.Options (WrapOption (..), WriterOptions (writerTableOfContents, writerTemplate, writerWrapText))
+import Text.Pandoc.Shared (camelCaseToHyphenated, escapeURI, isURI, linesToPara,
+ removeFormatting, substitute, trimr)
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Shared (defField, metaToJSON)
data WriterState = WriterState {
- stNotes :: Bool -- True if there are notes
}
data WriterEnvironment = WriterEnvironment {
- stIndent :: String -- Indent after the marker at the beginning of list items
- , stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
+ stIndent :: String -- Indent after the marker at the beginning of list items
+ , stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
, stBackSlashLB :: Bool -- True if we should produce formatted strings with newlines (as in a table cell)
}
instance Default WriterState where
- def = WriterState { stNotes = False }
+ def = WriterState {}
instance Default WriterEnvironment where
def = WriterEnvironment { stIndent = ""
, stUseTags = False
, stBackSlashLB = False }
-type DokuWiki = ReaderT WriterEnvironment (State WriterState)
+type DokuWiki m = ReaderT WriterEnvironment (StateT WriterState m)
-- | Convert Pandoc to DokuWiki.
-writeDokuWiki :: WriterOptions -> Pandoc -> String
+writeDokuWiki :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeDokuWiki opts document =
- runDokuWiki (pandocToDokuWiki opts $ normalize document)
+ runDokuWiki (pandocToDokuWiki opts document)
-runDokuWiki :: DokuWiki a -> a
-runDokuWiki = flip evalState def . flip runReaderT def
+runDokuWiki :: PandocMonad m => DokuWiki m a -> m a
+runDokuWiki = flip evalStateT def . flip runReaderT def
-- | Return DokuWiki representation of document.
-pandocToDokuWiki :: WriterOptions -> Pandoc -> DokuWiki String
+pandocToDokuWiki :: PandocMonad m
+ => WriterOptions -> Pandoc -> DokuWiki m Text
pandocToDokuWiki opts (Pandoc meta blocks) = do
metadata <- metaToJSON opts
(fmap trimr . blockListToDokuWiki opts)
(inlineListToDokuWiki opts)
meta
body <- blockListToDokuWiki opts blocks
- notesExist <- stNotes <$> get
- let notes = if notesExist
- then "" -- TODO Was "\n<references />" Check whether I can really remove this:
- -- if it is definitely to do with footnotes, can remove this whole bit
- else ""
- let main = body ++ notes
+ let main = pack body
let context = defField "body" main
- $ defField "toc" (writerTableOfContents opts)
- $ metadata
+ $ defField "toc" (writerTableOfContents opts) metadata
case writerTemplate opts of
Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
-- | Escape special characters for DokuWiki.
escapeString :: String -> String
@@ -112,9 +105,10 @@ escapeString = substitute "__" "%%__%%" .
substitute "//" "%%//%%"
-- | Convert Pandoc block element to DokuWiki.
-blockToDokuWiki :: WriterOptions -- ^ Options
+blockToDokuWiki :: PandocMonad m
+ => WriterOptions -- ^ Options
-> Block -- ^ Block element
- -> DokuWiki String
+ -> DokuWiki m String
blockToDokuWiki _ Null = return ""
@@ -149,12 +143,13 @@ blockToDokuWiki opts (Para inlines) = do
blockToDokuWiki opts (LineBlock lns) =
blockToDokuWiki opts $ linesToPara lns
-blockToDokuWiki _ (RawBlock f str)
+blockToDokuWiki _ b@(RawBlock f str)
| f == Format "dokuwiki" = return str
-- See https://www.dokuwiki.org/wiki:syntax
-- use uppercase HTML tag for block-level content:
| f == Format "html" = return $ "<HTML>\n" ++ str ++ "\n</HTML>"
- | otherwise = return ""
+ | otherwise = "" <$
+ report (BlockNotRendered b)
blockToDokuWiki _ HorizontalRule = return "\n----\n"
@@ -177,7 +172,7 @@ blockToDokuWiki _ (CodeBlock (_,classes,_) str) = do
"visualfoxpro", "winbatch", "xml", "xpp", "z80"]
return $ "<code" ++
(case at of
- [] -> ">\n"
+ [] -> ">\n"
(x:_) -> " " ++ x ++ ">\n") ++ str ++ "\n</code>"
blockToDokuWiki opts (BlockQuote blocks) = do
@@ -198,7 +193,7 @@ blockToDokuWiki opts (Table capt aligns _ headers rows) = do
rows' <- mapM (zipWithM (tableItemToDokuWiki opts) aligns) rows
let widths = map (maximum . map length) $ transpose (headers':rows')
let padTo (width, al) s =
- case (width - length s) of
+ case width - length s of
x | x > 0 ->
if al == AlignLeft || al == AlignDefault
then s ++ replicate x ' '
@@ -278,21 +273,27 @@ listAttribsToString (startnum, numstyle, _) =
else "")
-- | Convert bullet list item (list of blocks) to DokuWiki.
-listItemToDokuWiki :: WriterOptions -> [Block] -> DokuWiki String
+listItemToDokuWiki :: PandocMonad m
+ => WriterOptions -> [Block] -> DokuWiki m String
listItemToDokuWiki opts items = do
- contents <- blockListToDokuWiki opts items
useTags <- stUseTags <$> ask
if useTags
- then return $ "<HTML><li></HTML>" ++ contents ++ "<HTML></li></HTML>"
+ then do
+ contents <- blockListToDokuWiki opts items
+ return $ "<HTML><li></HTML>" ++ contents ++ "<HTML></li></HTML>"
else do
+ bs <- mapM (blockToDokuWiki opts) items
+ let contents = case items of
+ [_, CodeBlock _ _] -> concat bs
+ _ -> vcat bs
indent <- stIndent <$> ask
backSlash <- stBackSlashLB <$> ask
- let indent' = if backSlash then (drop 2 indent) else indent
+ let indent' = if backSlash then drop 2 indent else indent
return $ indent' ++ "* " ++ contents
-- | Convert ordered list item (list of blocks) to DokuWiki.
-- | TODO Emiminate dreadful duplication of text from listItemToDokuWiki
-orderedListItemToDokuWiki :: WriterOptions -> [Block] -> DokuWiki String
+orderedListItemToDokuWiki :: PandocMonad m => WriterOptions -> [Block] -> DokuWiki m String
orderedListItemToDokuWiki opts items = do
contents <- blockListToDokuWiki opts items
useTags <- stUseTags <$> ask
@@ -301,24 +302,25 @@ orderedListItemToDokuWiki opts items = do
else do
indent <- stIndent <$> ask
backSlash <- stBackSlashLB <$> ask
- let indent' = if backSlash then (drop 2 indent) else indent
+ let indent' = if backSlash then drop 2 indent else indent
return $ indent' ++ "- " ++ contents
-- | Convert definition list item (label, list of blocks) to DokuWiki.
-definitionListItemToDokuWiki :: WriterOptions
+definitionListItemToDokuWiki :: PandocMonad m
+ => WriterOptions
-> ([Inline],[[Block]])
- -> DokuWiki String
+ -> DokuWiki m String
definitionListItemToDokuWiki opts (label, items) = do
labelText <- inlineListToDokuWiki opts label
contents <- mapM (blockListToDokuWiki opts) items
useTags <- stUseTags <$> ask
if useTags
then return $ "<HTML><dt></HTML>" ++ labelText ++ "<HTML></dt></HTML>\n" ++
- (intercalate "\n" $ map (\d -> "<HTML><dd></HTML>" ++ d ++ "<HTML></dd></HTML>") contents)
+ intercalate "\n" (map (\d -> "<HTML><dd></HTML>" ++ d ++ "<HTML></dd></HTML>") contents)
else do
indent <- stIndent <$> ask
backSlash <- stBackSlashLB <$> ask
- let indent' = if backSlash then (drop 2 indent) else indent
+ let indent' = if backSlash then drop 2 indent else indent
return $ indent' ++ "* **" ++ labelText ++ "** " ++ concat contents
-- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.
@@ -337,18 +339,19 @@ isSimpleListItem :: [Block] -> Bool
isSimpleListItem [] = True
isSimpleListItem [x] =
case x of
- Plain _ -> True
- Para _ -> True
- BulletList _ -> isSimpleList x
- OrderedList _ _ -> isSimpleList x
- DefinitionList _ -> isSimpleList x
- _ -> False
+ Plain _ -> True
+ Para _ -> True
+ BulletList _ -> isSimpleList x
+ OrderedList _ _ -> isSimpleList x
+ DefinitionList _ -> isSimpleList x
+ _ -> False
isSimpleListItem [x, y] | isPlainOrPara x =
case y of
- BulletList _ -> isSimpleList y
- OrderedList _ _ -> isSimpleList y
- DefinitionList _ -> isSimpleList y
- _ -> False
+ BulletList _ -> isSimpleList y
+ OrderedList _ _ -> isSimpleList y
+ DefinitionList _ -> isSimpleList y
+ CodeBlock _ _ -> True
+ _ -> False
isSimpleListItem _ = False
isPlainOrPara :: Block -> Bool
@@ -368,14 +371,15 @@ backSlashLineBreaks cs = reverse $ g $ reverse $ concatMap f cs
where f '\n' = "\\\\ "
f c = [c]
g (' ' : '\\':'\\': xs) = xs
- g s = s
+ g s = s
-- Auxiliary functions for tables:
-tableItemToDokuWiki :: WriterOptions
- -> Alignment
- -> [Block]
- -> DokuWiki String
+tableItemToDokuWiki :: PandocMonad m
+ => WriterOptions
+ -> Alignment
+ -> [Block]
+ -> DokuWiki m String
tableItemToDokuWiki opts align' item = do
let mkcell x = (if align' == AlignRight || align' == AlignCenter
then " "
@@ -388,22 +392,32 @@ tableItemToDokuWiki opts align' item = do
return $ mkcell contents
-- | Convert list of Pandoc block elements to DokuWiki.
-blockListToDokuWiki :: WriterOptions -- ^ Options
+blockListToDokuWiki :: PandocMonad m
+ => WriterOptions -- ^ Options
-> [Block] -- ^ List of block elements
- -> DokuWiki String
+ -> DokuWiki m String
blockListToDokuWiki opts blocks = do
backSlash <- stBackSlashLB <$> ask
+ let blocks' = consolidateRawBlocks blocks
if backSlash
- then (backSlashLineBreaks . vcat) <$> mapM (blockToDokuWiki opts) blocks
- else vcat <$> mapM (blockToDokuWiki opts) blocks
+ then (backSlashLineBreaks . vcat) <$> mapM (blockToDokuWiki opts) blocks'
+ else vcat <$> mapM (blockToDokuWiki opts) blocks'
+
+consolidateRawBlocks :: [Block] -> [Block]
+consolidateRawBlocks [] = []
+consolidateRawBlocks (RawBlock f1 b1 : RawBlock f2 b2 : xs)
+ | f1 == f2 = consolidateRawBlocks (RawBlock f1 (b1 ++ "\n" ++ b2) : xs)
+consolidateRawBlocks (x:xs) = x : consolidateRawBlocks xs
-- | Convert list of Pandoc inline elements to DokuWiki.
-inlineListToDokuWiki :: WriterOptions -> [Inline] -> DokuWiki String
+inlineListToDokuWiki :: PandocMonad m
+ => WriterOptions -> [Inline] -> DokuWiki m String
inlineListToDokuWiki opts lst =
- concat <$> (mapM (inlineToDokuWiki opts) lst)
+ concat <$> mapM (inlineToDokuWiki opts) lst
-- | Convert Pandoc inline element to DokuWiki.
-inlineToDokuWiki :: WriterOptions -> Inline -> DokuWiki String
+inlineToDokuWiki :: PandocMonad m
+ => WriterOptions -> Inline -> DokuWiki m String
inlineToDokuWiki opts (Span _attrs ils) =
inlineListToDokuWiki opts ils
@@ -460,12 +474,12 @@ inlineToDokuWiki _ (Math mathType str) = return $ delim ++ str ++ delim
DisplayMath -> "$$"
InlineMath -> "$"
-inlineToDokuWiki _ (RawInline f str)
+inlineToDokuWiki _ il@(RawInline f str)
| f == Format "dokuwiki" = return str
| f == Format "html" = return $ "<html>" ++ str ++ "</html>"
- | otherwise = return ""
+ | otherwise = "" <$ report (InlineNotRendered il)
-inlineToDokuWiki _ (LineBreak) = return "\\\\\n"
+inlineToDokuWiki _ LineBreak = return "\\\\\n"
inlineToDokuWiki opts SoftBreak =
case writerWrapText opts of
@@ -498,7 +512,6 @@ inlineToDokuWiki opts (Image attr alt (source, tit)) = do
inlineToDokuWiki opts (Note contents) = do
contents' <- blockListToDokuWiki opts contents
- modify (\s -> s { stNotes = True })
return $ "((" ++ contents' ++ "))"
-- note - may not work for notes with multiple blocks
@@ -507,7 +520,7 @@ imageDims opts attr = go (toPx $ dimension Width attr) (toPx $ dimension Height
where
toPx = fmap (showInPixel opts) . checkPct
checkPct (Just (Percent _)) = Nothing
- checkPct maybeDim = maybeDim
+ checkPct maybeDim = maybeDim
go (Just w) Nothing = "?" ++ w
go (Just w) (Just h) = "?" ++ w ++ "x" ++ h
go Nothing (Just h) = "?0x" ++ h
diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs
index 00bf4a81c..7b4853a24 100644
--- a/src/Text/Pandoc/Writers/EPUB.hs
+++ b/src/Text/Pandoc/Writers/EPUB.hs
@@ -1,6 +1,9 @@
-{-# LANGUAGE PatternGuards, CPP, ScopedTypeVariables, ViewPatterns, FlexibleContexts #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.EPUB
- Copyright : Copyright (C) 2010-2015 John MacFarlane
+ Copyright : Copyright (C) 2010-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -28,47 +31,47 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to EPUB.
-}
-module Text.Pandoc.Writers.EPUB ( writeEPUB ) where
-import Data.IORef ( IORef, newIORef, readIORef, modifyIORef )
-import qualified Data.Map as M
-import qualified Data.Set as Set
-import Data.Maybe ( fromMaybe, catMaybes )
-import Data.List ( isPrefixOf, isInfixOf, intercalate )
-import System.Environment ( getEnv )
-import Text.Printf (printf)
-import System.FilePath ( takeExtension, takeFileName )
-import System.FilePath.Glob ( namesMatching )
-import Network.HTTP ( urlEncode )
+module Text.Pandoc.Writers.EPUB ( writeEPUB2, writeEPUB3 ) where
+import Codec.Archive.Zip (Entry, addEntryToArchive, eRelativePath, emptyArchive,
+ fromArchive, fromEntry, toEntry)
+import Control.Monad (mplus, unless, when, zipWithM)
+import Control.Monad.Except (catchError, throwError)
+import Control.Monad.State.Strict (State, StateT, evalState, evalStateT, get,
+ gets, lift, modify, put)
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as B8
-import qualified Text.Pandoc.UTF8 as UTF8
-import Codec.Archive.Zip ( emptyArchive, addEntryToArchive, eRelativePath, fromEntry , Entry, toEntry, fromArchive)
-import Data.Time.Clock.POSIX ( getPOSIXTime )
-import Text.Pandoc.Compat.Time
-import Text.Pandoc.Shared ( renderTags', safeRead, uniqueIdent, trim
- , normalizeDate, readDataFile, stringify, warn
- , hierarchicalize, fetchItem' )
-import qualified Text.Pandoc.Shared as S (Element(..))
+import Data.Char (isAlphaNum, isAscii, isDigit, toLower)
+import Data.List (intercalate, isInfixOf, isPrefixOf)
+import qualified Data.Map as M
+import Data.Maybe (fromMaybe, isNothing, mapMaybe, isJust)
+import qualified Data.Set as Set
+import qualified Data.Text as TS
+import qualified Data.Text.Lazy as TL
+import Network.HTTP (urlEncode)
+import System.FilePath (takeExtension, takeFileName, makeRelative)
+import Text.HTML.TagSoup (Tag (TagOpen), fromAttrib, parseTags)
import Text.Pandoc.Builder (fromList, setMeta)
-import Text.Pandoc.Options ( WriterOptions(..)
- , WrapOption(..)
- , HTMLMathMethod(..)
- , EPUBVersion(..)
- , ObfuscationMethod(NoObfuscation) )
+import Text.Pandoc.Class (PandocMonad, report)
+import qualified Text.Pandoc.Class as P
+import Text.Pandoc.Compat.Time
import Text.Pandoc.Definition
-import Text.Pandoc.Walk (walk, walkM, query)
-import Control.Monad.State (modify, get, State, put, evalState)
-import Control.Monad (mplus, liftM, when)
-import Text.XML.Light ( unode, Element(..), unqual, Attr(..), add_attrs
- , strContent, lookupAttr, Node(..), QName(..), parseXML
- , onlyElems, node, ppElement)
-import Text.Pandoc.UUID (getRandomUUID)
-import Text.Pandoc.Writers.HTML ( writeHtml )
-import Data.Char ( toLower, isDigit, isAlphaNum )
-import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType)
-import qualified Control.Exception as E
-import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
-import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags)
+import Text.Pandoc.Error
+import Text.Pandoc.Logging
+import Text.Pandoc.MIME (MimeType, extensionFromMimeType, getMimeType)
+import Text.Pandoc.Options (EPUBVersion (..), HTMLMathMethod (..),
+ ObfuscationMethod (NoObfuscation), WrapOption (..),
+ WriterOptions (..))
+import Text.Pandoc.Shared (hierarchicalize, normalizeDate, renderTags',
+ safeRead, stringify, trim, uniqueIdent)
+import qualified Text.Pandoc.Shared as S (Element (..))
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.Pandoc.UUID (getUUID)
+import Text.Pandoc.Walk (query, walk, walkM)
+import Text.Pandoc.Writers.HTML (writeHtmlStringForEPUB)
+import Text.Printf (printf)
+import Text.XML.Light (Attr (..), Element (..), Node (..), QName (..),
+ add_attrs, lookupAttr, node, onlyElems, parseXML,
+ ppElement, showElement, strContent, unode, unqual)
-- A Chapter includes a list of blocks and maybe a section
-- number offset. Note, some chapters are unnumbered. The section
@@ -76,51 +79,55 @@ import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags)
-- in filenames, chapter0003.xhtml.
data Chapter = Chapter (Maybe [Int]) [Block]
+data EPUBState = EPUBState {
+ stMediaPaths :: [(FilePath, (FilePath, Maybe Entry))]
+ , stEpubSubdir :: String
+ }
+
+type E m = StateT EPUBState m
+
data EPUBMetadata = EPUBMetadata{
- epubIdentifier :: [Identifier]
- , epubTitle :: [Title]
- , epubDate :: [Date]
- , epubLanguage :: String
- , epubCreator :: [Creator]
- , epubContributor :: [Creator]
- , epubSubject :: [String]
- , epubDescription :: Maybe String
- , epubType :: Maybe String
- , epubFormat :: Maybe String
- , epubPublisher :: Maybe String
- , epubSource :: Maybe String
- , epubRelation :: Maybe String
- , epubCoverage :: Maybe String
- , epubRights :: Maybe String
- , epubCoverImage :: Maybe String
- , epubStylesheet :: Maybe Stylesheet
- , epubPageDirection :: Maybe ProgressionDirection
+ epubIdentifier :: [Identifier]
+ , epubTitle :: [Title]
+ , epubDate :: [Date]
+ , epubLanguage :: String
+ , epubCreator :: [Creator]
+ , epubContributor :: [Creator]
+ , epubSubject :: [String]
+ , epubDescription :: Maybe String
+ , epubType :: Maybe String
+ , epubFormat :: Maybe String
+ , epubPublisher :: Maybe String
+ , epubSource :: Maybe String
+ , epubRelation :: Maybe String
+ , epubCoverage :: Maybe String
+ , epubRights :: Maybe String
+ , epubCoverImage :: Maybe String
+ , epubStylesheets :: [FilePath]
+ , epubPageDirection :: Maybe ProgressionDirection
+ , epubIbooksFields :: [(String, String)]
} deriving Show
-data Stylesheet = StylesheetPath FilePath
- | StylesheetContents String
- deriving Show
-
data Date = Date{
- dateText :: String
- , dateEvent :: Maybe String
+ dateText :: String
+ , dateEvent :: Maybe String
} deriving Show
data Creator = Creator{
- creatorText :: String
- , creatorRole :: Maybe String
- , creatorFileAs :: Maybe String
+ creatorText :: String
+ , creatorRole :: Maybe String
+ , creatorFileAs :: Maybe String
} deriving Show
data Identifier = Identifier{
- identifierText :: String
- , identifierScheme :: Maybe String
+ identifierText :: String
+ , identifierScheme :: Maybe String
} deriving Show
data Title = Title{
- titleText :: String
- , titleFileAs :: Maybe String
- , titleType :: Maybe String
+ titleText :: String
+ , titleFileAs :: Maybe String
+ , titleType :: Maybe String
} deriving Show
data ProgressionDirection = LTR | RTL deriving Show
@@ -143,15 +150,29 @@ removeNote :: Inline -> Inline
removeNote (Note _) = Str ""
removeNote x = x
-getEPUBMetadata :: WriterOptions -> Meta -> IO EPUBMetadata
+mkEntry :: PandocMonad m => FilePath -> B.ByteString -> E m Entry
+mkEntry path content = do
+ epubSubdir <- gets stEpubSubdir
+ let addEpubSubdir :: Entry -> Entry
+ addEpubSubdir e = e{ eRelativePath =
+ (if null epubSubdir
+ then ""
+ else epubSubdir ++ "/") ++ eRelativePath e }
+ epochtime <- floor <$> lift P.getPOSIXTime
+ return $
+ (if path == "mimetype" || "META-INF" `isPrefixOf` path
+ then id
+ else addEpubSubdir) $ toEntry path epochtime content
+
+getEPUBMetadata :: PandocMonad m => WriterOptions -> Meta -> E m EPUBMetadata
getEPUBMetadata opts meta = do
let md = metadataFromMeta opts meta
- let elts = onlyElems $ parseXML $ writerEpubMetadata opts
+ let elts = maybe [] (onlyElems . parseXML) $ writerEpubMetadata opts
let md' = foldr addMetadataFromXML md elts
let addIdentifier m =
if null (epubIdentifier m)
then do
- randomId <- fmap show getRandomUUID
+ randomId <- (show . getUUID) <$> lift P.newStdGen
return $ m{ epubIdentifier = [Identifier randomId Nothing] }
else return m
let addLanguage m =
@@ -159,16 +180,19 @@ getEPUBMetadata opts meta = do
then case lookup "lang" (writerVariables opts) of
Just x -> return m{ epubLanguage = x }
Nothing -> do
- localeLang <- E.catch (liftM
- (map (\c -> if c == '_' then '-' else c) .
- takeWhile (/='.')) $ getEnv "LANG")
- (\e -> let _ = (e :: E.SomeException) in return "en-US")
+ mLang <- lift $ P.lookupEnv "LANG"
+ let localeLang =
+ case mLang of
+ Just lang ->
+ map (\c -> if c == '_' then '-' else c) $
+ takeWhile (/='.') lang
+ Nothing -> "en-US"
return m{ epubLanguage = localeLang }
else return m
let fixDate m =
if null (epubDate m)
then do
- currentTime <- getCurrentTime
+ currentTime <- lift P.getCurrentTime
return $ m{ epubDate = [ Date{
dateText = showDateTimeISO8601 currentTime
, dateEvent = Nothing } ] }
@@ -225,12 +249,16 @@ addMetadataFromXML e@(Element (QName name _ (Just "dc")) attrs _ _) md
addMetadataFromXML _ md = md
metaValueToString :: MetaValue -> String
-metaValueToString (MetaString s) = s
+metaValueToString (MetaString s) = s
metaValueToString (MetaInlines ils) = stringify ils
-metaValueToString (MetaBlocks bs) = stringify bs
-metaValueToString (MetaBool True) = "true"
-metaValueToString (MetaBool False) = "false"
-metaValueToString _ = ""
+metaValueToString (MetaBlocks bs) = stringify bs
+metaValueToString (MetaBool True) = "true"
+metaValueToString (MetaBool False) = "false"
+metaValueToString _ = ""
+
+metaValueToPaths:: MetaValue -> [FilePath]
+metaValueToPaths (MetaList xs) = map metaValueToString xs
+metaValueToPaths x = [metaValueToString x]
getList :: String -> Meta -> (MetaValue -> a) -> [a]
getList s meta handleMetaValue =
@@ -267,19 +295,18 @@ getCreator s meta = getList s meta handleMetaValue
getDate :: String -> Meta -> [Date]
getDate s meta = getList s meta handleMetaValue
where handleMetaValue (MetaMap m) =
- Date{ dateText = maybe "" id $
+ Date{ dateText = fromMaybe "" $
M.lookup "text" m >>= normalizeDate' . metaValueToString
, dateEvent = metaValueToString <$> M.lookup "event" m }
- handleMetaValue mv = Date { dateText = maybe ""
- id $ normalizeDate' $ metaValueToString mv
+ handleMetaValue mv = Date { dateText = fromMaybe "" $ normalizeDate' $ metaValueToString mv
, dateEvent = Nothing }
simpleList :: String -> Meta -> [String]
simpleList s meta =
case lookupMeta s meta of
Just (MetaList xs) -> map metaValueToString xs
- Just x -> [metaValueToString x]
- Nothing -> []
+ Just x -> [metaValueToString x]
+ Nothing -> []
metadataFromMeta :: WriterOptions -> Meta -> EPUBMetadata
metadataFromMeta opts meta = EPUBMetadata{
@@ -299,8 +326,9 @@ metadataFromMeta opts meta = EPUBMetadata{
, epubCoverage = coverage
, epubRights = rights
, epubCoverImage = coverImage
- , epubStylesheet = stylesheet
+ , epubStylesheets = stylesheets
, epubPageDirection = pageDirection
+ , epubIbooksFields = ibooksFields
}
where identifiers = getIdentifier meta
titles = getTitle meta
@@ -320,70 +348,125 @@ metadataFromMeta opts meta = EPUBMetadata{
rights = metaValueToString <$> lookupMeta "rights" meta
coverImage = lookup "epub-cover-image" (writerVariables opts) `mplus`
(metaValueToString <$> lookupMeta "cover-image" meta)
- stylesheet = (StylesheetContents <$> writerEpubStylesheet opts) `mplus`
- ((StylesheetPath . metaValueToString) <$>
- lookupMeta "stylesheet" meta)
+ stylesheets = fromMaybe []
+ (metaValueToPaths <$> lookupMeta "stylesheet" meta) ++
+ [f | ("css",f) <- writerVariables opts]
pageDirection = case map toLower . metaValueToString <$>
lookupMeta "page-progression-direction" meta of
Just "ltr" -> Just LTR
Just "rtl" -> Just RTL
_ -> Nothing
+ ibooksFields = case lookupMeta "ibooks" meta of
+ Just (MetaMap mp)
+ -> M.toList $ M.map metaValueToString mp
+ _ -> []
+
+-- | Produce an EPUB2 file from a Pandoc document.
+writeEPUB2 :: PandocMonad m
+ => WriterOptions -- ^ Writer options
+ -> Pandoc -- ^ Document to convert
+ -> m B.ByteString
+writeEPUB2 = writeEPUB EPUB2
+
+-- | Produce an EPUB3 file from a Pandoc document.
+writeEPUB3 :: PandocMonad m
+ => WriterOptions -- ^ Writer options
+ -> Pandoc -- ^ Document to convert
+ -> m B.ByteString
+writeEPUB3 = writeEPUB EPUB3
-- | Produce an EPUB file from a Pandoc document.
-writeEPUB :: WriterOptions -- ^ Writer options
+writeEPUB :: PandocMonad m
+ => EPUBVersion
+ -> WriterOptions -- ^ Writer options
-> Pandoc -- ^ Document to convert
- -> IO B.ByteString
-writeEPUB opts doc@(Pandoc meta _) = do
- let version = fromMaybe EPUB2 (writerEpubVersion opts)
+ -> m B.ByteString
+writeEPUB epubVersion opts doc = do
+ let epubSubdir = writerEpubSubdirectory opts
+ -- sanity check on epubSubdir
+ unless (all (\c -> isAscii c && isAlphaNum c) epubSubdir) $
+ throwError $ PandocEpubSubdirectoryError epubSubdir
+ let initState = EPUBState { stMediaPaths = [], stEpubSubdir = epubSubdir }
+ evalStateT (pandocToEPUB epubVersion opts doc) initState
+
+pandocToEPUB :: PandocMonad m
+ => EPUBVersion
+ -> WriterOptions
+ -> Pandoc
+ -> E m B.ByteString
+pandocToEPUB version opts doc@(Pandoc meta _) = do
+ epubSubdir <- gets stEpubSubdir
let epub3 = version == EPUB3
- epochtime <- floor `fmap` getPOSIXTime
- let mkEntry path content = toEntry path epochtime content
+ let writeHtml o = fmap (UTF8.fromTextLazy . TL.fromStrict) .
+ writeHtmlStringForEPUB version o
+ metadata <- getEPUBMetadata opts meta
+
+ -- stylesheet
+ stylesheets <- case epubStylesheets metadata of
+ [] -> (\x -> [B.fromChunks [x]]) <$>
+ P.readDataFile "epub.css"
+ fs -> mapM P.readFileLazy fs
+ stylesheetEntries <- zipWithM
+ (\bs n -> mkEntry ("styles/stylesheet" ++ show n ++ ".css") bs)
+ stylesheets [(1 :: Int)..]
+
let vars = ("epub3", if epub3 then "true" else "false")
- : ("css", "stylesheet.css")
- : writerVariables opts
+ : [(x,y) | (x,y) <- writerVariables opts, x /= "css"]
+
+ let cssvars useprefix = map (\e -> ("css",
+ (if useprefix
+ then "../"
+ else "")
+ ++ makeRelative epubSubdir (eRelativePath e)))
+ stylesheetEntries
+
let opts' = opts{ writerEmailObfuscation = NoObfuscation
, writerSectionDivs = True
- , writerHtml5 = epub3
, writerVariables = vars
, writerHTMLMathMethod =
if epub3
- then MathML Nothing
+ then MathML
else writerHTMLMathMethod opts
, writerWrapText = WrapAuto }
- metadata <- getEPUBMetadata opts' meta
-- cover page
(cpgEntry, cpicEntry) <-
case epubCoverImage metadata of
Nothing -> return ([],[])
Just img -> do
- let coverImage = "media/" ++ takeFileName img
- let cpContent = renderHtml $ writeHtml
- opts'{ writerVariables = ("coverpage","true"):vars }
- (Pandoc meta [RawBlock (Format "html") $ "<div id=\"cover-image\">\n<img src=\"" ++ coverImage ++ "\" alt=\"cover image\" />\n</div>"])
- imgContent <- B.readFile img
- return ( [mkEntry "cover.xhtml" cpContent]
- , [mkEntry coverImage imgContent] )
+ let coverImage = takeFileName img
+ cpContent <- lift $ writeHtml
+ opts'{ writerVariables =
+ ("coverpage","true"):
+ cssvars True ++ vars }
+ (Pandoc meta [RawBlock (Format "html") $ "<div id=\"cover-image\">\n<img src=\"../media/" ++ coverImage ++ "\" alt=\"cover image\" />\n</div>"])
+ imgContent <- lift $ P.readFileLazy img
+ coverEntry <- mkEntry "text/cover.xhtml" cpContent
+ coverImageEntry <- mkEntry ("media/" ++ coverImage)
+ imgContent
+ return ( [ coverEntry ]
+ , [ coverImageEntry ] )
-- title page
- let tpContent = renderHtml $ writeHtml opts'{
- writerVariables = ("titlepage","true"):vars }
- (Pandoc meta [])
- let tpEntry = mkEntry "title_page.xhtml" tpContent
+ tpContent <- lift $ writeHtml opts'{
+ writerVariables = ("titlepage","true"):
+ cssvars True ++ vars }
+ (Pandoc meta [])
+ tpEntry <- mkEntry "text/title_page.xhtml" tpContent
-- handle pictures
- mediaRef <- newIORef []
- Pandoc _ blocks <- walkM (transformInline opts' mediaRef) doc >>=
- walkM (transformBlock opts' mediaRef)
- picEntries <- (catMaybes . map (snd . snd)) <$> readIORef mediaRef
-
+ -- mediaRef <- P.newIORef []
+ Pandoc _ blocks <- walkM (transformInline opts') doc >>=
+ walkM transformBlock
+ picEntries <- (mapMaybe (snd . snd)) <$> gets stMediaPaths
-- handle fonts
let matchingGlob f = do
- xs <- namesMatching f
+ xs <- lift $ P.glob f
when (null xs) $
- warn $ f ++ " did not match any font files."
+ report $ CouldNotFetchResource f "glob did not match any font files"
return xs
- let mkFontEntry f = mkEntry (takeFileName f) `fmap` B.readFile f
+ let mkFontEntry f = mkEntry ("fonts/" ++ takeFileName f) =<<
+ lift (P.readFileLazy f)
fontFiles <- concat <$> mapM matchingGlob (writerEpubFonts opts')
fontEntries <- mapM mkFontEntry fontFiles
@@ -420,7 +503,7 @@ writeEPUB opts doc@(Pandoc meta _) = do
mbnum <- if "unnumbered" `elem` classes
then return Nothing
else case splitAt (n - 1) nums of
- (ks, (m:_)) -> do
+ (ks, m:_) -> do
let nums' = ks ++ [m+1]
put nums'
return $ Just (ks ++ [m])
@@ -467,77 +550,93 @@ writeEPUB opts doc@(Pandoc meta _) = do
Chapter mbnum $ walk fixInternalReferences bs)
chapters'
- let chapToEntry :: Int -> Chapter -> Entry
- chapToEntry num (Chapter mbnum bs) = mkEntry (showChapter num)
- $ renderHtml
- $ writeHtml opts'{ writerNumberOffset =
- fromMaybe [] mbnum }
- $ case bs of
- (Header _ _ xs : _) ->
- -- remove notes or we get doubled footnotes
- Pandoc (setMeta "title" (walk removeNote $ fromList xs)
- nullMeta) bs
- _ ->
- Pandoc nullMeta bs
-
- let chapterEntries = zipWith chapToEntry [1..] chapters
+ let chapToEntry num (Chapter mbnum bs) =
+ mkEntry ("text/" ++ showChapter num) =<<
+ writeHtml opts'{ writerNumberOffset = fromMaybe [] mbnum
+ , writerVariables = cssvars True ++ vars }
+ (case bs of
+ (Header _ _ xs : _) ->
+ -- remove notes or we get doubled footnotes
+ Pandoc (setMeta "title" (walk removeNote $ fromList xs)
+ nullMeta) bs
+ _ -> Pandoc nullMeta bs)
+
+ chapterEntries <- zipWithM chapToEntry [1..] chapters
-- incredibly inefficient (TODO):
let containsMathML ent = epub3 &&
- "<math" `isInfixOf` (B8.unpack $ fromEntry ent)
+ "<math" `isInfixOf`
+ B8.unpack (fromEntry ent)
let containsSVG ent = epub3 &&
- "<svg" `isInfixOf` (B8.unpack $ fromEntry ent)
+ "<svg" `isInfixOf`
+ B8.unpack (fromEntry ent)
let props ent = ["mathml" | containsMathML ent] ++ ["svg" | containsSVG ent]
-- contents.opf
let chapterNode ent = unode "item" !
- ([("id", toId $ eRelativePath ent),
- ("href", eRelativePath ent),
+ ([("id", toId $ makeRelative epubSubdir
+ $ eRelativePath ent),
+ ("href", makeRelative epubSubdir
+ $ eRelativePath ent),
("media-type", "application/xhtml+xml")]
++ case props ent of
- [] -> []
- xs -> [("properties", unwords xs)])
+ [] -> []
+ xs -> [("properties", unwords xs)])
$ ()
+
let chapterRefNode ent = unode "itemref" !
- [("idref", toId $ eRelativePath ent)] $ ()
+ [("idref", toId $ makeRelative epubSubdir
+ $ eRelativePath ent)] $ ()
let pictureNode ent = unode "item" !
- [("id", toId $ eRelativePath ent),
- ("href", eRelativePath ent),
- ("media-type", fromMaybe "application/octet-stream"
+ [("id", toId $ makeRelative epubSubdir
+ $ eRelativePath ent),
+ ("href", makeRelative epubSubdir
+ $ eRelativePath ent),
+ ("media-type",
+ fromMaybe "application/octet-stream"
$ mediaTypeOf $ eRelativePath ent)] $ ()
let fontNode ent = unode "item" !
- [("id", toId $ eRelativePath ent),
- ("href", eRelativePath ent),
- ("media-type", fromMaybe "" $ getMimeType $ eRelativePath ent)] $ ()
+ [("id", toId $ makeRelative epubSubdir
+ $ eRelativePath ent),
+ ("href", makeRelative epubSubdir
+ $ eRelativePath ent),
+ ("media-type", fromMaybe "" $
+ getMimeType $ eRelativePath ent)] $ ()
let plainTitle = case docTitle' meta of
[] -> case epubTitle metadata of
- [] -> "UNTITLED"
+ [] -> "UNTITLED"
(x:_) -> titleText x
x -> stringify x
let tocTitle = fromMaybe plainTitle $
metaValueToString <$> lookupMeta "toc-title" meta
- let uuid = case epubIdentifier metadata of
- (x:_) -> identifierText x -- use first identifier as UUID
- [] -> error "epubIdentifier is null" -- shouldn't happen
- currentTime <- getCurrentTime
+ uuid <- case epubIdentifier metadata of
+ (x:_) -> return $ identifierText x -- use first identifier as UUID
+ [] -> throwError $ PandocShouldNeverHappenError "epubIdentifier is null" -- shouldn't happen
+ currentTime <- lift P.getCurrentTime
let contentsData = UTF8.fromStringLazy $ ppTopElement $
- unode "package" ! [("version", case version of
- EPUB2 -> "2.0"
- EPUB3 -> "3.0")
- ,("xmlns","http://www.idpf.org/2007/opf")
- ,("unique-identifier","epub-id-1")] $
+ unode "package" !
+ ([("version", case version of
+ EPUB2 -> "2.0"
+ EPUB3 -> "3.0")
+ ,("xmlns","http://www.idpf.org/2007/opf")
+ ,("unique-identifier","epub-id-1")
+ ] ++
+ [("prefix","ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/") | version == EPUB3]) $
[ metadataElement version metadata currentTime
, unode "manifest" $
[ unode "item" ! [("id","ncx"), ("href","toc.ncx")
,("media-type","application/x-dtbncx+xml")] $ ()
- , unode "item" ! [("id","style"), ("href","stylesheet.css")
- ,("media-type","text/css")] $ ()
, unode "item" ! ([("id","nav")
,("href","nav.xhtml")
,("media-type","application/xhtml+xml")] ++
[("properties","nav") | epub3 ]) $ ()
] ++
+ [ unode "item" ! [("id","style"), ("href",fp)
+ ,("media-type","text/css")] $ () |
+ fp <- map
+ (makeRelative epubSubdir . eRelativePath)
+ stylesheetEntries ] ++
map chapterNode (cpgEntry ++ (tpEntry : chapterEntries)) ++
(case cpicEntry of
[] -> []
@@ -546,7 +645,8 @@ writeEPUB opts doc@(Pandoc meta _) = do
(pictureNode x)]) ++
map pictureNode picEntries ++
map fontNode fontEntries
- , unode "spine" ! ([("toc","ncx")] ++ progressionDirection) $
+ , unode "spine" ! (
+ ("toc","ncx") : progressionDirection) $
case epubCoverImage metadata of
Nothing -> []
Just _ -> [ unode "itemref" !
@@ -565,48 +665,54 @@ writeEPUB opts doc@(Pandoc meta _) = do
("href","nav.xhtml")] $ ()
] ++
[ unode "reference" !
- [("type","cover"),("title","Cover"),("href","cover.xhtml")] $ () | epubCoverImage metadata /= Nothing
+ [("type","cover")
+ ,("title","Cover")
+ ,("href","text/cover.xhtml")] $ ()
+ | isJust (epubCoverImage metadata)
]
]
- let contentsEntry = mkEntry "content.opf" contentsData
+ contentsEntry <- mkEntry "content.opf" contentsData
-- toc.ncx
let secs = hierarchicalize blocks'
let tocLevel = writerTOCDepth opts
- let navPointNode :: (Int -> String -> String -> [Element] -> Element)
- -> S.Element -> State Int Element
+ let navPointNode :: PandocMonad m
+ => (Int -> [Inline] -> String -> [Element] -> Element)
+ -> S.Element -> StateT Int m Element
navPointNode formatter (S.Sec _ nums (ident,_,_) ils children) = do
n <- get
modify (+1)
let showNums :: [Int] -> String
showNums = intercalate "." . map show
- let tit' = stringify ils
let tit = if writerNumberSections opts && not (null nums)
- then showNums nums ++ " " ++ tit'
- else tit'
- let src = case lookup ident reftable of
- Just x -> x
- Nothing -> error (ident ++ " not found in reftable")
+ then Span ("", ["section-header-number"], [])
+ [Str (showNums nums)] : Space : ils
+ else ils
+ src <- case lookup ident reftable of
+ Just x -> return x
+ Nothing -> throwError $ PandocSomeError $ ident ++ " not found in reftable"
let isSec (S.Sec lev _ _ _ _) = lev <= tocLevel
- isSec _ = False
+ isSec _ = False
let subsecs = filter isSec children
subs <- mapM (navPointNode formatter) subsecs
return $ formatter n tit src subs
- navPointNode _ (S.Blk _) = error "navPointNode encountered Blk"
+ navPointNode _ (S.Blk _) = throwError $ PandocSomeError "navPointNode encountered Blk"
- let navMapFormatter :: Int -> String -> String -> [Element] -> Element
+ let navMapFormatter :: Int -> [Inline] -> String -> [Element] -> Element
navMapFormatter n tit src subs = unode "navPoint" !
[("id", "navPoint-" ++ show n)] $
- [ unode "navLabel" $ unode "text" tit
- , unode "content" ! [("src", src)] $ ()
+ [ unode "navLabel" $ unode "text" $ stringify tit
+ , unode "content" ! [("src", "text/" ++ src)] $ ()
] ++ subs
let tpNode = unode "navPoint" ! [("id", "navPoint-0")] $
[ unode "navLabel" $ unode "text" (stringify $ docTitle' meta)
- , unode "content" ! [("src","title_page.xhtml")] $ () ]
+ , unode "content" ! [("src", "text/title_page.xhtml")]
+ $ () ]
+ navMap <- lift $ evalStateT (mapM (navPointNode navMapFormatter) secs) 1
let tocData = UTF8.fromStringLazy $ ppTopElement $
unode "ncx" ! [("version","2005-1")
,("xmlns","http://www.daisy.org/z3986/2005/ncx/")] $
@@ -623,34 +729,48 @@ writeEPUB opts doc@(Pandoc meta _) = do
Nothing -> []
Just img -> [unode "meta" ! [("name","cover"),
("content", toId img)] $ ()]
- , unode "docTitle" $ unode "text" $ plainTitle
+ , unode "docTitle" $ unode "text" plainTitle
, unode "navMap" $
- tpNode : evalState (mapM (navPointNode navMapFormatter) secs) 1
+ tpNode : navMap
]
- let tocEntry = mkEntry "toc.ncx" tocData
+ tocEntry <- mkEntry "toc.ncx" tocData
- let navXhtmlFormatter :: Int -> String -> String -> [Element] -> Element
+ let navXhtmlFormatter :: Int -> [Inline] -> String -> [Element] -> Element
navXhtmlFormatter n tit src subs = unode "li" !
[("id", "toc-li-" ++ show n)] $
- (unode "a" ! [("href",src)]
- $ tit)
+ (unode "a" !
+ [("href", "text/" ++ src)]
+ $ titElements)
: case subs of
[] -> []
(_:_) -> [unode "ol" ! [("class","toc")] $ subs]
+ where titElements = parseXML titRendered
+ titRendered = case P.runPure
+ (writeHtmlStringForEPUB version
+ opts{ writerTemplate = Nothing }
+ (Pandoc nullMeta
+ [Plain $ walk delink tit])) of
+ Left _ -> TS.pack $ stringify tit
+ Right x -> x
+ -- can't have a element inside a...
+ delink (Link _ ils _) = Span ("", [], []) ils
+ delink x = x
let navtag = if epub3 then "nav" else "div"
- let navBlocks = [RawBlock (Format "html") $ ppElement $
+ tocBlocks <- lift $ evalStateT (mapM (navPointNode navXhtmlFormatter) secs) 1
+ let navBlocks = [RawBlock (Format "html")
+ $ showElement $ -- prettyprinting introduces bad spaces
unode navtag ! ([("epub:type","toc") | epub3] ++
[("id","toc")]) $
[ unode "h1" ! [("id","toc-title")] $ tocTitle
- , unode "ol" ! [("class","toc")] $ evalState (mapM (navPointNode navXhtmlFormatter) secs) 1]]
+ , unode "ol" ! [("class","toc")] $ tocBlocks ]]
let landmarks = if epub3
then [RawBlock (Format "html") $ ppElement $
unode "nav" ! [("epub:type","landmarks")
,("hidden","hidden")] $
[ unode "ol" $
[ unode "li"
- [ unode "a" ! [("href", "cover.xhtml")
+ [ unode "a" ! [("href", "text/cover.xhtml")
,("epub:type", "cover")] $
"Cover"] |
epubCoverImage metadata /= Nothing
@@ -664,52 +784,50 @@ writeEPUB opts doc@(Pandoc meta _) = do
]
]
else []
- let navData = renderHtml $ writeHtml
- opts'{ writerVariables = ("navpage","true"):vars }
+ navData <- lift $ writeHtml opts'{ writerVariables = ("navpage","true"):
+ cssvars False ++ vars }
(Pandoc (setMeta "title"
(walk removeNote $ fromList $ docTitle' meta) nullMeta)
(navBlocks ++ landmarks))
- let navEntry = mkEntry "nav.xhtml" navData
+ navEntry <- mkEntry "nav.xhtml" navData
-- mimetype
- let mimetypeEntry = mkEntry "mimetype" $ UTF8.fromStringLazy "application/epub+zip"
+ mimetypeEntry <- mkEntry "mimetype" $
+ UTF8.fromStringLazy "application/epub+zip"
-- container.xml
let containerData = UTF8.fromStringLazy $ ppTopElement $
unode "container" ! [("version","1.0")
,("xmlns","urn:oasis:names:tc:opendocument:xmlns:container")] $
unode "rootfiles" $
- unode "rootfile" ! [("full-path","content.opf")
+ unode "rootfile" ! [("full-path",
+ (if null epubSubdir
+ then ""
+ else epubSubdir ++ "/") ++ "content.opf")
,("media-type","application/oebps-package+xml")] $ ()
- let containerEntry = mkEntry "META-INF/container.xml" containerData
+ containerEntry <- mkEntry "META-INF/container.xml" containerData
-- com.apple.ibooks.display-options.xml
let apple = UTF8.fromStringLazy $ ppTopElement $
unode "display_options" $
unode "platform" ! [("name","*")] $
unode "option" ! [("name","specified-fonts")] $ "true"
- let appleEntry = mkEntry "META-INF/com.apple.ibooks.display-options.xml" apple
-
- -- stylesheet
- stylesheet <- case epubStylesheet metadata of
- Just (StylesheetPath fp) -> UTF8.readFile fp
- Just (StylesheetContents s) -> return s
- Nothing -> UTF8.toString `fmap`
- readDataFile (writerUserDataDir opts) "epub.css"
- let stylesheetEntry = mkEntry "stylesheet.css" $ UTF8.fromStringLazy stylesheet
+ appleEntry <- mkEntry "META-INF/com.apple.ibooks.display-options.xml" apple
-- construct archive
- let archive = foldr addEntryToArchive emptyArchive
- (mimetypeEntry : containerEntry : appleEntry : stylesheetEntry : tpEntry :
- contentsEntry : tocEntry : navEntry :
- (picEntries ++ cpicEntry ++ cpgEntry ++ chapterEntries ++ fontEntries))
+ let archive = foldr addEntryToArchive emptyArchive $
+ [mimetypeEntry, containerEntry, appleEntry,
+ contentsEntry, tocEntry, navEntry, tpEntry] ++
+ stylesheetEntries ++ picEntries ++ cpicEntry ++
+ cpgEntry ++ chapterEntries ++ fontEntries
return $ fromArchive archive
metadataElement :: EPUBVersion -> EPUBMetadata -> UTCTime -> Element
metadataElement version md currentTime =
unode "metadata" ! [("xmlns:dc","http://purl.org/dc/elements/1.1/")
,("xmlns:opf","http://www.idpf.org/2007/opf")] $ mdNodes
- where mdNodes = identifierNodes ++ titleNodes ++ dateNodes ++ languageNodes
+ where mdNodes = identifierNodes ++ titleNodes ++ dateNodes
+ ++ languageNodes ++ ibooksNodes
++ creatorNodes ++ contributorNodes ++ subjectNodes
++ descriptionNodes ++ typeNodes ++ formatNodes
++ publisherNodes ++ sourceNodes ++ relationNodes
@@ -728,6 +846,8 @@ metadataElement version md currentTime =
[] -> []
(x:_) -> [dcNode "date" ! [("id","epub-date")]
$ dateText x]
+ ibooksNodes = map ibooksNode (epubIbooksFields md)
+ ibooksNode (k, v) = unode "meta" ! [("property", "ibooks:" ++ k)] $ v
languageNodes = [dcTag "language" $ epubLanguage md]
creatorNodes = withIds "epub-creator" (toCreatorNode "creator") $
epubCreator md
@@ -747,7 +867,7 @@ metadataElement version md currentTime =
("content",toId img)] $ ()])
$ epubCoverImage md
modifiedNodes = [ unode "meta" ! [("property", "dcterms:modified")] $
- (showDateTimeISO8601 currentTime) | version == EPUB3 ]
+ showDateTimeISO8601 currentTime | version == EPUB3 ]
dcTag n s = unode ("dc:" ++ n) s
dcTag' n s = [dcTag n s]
toIdentifierNode id' (Identifier txt scheme)
@@ -791,99 +911,92 @@ metadataElement version md currentTime =
(("id",id') :
maybe [] (\x -> [("opf:event",x)]) (dateEvent date)) $
dateText date]
- schemeToOnix "ISBN-10" = "02"
- schemeToOnix "GTIN-13" = "03"
- schemeToOnix "UPC" = "04"
- schemeToOnix "ISMN-10" = "05"
- schemeToOnix "DOI" = "06"
- schemeToOnix "LCCN" = "13"
- schemeToOnix "GTIN-14" = "14"
- schemeToOnix "ISBN-13" = "15"
+ schemeToOnix "ISBN-10" = "02"
+ schemeToOnix "GTIN-13" = "03"
+ schemeToOnix "UPC" = "04"
+ schemeToOnix "ISMN-10" = "05"
+ schemeToOnix "DOI" = "06"
+ schemeToOnix "LCCN" = "13"
+ schemeToOnix "GTIN-14" = "14"
+ schemeToOnix "ISBN-13" = "15"
schemeToOnix "Legal deposit number" = "17"
- schemeToOnix "URN" = "22"
- schemeToOnix "OCLC" = "23"
- schemeToOnix "ISMN-13" = "25"
- schemeToOnix "ISBN-A" = "26"
- schemeToOnix "JP" = "27"
- schemeToOnix "OLCC" = "28"
- schemeToOnix _ = "01"
+ schemeToOnix "URN" = "22"
+ schemeToOnix "OCLC" = "23"
+ schemeToOnix "ISMN-13" = "25"
+ schemeToOnix "ISBN-A" = "26"
+ schemeToOnix "JP" = "27"
+ schemeToOnix "OLCC" = "28"
+ schemeToOnix _ = "01"
showDateTimeISO8601 :: UTCTime -> String
showDateTimeISO8601 = formatTime defaultTimeLocale "%FT%TZ"
-transformTag :: WriterOptions
- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media
- -> Tag String
- -> IO (Tag String)
-transformTag opts mediaRef tag@(TagOpen name attr)
+transformTag :: PandocMonad m
+ => Tag String
+ -> E m (Tag String)
+transformTag tag@(TagOpen name attr)
| name `elem` ["video", "source", "img", "audio"] &&
- lookup "data-external" attr == Nothing = do
+ isNothing (lookup "data-external" attr) = do
let src = fromAttrib "src" tag
let poster = fromAttrib "poster" tag
- newsrc <- modifyMediaRef opts mediaRef src
- newposter <- modifyMediaRef opts mediaRef poster
+ newsrc <- modifyMediaRef src
+ newposter <- modifyMediaRef poster
let attr' = filter (\(x,_) -> x /= "src" && x /= "poster") attr ++
- [("src", newsrc) | not (null newsrc)] ++
- [("poster", newposter) | not (null newposter)]
+ [("src", "../" ++ newsrc) | not (null newsrc)] ++
+ [("poster", "../" ++ newposter) | not (null newposter)]
return $ TagOpen name attr'
-transformTag _ _ tag = return tag
-
-modifyMediaRef :: WriterOptions
- -> IORef [(FilePath, (FilePath, Maybe Entry))]
- -> FilePath
- -> IO FilePath
-modifyMediaRef _ _ "" = return ""
-modifyMediaRef opts mediaRef oldsrc = do
- media <- readIORef mediaRef
+transformTag tag = return tag
+
+modifyMediaRef :: PandocMonad m
+ => FilePath
+ -> E m FilePath
+modifyMediaRef "" = return ""
+modifyMediaRef oldsrc = do
+ media <- gets stMediaPaths
case lookup oldsrc media of
Just (n,_) -> return n
- Nothing -> do
- res <- fetchItem' (writerMediaBag opts)
- (writerSourceURL opts) oldsrc
- (new, mbEntry) <-
- case res of
- Left _ -> do
- warn $ "Could not find media `" ++ oldsrc ++ "', skipping..."
- return (oldsrc, Nothing)
- Right (img,mbMime) -> do
- let new = "media/file" ++ show (length media) ++
- fromMaybe (takeExtension (takeWhile (/='?') oldsrc))
- (('.':) <$> (mbMime >>= extensionFromMimeType))
- epochtime <- floor `fmap` getPOSIXTime
- let entry = toEntry new epochtime $ B.fromChunks . (:[]) $ img
- return (new, Just entry)
- modifyIORef mediaRef ( (oldsrc, (new, mbEntry)): )
- return new
-
-transformBlock :: WriterOptions
- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media
- -> Block
- -> IO Block
-transformBlock opts mediaRef (RawBlock fmt raw)
+ Nothing -> catchError
+ (do (img, mbMime) <- P.fetchItem oldsrc
+ let new = "media/file" ++ show (length media) ++
+ fromMaybe (takeExtension (takeWhile (/='?') oldsrc))
+ (('.':) <$> (mbMime >>= extensionFromMimeType))
+ entry <- mkEntry new (B.fromChunks . (:[]) $ img)
+ modify $ \st -> st{ stMediaPaths =
+ (oldsrc, (new, Just entry)):media}
+ return new)
+ (\e -> do
+ report $ CouldNotFetchResource oldsrc (show e)
+ return oldsrc)
+
+transformBlock :: PandocMonad m
+ => Block
+ -> E m Block
+transformBlock (RawBlock fmt raw)
| fmt == Format "html" = do
let tags = parseTags raw
- tags' <- mapM (transformTag opts mediaRef) tags
+ tags' <- mapM transformTag tags
return $ RawBlock fmt (renderTags' tags')
-transformBlock _ _ b = return b
+transformBlock b = return b
-transformInline :: WriterOptions
- -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath) media
+transformInline :: PandocMonad m
+ => WriterOptions
-> Inline
- -> IO Inline
-transformInline opts mediaRef (Image attr lab (src,tit)) = do
- newsrc <- modifyMediaRef opts mediaRef src
- return $ Image attr lab (newsrc, tit)
-transformInline opts mediaRef (x@(Math t m))
+ -> E m Inline
+transformInline _opts (Image attr lab (src,tit)) = do
+ newsrc <- modifyMediaRef src
+ return $ Image attr lab ("../" ++ newsrc, tit)
+transformInline opts (x@(Math t m))
| WebTeX url <- writerHTMLMathMethod opts = do
- newsrc <- modifyMediaRef opts mediaRef (url ++ urlEncode m)
+ newsrc <- modifyMediaRef (url ++ urlEncode m)
let mathclass = if t == DisplayMath then "display" else "inline"
- return $ Span ("",["math",mathclass],[]) [Image nullAttr [x] (newsrc, "")]
-transformInline opts mediaRef (RawInline fmt raw)
+ return $ Span ("",["math",mathclass],[])
+ [Image nullAttr [x] ("../" ++ newsrc, "")]
+transformInline _opts (RawInline fmt raw)
| fmt == Format "html" = do
let tags = parseTags raw
- tags' <- mapM (transformTag opts mediaRef) tags
+ tags' <- mapM transformTag tags
return $ RawInline fmt (renderTags' tags')
-transformInline _ _ x = return x
+transformInline _ x = return x
(!) :: (t -> Element) -> [(String, String)] -> t -> Element
(!) f attrs n = add_attrs (map (\(k,v) -> Attr (unqual k) v) attrs) (f n)
@@ -898,8 +1011,8 @@ ppTopElement = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ++) . unEntity .
let (ds,ys) = break (==';') xs
rest = drop 1 ys
in case safeRead ('\'':'\\':ds ++ "'") of
- Just x -> x : unEntity rest
- Nothing -> '&':'#':unEntity xs
+ Just x -> x : unEntity rest
+ Nothing -> '&':'#':unEntity xs
unEntity (x:xs) = x : unEntity xs
mediaTypeOf :: FilePath -> Maybe MimeType
@@ -907,7 +1020,7 @@ mediaTypeOf x =
let mediaPrefixes = ["image", "video", "audio"] in
case getMimeType x of
Just y | any (`isPrefixOf` y) mediaPrefixes -> Just y
- _ -> Nothing
+ _ -> Nothing
-- Returns filename for chapter number.
showChapter :: Int -> String
diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs
index 5538ca061..e322c7d98 100644
--- a/src/Text/Pandoc/Writers/FB2.hs
+++ b/src/Text/Pandoc/Writers/FB2.hs
@@ -1,8 +1,8 @@
{-# LANGUAGE PatternGuards #-}
{-
-Copyright (c) 2011-2012, Sergey Astanin
-All rights reserved.
+Copyright (c) 2011-2012 Sergey Astanin
+ 2012-2018 John MacFarlane
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,17 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
-{- | Conversion of 'Pandoc' documents to FB2 (FictionBook2) format.
+{- |
+Module : Text.Pandoc.Writers.FB2
+Copyright : Copyright (C) 2011-2012 Sergey Astanin
+ 2012-2018 John MacFarlane
+License : GNU GPL, version 2 or above
+
+Maintainer : John MacFarlane
+Stability : alpha
+Portability : portable
+
+Conversion of 'Pandoc' documents to FB2 (FictionBook2) format.
FictionBook is an XML-based e-book format. For more information see:
<http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1>
@@ -27,44 +37,42 @@ FictionBook is an XML-based e-book format. For more information see:
-}
module Text.Pandoc.Writers.FB2 (writeFB2) where
-import Control.Monad.State (StateT, evalStateT, get, modify)
-import Control.Monad.State (liftM, liftM2, liftIO)
+import Control.Monad (zipWithM)
+import Control.Monad.Except (catchError)
+import Control.Monad.State.Strict (StateT, evalStateT, get, lift, liftM, modify)
import Data.ByteString.Base64 (encode)
-import Data.Char (toLower, isSpace, isAscii, isControl)
-import Data.List (intersperse, intercalate, isPrefixOf, stripPrefix)
+import qualified Data.ByteString.Char8 as B8
+import Data.Char (isAscii, isControl, isSpace, toLower)
import Data.Either (lefts, rights)
-import Network.Browser (browse, request, setAllowRedirects, setOutHandler)
-import Network.HTTP (catchIO_, getRequest, getHeaders, getResponseBody)
-import Network.HTTP (lookupHeader, HeaderName(..), urlEncode)
-import Network.URI (isURI, unEscapeString)
-import System.FilePath (takeExtension)
+import Data.List (intercalate, intersperse, isPrefixOf, stripPrefix)
+import Data.Text (Text, pack)
+import Network.HTTP (urlEncode)
import Text.XML.Light
-import qualified Control.Exception as E
-import qualified Data.ByteString as B
import qualified Text.XML.Light as X
import qualified Text.XML.Light.Cursor as XC
+import Text.Pandoc.Class (PandocMonad, report)
+import qualified Text.Pandoc.Class as P
import Text.Pandoc.Definition
-import Text.Pandoc.Options (WriterOptions(..), HTMLMathMethod(..), def)
-import Text.Pandoc.Shared (orderedListMarkers, isHeaderBlock, capitalize,
- linesToPara)
+import Text.Pandoc.Logging
+import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
+import Text.Pandoc.Shared (capitalize, isHeaderBlock, isURI, orderedListMarkers)
-- | Data to be written at the end of the document:
-- (foot)notes, URLs, references, images.
data FbRenderState = FbRenderState
- { footnotes :: [ (Int, String, [Content]) ] -- ^ #, ID, text
- , imagesToFetch :: [ (String, String) ] -- ^ filename, URL or path
- , parentListMarker :: String -- ^ list marker of the parent ordered list
- , parentBulletLevel :: Int -- ^ nesting level of the unordered list
- , writerOptions :: WriterOptions
+ { footnotes :: [ (Int, String, [Content]) ] -- ^ #, ID, text
+ , imagesToFetch :: [ (String, String) ] -- ^ filename, URL or path
+ , parentListMarker :: String -- ^ list marker of the parent ordered list
+ , writerOptions :: WriterOptions
} deriving (Show)
-- | FictionBook building monad.
-type FBM = StateT FbRenderState IO
+type FBM m = StateT FbRenderState m
newFB :: FbRenderState
newFB = FbRenderState { footnotes = [], imagesToFetch = []
- , parentListMarker = "", parentBulletLevel = 0
+ , parentListMarker = ""
, writerOptions = def }
data ImageMode = NormalImage | InlineImage deriving (Eq)
@@ -73,20 +81,27 @@ instance Show ImageMode where
show InlineImage = "inlineImageType"
-- | Produce an FB2 document from a 'Pandoc' document.
-writeFB2 :: WriterOptions -- ^ conversion options
+writeFB2 :: PandocMonad m
+ => WriterOptions -- ^ conversion options
-> Pandoc -- ^ document to convert
- -> IO String -- ^ FictionBook2 document (not encoded yet)
-writeFB2 opts (Pandoc meta blocks) = flip evalStateT newFB $ do
+ -> m Text -- ^ FictionBook2 document (not encoded yet)
+writeFB2 opts doc = flip evalStateT newFB $ pandocToFB2 opts doc
+
+pandocToFB2 :: PandocMonad m
+ => WriterOptions
+ -> Pandoc
+ -> FBM m Text
+pandocToFB2 opts (Pandoc meta blocks) = do
modify (\s -> s { writerOptions = opts })
desc <- description meta
- fp <- frontpage meta
+ title <- cMapM toXml . docTitle $ meta
secs <- renderSections 1 blocks
- let body = el "body" $ fp ++ secs
+ let body = el "body" $ el "title" (el "p" title) : secs
notes <- renderFootnotes
- (imgs,missing) <- liftM imagesToFetch get >>= \s -> liftIO (fetchImages s)
+ (imgs,missing) <- fmap imagesToFetch get >>= \s -> lift (fetchImages s)
let body' = replaceImagesWithAlt missing body
let fb2_xml = el "FictionBook" (fb2_attrs, [desc, body'] ++ notes ++ imgs)
- return $ xml_head ++ (showContent fb2_xml) ++ "\n"
+ return $ pack $ xml_head ++ showContent fb2_xml ++ "\n"
where
xml_head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
fb2_attrs =
@@ -94,67 +109,77 @@ writeFB2 opts (Pandoc meta blocks) = flip evalStateT newFB $ do
xlink = "http://www.w3.org/1999/xlink"
in [ uattr "xmlns" xmlns
, attr ("xmlns", "l") xlink ]
- --
- frontpage :: Meta -> FBM [Content]
- frontpage meta' = do
- t <- cMapM toXml . docTitle $ meta'
- return $
- [ el "title" (el "p" t)
- , el "annotation" (map (el "p" . cMap plain)
- (docAuthors meta' ++ [docDate meta']))
- ]
- description :: Meta -> FBM Content
- description meta' = do
- bt <- booktitle meta'
- let as = authors meta'
- dd <- docdate meta'
- return $ el "description"
- [ el "title-info" (bt ++ as ++ dd)
- , el "document-info" [ el "program-used" "pandoc" ] -- FIXME: +version
- ]
- booktitle :: Meta -> FBM [Content]
- booktitle meta' = do
- t <- cMapM toXml . docTitle $ meta'
- return $ if null t
- then []
- else [ el "book-title" t ]
- authors :: Meta -> [Content]
- authors meta' = cMap author (docAuthors meta')
- author :: [Inline] -> [Content]
- author ss =
- let ws = words . cMap plain $ ss
- email = (el "email") `fmap` (take 1 $ filter ('@' `elem`) ws)
- ws' = filter ('@' `notElem`) ws
- names = case ws' of
- (nickname:[]) -> [ el "nickname" nickname ]
- (fname:lname:[]) -> [ el "first-name" fname
- , el "last-name" lname ]
- (fname:rest) -> [ el "first-name" fname
- , el "middle-name" (concat . init $ rest)
- , el "last-name" (last rest) ]
- ([]) -> []
- in list $ el "author" (names ++ email)
- docdate :: Meta -> FBM [Content]
- docdate meta' = do
- let ss = docDate meta'
- d <- cMapM toXml ss
- return $ if null d
- then []
- else [el "date" d]
+
+description :: PandocMonad m => Meta -> FBM m Content
+description meta' = do
+ let genre = el "genre" "unrecognised"
+ bt <- booktitle meta'
+ let as = authors meta'
+ dd <- docdate meta'
+ let lang = case lookupMeta "lang" meta' of
+ Just (MetaInlines [Str s]) -> [el "lang" $ iso639 s]
+ Just (MetaString s) -> [el "lang" $ iso639 s]
+ _ -> []
+ where iso639 = takeWhile (/= '-') -- Convert BCP 47 to ISO 639
+ let coverimage url = do
+ let img = Image nullAttr mempty (url, "")
+ im <- insertImage InlineImage img
+ return [el "coverpage" im]
+ coverpage <- case lookupMeta "cover-image" meta' of
+ Just (MetaInlines [Str s]) -> coverimage s
+ Just (MetaString s) -> coverimage s
+ _ -> return []
+ return $ el "description"
+ [ el "title-info" (genre : (bt ++ as ++ dd ++ lang))
+ , el "document-info" (el "program-used" "pandoc" : coverpage)
+ ]
+
+booktitle :: PandocMonad m => Meta -> FBM m [Content]
+booktitle meta' = do
+ t <- cMapM toXml . docTitle $ meta'
+ return $ if null t
+ then []
+ else [ el "book-title" t ]
+
+authors :: Meta -> [Content]
+authors meta' = cMap author (docAuthors meta')
+
+author :: [Inline] -> [Content]
+author ss =
+ let ws = words . cMap plain $ ss
+ email = el "email" <$> take 1 (filter ('@' `elem`) ws)
+ ws' = filter ('@' `notElem`) ws
+ names = case ws' of
+ [nickname] -> [ el "nickname" nickname ]
+ [fname, lname] -> [ el "first-name" fname
+ , el "last-name" lname ]
+ (fname:rest) -> [ el "first-name" fname
+ , el "middle-name" (concat . init $ rest)
+ , el "last-name" (last rest) ]
+ [] -> []
+ in list $ el "author" (names ++ email)
+
+docdate :: PandocMonad m => Meta -> FBM m [Content]
+docdate meta' = do
+ let ss = docDate meta'
+ d <- cMapM toXml ss
+ return $ if null d
+ then []
+ else [el "date" d]
-- | Divide the stream of blocks into sections and convert to XML
-- representation.
-renderSections :: Int -> [Block] -> FBM [Content]
+renderSections :: PandocMonad m => Int -> [Block] -> FBM m [Content]
renderSections level blocks = do
let secs = splitSections level blocks
mapM (renderSection level) secs
-renderSection :: Int -> ([Inline], [Block]) -> FBM Content
+renderSection :: PandocMonad m => Int -> ([Inline], [Block]) -> FBM m Content
renderSection level (ttl, body) = do
title <- if null ttl
then return []
else return . list . el "title" . formatTitle $ ttl
- content <- if (hasSubsections body)
+ content <- if hasSubsections body
then renderSections (level + 1) body
else cMapM blockToXml body
return $ el "section" (title ++ content)
@@ -175,7 +200,7 @@ split cond xs = let (b,a) = break cond xs
isLineBreak :: Inline -> Bool
isLineBreak LineBreak = True
-isLineBreak _ = False
+isLineBreak _ = False
-- | Divide the stream of block elements into sections: [(title, blocks)].
splitSections :: Int -> [Block] -> [([Inline], [Block])]
@@ -186,17 +211,17 @@ splitSections level blocks = reverse $ revSplit (reverse blocks)
let (lastsec, before) = break sameLevel rblocks
(header, prevblocks) =
case before of
- ((Header n _ title):prevblocks') ->
+ (Header n _ title:prevblocks') ->
if n == level
then (title, prevblocks')
else ([], before)
_ -> ([], before)
in (header, reverse lastsec) : revSplit prevblocks
sameLevel (Header n _ _) = n == level
- sameLevel _ = False
+ sameLevel _ = False
-- | Make another FictionBook body with footnotes.
-renderFootnotes :: FBM [Content]
+renderFootnotes :: PandocMonad m => FBM m [Content]
renderFootnotes = do
fns <- footnotes `liftM` get
if null fns
@@ -205,19 +230,19 @@ renderFootnotes = do
el "body" ([uattr "name" "notes"], map renderFN (reverse fns))
where
renderFN (n, idstr, cs) =
- let fn_texts = (el "title" (el "p" (show n))) : cs
+ let fn_texts = el "title" (el "p" (show n)) : cs
in el "section" ([uattr "id" idstr], fn_texts)
-- | Fetch images and encode them for the FictionBook XML.
-- Return image data and a list of hrefs of the missing images.
-fetchImages :: [(String,String)] -> IO ([Content],[String])
+fetchImages :: PandocMonad m => [(String,String)] -> m ([Content],[String])
fetchImages links = do
imgs <- mapM (uncurry fetchImage) links
- return $ (rights imgs, lefts imgs)
+ return (rights imgs, lefts imgs)
-- | Fetch image data from disk or from network and make a <binary> XML section.
-- Return either (Left hrefOfMissingImage) or (Right xmlContent).
-fetchImage :: String -> String -> IO (Either String Content)
+fetchImage :: PandocMonad m => String -> String -> m (Either String Content)
fetchImage href link = do
mbimg <-
case (isURI link, readDataURI link) of
@@ -227,28 +252,25 @@ fetchImage href link = do
then return (Just (mime',base64))
else return Nothing
(True, Just _) -> return Nothing -- not base64-encoded
- (True, Nothing) -> fetchURL link
- (False, _) -> do
- d <- nothingOnError $ B.readFile (unEscapeString link)
- let t = case map toLower (takeExtension link) of
- ".png" -> Just "image/png"
- ".jpg" -> Just "image/jpeg"
- ".jpeg" -> Just "image/jpeg"
- ".jpe" -> Just "image/jpeg"
- _ -> Nothing -- only PNG and JPEG are supported in FB2
- return $ liftM2 (,) t (liftM (toStr . encode) d)
+ _ ->
+ catchError (do (bs, mbmime) <- P.fetchItem link
+ case mbmime of
+ Nothing -> do
+ report $ CouldNotDetermineMimeType link
+ return Nothing
+ Just mime -> return $ Just (mime,
+ B8.unpack $ encode bs))
+ (\e ->
+ do report $ CouldNotFetchResource link (show e)
+ return Nothing)
case mbimg of
- Just (imgtype, imgdata) -> do
+ Just (imgtype, imgdata) ->
return . Right $ el "binary"
( [uattr "id" href
, uattr "content-type" imgtype]
, txt imgdata )
_ -> return (Left ('#':href))
- where
- nothingOnError :: (IO B.ByteString) -> (IO (Maybe B.ByteString))
- nothingOnError action = liftM Just action `E.catch` omnihandler
- omnihandler :: E.SomeException -> IO (Maybe B.ByteString)
- omnihandler _ = return Nothing
+
-- | Extract mime type and encoded data from the Data URI.
readDataURI :: String -- ^ URI
@@ -276,8 +298,8 @@ isMimeType :: String -> Bool
isMimeType s =
case split (=='/') s of
[mtype,msubtype] ->
- ((map toLower mtype) `elem` types
- || "x-" `isPrefixOf` (map toLower mtype))
+ (map toLower mtype `elem` types
+ || "x-" `isPrefixOf` map toLower mtype)
&& all valid mtype
&& all valid msubtype
_ -> False
@@ -286,85 +308,63 @@ isMimeType s =
valid c = isAscii c && not (isControl c) && not (isSpace c) &&
c `notElem` "()<>@,;:\\\"/[]?="
--- | Fetch URL, return its Content-Type and binary data on success.
-fetchURL :: String -> IO (Maybe (String, String))
-fetchURL url = do
- flip catchIO_ (return Nothing) $ do
- r <- browse $ do
- setOutHandler (const (return ()))
- setAllowRedirects True
- liftM snd . request . getRequest $ url
- let content_type = lookupHeader HdrContentType (getHeaders r)
- content <- liftM (Just . toStr . encode . toBS) . getResponseBody $ Right r
- return $ liftM2 (,) content_type content
-
-toBS :: String -> B.ByteString
-toBS = B.pack . map (toEnum . fromEnum)
-
-toStr :: B.ByteString -> String
-toStr = map (toEnum . fromEnum) . B.unpack
-
footnoteID :: Int -> String
-footnoteID i = "n" ++ (show i)
+footnoteID i = "n" ++ show i
linkID :: Int -> String
-linkID i = "l" ++ (show i)
+linkID i = "l" ++ show i
-- | Convert a block-level Pandoc's element to FictionBook XML representation.
-blockToXml :: Block -> FBM [Content]
+blockToXml :: PandocMonad m => Block -> FBM m [Content]
blockToXml (Plain ss) = cMapM toXml ss -- FIXME: can lead to malformed FB2
blockToXml (Para [Math DisplayMath formula]) = insertMath NormalImage formula
-- title beginning with fig: indicates that the image is a figure
blockToXml (Para [Image atr alt (src,'f':'i':'g':':':tit)]) =
insertImage NormalImage (Image atr alt (src,tit))
-blockToXml (Para ss) = liftM (list . el "p") $ cMapM toXml ss
+blockToXml (Para ss) = (list . el "p") <$> cMapM toXml ss
blockToXml (CodeBlock _ s) = return . spaceBeforeAfter .
map (el "p" . el "code") . lines $ s
-blockToXml (RawBlock _ s) = return . spaceBeforeAfter .
- map (el "p" . el "code") . lines $ s
+blockToXml b@(RawBlock _ _) = do
+ report $ BlockNotRendered b
+ return []
blockToXml (Div _ bs) = cMapM blockToXml bs
-blockToXml (BlockQuote bs) = liftM (list . el "cite") $ cMapM blockToXml bs
-blockToXml (LineBlock lns) = blockToXml $ linesToPara lns
+blockToXml (BlockQuote bs) = (list . el "cite") <$> cMapM blockToXml bs
+blockToXml (LineBlock lns) =
+ (list . el "poem") <$> mapM stanza (split null lns)
+ where
+ v xs = el "v" <$> cMapM toXml xs
+ stanza xs = el "stanza" <$> mapM v xs
blockToXml (OrderedList a bss) = do
state <- get
let pmrk = parentListMarker state
- let markers = map ((pmrk ++ " ") ++) $ orderedListMarkers a
+ let markers = (pmrk ++) <$> orderedListMarkers a
let mkitem mrk bs = do
- modify (\s -> s { parentListMarker = mrk })
- itemtext <- cMapM blockToXml . paraToPlain $ bs
+ modify (\s -> s { parentListMarker = mrk ++ " "})
+ item <- cMapM blockToXml $ plainToPara $ indentBlocks (mrk ++ " ") bs
modify (\s -> s { parentListMarker = pmrk }) -- old parent marker
- return . el "p" $ [ txt mrk, txt " " ] ++ itemtext
- mapM (uncurry mkitem) (zip markers bss)
+ return item
+ concat <$> zipWithM mkitem markers bss
blockToXml (BulletList bss) = do
state <- get
- let level = parentBulletLevel state
let pmrk = parentListMarker state
- let prefix = replicate (length pmrk) ' '
- let bullets = ["\x2022", "\x25e6", "*", "\x2043", "\x2023"]
- let mrk = prefix ++ bullets !! (level `mod` (length bullets))
+ let mrk = pmrk ++ "•"
let mkitem bs = do
- modify (\s -> s { parentBulletLevel = (level+1) })
- itemtext <- cMapM blockToXml . paraToPlain $ bs
- modify (\s -> s { parentBulletLevel = level }) -- restore bullet level
- return $ el "p" $ [ txt (mrk ++ " ") ] ++ itemtext
- mapM mkitem bss
+ modify (\s -> s { parentListMarker = mrk ++ " "})
+ item <- cMapM blockToXml $ plainToPara $ indentBlocks (mrk ++ " ") bs
+ modify (\s -> s { parentListMarker = pmrk }) -- old parent marker
+ return item
+ cMapM mkitem bss
blockToXml (DefinitionList defs) =
cMapM mkdef defs
where
mkdef (term, bss) = do
- def' <- cMapM (cMapM blockToXml . sep . paraToPlain . map indent) bss
+ items <- cMapM (cMapM blockToXml . plainToPara . indentBlocks (replicate 4 ' ')) bss
t <- wrap "strong" term
- return [ el "p" t, el "p" def' ]
- sep blocks =
- if all needsBreak blocks then
- blocks ++ [Plain [LineBreak]]
- else
- blocks
- needsBreak (Para _) = False
- needsBreak (Plain ins) = LineBreak `notElem` ins
- needsBreak _ = True
-blockToXml (Header _ _ _) = -- should never happen, see renderSections
- error "unexpected header in section text"
+ return (el "p" t : items)
+blockToXml h@Header{} = do
+ -- should not occur after hierarchicalize, except inside lists/blockquotes
+ report $ BlockNotRendered h
+ return []
blockToXml HorizontalRule = return
[ el "empty-line" ()
, el "p" (txt (replicate 10 '—'))
@@ -372,45 +372,42 @@ blockToXml HorizontalRule = return
blockToXml (Table caption aligns _ headers rows) = do
hd <- mkrow "th" headers aligns
bd <- mapM (\r -> mkrow "td" r aligns) rows
- c <- return . el "emphasis" =<< cMapM toXml caption
+ c <- el "emphasis" <$> cMapM toXml caption
return [el "table" (hd : bd), el "p" c]
where
- mkrow :: String -> [TableCell] -> [Alignment] -> FBM Content
+ mkrow :: PandocMonad m => String -> [TableCell] -> [Alignment] -> FBM m Content
mkrow tag cells aligns' =
- (el "tr") `liftM` (mapM (mkcell tag) (zip cells aligns'))
+ el "tr" <$> mapM (mkcell tag) (zip cells aligns')
--
- mkcell :: String -> (TableCell, Alignment) -> FBM Content
+ mkcell :: PandocMonad m => String -> (TableCell, Alignment) -> FBM m Content
mkcell tag (cell, align) = do
cblocks <- cMapM blockToXml cell
return $ el tag ([align_attr align], cblocks)
--
align_attr a = Attr (QName "align" Nothing Nothing) (align_str a)
- align_str AlignLeft = "left"
- align_str AlignCenter = "center"
- align_str AlignRight = "right"
+ align_str AlignLeft = "left"
+ align_str AlignCenter = "center"
+ align_str AlignRight = "right"
align_str AlignDefault = "left"
blockToXml Null = return []
--- Replace paragraphs with plain text and line break.
--- Necessary to simulate multi-paragraph lists in FB2.
-paraToPlain :: [Block] -> [Block]
-paraToPlain [] = []
-paraToPlain (Para inlines : rest) =
- let p = (Plain (inlines ++ [LineBreak]))
- in p : paraToPlain rest
-paraToPlain (p:rest) = p : paraToPlain rest
+-- Replace plain text with paragraphs and add line break after paragraphs.
+-- It is used to convert plain text from tight list items to paragraphs.
+plainToPara :: [Block] -> [Block]
+plainToPara [] = []
+plainToPara (Plain inlines : rest) =
+ Para inlines : plainToPara rest
+plainToPara (Para inlines : rest) =
+ Para inlines : Plain [LineBreak] : plainToPara rest
+plainToPara (p:rest) = p : plainToPara rest
-- Simulate increased indentation level. Will not really work
-- for multi-line paragraphs.
-indent :: Block -> Block
-indent = indentBlock
+indentPrefix :: String -> Block -> Block
+indentPrefix spacer = indentBlock
where
- -- indentation space
- spacer :: String
- spacer = replicate 4 ' '
- --
- indentBlock (Plain ins) = Plain ((Str spacer):ins)
- indentBlock (Para ins) = Para ((Str spacer):ins)
+ indentBlock (Plain ins) = Plain (Str spacer:ins)
+ indentBlock (Para ins) = Para (Str spacer:ins)
indentBlock (CodeBlock a s) =
let s' = unlines . map (spacer++) . lines $ s
in CodeBlock a s'
@@ -420,10 +417,21 @@ indent = indentBlock
-- indent every (explicit) line
indentLines :: [Inline] -> [Inline]
indentLines ins = let lns = split isLineBreak ins :: [[Inline]]
- in intercalate [LineBreak] $ map ((Str spacer):) lns
+ in intercalate [LineBreak] $ map (Str spacer:) lns
+
+indent :: Block -> Block
+indent = indentPrefix spacer
+ where
+ -- indentation space
+ spacer :: String
+ spacer = replicate 4 ' '
+
+indentBlocks :: String -> [Block] -> [Block]
+indentBlocks _ [] = []
+indentBlocks prefix (x:xs) = indentPrefix prefix x : map (indentPrefix $ replicate (length prefix) ' ') xs
-- | Convert a Pandoc's Inline element to FictionBook XML representation.
-toXml :: Inline -> FBM [Content]
+toXml :: PandocMonad m => Inline -> FBM m [Content]
toXml (Str s) = return [txt s]
toXml (Span _ ils) = cMapM toXml ils
toXml (Emph ss) = list `liftM` wrap "emphasis" ss
@@ -444,7 +452,9 @@ toXml Space = return [txt " "]
toXml SoftBreak = return [txt " "]
toXml LineBreak = return [el "empty-line" ()]
toXml (Math _ formula) = insertMath InlineImage formula
-toXml (RawInline _ _) = return [] -- raw TeX and raw HTML are suppressed
+toXml il@(RawInline _ _) = do
+ report $ InlineNotRendered il
+ return [] -- raw TeX and raw HTML are suppressed
toXml (Link _ text (url,ttl)) = do
fns <- footnotes `liftM` get
let n = 1 + length fns
@@ -462,7 +472,7 @@ toXml (Link _ text (url,ttl)) = do
( [ attr ("l","href") ('#':ln_id)
, uattr "type" "note" ]
, ln_ref) ]
-toXml img@(Image _ _ _) = insertImage InlineImage img
+toXml img@Image{} = insertImage InlineImage img
toXml (Note bs) = do
fns <- footnotes `liftM` get
let n = 1 + length fns
@@ -474,9 +484,9 @@ toXml (Note bs) = do
, uattr "type" "note" ]
, fn_ref )
-insertMath :: ImageMode -> String -> FBM [Content]
+insertMath :: PandocMonad m => ImageMode -> String -> FBM m [Content]
insertMath immode formula = do
- htmlMath <- return . writerHTMLMathMethod . writerOptions =<< get
+ htmlMath <- fmap (writerHTMLMathMethod . writerOptions) get
case htmlMath of
WebTeX url -> do
let alt = [Code nullAttr formula]
@@ -485,7 +495,7 @@ insertMath immode formula = do
insertImage immode img
_ -> return [el "code" formula]
-insertImage :: ImageMode -> Inline -> FBM [Content]
+insertImage :: PandocMonad m => ImageMode -> Inline -> FBM m [Content]
insertImage immode (Image _ alt (url,ttl)) = do
images <- imagesToFetch `liftM` get
let n = 1 + length images
@@ -493,7 +503,7 @@ insertImage immode (Image _ alt (url,ttl)) = do
modify (\s -> s { imagesToFetch = (fname, url) : images })
let ttlattr = case (immode, null ttl) of
(NormalImage, False) -> [ uattr "title" ttl ]
- _ -> []
+ _ -> []
return . list $
el "image" $
[ attr ("l","href") ('#':fname)
@@ -517,20 +527,20 @@ replaceImagesWithAlt missingHrefs body =
else c
in case XC.nextDF c' of
(Just cnext) -> replaceAll cnext
- Nothing -> c' -- end of document
+ Nothing -> c' -- end of document
--
isImage :: Content -> Bool
- isImage (Elem e) = (elName e) == (uname "image")
- isImage _ = False
+ isImage (Elem e) = elName e == uname "image"
+ isImage _ = False
--
- isMissing (Elem img@(Element _ _ _ _)) =
+ isMissing (Elem img@Element{}) =
let imgAttrs = elAttribs img
badAttrs = map (attr ("l","href")) missingHrefs
in any (`elem` imgAttrs) badAttrs
isMissing _ = False
--
replaceNode :: Content -> Content
- replaceNode n@(Elem img@(Element _ _ _ _)) =
+ replaceNode n@(Elem img@Element{}) =
let attrs = elAttribs img
alt = getAttrVal attrs (uname "alt")
imtype = getAttrVal attrs (qname "l" "type")
@@ -551,7 +561,7 @@ replaceImagesWithAlt missingHrefs body =
-- | Wrap all inlines with an XML tag (given its unqualified name).
-wrap :: String -> [Inline] -> FBM Content
+wrap :: PandocMonad m => String -> [Inline] -> FBM m Content
wrap tagname inlines = el tagname `liftM` cMapM toXml inlines
-- " Create a singleton list.
@@ -560,25 +570,25 @@ list = (:[])
-- | Convert an 'Inline' to plaintext.
plain :: Inline -> String
-plain (Str s) = s
-plain (Emph ss) = concat (map plain ss)
-plain (Span _ ss) = concat (map plain ss)
-plain (Strong ss) = concat (map plain ss)
-plain (Strikeout ss) = concat (map plain ss)
-plain (Superscript ss) = concat (map plain ss)
-plain (Subscript ss) = concat (map plain ss)
-plain (SmallCaps ss) = concat (map plain ss)
-plain (Quoted _ ss) = concat (map plain ss)
-plain (Cite _ ss) = concat (map plain ss) -- FIXME
-plain (Code _ s) = s
-plain Space = " "
-plain SoftBreak = " "
-plain LineBreak = "\n"
-plain (Math _ s) = s
-plain (RawInline _ s) = s
+plain (Str s) = s
+plain (Emph ss) = cMap plain ss
+plain (Span _ ss) = cMap plain ss
+plain (Strong ss) = cMap plain ss
+plain (Strikeout ss) = cMap plain ss
+plain (Superscript ss) = cMap plain ss
+plain (Subscript ss) = cMap plain ss
+plain (SmallCaps ss) = cMap plain ss
+plain (Quoted _ ss) = cMap plain ss
+plain (Cite _ ss) = cMap plain ss -- FIXME
+plain (Code _ s) = s
+plain Space = " "
+plain SoftBreak = " "
+plain LineBreak = "\n"
+plain (Math _ s) = s
+plain (RawInline _ _) = ""
plain (Link _ text (url,_)) = concat (map plain text ++ [" <", url, ">"])
-plain (Image _ alt _) = concat (map plain alt)
-plain (Note _) = "" -- FIXME
+plain (Image _ alt _) = cMap plain alt
+plain (Note _) = "" -- FIXME
-- | Create an XML element.
el :: (Node t)
@@ -599,11 +609,11 @@ txt s = Text $ CData CDataText s Nothing
-- | Create an XML attribute with an unqualified name.
uattr :: String -> String -> Text.XML.Light.Attr
-uattr name val = Attr (uname name) val
+uattr name = Attr (uname name)
-- | Create an XML attribute with a qualified name from given namespace.
attr :: (String, String) -> String -> Text.XML.Light.Attr
-attr (ns, name) val = Attr (qname ns name) val
+attr (ns, name) = Attr (qname ns name)
-- | Unqualified name
uname :: String -> QName
diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
index 3c8c264d2..1647df7ea 100644
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -1,6 +1,10 @@
-{-# LANGUAGE OverloadedStrings, CPP, ViewPatterns, ScopedTypeVariables #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE MultiWayIf #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.HTML
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -28,60 +32,92 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to HTML.
-}
-module Text.Pandoc.Writers.HTML ( writeHtml , writeHtmlString ) where
-import Text.Pandoc.Definition
+module Text.Pandoc.Writers.HTML (
+ writeHtml4,
+ writeHtml4String,
+ writeHtml5,
+ writeHtml5String,
+ writeHtmlStringForEPUB,
+ writeS5,
+ writeSlidy,
+ writeSlideous,
+ writeDZSlides,
+ writeRevealJs,
+ tagWithAttributes
+ ) where
+import Control.Monad.State.Strict
+import Data.Char (ord, toLower)
+import Data.List (intercalate, intersperse, isPrefixOf, partition)
+import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
import Data.Monoid ((<>))
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
-import Text.Pandoc.Options
+import qualified Data.Set as Set
+import Data.String (fromString)
+import Data.Text (Text)
+import qualified Data.Text.Lazy as TL
+import Network.HTTP (urlEncode)
+import Network.URI (URI (..), parseURIReference, unEscapeString)
+import Numeric (showHex)
+import Text.Blaze.Internal (customLeaf, MarkupM(Empty))
+#if MIN_VERSION_blaze_markup(0,6,3)
+#else
+import Text.Blaze.Internal (preEscapedString, preEscapedText)
+#endif
+import Text.Blaze.Html hiding (contents)
+import Text.Pandoc.Definition
+import Text.Pandoc.Highlighting (formatHtmlBlock, formatHtmlInline, highlight,
+ styleToCss)
import Text.Pandoc.ImageSize
-import Text.Pandoc.Templates
-import Text.Pandoc.Readers.TeXMath
+import Text.Pandoc.Options
+import Text.Pandoc.Shared
import Text.Pandoc.Slides
-import Text.Pandoc.Highlighting ( highlight, styleToCss,
- formatHtmlInline, formatHtmlBlock )
-import Text.Pandoc.XML (fromEntities, escapeStringForXML)
-import Network.URI ( parseURIReference, URI(..), unEscapeString )
-import Network.HTTP ( urlEncode )
-import Numeric ( showHex )
-import Data.Char ( ord, toLower )
-import Data.List ( isPrefixOf, intersperse )
-import Data.String ( fromString )
-import Data.Maybe ( catMaybes, fromMaybe, isJust )
-import Control.Monad.State
-import Text.Blaze.Html hiding(contents)
+import Text.Pandoc.Templates
+import Text.Pandoc.Walk
+import Text.Pandoc.Writers.Math
+import Text.Pandoc.Writers.Shared
+import Text.Pandoc.XML (escapeStringForXML, fromEntities)
#if MIN_VERSION_blaze_markup(0,6,3)
#else
-import Text.Blaze.Internal(preEscapedString)
+import Text.Blaze.Internal (preEscapedString, preEscapedText)
#endif
#if MIN_VERSION_blaze_html(0,5,1)
import qualified Text.Blaze.XHtml5 as H5
#else
import qualified Text.Blaze.Html5 as H5
#endif
+import Control.Monad.Except (throwError)
+import Data.Aeson (Value)
+import System.FilePath (takeBaseName, takeExtension)
+import Text.Blaze.Html.Renderer.Text (renderHtml)
import qualified Text.Blaze.XHtml1.Transitional as H
import qualified Text.Blaze.XHtml1.Transitional.Attributes as A
-import Text.Blaze.Html.Renderer.String (renderHtml)
+import Text.Pandoc.Class (PandocMonad, report, runPure)
+import Text.Pandoc.Error
+import Text.Pandoc.Logging
import Text.TeXMath
-import Text.XML.Light.Output
-import Text.XML.Light (unode, elChildren, unqual)
+import Text.XML.Light (elChildren, unode, unqual)
import qualified Text.XML.Light as XML
-import System.FilePath (takeExtension)
-import Data.Aeson (Value)
+import Text.XML.Light.Output
data WriterState = WriterState
- { stNotes :: [Html] -- ^ List of notes
- , stMath :: Bool -- ^ Math is used in document
- , stQuotes :: Bool -- ^ <q> tag is used
- , stHighlighting :: Bool -- ^ Syntax highlighting is used
- , stSecNum :: [Int] -- ^ Number of current section
- , stElement :: Bool -- ^ Processing an Element
+ { stNotes :: [Html] -- ^ List of notes
+ , stMath :: Bool -- ^ Math is used in document
+ , stQuotes :: Bool -- ^ <q> tag is used
+ , stHighlighting :: Bool -- ^ Syntax highlighting is used
+ , stSecNum :: [Int] -- ^ Number of current section
+ , stElement :: Bool -- ^ Processing an Element
+ , stHtml5 :: Bool -- ^ Use HTML5
+ , stEPUBVersion :: Maybe EPUBVersion -- ^ EPUB version if for epub
+ , stSlideVariant :: HTMLSlideVariant
+ , stCodeBlockNum :: Int -- ^ Number of code block
}
defaultWriterState :: WriterState
defaultWriterState = WriterState {stNotes= [], stMath = False, stQuotes = False,
stHighlighting = False, stSecNum = [],
- stElement = False}
+ stElement = False, stHtml5 = False,
+ stEPUBVersion = Nothing,
+ stSlideVariant = NoSlides,
+ stCodeBlockNum = 0}
-- Helpers to render HTML with the appropriate function.
@@ -98,62 +134,141 @@ nl opts = if writerWrapText opts == WrapNone
then mempty
else preEscapedString "\n"
--- | Convert Pandoc document to Html string.
-writeHtmlString :: WriterOptions -> Pandoc -> String
-writeHtmlString opts d =
- let (body, context) = evalState (pandocToHtml opts d) defaultWriterState
- in case writerTemplate opts of
- Nothing -> renderHtml body
- Just tpl -> renderTemplate' tpl $
- defField "body" (renderHtml body) context
-
--- | Convert Pandoc document to Html structure.
-writeHtml :: WriterOptions -> Pandoc -> Html
-writeHtml opts d =
- let (body, context) = evalState (pandocToHtml opts d) defaultWriterState
- in case writerTemplate opts of
- Nothing -> body
- Just tpl -> renderTemplate' tpl $
- defField "body" (renderHtml body) context
+-- | Convert Pandoc document to Html 5 string.
+writeHtml5String :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeHtml5String = writeHtmlString'
+ defaultWriterState{ stHtml5 = True }
+
+-- | Convert Pandoc document to Html 5 structure.
+writeHtml5 :: PandocMonad m => WriterOptions -> Pandoc -> m Html
+writeHtml5 = writeHtml' defaultWriterState{ stHtml5 = True }
+
+-- | Convert Pandoc document to Html 4 string.
+writeHtml4String :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeHtml4String = writeHtmlString'
+ defaultWriterState{ stHtml5 = False }
+
+-- | Convert Pandoc document to Html 4 structure.
+writeHtml4 :: PandocMonad m => WriterOptions -> Pandoc -> m Html
+writeHtml4 = writeHtml' defaultWriterState{ stHtml5 = False }
+
+-- | Convert Pandoc document to Html appropriate for an epub version.
+writeHtmlStringForEPUB :: PandocMonad m
+ => EPUBVersion -> WriterOptions -> Pandoc
+ -> m Text
+writeHtmlStringForEPUB version o = writeHtmlString'
+ defaultWriterState{ stHtml5 = version == EPUB3,
+ stEPUBVersion = Just version } o
+
+-- | Convert Pandoc document to Reveal JS HTML slide show.
+writeRevealJs :: PandocMonad m
+ => WriterOptions -> Pandoc -> m Text
+writeRevealJs = writeHtmlSlideShow' RevealJsSlides
+
+-- | Convert Pandoc document to S5 HTML slide show.
+writeS5 :: PandocMonad m
+ => WriterOptions -> Pandoc -> m Text
+writeS5 = writeHtmlSlideShow' S5Slides
+
+-- | Convert Pandoc document to Slidy HTML slide show.
+writeSlidy :: PandocMonad m
+ => WriterOptions -> Pandoc -> m Text
+writeSlidy = writeHtmlSlideShow' SlidySlides
+
+-- | Convert Pandoc document to Slideous HTML slide show.
+writeSlideous :: PandocMonad m
+ => WriterOptions -> Pandoc -> m Text
+writeSlideous = writeHtmlSlideShow' SlideousSlides
+
+-- | Convert Pandoc document to DZSlides HTML slide show.
+writeDZSlides :: PandocMonad m
+ => WriterOptions -> Pandoc -> m Text
+writeDZSlides = writeHtmlSlideShow' DZSlides
+
+writeHtmlSlideShow' :: PandocMonad m
+ => HTMLSlideVariant -> WriterOptions -> Pandoc -> m Text
+writeHtmlSlideShow' variant = writeHtmlString'
+ defaultWriterState{ stSlideVariant = variant
+ , stHtml5 = case variant of
+ RevealJsSlides -> True
+ S5Slides -> False
+ SlidySlides -> False
+ DZSlides -> True
+ SlideousSlides -> False
+ NoSlides -> False
+ }
+
+renderHtml' :: Html -> Text
+renderHtml' = TL.toStrict . renderHtml
+
+writeHtmlString' :: PandocMonad m
+ => WriterState -> WriterOptions -> Pandoc -> m Text
+writeHtmlString' st opts d = do
+ (body, context) <- evalStateT (pandocToHtml opts d) st
+ case writerTemplate opts of
+ Nothing -> return $ renderHtml' body
+ Just tpl -> do
+ -- warn if empty lang
+ when (isNothing (getField "lang" context :: Maybe String)) $
+ report NoLangSpecified
+ -- check for empty pagetitle
+ context' <-
+ case getField "pagetitle" context of
+ Just (s :: String) | not (null s) -> return context
+ _ -> do
+ let fallback = fromMaybe "Untitled" $ takeBaseName <$>
+ lookup "sourcefile" (writerVariables opts)
+ report $ NoTitleElement fallback
+ return $ resetField "pagetitle" fallback context
+ renderTemplate' tpl $
+ defField "body" (renderHtml' body) context'
+
+writeHtml' :: PandocMonad m => WriterState -> WriterOptions -> Pandoc -> m Html
+writeHtml' st opts d =
+ case writerTemplate opts of
+ Just _ -> preEscapedText <$> writeHtmlString' st opts d
+ Nothing -> do
+ (body, _) <- evalStateT (pandocToHtml opts d) st
+ return body
-- result is (title, authors, date, toc, body, new variables)
-pandocToHtml :: WriterOptions
+pandocToHtml :: PandocMonad m
+ => WriterOptions
-> Pandoc
- -> State WriterState (Html, Value)
+ -> StateT WriterState m (Html, Value)
pandocToHtml opts (Pandoc meta blocks) = do
metadata <- metaToJSON opts
- (fmap renderHtml . blockListToHtml opts)
- (fmap renderHtml . inlineListToHtml opts)
+ (fmap renderHtml' . blockListToHtml opts)
+ (fmap renderHtml' . inlineListToHtml opts)
meta
let stringifyHTML = escapeStringForXML . stringify
let authsMeta = map stringifyHTML $ docAuthors meta
let dateMeta = stringifyHTML $ docDate meta
let slideLevel = fromMaybe (getSlideLevel blocks) $ writerSlideLevel opts
+ slideVariant <- gets stSlideVariant
let sects = hierarchicalize $
- if writerSlideVariant opts == NoSlides
+ if slideVariant == NoSlides
then blocks
else prepSlides slideLevel blocks
- toc <- if writerTableOfContents opts
- then tableOfContents opts sects
+ toc <- if writerTableOfContents opts && slideVariant /= S5Slides
+ then fmap renderHtml' <$> tableOfContents opts sects
else return Nothing
blocks' <- liftM (mconcat . intersperse (nl opts)) $
mapM (elementToHtml slideLevel opts) sects
st <- get
- let notes = reverse (stNotes st)
- let thebody = blocks' >> footnoteSection opts notes
+ notes <- footnoteSection opts (reverse (stNotes st))
+ let thebody = blocks' >> notes
let math = case writerHTMLMathMethod opts of
LaTeXMathML (Just url) ->
H.script ! A.src (toValue url)
! A.type_ "text/javascript"
$ mempty
- MathML (Just url) ->
+ MathJax url
+ | slideVariant /= RevealJsSlides ->
+ -- mathjax is handled via a special plugin in revealjs
H.script ! A.src (toValue url)
! A.type_ "text/javascript"
- $ mempty
- MathJax url ->
- H.script ! A.src (toValue url)
- ! A.type_ "text/javascript"
- $ case writerSlideVariant opts of
+ $ case slideVariant of
SlideousSlides ->
preEscapedString
"MathJax.Hub.Queue([\"Typeset\",MathJax.Hub]);"
@@ -162,37 +277,55 @@ pandocToHtml opts (Pandoc meta blocks) = do
H.script ! A.src (toValue url)
! A.type_ "text/javascript"
$ mempty
- KaTeX js css ->
- (H.script ! A.src (toValue js) $ mempty) <>
- (H.link ! A.rel "stylesheet" ! A.href (toValue css)) <>
- (H.script ! A.type_ "text/javascript" $ toHtml renderKaTeX)
+ KaTeX url ->
+ (H.script !
+ A.src (toValue $ url ++ "katex.min.js") $ mempty) <>
+ (H.script !
+ A.src (toValue $ url ++ "contrib/auto-render.min.js")
+ $ mempty) <>
+ (
+ H.script
+ "document.addEventListener(\"DOMContentLoaded\", function() {\n renderMathInElement(document.body);\n});") <>
+ (H.link ! A.rel "stylesheet" !
+ A.href (toValue $ url ++ "katex.min.css"))
+
_ -> case lookup "mathml-script" (writerVariables opts) of
- Just s | not (writerHtml5 opts) ->
+ Just s | not (stHtml5 st) ->
H.script ! A.type_ "text/javascript"
$ preEscapedString
("/*<![CDATA[*/\n" ++ s ++ "/*]]>*/\n")
| otherwise -> mempty
Nothing -> mempty
let context = (if stHighlighting st
- then defField "highlighting-css"
- (styleToCss $ writerHighlightStyle opts)
+ then case writerHighlightStyle opts of
+ Just sty -> defField "highlighting-css"
+ (styleToCss sty)
+ Nothing -> id
else id) $
(if stMath st
- then defField "math" (renderHtml math)
+ then defField "math" (renderHtml' math)
else id) $
+ defField "mathjax"
+ (case writerHTMLMathMethod opts of
+ MathJax _ -> True
+ _ -> False) $
defField "quotes" (stQuotes st) $
- maybe id (defField "toc" . renderHtml) toc $
+ -- for backwards compatibility we populate toc
+ -- with the contents of the toc, rather than a
+ -- boolean:
+ maybe id (defField "toc") toc $
+ maybe id (defField "table-of-contents") toc $
defField "author-meta" authsMeta $
maybe id (defField "date-meta") (normalizeDate dateMeta) $
- defField "pagetitle" (stringifyHTML $ docTitle meta) $
+ defField "pagetitle" (stringifyHTML (docTitle meta)) $
defField "idprefix" (writerIdentifierPrefix opts) $
-- these should maybe be set in pandoc.hs
defField "slidy-url"
- ("http://www.w3.org/Talks/Tools/Slidy2" :: String) $
+ ("https://www.w3.org/Talks/Tools/Slidy2" :: String) $
defField "slideous-url" ("slideous" :: String) $
defField "revealjs-url" ("reveal.js" :: String) $
defField "s5-url" ("s5/default" :: String) $
- defField "html5" (writerHtml5 opts) $
+ defField "html5" (stHtml5 st)
metadata
return (thebody, context)
@@ -200,44 +333,52 @@ pandocToHtml opts (Pandoc meta blocks) = do
prefixedId :: WriterOptions -> String -> Attribute
prefixedId opts s =
case s of
- "" -> mempty
- _ -> A.id $ toValue $ writerIdentifierPrefix opts ++ s
+ "" -> mempty
+ _ -> A.id $ toValue $ writerIdentifierPrefix opts ++ s
-toList :: (Html -> Html) -> WriterOptions -> ([Html] -> Html)
+toList :: PandocMonad m
+ => (Html -> Html)
+ -> WriterOptions
+ -> [Html]
+ -> StateT WriterState m Html
toList listop opts items = do
- if (writerIncremental opts)
- then if (writerSlideVariant opts /= RevealJsSlides)
- then (listop $ mconcat items) ! A.class_ "incremental"
- else listop $ mconcat $ map (! A.class_ "fragment") items
- else listop $ mconcat items
+ slideVariant <- gets stSlideVariant
+ return $
+ if writerIncremental opts
+ then if slideVariant /= RevealJsSlides
+ then listop (mconcat items) ! A.class_ "incremental"
+ else listop $ mconcat $ map (! A.class_ "fragment") items
+ else listop $ mconcat items
-unordList :: WriterOptions -> [Html] -> Html
+unordList :: PandocMonad m
+ => WriterOptions -> [Html] -> StateT WriterState m Html
unordList opts = toList H.ul opts . toListItems opts
-ordList :: WriterOptions -> [Html] -> Html
+ordList :: PandocMonad m
+ => WriterOptions -> [Html] -> StateT WriterState m Html
ordList opts = toList H.ol opts . toListItems opts
-defList :: WriterOptions -> [Html] -> Html
+defList :: PandocMonad m
+ => WriterOptions -> [Html] -> StateT WriterState m Html
defList opts items = toList H.dl opts (items ++ [nl opts])
-- | Construct table of contents from list of elements.
-tableOfContents :: WriterOptions -> [Element] -> State WriterState (Maybe Html)
+tableOfContents :: PandocMonad m => WriterOptions -> [Element] -> StateT WriterState m (Maybe Html)
tableOfContents _ [] = return Nothing
tableOfContents opts sects = do
- let opts' = opts { writerIgnoreNotes = True }
- contents <- mapM (elementToListItem opts') sects
+ contents <- mapM (elementToListItem opts) sects
let tocList = catMaybes contents
- return $ if null tocList
- then Nothing
- else Just $ unordList opts tocList
+ if null tocList
+ then return Nothing
+ else Just <$> unordList opts tocList
-- | Convert section number to string
showSecNum :: [Int] -> String
-showSecNum = concat . intersperse "." . map show
+showSecNum = intercalate "." . map show
-- | Converts an Element to a list item for a table of contents,
-- retrieving the appropriate identifier from state.
-elementToListItem :: WriterOptions -> Element -> State WriterState (Maybe Html)
+elementToListItem :: PandocMonad m => WriterOptions -> Element -> StateT WriterState m (Maybe Html)
-- Don't include the empty headers created in slide shows
-- shows when an hrule is used to separate slides without a new title:
elementToListItem _ (Sec _ _ _ [Str "\0"] _) = return Nothing
@@ -249,45 +390,52 @@ elementToListItem opts (Sec lev num (id',classes,_) headerText subsecs)
then (H.span ! A.class_ "toc-section-number"
$ toHtml $ showSecNum num') >> preEscapedString " "
else mempty
- txt <- liftM (sectnum >>) $ inlineListToHtml opts headerText
+ txt <- liftM (sectnum >>) $ inlineListToHtml opts $ walk deNote headerText
subHeads <- mapM (elementToListItem opts) subsecs >>= return . catMaybes
- let subList = if null subHeads
- then mempty
- else unordList opts subHeads
+ subList <- if null subHeads
+ then return mempty
+ else unordList opts subHeads
-- in reveal.js, we need #/apples, not #apples:
- let revealSlash = ['/' | writerSlideVariant opts == RevealJsSlides]
+ slideVariant <- gets stSlideVariant
+ let revealSlash = ['/' | slideVariant== RevealJsSlides]
return $ Just
$ if null id'
- then (H.a $ toHtml txt) >> subList
+ then H.a (toHtml txt) >> subList
else (H.a ! A.href (toValue $ "#" ++ revealSlash ++
writerIdentifierPrefix opts ++ id')
$ toHtml txt) >> subList
elementToListItem _ _ = return Nothing
-- | Convert an Element to Html.
-elementToHtml :: Int -> WriterOptions -> Element -> State WriterState Html
+elementToHtml :: PandocMonad m => Int -> WriterOptions -> Element -> StateT WriterState m Html
elementToHtml _slideLevel opts (Blk block) = blockToHtml opts block
elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elements) = do
- let slide = writerSlideVariant opts /= NoSlides && level <= slideLevel
+ slideVariant <- gets stSlideVariant
+ let slide = slideVariant /= NoSlides && level <= slideLevel
let num' = zipWith (+) num (writerNumberOffset opts ++ repeat 0)
modify $ \st -> st{stSecNum = num'} -- update section number
+ html5 <- gets stHtml5
let titleSlide = slide && level < slideLevel
header' <- if title' == [Str "\0"] -- marker for hrule
then return mempty
else do
modify (\st -> st{ stElement = True})
+ let level' = if level <= slideLevel &&
+ slideVariant == SlidySlides
+ then 1 -- see #3566
+ else level
res <- blockToHtml opts
- (Header level (id',classes,keyvals) title')
+ (Header level' (id',classes,keyvals) title')
modify (\st -> st{ stElement = False})
return res
- let isSec (Sec _ _ _ _ _) = True
- isSec (Blk _) = False
+ let isSec Sec{} = True
+ isSec (Blk _) = False
let isPause (Blk x) = x == Para [Str ".",Space,Str ".",Space,Str "."]
isPause _ = False
- let fragmentClass = case writerSlideVariant opts of
- RevealJsSlides -> "fragment"
- _ -> "incremental"
+ let fragmentClass = case slideVariant of
+ RevealJsSlides -> "fragment"
+ _ -> "incremental"
let inDiv xs = Blk (RawBlock (Format "html") ("<div class=\""
++ fragmentClass ++ "\">")) :
(xs ++ [Blk (RawBlock (Format "html") "</div>")])
@@ -299,45 +447,51 @@ elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elemen
[] -> []
(x:xs) -> x ++ concatMap inDiv xs
let inNl x = mconcat $ nl opts : intersperse (nl opts) x ++ [nl opts]
- let classes' = ["titleslide" | titleSlide] ++ ["slide" | slide] ++
+ let classes' = ["title-slide" | titleSlide] ++ ["slide" | slide] ++
["section" | (slide || writerSectionDivs opts) &&
- not (writerHtml5 opts) ] ++
+ not html5 ] ++
["level" ++ show level | slide || writerSectionDivs opts ]
++ classes
- let secttag = if writerHtml5 opts
+ let secttag = if html5
then H5.section
else H.div
let attr = (id',classes',keyvals)
- return $ if titleSlide
- then (if writerSlideVariant opts == RevealJsSlides
- then H5.section
- else id) $ mconcat $
- (addAttrs opts attr $ secttag $ header') : innerContents
- else if writerSectionDivs opts || slide
- then addAttrs opts attr
- $ secttag $ inNl $ header' : innerContents
- else mconcat $ intersperse (nl opts)
- $ addAttrs opts attr header' : innerContents
+ if titleSlide
+ then do
+ t <- addAttrs opts attr $
+ secttag header'
+ return $
+ (if slideVariant == RevealJsSlides
+ then H5.section
+ else id) $ mconcat $ t : innerContents
+ else if writerSectionDivs opts || slide
+ then addAttrs opts attr
+ $ secttag $ inNl $ header' : innerContents
+ else do
+ t <- addAttrs opts attr header'
+ return $ mconcat $ intersperse (nl opts) (t : innerContents)
-- | Convert list of Note blocks to a footnote <div>.
-- Assumes notes are sorted.
-footnoteSection :: WriterOptions -> [Html] -> Html
-footnoteSection opts notes =
- if null notes
- then mempty
- else nl opts >> (container
- $ nl opts >> hrtag >> nl opts >>
- H.ol (mconcat notes >> nl opts) >> nl opts)
- where container x = if writerHtml5 opts
- then H5.section ! A.class_ "footnotes" $ x
- else if writerSlideVariant opts /= NoSlides
- then H.div ! A.class_ "footnotes slide" $ x
- else H.div ! A.class_ "footnotes" $ x
- hrtag = if writerHtml5 opts then H5.hr else H.hr
+footnoteSection :: PandocMonad m
+ => WriterOptions -> [Html] -> StateT WriterState m Html
+footnoteSection opts notes = do
+ html5 <- gets stHtml5
+ slideVariant <- gets stSlideVariant
+ let hrtag = if html5 then H5.hr else H.hr
+ let container x
+ | html5 = H5.section ! A.class_ "footnotes" $ x
+ | slideVariant /= NoSlides = H.div ! A.class_ "footnotes slide" $ x
+ | otherwise = H.div ! A.class_ "footnotes" $ x
+ return $
+ if null notes
+ then mempty
+ else nl opts >> container (nl opts >> hrtag >> nl opts >>
+ H.ol (mconcat notes >> nl opts) >> nl opts)
-- | Parse a mailto link; return Just (name, domain) or Nothing.
parseMailto :: String -> Maybe (String, String)
-parseMailto s = do
+parseMailto s =
case break (==':') s of
(xs,':':addr) | map toLower xs == "mailto" -> do
let (name', rest) = span (/='@') addr
@@ -346,10 +500,12 @@ parseMailto s = do
_ -> fail "not a mailto: URL"
-- | Obfuscate a "mailto:" link.
-obfuscateLink :: WriterOptions -> Attr -> Html -> String -> Html
+obfuscateLink :: PandocMonad m
+ => WriterOptions -> Attr -> Html -> String
+ -> StateT WriterState m Html
obfuscateLink opts attr txt s | writerEmailObfuscation opts == NoObfuscation =
addAttrs opts attr $ H.a ! A.href (toValue s) $ txt
-obfuscateLink opts attr (renderHtml -> txt) s =
+obfuscateLink opts attr (TL.unpack . renderHtml -> txt) s =
let meth = writerEmailObfuscation opts
s' = map toLower (take 7 s) ++ drop 7 s
in case parseMailto s' of
@@ -361,20 +517,25 @@ obfuscateLink opts attr (renderHtml -> txt) s =
then ("e", name' ++ " at " ++ domain')
else ("'" ++ obfuscateString txt ++ "'",
txt ++ " (" ++ name' ++ " at " ++ domain' ++ ")")
+ (_, classNames, _) = attr
+ classNamesStr = concatMap (' ':) classNames
in case meth of
ReferenceObfuscation ->
-- need to use preEscapedString or &'s are escaped to &amp; in URL
- preEscapedString $ "<a href=\"" ++ (obfuscateString s')
- ++ "\" class=\"email\">" ++ (obfuscateString txt) ++ "</a>"
+ return $
+ preEscapedString $ "<a href=\"" ++ obfuscateString s'
+ ++ "\" class=\"email\">" ++ obfuscateString txt ++ "</a>"
JavascriptObfuscation ->
+ return $
(H.script ! A.type_ "text/javascript" $
preEscapedString ("\n<!--\nh='" ++
obfuscateString domain ++ "';a='" ++ at' ++ "';n='" ++
obfuscateString name' ++ "';e=n+a+h;\n" ++
- "document.write('<a h'+'ref'+'=\"ma'+'ilto'+':'+e+'\" clas'+'s=\"em' + 'ail\">'+" ++
+ "document.write('<a h'+'ref'+'=\"ma'+'ilto'+':'+e+'\" clas'+'s=\"em' + 'ail" ++
+ classNamesStr ++ "\">'+" ++
linkText ++ "+'<\\/'+'a'+'>');\n// -->\n")) >>
H.noscript (preEscapedString $ obfuscateString altText)
- _ -> error $ "Unknown obfuscation method: " ++ show meth
+ _ -> throwError $ PandocSomeError $ "Unknown obfuscation method: " ++ show meth
_ -> addAttrs opts attr $ H.a ! A.href (toValue s) $ toHtml txt -- malformed email
-- | Obfuscate character as entity.
@@ -388,36 +549,71 @@ obfuscateChar char =
obfuscateString :: String -> String
obfuscateString = concatMap obfuscateChar . fromEntities
-addAttrs :: WriterOptions -> Attr -> Html -> Html
-addAttrs opts attr h = foldl (!) h (attrsToHtml opts attr)
+-- | Create HTML tag with attributes.
+tagWithAttributes :: WriterOptions
+ -> Bool -- ^ True for HTML5
+ -> Bool -- ^ True if self-closing tag
+ -> Text -- ^ Tag text
+ -> Attr -- ^ Pandoc style tag attributes
+ -> Text
+tagWithAttributes opts html5 selfClosing tagname attr =
+ let mktag = (TL.toStrict . renderHtml <$> evalStateT
+ (addAttrs opts attr (customLeaf (textTag tagname) selfClosing))
+ defaultWriterState{ stHtml5 = html5 })
+ in case runPure mktag of
+ Left _ -> mempty
+ Right t -> t
-toAttrs :: [(String, String)] -> [Attribute]
-toAttrs kvs = map (\(x,y) -> customAttribute (fromString x) (toValue y)) kvs
+addAttrs :: PandocMonad m
+ => WriterOptions -> Attr -> Html -> StateT WriterState m Html
+addAttrs opts attr h = foldl (!) h <$> attrsToHtml opts attr
-attrsToHtml :: WriterOptions -> Attr -> [Attribute]
-attrsToHtml opts (id',classes',keyvals) =
- [prefixedId opts id' | not (null id')] ++
- [A.class_ (toValue $ unwords classes') | not (null classes')] ++ toAttrs keyvals
+toAttrs :: PandocMonad m
+ => [(String, String)] -> StateT WriterState m [Attribute]
+toAttrs kvs = do
+ html5 <- gets stHtml5
+ return $ map (\(x,y) ->
+ customAttribute
+ (fromString (if not html5 || x `Set.member` html5Attributes
+ || "data-" `isPrefixOf` x
+ then x
+ else "data-" ++ x)) (toValue y)) kvs
-imgAttrsToHtml :: WriterOptions -> Attr -> [Attribute]
-imgAttrsToHtml opts attr =
- attrsToHtml opts (ident,cls,kvs') ++
- toAttrs (dimensionsToAttrList opts attr)
+attrsToHtml :: PandocMonad m
+ => WriterOptions -> Attr -> StateT WriterState m [Attribute]
+attrsToHtml opts (id',classes',keyvals) = do
+ attrs <- toAttrs keyvals
+ return $
+ [prefixedId opts id' | not (null id')] ++
+ [A.class_ (toValue $ unwords classes') | not (null classes')] ++ attrs
+
+imgAttrsToHtml :: PandocMonad m
+ => WriterOptions -> Attr -> StateT WriterState m [Attribute]
+imgAttrsToHtml opts attr = do
+ attrs <- attrsToHtml opts (ident,cls,kvs')
+ dimattrs <- toAttrs (dimensionsToAttrList attr)
+ return $ attrs ++ dimattrs
where
(ident,cls,kvs) = attr
kvs' = filter isNotDim kvs
isNotDim ("width", _) = False
isNotDim ("height", _) = False
- isNotDim _ = True
+ isNotDim _ = True
-dimensionsToAttrList :: WriterOptions -> Attr -> [(String, String)]
-dimensionsToAttrList opts attr = (go Width) ++ (go Height)
+dimensionsToAttrList :: Attr -> [(String, String)]
+dimensionsToAttrList attr = consolidateStyles $ go Width ++ go Height
where
- go dir = case (dimension dir attr) of
- (Just (Percent a)) -> [("style", show dir ++ ":" ++ show (Percent a))]
- (Just dim) -> [(show dir, showInPixel opts dim)]
- _ -> []
-
+ consolidateStyles :: [(String, String)] -> [(String, String)]
+ consolidateStyles xs =
+ case partition isStyle xs of
+ ([], _) -> xs
+ (ss, rest) -> ("style", intercalate ";" $ map snd ss) : rest
+ isStyle ("style", _) = True
+ isStyle _ = False
+ go dir = case dimension dir attr of
+ (Just (Pixel a)) -> [(show dir, show a)]
+ (Just x) -> [("style", show dir ++ ":" ++ show x)]
+ Nothing -> []
imageExts :: [String]
imageExts = [ "art", "bmp", "cdr", "cdt", "cpt", "cr2", "crw", "djvu", "erf",
@@ -427,71 +623,121 @@ imageExts = [ "art", "bmp", "cdr", "cdt", "cpt", "cr2", "crw", "djvu", "erf",
treatAsImage :: FilePath -> Bool
treatAsImage fp =
- let path = case uriPath `fmap` parseURIReference fp of
- Nothing -> fp
- Just up -> up
+ let path = maybe fp uriPath (parseURIReference fp)
ext = map toLower $ drop 1 $ takeExtension path
in null ext || ext `elem` imageExts
--- | Convert Pandoc block element to HTML.
-blockToHtml :: WriterOptions -> Block -> State WriterState Html
-blockToHtml _ Null = return mempty
-blockToHtml opts (Plain lst) = inlineListToHtml opts lst
--- title beginning with fig: indicates that the image is a figure
-blockToHtml opts (Para [Image attr txt (s,'f':'i':'g':':':tit)]) = do
+figure :: PandocMonad m
+ => WriterOptions -> Attr -> [Inline] -> (String, String)
+ -> StateT WriterState m Html
+figure opts attr txt (s,tit) = do
img <- inlineToHtml opts (Image attr txt (s,tit))
- let tocapt = if writerHtml5 opts
+ html5 <- gets stHtml5
+ let tocapt = if html5
then H5.figcaption
else H.p ! A.class_ "caption"
capt <- if null txt
then return mempty
else tocapt `fmap` inlineListToHtml opts txt
- return $ if writerHtml5 opts
+ return $ if html5
then H5.figure $ mconcat
[nl opts, img, capt, nl opts]
else H.div ! A.class_ "figure" $ mconcat
[nl opts, img, nl opts, capt, nl opts]
+
+-- | Convert Pandoc block element to HTML.
+blockToHtml :: PandocMonad m => WriterOptions -> Block -> StateT WriterState m Html
+blockToHtml _ Null = return mempty
+blockToHtml opts (Plain lst) = inlineListToHtml opts lst
+blockToHtml opts (Para [Image attr@(_,classes,_) txt (src,tit)])
+ | "stretch" `elem` classes = do
+ slideVariant <- gets stSlideVariant
+ case slideVariant of
+ RevealJsSlides ->
+ -- a "stretched" image in reveal.js must be a direct child
+ -- of the slide container
+ inlineToHtml opts (Image attr txt (src, tit))
+ _ -> figure opts attr txt (src, tit)
+-- title beginning with fig: indicates that the image is a figure
+blockToHtml opts (Para [Image attr txt (s,'f':'i':'g':':':tit)]) =
+ figure opts attr txt (s,tit)
blockToHtml opts (Para lst)
| isEmptyRaw lst = return mempty
+ | null lst && not (isEnabled Ext_empty_paragraphs opts) = return mempty
| otherwise = do
contents <- inlineListToHtml opts lst
return $ H.p contents
where
- isEmptyRaw [RawInline f _] = f /= (Format "html")
- isEmptyRaw _ = False
+ isEmptyRaw [RawInline f _] = f `notElem` [Format "html",
+ Format "html4", Format "html5"]
+ isEmptyRaw _ = False
blockToHtml opts (LineBlock lns) =
if writerWrapText opts == WrapNone
then blockToHtml opts $ linesToPara lns
else do
- let lf = preEscapedString "\n"
- htmlLines <- mconcat . intersperse lf <$> mapM (inlineListToHtml opts) lns
- return $ H.div ! A.style "white-space: pre-line;" $ htmlLines
-blockToHtml opts (Div attr@(ident, classes, kvs) bs) = do
+ htmlLines <- inlineListToHtml opts $ intercalate [LineBreak] lns
+ return $ H.div ! A.class_ "line-block" $ htmlLines
+blockToHtml opts (Div attr@(ident, classes, kvs') bs) = do
+ html5 <- gets stHtml5
+ slideVariant <- gets stSlideVariant
+ let kvs = [(k,v) | (k,v) <- kvs', k /= "width"] ++
+ [("style", "width:" ++ w ++ ";")
+ | ("width",w) <- kvs', "column" `elem` classes]
let speakerNotes = "notes" `elem` classes
-- we don't want incremental output inside speaker notes, see #1394
- let opts' = if speakerNotes then opts{ writerIncremental = False } else opts
- contents <- blockListToHtml opts' bs
+ let opts' = if | speakerNotes -> opts{ writerIncremental = False }
+ | "incremental" `elem` classes -> opts{ writerIncremental = True }
+ | "nonincremental" `elem` classes -> opts{ writerIncremental = False }
+ | otherwise -> opts
+ -- we remove "incremental" and "nonincremental" if we're in a
+ -- slide presentaiton format.
+ classes' = case slideVariant of
+ NoSlides -> classes
+ _ -> filter (\k -> k /= "incremental" && k /= "nonincremental") classes
+ contents <- if "columns" `elem` classes'
+ then -- we don't use blockListToHtml because it inserts
+ -- a newline between the column divs, which throws
+ -- off widths! see #4028
+ mconcat <$> mapM (blockToHtml opts) bs
+ else blockListToHtml opts' bs
let contents' = nl opts >> contents >> nl opts
- let (divtag, classes') = if writerHtml5 opts && "section" `elem` classes
- then (H5.section, filter (/= "section") classes)
- else (H.div, classes)
- return $
- if speakerNotes
- then case writerSlideVariant opts of
- RevealJsSlides -> addAttrs opts' attr $ H5.aside $ contents'
- DZSlides -> (addAttrs opts' attr $ H5.div $ contents')
- ! (H5.customAttribute "role" "note")
- NoSlides -> addAttrs opts' attr $ H.div $ contents'
- _ -> mempty
- else addAttrs opts (ident, classes', kvs) $ divtag $ contents'
-blockToHtml opts (RawBlock f str)
- | f == Format "html" = return $ preEscapedString str
- | (f == Format "latex" || f == Format "tex") &&
- allowsMathEnvironments (writerHTMLMathMethod opts) &&
- isMathEnvironment str = blockToHtml opts $ Plain [Math DisplayMath str]
- | otherwise = return mempty
-blockToHtml opts (HorizontalRule) = return $ if writerHtml5 opts then H5.hr else H.hr
+ let (divtag, classes'') = if html5 && "section" `elem` classes'
+ then (H5.section, filter (/= "section") classes')
+ else (H.div, classes')
+ if speakerNotes
+ then case slideVariant of
+ RevealJsSlides -> addAttrs opts' attr $
+ H5.aside contents'
+ DZSlides -> do
+ t <- addAttrs opts' attr $
+ H5.div contents'
+ return $ t ! H5.customAttribute "role" "note"
+ NoSlides -> addAttrs opts' attr $
+ H.div contents'
+ _ -> return mempty
+ else addAttrs opts (ident, classes'', kvs) $
+ divtag contents'
+blockToHtml opts (RawBlock f str) = do
+ ishtml <- isRawHtml f
+ if ishtml
+ then return $ preEscapedString str
+ else if (f == Format "latex" || f == Format "tex") &&
+ allowsMathEnvironments (writerHTMLMathMethod opts) &&
+ isMathEnvironment str
+ then blockToHtml opts $ Plain [Math DisplayMath str]
+ else do
+ report $ BlockNotRendered (RawBlock f str)
+ return mempty
+blockToHtml _ HorizontalRule = do
+ html5 <- gets stHtml5
+ return $ if html5 then H5.hr else H.hr
blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do
+ id'' <- if null id'
+ then do
+ modify $ \st -> st{ stCodeBlockNum = stCodeBlockNum st + 1 }
+ codeblocknum <- gets stCodeBlockNum
+ return ("cb" ++ show codeblocknum)
+ else return id'
let tolhs = isEnabled Ext_literate_haskell opts &&
any (\c -> map toLower c == "haskell") classes &&
any (\c -> map toLower c == "literate") classes
@@ -503,19 +749,24 @@ blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do
adjCode = if tolhs
then unlines . map ("> " ++) . lines $ rawCode
else rawCode
- hlCode = if writerHighlight opts -- check highlighting options
- then highlight formatHtmlBlock (id',classes',keyvals) adjCode
- else Nothing
+ hlCode = if isJust (writerHighlightStyle opts)
+ then highlight (writerSyntaxMap opts) formatHtmlBlock
+ (id'',classes',keyvals) adjCode
+ else Left ""
case hlCode of
- Nothing -> return $ addAttrs opts (id',classes,keyvals)
- $ H.pre $ H.code $ toHtml adjCode
- Just h -> modify (\st -> st{ stHighlighting = True }) >>
- return (addAttrs opts (id',[],keyvals) h)
-blockToHtml opts (BlockQuote blocks) =
+ Left msg -> do
+ unless (null msg) $
+ report $ CouldNotHighlight msg
+ addAttrs opts (id',classes,keyvals)
+ $ H.pre $ H.code $ toHtml adjCode
+ Right h -> modify (\st -> st{ stHighlighting = True }) >>
+ addAttrs opts (id'',[],keyvals) h
+blockToHtml opts (BlockQuote blocks) = do
-- in S5, treat list in blockquote specially
-- if default is incremental, make it nonincremental;
-- otherwise incremental
- if writerSlideVariant opts /= NoSlides
+ slideVariant <- gets stSlideVariant
+ if slideVariant /= NoSlides
then let inc = not (writerIncremental opts) in
case blocks of
[BulletList lst] -> blockToHtml (opts {writerIncremental = inc})
@@ -541,7 +792,7 @@ blockToHtml opts (Header level attr@(_,classes,_) lst) = do
$ showSecNum secnum) >> strToHtml " " >> contents
else contents
inElement <- gets stElement
- return $ (if inElement then id else addAttrs opts attr)
+ (if inElement then return else addAttrs opts attr)
$ case level of
1 -> H.h1 contents'
2 -> H.h2 contents'
@@ -552,20 +803,17 @@ blockToHtml opts (Header level attr@(_,classes,_) lst) = do
_ -> H.p contents'
blockToHtml opts (BulletList lst) = do
contents <- mapM (blockListToHtml opts) lst
- return $ unordList opts contents
+ unordList opts contents
blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do
contents <- mapM (blockListToHtml opts) lst
+ html5 <- gets stHtml5
let numstyle' = case numstyle of
Example -> "decimal"
_ -> camelCaseToHyphenated $ show numstyle
- let attribs = (if startnum /= 1
- then [A.start $ toValue startnum]
- else []) ++
- (if numstyle == Example
- then [A.class_ "example"]
- else []) ++
+ let attribs = [A.start $ toValue startnum | startnum /= 1] ++
+ [A.class_ "example" | numstyle == Example] ++
(if numstyle /= DefaultStyle
- then if writerHtml5 opts
+ then if html5
then [A.type_ $
case numstyle of
Decimal -> "1"
@@ -577,23 +825,25 @@ blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do
else [A.style $ toValue $ "list-style-type: " ++
numstyle']
else [])
- return $ foldl (!) (ordList opts contents) attribs
+ l <- ordList opts contents
+ return $ foldl (!) l attribs
blockToHtml opts (DefinitionList lst) = do
contents <- mapM (\(term, defs) ->
do term' <- if null term
then return mempty
else liftM H.dt $ inlineListToHtml opts term
- defs' <- mapM ((liftM (\x -> H.dd $ (x >> nl opts))) .
+ defs' <- mapM (liftM (\x -> H.dd (x >> nl opts)) .
blockListToHtml opts) defs
return $ mconcat $ nl opts : term' : nl opts :
intersperse (nl opts) defs') lst
- return $ defList opts contents
+ defList opts contents
blockToHtml opts (Table capt aligns widths headers rows') = do
captionDoc <- if null capt
then return mempty
else do
cs <- inlineListToHtml opts capt
return $ H.caption cs >> nl opts
+ html5 <- gets stHtml5
let percent w = show (truncate (100*w) :: Integer) ++ "%"
let coltags = if all (== 0.0) widths
then mempty
@@ -601,7 +851,7 @@ blockToHtml opts (Table capt aligns widths headers rows') = do
H.colgroup $ do
nl opts
mapM_ (\w -> do
- if writerHtml5 opts
+ if html5
then H.col ! A.style (toValue $ "width: " ++
percent w)
else H.col ! A.width (toValue $ percent w)
@@ -624,18 +874,19 @@ blockToHtml opts (Table capt aligns widths headers rows') = do
else tbl ! A.style (toValue $ "width:" ++
show (round (totalWidth * 100) :: Int) ++ "%;")
-tableRowToHtml :: WriterOptions
+tableRowToHtml :: PandocMonad m
+ => WriterOptions
-> [Alignment]
-> Int
-> [[Block]]
- -> State WriterState Html
+ -> StateT WriterState m Html
tableRowToHtml opts aligns rownum cols' = do
let mkcell = if rownum == 0 then H.th else H.td
let rowclass = case rownum of
- 0 -> "header"
+ 0 -> "header"
x | x `rem` 2 == 1 -> "odd"
- _ -> "even"
- cols'' <- sequence $ zipWith
+ _ -> "even"
+ cols'' <- zipWithM
(\alignment item -> tableItemToHtml opts mkcell alignment item)
aligns cols'
return $ (H.tr ! A.class_ rowclass $ nl opts >> mconcat cols'')
@@ -648,21 +899,23 @@ alignmentToString alignment = case alignment of
AlignCenter -> "center"
AlignDefault -> ""
-tableItemToHtml :: WriterOptions
+tableItemToHtml :: PandocMonad m
+ => WriterOptions
-> (Html -> Html)
-> Alignment
-> [Block]
- -> State WriterState Html
+ -> StateT WriterState m Html
tableItemToHtml opts tag' align' item = do
contents <- blockListToHtml opts item
+ html5 <- gets stHtml5
let alignStr = alignmentToString align'
- let attribs = if writerHtml5 opts
+ let attribs = if html5
then A.style (toValue $ "text-align: " ++ alignStr ++ ";")
else A.align (toValue alignStr)
let tag'' = if null alignStr
then tag'
else tag' ! attribs
- return $ (tag'' $ contents) >> nl opts
+ return $ tag'' contents >> nl opts
toListItems :: WriterOptions -> [Html] -> [Html]
toListItems opts items = map (toListItem opts) items ++ [nl opts]
@@ -670,12 +923,16 @@ toListItems opts items = map (toListItem opts) items ++ [nl opts]
toListItem :: WriterOptions -> Html -> Html
toListItem opts item = nl opts >> H.li item
-blockListToHtml :: WriterOptions -> [Block] -> State WriterState Html
+blockListToHtml :: PandocMonad m
+ => WriterOptions -> [Block] -> StateT WriterState m Html
blockListToHtml opts lst =
- fmap (mconcat . intersperse (nl opts)) $ mapM (blockToHtml opts) lst
+ (mconcat . intersperse (nl opts) . filter nonempty)
+ <$> mapM (blockToHtml opts) lst
+ where nonempty (Empty _) = False
+ nonempty _ = True
-- | Convert list of Pandoc inline elements to HTML.
-inlineListToHtml :: WriterOptions -> [Inline] -> State WriterState Html
+inlineListToHtml :: PandocMonad m => WriterOptions -> [Inline] -> StateT WriterState m Html
inlineListToHtml opts lst =
mapM (inlineToHtml opts) lst >>= return . mconcat
@@ -684,9 +941,9 @@ annotateMML :: XML.Element -> String -> XML.Element
annotateMML e tex = math (unode "semantics" [cs, unode "annotation" (annotAttrs, tex)])
where
cs = case elChildren e of
- [] -> unode "mrow" ()
+ [] -> unode "mrow" ()
[x] -> x
- xs -> unode "mrow" xs
+ xs -> unode "mrow" xs
math childs = XML.Element q as [XML.Elem childs] l
where
(XML.Element q as _ l) = e
@@ -694,27 +951,29 @@ annotateMML e tex = math (unode "semantics" [cs, unode "annotation" (annotAttrs,
-- | Convert Pandoc inline element to HTML.
-inlineToHtml :: WriterOptions -> Inline -> State WriterState Html
-inlineToHtml opts inline =
+inlineToHtml :: PandocMonad m
+ => WriterOptions -> Inline -> StateT WriterState m Html
+inlineToHtml opts inline = do
+ html5 <- gets stHtml5
case inline of
(Str str) -> return $ strToHtml str
- (Space) -> return $ strToHtml " "
- (SoftBreak) -> return $ case writerWrapText opts of
- WrapNone -> preEscapedString " "
- WrapAuto -> preEscapedString " "
- WrapPreserve -> preEscapedString "\n"
- (LineBreak) -> return $ (if writerHtml5 opts then H5.br else H.br)
+ Space -> return $ strToHtml " "
+ SoftBreak -> return $ case writerWrapText opts of
+ WrapNone -> preEscapedString " "
+ WrapAuto -> preEscapedString " "
+ WrapPreserve -> preEscapedString "\n"
+ LineBreak -> return $ (if html5 then H5.br else H.br)
<> strToHtml "\n"
(Span (id',classes,kvs) ils)
-> inlineListToHtml opts ils >>=
- return . addAttrs opts attr' . H.span
+ addAttrs opts attr' . H.span
where attr' = (id',classes',kvs')
classes' = filter (`notElem` ["csl-no-emph",
"csl-no-strong",
"csl-no-smallcaps"]) classes
kvs' = if null styles
then kvs
- else (("style", concat styles) : kvs)
+ else ("style", concat styles) : kvs
styles = ["font-style:normal;"
| "csl-no-emph" `elem` classes]
++ ["font-weight:normal;"
@@ -724,20 +983,23 @@ inlineToHtml opts inline =
(Emph lst) -> inlineListToHtml opts lst >>= return . H.em
(Strong lst) -> inlineListToHtml opts lst >>= return . H.strong
(Code attr str) -> case hlCode of
- Nothing -> return
- $ addAttrs opts attr
- $ H.code $ strToHtml str
- Just h -> do
+ Left msg -> do
+ unless (null msg) $
+ report $ CouldNotHighlight msg
+ addAttrs opts attr $ H.code $ strToHtml str
+ Right h -> do
modify $ \st -> st{ stHighlighting = True }
- return $ addAttrs opts (id',[],keyvals) h
+ addAttrs opts (id',[],keyvals) h
where (id',_,keyvals) = attr
- hlCode = if writerHighlight opts
- then highlight formatHtmlInline attr str
- else Nothing
+ hlCode = if isJust (writerHighlightStyle opts)
+ then highlight
+ (writerSyntaxMap opts)
+ formatHtmlInline attr str
+ else Left ""
(Strikeout lst) -> inlineListToHtml opts lst >>=
return . H.del
(SmallCaps lst) -> inlineListToHtml opts lst >>=
- return . (H.span ! A.style "font-variant: small-caps;")
+ return . (H.span ! A.class_ "smallcaps")
(Superscript lst) -> inlineListToHtml opts lst >>= return . H.sup
(Subscript lst) -> inlineListToHtml opts lst >>= return . H.sub
(Quoted quoteType lst) ->
@@ -768,15 +1030,15 @@ inlineToHtml opts inline =
JsMath _ -> do
let m = preEscapedString str
return $ case t of
- InlineMath -> H.span ! A.class_ mathClass $ m
+ InlineMath -> H.span ! A.class_ mathClass $ m
DisplayMath -> H.div ! A.class_ mathClass $ m
WebTeX url -> do
- let imtag = if writerHtml5 opts then H5.img else H.img
+ let imtag = if html5 then H5.img else H.img
let m = imtag ! A.style "vertical-align:middle"
! A.src (toValue $ url ++ urlEncode str)
! A.alt (toValue str)
! A.title (toValue str)
- let brtag = if writerHtml5 opts then H5.br else H.br
+ let brtag = if html5 then H5.br else H.br
return $ case t of
InlineMath -> m
DisplayMath -> brtag >> m >> brtag
@@ -784,103 +1046,124 @@ inlineToHtml opts inline =
return $ case t of
InlineMath -> preEscapedString $ "<EQ ENV=\"math\">" ++ str ++ "</EQ>"
DisplayMath -> preEscapedString $ "<EQ ENV=\"displaymath\">" ++ str ++ "</EQ>"
- MathML _ -> do
- let dt = if t == InlineMath
- then DisplayInline
- else DisplayBlock
+ MathML -> do
let conf = useShortEmptyTags (const False)
defaultConfigPP
- case writeMathML dt <$> readTeX str of
+ res <- lift $ convertMath writeMathML t str
+ case res of
Right r -> return $ preEscapedString $
ppcElement conf (annotateMML r str)
- Left _ -> inlineListToHtml opts
- (texMathToInlines t str) >>=
- return . (H.span ! A.class_ mathClass)
+ Left il -> (H.span ! A.class_ mathClass) <$>
+ inlineToHtml opts il
MathJax _ -> return $ H.span ! A.class_ mathClass $ toHtml $
case t of
InlineMath -> "\\(" ++ str ++ "\\)"
DisplayMath -> "\\[" ++ str ++ "\\]"
- KaTeX _ _ -> return $ H.span ! A.class_ mathClass $
- toHtml (case t of
- InlineMath -> str
- DisplayMath -> "\\displaystyle " ++ str)
+ KaTeX _ -> return $ H.span ! A.class_ mathClass $ toHtml $
+ case t of
+ InlineMath -> "\\(" ++ str ++ "\\)"
+ DisplayMath -> "\\[" ++ str ++ "\\]"
PlainMath -> do
- x <- inlineListToHtml opts (texMathToInlines t str)
+ x <- lift (texMathToInlines t str) >>= inlineListToHtml opts
let m = H.span ! A.class_ mathClass $ x
- let brtag = if writerHtml5 opts then H5.br else H.br
+ let brtag = if html5 then H5.br else H.br
return $ case t of
InlineMath -> m
DisplayMath -> brtag >> m >> brtag
- (RawInline f str)
- | f == Format "html" -> return $ preEscapedString str
- | otherwise -> return mempty
+ (RawInline f str) -> do
+ ishtml <- isRawHtml f
+ if ishtml
+ then return $ preEscapedString str
+ else if (f == Format "latex" || f == Format "tex") &&
+ "\\begin" `isPrefixOf` str &&
+ allowsMathEnvironments (writerHTMLMathMethod opts) &&
+ isMathEnvironment str
+ then inlineToHtml opts $ Math DisplayMath str
+ else do
+ report $ InlineNotRendered inline
+ return mempty
(Link attr txt (s,_)) | "mailto:" `isPrefixOf` s -> do
linkText <- inlineListToHtml opts txt
- return $ obfuscateLink opts attr linkText s
- (Link attr txt (s,tit)) -> do
+ obfuscateLink opts attr linkText s
+ (Link (ident,classes,kvs) txt (s,tit)) -> do
linkText <- inlineListToHtml opts txt
+ slideVariant <- gets stSlideVariant
let s' = case s of
- '#':xs | writerSlideVariant opts ==
- RevealJsSlides -> '#':'/':xs
- _ -> s
+ '#':xs -> let prefix = if slideVariant == RevealJsSlides
+ then "/"
+ else writerIdentifierPrefix opts
+ in '#' : prefix ++ xs
+ _ -> s
let link = H.a ! A.href (toValue s') $ linkText
- let link' = if txt == [Str (unEscapeString s)]
- then link ! A.class_ "uri"
- else link
- let link'' = addAttrs opts attr link'
+ let attr = if txt == [Str (unEscapeString s)]
+ then (ident, "uri" : classes, kvs)
+ else (ident, classes, kvs)
+ link' <- addAttrs opts attr link
return $ if null tit
- then link''
- else link'' ! A.title (toValue tit)
+ then link'
+ else link' ! A.title (toValue tit)
(Image attr txt (s,tit)) | treatAsImage s -> do
let alternate' = stringify txt
- let attributes = [A.src $ toValue s] ++
- [A.title $ toValue tit | not (null tit)] ++
- [A.alt $ toValue alternate' | not (null txt)] ++
- imgAttrsToHtml opts attr
- let tag = if writerHtml5 opts then H5.img else H.img
+ slideVariant <- gets stSlideVariant
+ let isReveal = slideVariant == RevealJsSlides
+ attrs <- imgAttrsToHtml opts attr
+ let attributes =
+ -- reveal.js uses data-src for lazy loading
+ (if isReveal
+ then customAttribute "data-src" $ toValue s
+ else A.src $ toValue s) :
+ [A.title $ toValue tit | not (null tit)] ++
+ [A.alt $ toValue alternate' | not (null txt)] ++
+ attrs
+ let tag = if html5 then H5.img else H.img
return $ foldl (!) tag attributes
-- note: null title included, as in Markdown.pl
(Image attr _ (s,tit)) -> do
- let attributes = [A.src $ toValue s] ++
- [A.title $ toValue tit | not (null tit)] ++
- imgAttrsToHtml opts attr
+ slideVariant <- gets stSlideVariant
+ let isReveal = slideVariant == RevealJsSlides
+ attrs <- imgAttrsToHtml opts attr
+ let attributes =
+ (if isReveal
+ then customAttribute "data-src" $ toValue s
+ else A.src $ toValue s) :
+ [A.title $ toValue tit | not (null tit)] ++
+ attrs
return $ foldl (!) H5.embed attributes
-- note: null title included, as in Markdown.pl
- (Note contents)
- | writerIgnoreNotes opts -> return mempty
- | otherwise -> do
+ (Note contents) -> do
notes <- gets stNotes
- let number = (length notes) + 1
+ let number = length notes + 1
let ref = show number
htmlContents <- blockListToNote opts ref contents
+ epubVersion <- gets stEPUBVersion
-- push contents onto front of notes
- modify $ \st -> st {stNotes = (htmlContents:notes)}
- let revealSlash = ['/' | writerSlideVariant opts
- == RevealJsSlides]
+ modify $ \st -> st {stNotes = htmlContents:notes}
+ slideVariant <- gets stSlideVariant
+ let revealSlash = ['/' | slideVariant == RevealJsSlides]
let link = H.a ! A.href (toValue $ "#" ++
revealSlash ++
writerIdentifierPrefix opts ++ "fn" ++ ref)
- ! A.class_ "footnoteRef"
+ ! A.class_ "footnote-ref"
! prefixedId opts ("fnref" ++ ref)
- $ (if isJust (writerEpubVersion opts)
+ $ (if isJust epubVersion
then id
else H.sup)
$ toHtml ref
- return $ case writerEpubVersion opts of
+ return $ case epubVersion of
Just EPUB3 -> link ! customAttribute "epub:type" "noteref"
_ -> link
(Cite cits il)-> do contents <- inlineListToHtml opts il
let citationIds = unwords $ map citationId cits
let result = H.span ! A.class_ "citation" $ contents
- return $ if writerHtml5 opts
+ return $ if html5
then result ! customAttribute "data-cites" (toValue citationIds)
else result
-blockListToNote :: WriterOptions -> String -> [Block] -> State WriterState Html
+blockListToNote :: PandocMonad m => WriterOptions -> String -> [Block] -> StateT WriterState m Html
blockListToNote opts ref blocks =
-- If last block is Para or Plain, include the backlink at the end of
-- that block. Otherwise, insert a new Plain block with the backlink.
- let backlink = [Link nullAttr [Str "↩"] ("#" ++ writerIdentifierPrefix opts ++ "fnref" ++ ref,[])]
+ let backlink = [Link ("",["footnote-back"],[]) [Str "↩"] ("#" ++ "fnref" ++ ref,[])]
blocks' = if null blocks
then []
else let lastBlock = last blocks
@@ -893,23 +1176,13 @@ blockListToNote opts ref blocks =
_ -> otherBlocks ++ [lastBlock,
Plain backlink]
in do contents <- blockListToHtml opts blocks'
- let noteItem = H.li ! (prefixedId opts ("fn" ++ ref)) $ contents
- let noteItem' = case writerEpubVersion opts of
+ let noteItem = H.li ! prefixedId opts ("fn" ++ ref) $ contents
+ epubVersion <- gets stEPUBVersion
+ let noteItem' = case epubVersion of
Just EPUB3 -> noteItem ! customAttribute "epub:type" "footnote"
_ -> noteItem
return $ nl opts >> noteItem'
--- Javascript snippet to render all KaTeX elements
-renderKaTeX :: String
-renderKaTeX = unlines [
- "window.onload = function(){var mathElements = document.getElementsByClassName(\"math\");"
- , "for (var i=0; i < mathElements.length; i++)"
- , "{"
- , " var texText = mathElements[i].firstChild"
- , " katex.render(texText.data, mathElements[i])"
- , "}}"
- ]
-
isMathEnvironment :: String -> Bool
isMathEnvironment s = "\\begin{" `isPrefixOf` s &&
envName `elem` mathmlenvs
@@ -944,6 +1217,219 @@ isMathEnvironment s = "\\begin{" `isPrefixOf` s &&
allowsMathEnvironments :: HTMLMathMethod -> Bool
allowsMathEnvironments (MathJax _) = True
-allowsMathEnvironments (MathML _) = True
+allowsMathEnvironments MathML = True
allowsMathEnvironments (WebTeX _) = True
allowsMathEnvironments _ = False
+
+isRawHtml :: PandocMonad m => Format -> StateT WriterState m Bool
+isRawHtml f = do
+ html5 <- gets stHtml5
+ return $ f == Format "html" ||
+ ((html5 && f == Format "html5") || f == Format "html4")
+
+html5Attributes :: Set.Set String
+html5Attributes = Set.fromList
+ [ "abbr"
+ , "accept"
+ , "accept-charset"
+ , "accesskey"
+ , "action"
+ , "allowfullscreen"
+ , "allowpaymentrequest"
+ , "allowusermedia"
+ , "alt"
+ , "as"
+ , "async"
+ , "autocomplete"
+ , "autofocus"
+ , "autoplay"
+ , "charset"
+ , "checked"
+ , "cite"
+ , "class"
+ , "color"
+ , "cols"
+ , "colspan"
+ , "content"
+ , "contenteditable"
+ , "controls"
+ , "coords"
+ , "crossorigin"
+ , "data"
+ , "datetime"
+ , "default"
+ , "defer"
+ , "dir"
+ , "dirname"
+ , "disabled"
+ , "download"
+ , "draggable"
+ , "enctype"
+ , "for"
+ , "form"
+ , "formaction"
+ , "formenctype"
+ , "formmethod"
+ , "formnovalidate"
+ , "formtarget"
+ , "headers"
+ , "height"
+ , "hidden"
+ , "high"
+ , "href"
+ , "hreflang"
+ , "http-equiv"
+ , "id"
+ , "inputmode"
+ , "integrity"
+ , "is"
+ , "ismap"
+ , "itemid"
+ , "itemprop"
+ , "itemref"
+ , "itemscope"
+ , "itemtype"
+ , "kind"
+ , "label"
+ , "lang"
+ , "list"
+ , "loop"
+ , "low"
+ , "manifest"
+ , "max"
+ , "maxlength"
+ , "media"
+ , "method"
+ , "min"
+ , "minlength"
+ , "multiple"
+ , "muted"
+ , "name"
+ , "nomodule"
+ , "nonce"
+ , "novalidate"
+ , "onabort"
+ , "onafterprint"
+ , "onauxclick"
+ , "onbeforeprint"
+ , "onbeforeunload"
+ , "onblur"
+ , "oncancel"
+ , "oncanplay"
+ , "oncanplaythrough"
+ , "onchange"
+ , "onclick"
+ , "onclose"
+ , "oncontextmenu"
+ , "oncopy"
+ , "oncuechange"
+ , "oncut"
+ , "ondblclick"
+ , "ondrag"
+ , "ondragend"
+ , "ondragenter"
+ , "ondragexit"
+ , "ondragleave"
+ , "ondragover"
+ , "ondragstart"
+ , "ondrop"
+ , "ondurationchange"
+ , "onemptied"
+ , "onended"
+ , "onerror"
+ , "onfocus"
+ , "onhashchange"
+ , "oninput"
+ , "oninvalid"
+ , "onkeydown"
+ , "onkeypress"
+ , "onkeyup"
+ , "onlanguagechange"
+ , "onload"
+ , "onloadeddata"
+ , "onloadedmetadata"
+ , "onloadend"
+ , "onloadstart"
+ , "onmessage"
+ , "onmessageerror"
+ , "onmousedown"
+ , "onmouseenter"
+ , "onmouseleave"
+ , "onmousemove"
+ , "onmouseout"
+ , "onmouseover"
+ , "onmouseup"
+ , "onoffline"
+ , "ononline"
+ , "onpagehide"
+ , "onpageshow"
+ , "onpaste"
+ , "onpause"
+ , "onplay"
+ , "onplaying"
+ , "onpopstate"
+ , "onprogress"
+ , "onratechange"
+ , "onrejectionhandled"
+ , "onreset"
+ , "onresize"
+ , "onscroll"
+ , "onsecuritypolicyviolation"
+ , "onseeked"
+ , "onseeking"
+ , "onselect"
+ , "onstalled"
+ , "onstorage"
+ , "onsubmit"
+ , "onsuspend"
+ , "ontimeupdate"
+ , "ontoggle"
+ , "onunhandledrejection"
+ , "onunload"
+ , "onvolumechange"
+ , "onwaiting"
+ , "onwheel"
+ , "open"
+ , "optimum"
+ , "pattern"
+ , "ping"
+ , "placeholder"
+ , "playsinline"
+ , "poster"
+ , "preload"
+ , "readonly"
+ , "referrerpolicy"
+ , "rel"
+ , "required"
+ , "reversed"
+ , "rows"
+ , "rowspan"
+ , "sandbox"
+ , "scope"
+ , "selected"
+ , "shape"
+ , "size"
+ , "sizes"
+ , "slot"
+ , "span"
+ , "spellcheck"
+ , "src"
+ , "srcdoc"
+ , "srclang"
+ , "srcset"
+ , "start"
+ , "step"
+ , "style"
+ , "tabindex"
+ , "target"
+ , "title"
+ , "translate"
+ , "type"
+ , "typemustmatch"
+ , "updateviacache"
+ , "usemap"
+ , "value"
+ , "width"
+ , "workertype"
+ , "wrap"
+ ]
diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs
index 29fdafe15..688c1f390 100644
--- a/src/Text/Pandoc/Writers/Haddock.hs
+++ b/src/Text/Pandoc/Writers/Haddock.hs
@@ -1,6 +1,8 @@
-{-# LANGUAGE OverloadedStrings, TupleSections, ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TupleSections #-}
{-
-Copyright (C) 2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2014-2015, 2017-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Haddock
- Copyright : Copyright (C) 2014 John MacFarlane
+ Copyright : Copyright (C) 2014-2015,2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,17 +33,19 @@ Conversion of 'Pandoc' documents to haddock markup.
Haddock: <http://www.haskell.org/haddock/doc/html/>
-}
module Text.Pandoc.Writers.Haddock (writeHaddock) where
+import Control.Monad.State.Strict
+import Data.Default
+import Data.List (intersperse, transpose)
+import Data.Text (Text)
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
-import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Data.List ( intersperse, transpose )
import Text.Pandoc.Pretty
-import Control.Monad.State
-import Text.Pandoc.Readers.TeXMath (texMathToInlines)
-import Network.URI (isURI)
-import Data.Default
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Math (texMathToInlines)
+import Text.Pandoc.Writers.Shared
type Notes = [[Block]]
data WriterState = WriterState { stNotes :: Notes }
@@ -49,13 +53,14 @@ instance Default WriterState
where def = WriterState{ stNotes = [] }
-- | Convert Pandoc to Haddock.
-writeHaddock :: WriterOptions -> Pandoc -> String
+writeHaddock :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeHaddock opts document =
- evalState (pandocToHaddock opts{
+ evalStateT (pandocToHaddock opts{
writerWrapText = writerWrapText opts } document) def
-- | Return haddock representation of document.
-pandocToHaddock :: WriterOptions -> Pandoc -> State WriterState String
+pandocToHaddock :: PandocMonad m
+ => WriterOptions -> Pandoc -> StateT WriterState m Text
pandocToHaddock opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
@@ -63,22 +68,22 @@ pandocToHaddock opts (Pandoc meta blocks) = do
body <- blockListToHaddock opts blocks
st <- get
notes' <- notesToHaddock opts (reverse $ stNotes st)
- let render' :: Doc -> String
+ let render' :: Doc -> Text
render' = render colwidth
let main = render' $ body <>
(if isEmpty notes' then empty else blankline <> notes')
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToHaddock opts)
- (fmap (render colwidth) . inlineListToHaddock opts)
+ (fmap render' . blockListToHaddock opts)
+ (fmap render' . inlineListToHaddock opts)
meta
- let context = defField "body" main
- $ metadata
+ let context = defField "body" main metadata
case writerTemplate opts of
Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
-- | Return haddock representation of notes.
-notesToHaddock :: WriterOptions -> [[Block]] -> State WriterState Doc
+notesToHaddock :: PandocMonad m
+ => WriterOptions -> [[Block]] -> StateT WriterState m Doc
notesToHaddock opts notes =
if null notes
then return empty
@@ -92,9 +97,10 @@ escapeString = escapeStringUsing haddockEscapes
where haddockEscapes = backslashEscapes "\\/'`\"@<"
-- | Convert Pandoc block element to haddock.
-blockToHaddock :: WriterOptions -- ^ Options
- -> Block -- ^ Block element
- -> State WriterState Doc
+blockToHaddock :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> Block -- ^ Block element
+ -> StateT WriterState m Doc
blockToHaddock _ Null = return empty
blockToHaddock opts (Div _ ils) = do
contents <- blockListToHaddock opts ils
@@ -110,10 +116,12 @@ blockToHaddock opts (Para inlines) =
(<> blankline) `fmap` blockToHaddock opts (Plain inlines)
blockToHaddock opts (LineBlock lns) =
blockToHaddock opts $ linesToPara lns
-blockToHaddock _ (RawBlock f str)
- | f == "haddock" = do
+blockToHaddock _ b@(RawBlock f str)
+ | f == "haddock" =
return $ text str <> text "\n"
- | otherwise = return empty
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
blockToHaddock opts HorizontalRule =
return $ blankline <> text (replicate (writerColumns opts) '_') <> blankline
blockToHaddock opts (Header level (ident,_,_) inlines) = do
@@ -141,16 +149,16 @@ blockToHaddock opts (Table caption aligns widths headers rows) = do
isPlainBlock _ = False
let hasBlocks = not (all isPlainBlock $ concat . concat $ headers:rows)
(nst,tbl) <- case True of
- _ | isSimple -> fmap (nest 2,) $
+ _ | isSimple -> (nest 2,) <$>
pandocTable opts (all null headers) aligns widths
rawHeaders rawRows
- | not hasBlocks -> fmap (nest 2,) $
+ | not hasBlocks -> (nest 2,) <$>
pandocTable opts (all null headers) aligns widths
rawHeaders rawRows
- | otherwise -> fmap (id,) $
- gridTable opts (all null headers) aligns widths
- rawHeaders rawRows
- return $ (prefixed "> " $ nst $ tbl $$ blankline $$ caption'') $$ blankline
+ | otherwise -> (id,) <$>
+ gridTable opts blockListToHaddock
+ (all null headers) aligns widths headers rows
+ return $ prefixed "> " (nst $ tbl $$ blankline $$ caption'') $$ blankline
blockToHaddock opts (BulletList items) = do
contents <- mapM (bulletListItemToHaddock opts) items
return $ cat contents <> blankline
@@ -160,15 +168,15 @@ blockToHaddock opts (OrderedList (start,_,delim) items) = do
let markers' = map (\m -> if length m < 3
then m ++ replicate (3 - length m) ' '
else m) markers
- contents <- mapM (\(item, num) -> orderedListItemToHaddock opts item num) $
- zip markers' items
+ contents <- zipWithM (orderedListItemToHaddock opts) markers' items
return $ cat contents <> blankline
blockToHaddock opts (DefinitionList items) = do
contents <- mapM (definitionListItemToHaddock opts) items
return $ cat contents <> blankline
-pandocTable :: WriterOptions -> Bool -> [Alignment] -> [Double]
- -> [Doc] -> [[Doc]] -> State WriterState Doc
+pandocTable :: PandocMonad m
+ => WriterOptions -> Bool -> [Alignment] -> [Double]
+ -> [Doc] -> [[Doc]] -> StateT WriterState m Doc
pandocTable opts headless aligns widths rawHeaders rawRows = do
let isSimple = all (==0) widths
let alignHeader alignment = case alignment of
@@ -184,18 +192,17 @@ pandocTable opts headless aligns widths rawHeaders rawRows = do
(floor . (fromIntegral (writerColumns opts) *))
widths
let makeRow = hcat . intersperse (lblock 1 (text " ")) .
- (zipWith3 alignHeader aligns widthsInChars)
+ zipWith3 alignHeader aligns widthsInChars
let rows' = map makeRow rawRows
let head' = makeRow rawHeaders
let maxRowHeight = maximum $ map height (head':rows')
let underline = cat $ intersperse (text " ") $
map (\width -> text (replicate width '-')) widthsInChars
- let border = if maxRowHeight > 1
- then text (replicate (sum widthsInChars +
- length widthsInChars - 1) '-')
- else if headless
- then underline
- else empty
+ let border
+ | maxRowHeight > 1 = text (replicate (sum widthsInChars +
+ length widthsInChars - 1) '-')
+ | headless = underline
+ | otherwise = empty
let head'' = if headless
then empty
else border <> cr <> head'
@@ -207,35 +214,9 @@ pandocTable opts headless aligns widths rawHeaders rawRows = do
else border
return $ head'' $$ underline $$ body $$ bottom
-gridTable :: WriterOptions -> Bool -> [Alignment] -> [Double]
- -> [Doc] -> [[Doc]] -> State WriterState Doc
-gridTable opts headless _aligns widths headers' rawRows = do
- let numcols = length headers'
- let widths' = if all (==0) widths
- then replicate numcols (1.0 / fromIntegral numcols)
- else widths
- let widthsInChars = map (floor . (fromIntegral (writerColumns opts) *)) widths'
- let hpipeBlocks blocks = hcat [beg, middle, end]
- where h = maximum (map height blocks)
- sep' = lblock 3 $ vcat (map text $ replicate h " | ")
- beg = lblock 2 $ vcat (map text $ replicate h "| ")
- end = lblock 2 $ vcat (map text $ replicate h " |")
- middle = chomp $ hcat $ intersperse sep' blocks
- let makeRow = hpipeBlocks . zipWith lblock widthsInChars
- let head' = makeRow headers'
- let rows' = map (makeRow . map chomp) rawRows
- let border ch = char '+' <> char ch <>
- (hcat $ intersperse (char ch <> char '+' <> char ch) $
- map (\l -> text $ replicate l ch) widthsInChars) <>
- char ch <> char '+'
- let body = vcat $ intersperse (border '-') rows'
- let head'' = if headless
- then empty
- else head' $$ border '='
- return $ border '-' $$ head'' $$ body $$ border '-'
-
-- | Convert bullet list item (list of blocks) to haddock
-bulletListItemToHaddock :: WriterOptions -> [Block] -> State WriterState Doc
+bulletListItemToHaddock :: PandocMonad m
+ => WriterOptions -> [Block] -> StateT WriterState m Doc
bulletListItemToHaddock opts items = do
contents <- blockListToHaddock opts items
let sps = replicate (writerTabStop opts - 2) ' '
@@ -250,22 +231,24 @@ bulletListItemToHaddock opts items = do
return $ hang (writerTabStop opts) start $ contents' <> cr
-- | Convert ordered list item (a list of blocks) to haddock
-orderedListItemToHaddock :: WriterOptions -- ^ options
- -> String -- ^ list item marker
- -> [Block] -- ^ list item (list of blocks)
- -> State WriterState Doc
+orderedListItemToHaddock :: PandocMonad m
+ => WriterOptions -- ^ options
+ -> String -- ^ list item marker
+ -> [Block] -- ^ list item (list of blocks)
+ -> StateT WriterState m Doc
orderedListItemToHaddock opts marker items = do
contents <- blockListToHaddock opts items
let sps = case length marker - writerTabStop opts of
n | n > 0 -> text $ replicate n ' '
- _ -> text " "
+ _ -> text " "
let start = text marker <> sps
return $ hang (writerTabStop opts) start $ contents <> cr
-- | Convert definition list item (label, list of blocks) to haddock
-definitionListItemToHaddock :: WriterOptions
- -> ([Inline],[[Block]])
- -> State WriterState Doc
+definitionListItemToHaddock :: PandocMonad m
+ => WriterOptions
+ -> ([Inline],[[Block]])
+ -> StateT WriterState m Doc
definitionListItemToHaddock opts (label, defs) = do
labelText <- inlineListToHaddock opts label
defs' <- mapM (mapM (blockToHaddock opts)) defs
@@ -273,19 +256,22 @@ definitionListItemToHaddock opts (label, defs) = do
return $ nowrap (brackets labelText) <> cr <> contents <> cr
-- | Convert list of Pandoc block elements to haddock
-blockListToHaddock :: WriterOptions -- ^ Options
- -> [Block] -- ^ List of block elements
- -> State WriterState Doc
+blockListToHaddock :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> [Block] -- ^ List of block elements
+ -> StateT WriterState m Doc
blockListToHaddock opts blocks =
mapM (blockToHaddock opts) blocks >>= return . cat
-- | Convert list of Pandoc inline elements to haddock.
-inlineListToHaddock :: WriterOptions -> [Inline] -> State WriterState Doc
+inlineListToHaddock :: PandocMonad m
+ => WriterOptions -> [Inline] -> StateT WriterState m Doc
inlineListToHaddock opts lst =
mapM (inlineToHaddock opts) lst >>= return . cat
-- | Convert Pandoc inline element to haddock.
-inlineToHaddock :: WriterOptions -> Inline -> State WriterState Doc
+inlineToHaddock :: PandocMonad m
+ => WriterOptions -> Inline -> StateT WriterState m Doc
inlineToHaddock opts (Span (ident,_,_) ils) = do
contents <- inlineListToHaddock opts ils
if not (null ident) && null ils
@@ -315,18 +301,20 @@ inlineToHaddock opts (Quoted DoubleQuote lst) = do
return $ "“" <> contents <> "”"
inlineToHaddock _ (Code _ str) =
return $ "@" <> text (escapeString str) <> "@"
-inlineToHaddock _ (Str str) = do
+inlineToHaddock _ (Str str) =
return $ text $ escapeString str
inlineToHaddock opts (Math mt str) = do
let adjust x = case mt of
DisplayMath -> cr <> x <> cr
InlineMath -> x
- adjust `fmap` (inlineListToHaddock opts $ texMathToInlines mt str)
-inlineToHaddock _ (RawInline f str)
+ adjust <$> (lift (texMathToInlines mt str) >>= inlineListToHaddock opts)
+inlineToHaddock _ il@(RawInline f str)
| f == "haddock" = return $ text str
- | otherwise = return empty
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
-- no line break in haddock (see above on CodeBlock)
-inlineToHaddock _ (LineBreak) = return cr
+inlineToHaddock _ LineBreak = return cr
inlineToHaddock opts SoftBreak =
case writerWrapText opts of
WrapAuto -> return space
@@ -339,7 +327,7 @@ inlineToHaddock _ (Link _ txt (src, _)) = do
let useAuto = isURI src &&
case txt of
[Str s] | escapeURI s == src -> True
- _ -> False
+ _ -> False
return $ nowrap $ "<" <> text src <>
(if useAuto then empty else space <> linktext) <> ">"
inlineToHaddock opts (Image attr alternate (source, tit)) = do
diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs
index 8f0d21cf5..a5d851e40 100644
--- a/src/Text/Pandoc/Writers/ICML.hs
+++ b/src/Text/Pandoc/Writers/ICML.hs
@@ -1,8 +1,10 @@
-{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{- |
Module : Text.Pandoc.Writers.ICML
- Copyright : Copyright (C) 2013-2016 github.com/mb21
+ Copyright : Copyright (C) 2013-2018 github.com/mb21
License : GNU GPL, version 2 or above
Stability : alpha
@@ -14,20 +16,25 @@ InCopy is the companion word-processor to Adobe InDesign and ICML documents can
into InDesign with File -> Place.
-}
module Text.Pandoc.Writers.ICML (writeICML) where
+import Control.Monad.Except (catchError)
+import Control.Monad.State.Strict
+import Data.List (intersperse, isInfixOf, isPrefixOf, stripPrefix)
+import Data.Maybe (fromMaybe)
+import qualified Data.Set as Set
+import Data.Text as Text (breakOnAll, pack)
+import Data.Text (Text)
+import Text.Pandoc.Class (PandocMonad, report)
+import qualified Text.Pandoc.Class as P
import Text.Pandoc.Definition
-import Text.Pandoc.XML
-import Text.Pandoc.Readers.TeXMath (texMathToInlines)
-import Text.Pandoc.Writers.Shared
-import Text.Pandoc.Shared (linesToPara, splitBy, fetchItem, warn)
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Templates (renderTemplate')
import Text.Pandoc.Pretty
-import Text.Pandoc.ImageSize
-import Data.List (isPrefixOf, isInfixOf, stripPrefix, intersperse)
-import Data.Text as Text (breakOnAll, pack)
-import Control.Monad.State
-import Network.URI (isURI)
-import qualified Data.Set as Set
+import Text.Pandoc.Shared (isURI, linesToPara, splitBy)
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Math (texMathToInlines)
+import Text.Pandoc.Writers.Shared
+import Text.Pandoc.XML
type Style = [String]
type Hyperlink = [(Int, String)]
@@ -40,7 +47,7 @@ data WriterState = WriterState{
, maxListDepth :: Int
}
-type WS a = StateT WriterState IO a
+type WS m = StateT WriterState m
defaultWriterState :: WriterState
defaultWriterState = WriterState{
@@ -121,13 +128,13 @@ subListParName = "subParagraph"
footnoteName = "Footnote"
citeName = "Cite"
-
-- | Convert Pandoc document to string in ICML format.
-writeICML :: WriterOptions -> Pandoc -> IO String
+writeICML :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeICML opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ render' :: Doc -> Text
render' = render colwidth
renderMeta f s = liftM (render' . fst) $ runStateT (f opts [] s) defaultWriterState
metadata <- metaToJSON opts
@@ -139,18 +146,15 @@ writeICML opts (Pandoc meta blocks) = do
context = defField "body" main
$ defField "charStyles" (render' $ charStylesToDoc st)
$ defField "parStyles" (render' $ parStylesToDoc st)
- $ defField "hyperlinks" (render' $ hyperlinksToDoc $ links st)
- $ metadata
- return $ case writerTemplate opts of
- Nothing -> main
- Just tpl -> renderTemplate' tpl context
+ $ defField "hyperlinks" (render' $ hyperlinksToDoc $ links st) metadata
+ case writerTemplate opts of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
-- | Auxilary functions for parStylesToDoc and charStylesToDoc.
contains :: String -> (String, (String, String)) -> [(String, String)]
contains s rule =
- if isInfixOf (fst rule) s
- then [snd rule]
- else []
+ [snd rule | (fst rule) `isInfixOf` s]
-- | The monospaced font to use as default.
monospacedFont :: Doc
@@ -174,7 +178,7 @@ parStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ blockStyles st
where
makeStyle s =
let countSubStrs sub str = length $ Text.breakOnAll (Text.pack sub) (Text.pack str)
- attrs = concat $ map (contains s) $ [
+ attrs = concatMap (contains s) [
(defListTermName, ("BulletsAndNumberingListType", "BulletList"))
, (defListTermName, ("FontStyle", "Bold"))
, (tableHeaderName, ("FontStyle", "Bold"))
@@ -200,9 +204,9 @@ parStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ blockStyles st
where
numbering | isOrderedList = [("NumberingExpression", "^#.^t"), ("NumberingLevel", show nOrds)]
| otherwise = []
- listType | isOrderedList && (not $ isInfixOf subListParName s)
+ listType | isOrderedList && not (subListParName `isInfixOf` s)
= [("BulletsAndNumberingListType", "NumberedList")]
- | isBulletList && (not $ isInfixOf subListParName s)
+ | isBulletList && not (subListParName `isInfixOf` s)
= [("BulletsAndNumberingListType", "BulletList")]
| otherwise = []
indent = [("LeftIndent", show indt)]
@@ -210,9 +214,9 @@ parStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ blockStyles st
nBlockQuotes = countSubStrs blockQuoteName s
nDefLists = countSubStrs defListDefName s
indt = max 0 $ defaultListIndent*(nBuls + nOrds - 1) + defaultIndent*(nBlockQuotes + nDefLists)
- props = inTags True "Properties" [] $ (basedOn $$ tabList $$ numbForm)
+ props = inTags True "Properties" [] (basedOn $$ tabList $$ numbForm)
where
- font = if isInfixOf codeBlockName s
+ font = if codeBlockName `isInfixOf` s
then monospacedFont
else empty
basedOn = inTags False "BasedOn" [("type", "object")] (text "$ID/NormalParagraphStyle") $$ font
@@ -239,7 +243,7 @@ charStylesToDoc :: WriterState -> Doc
charStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ inlineStyles st
where
makeStyle s =
- let attrs = concat $ map (contains s) [
+ let attrs = concatMap (contains s) [
(strikeoutName, ("StrikeThru", "true"))
, (superscriptName, ("Position", "Superscript"))
, (subscriptName, ("Position", "Subscript"))
@@ -253,7 +257,7 @@ charStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ inlineStyles st
inTags False "BasedOn" [("type", "object")] (text "$ID/NormalCharacterStyle") $$ font
where
font =
- if isInfixOf codeName s
+ if codeName `isInfixOf` s
then monospacedFont
else empty
in inTags True "CharacterStyle" ([("Self", "CharacterStyle/"++s), ("Name", s)] ++ attrs') props
@@ -273,23 +277,22 @@ hyperlinksToDoc (x:xs) = hyp x $$ hyperlinksToDoc xs
hyp (ident, url) = hdest $$ hlink
where
hdest = selfClosingTag "HyperlinkURLDestination"
- [("Self", "HyperlinkURLDestination/"++(escapeColons url)), ("Name","link"), ("DestinationURL",url), ("DestinationUniqueKey","1")] -- HyperlinkURLDestination with more than one colon crashes CS6
+ [("Self", "HyperlinkURLDestination/"++escapeColons url), ("Name","link"), ("DestinationURL",url), ("DestinationUniqueKey","1")] -- HyperlinkURLDestination with more than one colon crashes CS6
hlink = inTags True "Hyperlink" [("Self","uf-"++show ident), ("Name",url),
("Source","htss-"++show ident), ("Visible","true"), ("DestinationUniqueKey","1")]
$ inTags True "Properties" []
$ inTags False "BorderColor" [("type","enumeration")] (text "Black")
- $$ (inTags False "Destination" [("type","object")]
- $ text $ "HyperlinkURLDestination/"++(escapeColons (escapeStringForXML url))) -- HyperlinkURLDestination with more than one colon crashes CS6
+ $$ inTags False "Destination" [("type","object")] (text $ "HyperlinkURLDestination/"++escapeColons (escapeStringForXML url)) -- HyperlinkURLDestination with more than one colon crashes CS6
-- | Convert a list of Pandoc blocks to ICML.
-blocksToICML :: WriterOptions -> Style -> [Block] -> WS Doc
+blocksToICML :: PandocMonad m => WriterOptions -> Style -> [Block] -> WS m Doc
blocksToICML opts style lst = do
docs <- mapM (blockToICML opts style) lst
return $ intersperseBrs docs
-- | Convert a Pandoc block element to ICML.
-blockToICML :: WriterOptions -> Style -> Block -> WS Doc
+blockToICML :: PandocMonad m => WriterOptions -> Style -> Block -> WS m Doc
blockToICML opts style (Plain lst) = parStyle opts style lst
-- title beginning with fig: indicates that the image is a figure
blockToICML opts style (Para img@[Image _ txt (_,'f':'i':'g':':':_)]) = do
@@ -299,10 +302,12 @@ blockToICML opts style (Para img@[Image _ txt (_,'f':'i':'g':':':_)]) = do
blockToICML opts style (Para lst) = parStyle opts (paragraphName:style) lst
blockToICML opts style (LineBlock lns) =
blockToICML opts style $ linesToPara lns
-blockToICML opts style (CodeBlock _ str) = parStyle opts (codeBlockName:style) $ [Str str]
-blockToICML _ _ (RawBlock f str)
+blockToICML opts style (CodeBlock _ str) = parStyle opts (codeBlockName:style) [Str str]
+blockToICML _ _ b@(RawBlock f str)
| f == Format "icml" = return $ text str
- | otherwise = return empty
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
blockToICML opts style (BlockQuote blocks) = blocksToICML opts (blockQuoteName:style) blocks
blockToICML opts style (OrderedList attribs lst) = listItemsToICML opts orderedListName style (Just attribs) lst
blockToICML opts style (BulletList lst) = listItemsToICML opts bulletListName style Nothing lst
@@ -343,11 +348,10 @@ blockToICML opts style (Table caption aligns widths headers rows) =
then rows
else headers:rows
cells <- rowsToICML tabl (0::Int)
- let colWidths w = if w > 0
- then [("SingleColumnWidth",show $ 500 * w)]
- else []
- let tupToDoc tup = selfClosingTag "Column" $ [("Name",show $ fst tup)] ++ (colWidths $ snd tup)
- let colDescs = vcat $ map tupToDoc $ zip [0..nrCols-1] widths
+ let colWidths w =
+ [("SingleColumnWidth",show $ 500 * w) | w > 0]
+ let tupToDoc tup = selfClosingTag "Column" $ ("Name",show $ fst tup) : colWidths (snd tup)
+ let colDescs = vcat $ zipWith (curry tupToDoc) [0..nrCols-1] widths
let tableDoc = return $ inTags True "Table" [
("AppliedTableStyle","TableStyle/Table")
, ("HeaderRowCount", nrHeaders)
@@ -359,7 +363,7 @@ blockToICML opts style (Div _ lst) = blocksToICML opts style lst
blockToICML _ _ Null = return empty
-- | Convert a list of lists of blocks to ICML list items.
-listItemsToICML :: WriterOptions -> String -> Style -> Maybe ListAttributes -> [[Block]] -> WS Doc
+listItemsToICML :: PandocMonad m => WriterOptions -> String -> Style -> Maybe ListAttributes -> [[Block]] -> WS m Doc
listItemsToICML _ _ _ _ [] = return empty
listItemsToICML opts listType style attribs (first:rest) = do
st <- get
@@ -374,18 +378,17 @@ listItemsToICML opts listType style attribs (first:rest) = do
return $ intersperseBrs docs
-- | Convert a list of blocks to ICML list items.
-listItemToICML :: WriterOptions -> Style -> Bool-> Maybe ListAttributes -> [Block] -> WS Doc
+listItemToICML :: PandocMonad m => WriterOptions -> Style -> Bool-> Maybe ListAttributes -> [Block] -> WS m Doc
listItemToICML opts style isFirst attribs item =
let makeNumbStart (Just (beginsWith, numbStl, _)) =
let doN DefaultStyle = []
- doN LowerRoman = [lowerRomanName]
- doN UpperRoman = [upperRomanName]
- doN LowerAlpha = [lowerAlphaName]
- doN UpperAlpha = [upperAlphaName]
- doN _ = []
- bw = if beginsWith > 1
- then [beginsWithName ++ show beginsWith]
- else []
+ doN LowerRoman = [lowerRomanName]
+ doN UpperRoman = [upperRomanName]
+ doN LowerAlpha = [lowerAlphaName]
+ doN UpperAlpha = [upperAlphaName]
+ doN _ = []
+ bw =
+ [beginsWithName ++ show beginsWith | beginsWith > 1]
in doN numbStl ++ bw
makeNumbStart Nothing = []
stl = if isFirst
@@ -394,26 +397,26 @@ listItemToICML opts style isFirst attribs item =
stl' = makeNumbStart attribs ++ stl
in if length item > 1
then do
- let insertTab (Para lst) = blockToICML opts (subListParName:style) $ Para $ (Str "\t"):lst
+ let insertTab (Para lst) = blockToICML opts (subListParName:style) $ Para $ Str "\t":lst
insertTab block = blockToICML opts style block
f <- blockToICML opts stl' $ head item
r <- mapM insertTab $ tail item
return $ intersperseBrs (f : r)
else blocksToICML opts stl' item
-definitionListItemToICML :: WriterOptions -> Style -> ([Inline],[[Block]]) -> WS Doc
+definitionListItemToICML :: PandocMonad m => WriterOptions -> Style -> ([Inline],[[Block]]) -> WS m Doc
definitionListItemToICML opts style (term,defs) = do
term' <- parStyle opts (defListTermName:style) term
defs' <- mapM (blocksToICML opts (defListDefName:style)) defs
- return $ intersperseBrs $ (term' : defs')
+ return $ intersperseBrs (term' : defs')
-- | Convert a list of inline elements to ICML.
-inlinesToICML :: WriterOptions -> Style -> [Inline] -> WS Doc
+inlinesToICML :: PandocMonad m => WriterOptions -> Style -> [Inline] -> WS m Doc
inlinesToICML opts style lst = vcat `fmap` mapM (inlineToICML opts style) (mergeSpaces lst)
-- | Convert an inline element to ICML.
-inlineToICML :: WriterOptions -> Style -> Inline -> WS Doc
+inlineToICML :: PandocMonad m => WriterOptions -> Style -> Inline -> WS m Doc
inlineToICML _ style (Str str) = charStyle style $ text $ escapeStringForXML str
inlineToICML opts style (Emph lst) = inlinesToICML opts (emphName:style) lst
inlineToICML opts style (Strong lst) = inlinesToICML opts (strongName:style) lst
@@ -433,17 +436,20 @@ inlineToICML opts style SoftBreak =
WrapPreserve -> charStyle style cr
inlineToICML _ style LineBreak = charStyle style $ text lineSeparator
inlineToICML opts style (Math mt str) =
- cat <$> mapM (inlineToICML opts style) (texMathToInlines mt str)
-inlineToICML _ _ (RawInline f str)
+ lift (texMathToInlines mt str) >>=
+ (fmap cat . mapM (inlineToICML opts style))
+inlineToICML _ _ il@(RawInline f str)
| f == Format "icml" = return $ text str
- | otherwise = return empty
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
inlineToICML opts style (Link _ lst (url, title)) = do
content <- inlinesToICML opts (linkName:style) lst
state $ \st ->
let ident = if null $ links st
then 1::Int
- else 1 + (fst $ head $ links st)
- newst = st{ links = (ident, url):(links st) }
+ else 1 + fst (head $ links st)
+ newst = st{ links = (ident, url):links st }
cont = inTags True "HyperlinkTextSource"
[("Self","htss-"++show ident), ("Name",title), ("Hidden","false")] content
in (cont, newst)
@@ -452,9 +458,9 @@ inlineToICML opts style (Note lst) = footnoteToICML opts style lst
inlineToICML opts style (Span _ lst) = inlinesToICML opts style lst
-- | Convert a list of block elements to an ICML footnote.
-footnoteToICML :: WriterOptions -> Style -> [Block] -> WS Doc
+footnoteToICML :: PandocMonad m => WriterOptions -> Style -> [Block] -> WS m Doc
footnoteToICML opts style lst =
- let insertTab (Para ls) = blockToICML opts (footnoteName:style) $ Para $ (Str "\t"):ls
+ let insertTab (Para ls) = blockToICML opts (footnoteName:style) $ Para $ Str "\t":ls
insertTab block = blockToICML opts (footnoteName:style) block
in do
contents <- mapM insertTab lst
@@ -466,24 +472,24 @@ footnoteToICML opts style lst =
-- | Auxiliary function to merge Space elements into the adjacent Strs.
mergeSpaces :: [Inline] -> [Inline]
-mergeSpaces ((Str s):(x:((Str s'):xs))) | isSp x =
+mergeSpaces (Str s:(x:(Str s':xs))) | isSp x =
mergeSpaces $ Str(s++" "++s') : xs
-mergeSpaces (x:((Str s):xs)) | isSp x = mergeSpaces $ Str (" "++s) : xs
-mergeSpaces ((Str s):(x:xs)) | isSp x = mergeSpaces $ Str (s++" ") : xs
-mergeSpaces (x:xs) = x : (mergeSpaces xs)
+mergeSpaces (x:(Str s:xs)) | isSp x = mergeSpaces $ Str (" "++s) : xs
+mergeSpaces (Str s:(x:xs)) | isSp x = mergeSpaces $ Str (s++" ") : xs
+mergeSpaces (x:xs) = x : mergeSpaces xs
mergeSpaces [] = []
isSp :: Inline -> Bool
-isSp Space = True
+isSp Space = True
isSp SoftBreak = True
-isSp _ = False
+isSp _ = False
-- | Intersperse line breaks
intersperseBrs :: [Doc] -> Doc
intersperseBrs = vcat . intersperse (selfClosingTag "Br" []) . filter (not . isEmpty)
-- | Wrap a list of inline elements in an ICML Paragraph Style
-parStyle :: WriterOptions -> Style -> [Inline] -> WS Doc
+parStyle :: PandocMonad m => WriterOptions -> Style -> [Inline] -> WS m Doc
parStyle opts style lst =
let slipIn x y = if null y
then x
@@ -498,7 +504,7 @@ parStyle opts style lst =
begins = filter (isPrefixOf beginsWithName) style
in if null begins
then ats
- else let i = maybe "" id $ stripPrefix beginsWithName $ head begins
+ else let i = fromMaybe "" $ stripPrefix beginsWithName $ head begins
in ("NumberingStartAt", i) : ats
else [attrs]
in do
@@ -507,16 +513,16 @@ parStyle opts style lst =
state $ \st -> (cont, st{ blockStyles = Set.insert stlStr $ blockStyles st })
-- | Wrap a Doc in an ICML Character Style.
-charStyle :: Style -> Doc -> WS Doc
+charStyle :: PandocMonad m => Style -> Doc -> WS m Doc
charStyle style content =
let (stlStr, attrs) = styleToStrAttr style
doc = inTags True "CharacterStyleRange" attrs $ inTagsSimple "Content" $ flush content
- in do
+ in
state $ \st ->
- let styles = if null stlStr
- then st
- else st{ inlineStyles = Set.insert stlStr $ inlineStyles st }
- in (doc, styles)
+ let styles = if null stlStr
+ then st
+ else st{ inlineStyles = Set.insert stlStr $ inlineStyles st }
+ in (doc, styles)
-- | Transform a Style to a tuple of String (eliminating duplicates and ordered) and corresponding attribute.
styleToStrAttr :: Style -> (String, [(String, String)])
@@ -529,20 +535,18 @@ styleToStrAttr style =
in (stlStr, attrs)
-- | Assemble an ICML Image.
-imageICML :: WriterOptions -> Style -> Attr -> Target -> WS Doc
+imageICML :: PandocMonad m => WriterOptions -> Style -> Attr -> Target -> WS m Doc
imageICML opts style attr (src, _) = do
- res <- liftIO $ fetchItem (writerSourceURL opts) src
- imgS <- case res of
- Left (_) -> do
- warn $ "Could not find image `" ++ src ++ "', skipping..."
- return def
- Right (img, _) -> do
- case imageSize img of
+ imgS <- catchError
+ (do (img, _) <- P.fetchItem src
+ case imageSize opts img of
Right size -> return size
Left msg -> do
- warn $ "Could not determine image size in `" ++
- src ++ "': " ++ msg
- return def
+ report $ CouldNotDetermineImageSize src msg
+ return def)
+ (\e -> do
+ report $ CouldNotFetchResource src (show e)
+ return def)
let (ow, oh) = sizeInPoints imgS
(imgWidth, imgHeight) = desiredSizeInPoints opts attr imgS
hw = showFl $ ow / 2
@@ -571,6 +575,5 @@ imageICML opts style attr (src, _) = do
]
doc = inTags True "CharacterStyleRange" attrs
$ inTags True "Rectangle" [("Self","uec"), ("StrokeWeight", "0"),
- ("ItemTransform", scale++" "++hw++" -"++hh)]
- $ (props $$ image)
+ ("ItemTransform", scale++" "++hw++" -"++hh)] (props $$ image)
state $ \st -> (doc, st{ inlineStyles = Set.insert stlStr $ inlineStyles st } )
diff --git a/src/Text/Pandoc/Writers/JATS.hs b/src/Text/Pandoc/Writers/JATS.hs
new file mode 100644
index 000000000..639961acd
--- /dev/null
+++ b/src/Text/Pandoc/Writers/JATS.hs
@@ -0,0 +1,455 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{- |
+ Module : Text.Pandoc.Writers.JATS
+ Copyright : Copyright (C) 2017-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to JATS XML.
+Reference:
+https://jats.nlm.nih.gov/publishing/tag-library/1.1d3/element/mml-math.html
+-}
+module Text.Pandoc.Writers.JATS ( writeJATS ) where
+import Control.Monad.Reader
+import Data.Char (toLower)
+import Data.Generics (everywhere, mkT)
+import Data.List (isSuffixOf, partition)
+import Data.Maybe (fromMaybe)
+import Data.Text (Text)
+import Text.Pandoc.Class (PandocMonad, report)
+import Text.Pandoc.Definition
+import Text.Pandoc.Highlighting (languages, languagesByExtension)
+import Text.Pandoc.Logging
+import Text.Pandoc.MIME (getMimeType)
+import Text.Pandoc.Options
+import Text.Pandoc.Pretty
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Math
+import Text.Pandoc.Writers.Shared
+import Text.Pandoc.XML
+import Text.TeXMath
+import qualified Text.XML.Light as Xml
+
+data JATSVersion = JATS1_1
+ deriving (Eq, Show)
+
+type JATS = ReaderT JATSVersion
+
+writeJATS :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeJATS opts d =
+ runReaderT (docToJATS opts d) JATS1_1
+
+-- | Convert Pandoc document to string in JATS format.
+docToJATS :: PandocMonad m => WriterOptions -> Pandoc -> JATS m Text
+docToJATS opts (Pandoc meta blocks) = do
+ let isBackBlock (Div ("refs",_,_) _) = True
+ isBackBlock _ = False
+ let (backblocks, bodyblocks) = partition isBackBlock blocks
+ let elements = hierarchicalize bodyblocks
+ let backElements = hierarchicalize backblocks
+ let colwidth = if writerWrapText opts == WrapAuto
+ then Just $ writerColumns opts
+ else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
+ let opts' = if maybe False (("/book>" `isSuffixOf`) . trimr)
+ (writerTemplate opts) &&
+ TopLevelDefault == writerTopLevelDivision opts
+ then opts{ writerTopLevelDivision = TopLevelChapter }
+ else opts
+ -- The numbering here follows LaTeX's internal numbering
+ let startLvl = case writerTopLevelDivision opts' of
+ TopLevelPart -> -1
+ TopLevelChapter -> 0
+ TopLevelSection -> 1
+ TopLevelDefault -> 1
+ metadata <- metaToJSON opts
+ (fmap (render' . vcat) .
+ mapM (elementToJATS opts' startLvl) .
+ hierarchicalize)
+ (fmap render' . inlinesToJATS opts')
+ meta
+ main <- (render' . vcat) <$>
+ mapM (elementToJATS opts' startLvl) elements
+ back <- (render' . vcat) <$>
+ mapM (elementToJATS opts' startLvl) backElements
+ let context = defField "body" main
+ $ defField "back" back
+ $ defField "mathml" (case writerHTMLMathMethod opts of
+ MathML -> True
+ _ -> False) metadata
+ case writerTemplate opts of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
+
+-- | Convert an Element to JATS.
+elementToJATS :: PandocMonad m => WriterOptions -> Int -> Element -> JATS m Doc
+elementToJATS opts _ (Blk block) = blockToJATS opts block
+elementToJATS opts lvl (Sec _ _num (id',_,kvs) title elements) = do
+ let idAttr = [("id", writerIdentifierPrefix opts ++ id') | not (null id')]
+ let otherAttrs = ["sec-type", "specific-use"]
+ let attribs = idAttr ++ [(k,v) | (k,v) <- kvs, k `elem` otherAttrs]
+ contents <- mapM (elementToJATS opts (lvl + 1)) elements
+ title' <- inlinesToJATS opts title
+ return $ inTags True "sec" attribs $
+ inTagsSimple "title" title' $$ vcat contents
+
+-- | Convert a list of Pandoc blocks to JATS.
+blocksToJATS :: PandocMonad m => WriterOptions -> [Block] -> JATS m Doc
+blocksToJATS opts = fmap vcat . mapM (blockToJATS opts)
+
+-- | Auxiliary function to convert Plain block to Para.
+plainToPara :: Block -> Block
+plainToPara (Plain x) = Para x
+plainToPara x = x
+
+-- | Convert a list of pairs of terms and definitions into a list of
+-- JATS varlistentrys.
+deflistItemsToJATS :: PandocMonad m
+ => WriterOptions -> [([Inline],[[Block]])] -> JATS m Doc
+deflistItemsToJATS opts items =
+ vcat <$> mapM (uncurry (deflistItemToJATS opts)) items
+
+-- | Convert a term and a list of blocks into a JATS varlistentry.
+deflistItemToJATS :: PandocMonad m
+ => WriterOptions -> [Inline] -> [[Block]] -> JATS m Doc
+deflistItemToJATS opts term defs = do
+ term' <- inlinesToJATS opts term
+ def' <- blocksToJATS opts $ concatMap (map plainToPara) defs
+ return $ inTagsIndented "def-item" $
+ inTagsIndented "term" term' $$
+ inTagsIndented "def" def'
+
+-- | Convert a list of lists of blocks to a list of JATS list items.
+listItemsToJATS :: PandocMonad m
+ => WriterOptions -> Maybe [String] -> [[Block]] -> JATS m Doc
+listItemsToJATS opts markers items =
+ case markers of
+ Nothing -> vcat <$> mapM (listItemToJATS opts Nothing) items
+ Just ms -> vcat <$> zipWithM (listItemToJATS opts) (map Just ms) items
+
+-- | Convert a list of blocks into a JATS list item.
+listItemToJATS :: PandocMonad m
+ => WriterOptions -> Maybe String -> [Block] -> JATS m Doc
+listItemToJATS opts mbmarker item = do
+ contents <- blocksToJATS opts item
+ return $ inTagsIndented "list-item" $
+ maybe empty (\lbl -> inTagsIndented "label" (text lbl)) mbmarker
+ $$ contents
+
+imageMimeType :: String -> [(String, String)] -> (String, String)
+imageMimeType src kvs =
+ let mbMT = getMimeType src
+ maintype = fromMaybe "image" $
+ lookup "mimetype" kvs `mplus`
+ (takeWhile (/='/') <$> mbMT)
+ subtype = fromMaybe "" $
+ lookup "mime-subtype" kvs `mplus`
+ ((drop 1 . dropWhile (/='/')) <$> mbMT)
+ in (maintype, subtype)
+
+languageFor :: [String] -> String
+languageFor classes =
+ case langs of
+ (l:_) -> escapeStringForXML l
+ [] -> ""
+ where isLang l = map toLower l `elem` map (map toLower) languages
+ langsFrom s = if isLang s
+ then [s]
+ else languagesByExtension . map toLower $ s
+ langs = concatMap langsFrom classes
+
+codeAttr :: Attr -> (String, [(String, String)])
+codeAttr (ident,classes,kvs) = (lang, attr)
+ where
+ attr = [("id",ident) | not (null ident)] ++
+ [("language",lang) | not (null lang)] ++
+ [(k,v) | (k,v) <- kvs, k `elem` ["code-type",
+ "code-version", "executable",
+ "language-version", "orientation",
+ "platforms", "position", "specific-use"]]
+ lang = languageFor classes
+
+-- | Convert a Pandoc block element to JATS.
+blockToJATS :: PandocMonad m => WriterOptions -> Block -> JATS m Doc
+blockToJATS _ Null = return empty
+-- Bibliography reference:
+blockToJATS opts (Div ('r':'e':'f':'-':_,_,_) [Para lst]) =
+ inlinesToJATS opts lst
+blockToJATS opts (Div ("refs",_,_) xs) = do
+ contents <- blocksToJATS opts xs
+ return $ inTagsIndented "ref-list" contents
+blockToJATS opts (Div (ident,[cls],kvs) bs) | cls `elem` ["fig", "caption", "table-wrap"] = do
+ contents <- blocksToJATS opts bs
+ let attr = [("id", ident) | not (null ident)] ++
+ [("xml:lang",l) | ("lang",l) <- kvs] ++
+ [(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
+ "content-type", "orientation", "position"]]
+ return $ inTags True cls attr contents
+blockToJATS opts (Div (ident,_,kvs) bs) = do
+ contents <- blocksToJATS opts bs
+ let attr = [("id", ident) | not (null ident)] ++
+ [("xml:lang",l) | ("lang",l) <- kvs] ++
+ [(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
+ "content-type", "orientation", "position"]]
+ return $ inTags True "boxed-text" attr contents
+blockToJATS opts (Header _ _ title) = do
+ title' <- inlinesToJATS opts title
+ return $ inTagsSimple "title" title'
+-- No Plain, everything needs to be in a block-level tag
+blockToJATS opts (Plain lst) = blockToJATS opts (Para lst)
+-- title beginning with fig: indicates that the image is a figure
+blockToJATS opts (Para [Image (ident,_,kvs) txt
+ (src,'f':'i':'g':':':tit)]) = do
+ alt <- inlinesToJATS opts txt
+ let (maintype, subtype) = imageMimeType src kvs
+ let capt = if null txt
+ then empty
+ else inTagsSimple "caption" alt
+ let attr = [("id", ident) | not (null ident)] ++
+ [(k,v) | (k,v) <- kvs, k `elem` ["fig-type", "orientation",
+ "position", "specific-use"]]
+ let graphicattr = [("mimetype",maintype),
+ ("mime-subtype",subtype),
+ ("xlink:href",src), -- do we need to URL escape this?
+ ("xlink:title",tit)]
+ return $ inTags True "fig" attr $
+ capt $$ selfClosingTag "graphic" graphicattr
+blockToJATS _ (Para [Image (ident,_,kvs) _ (src, tit)]) = do
+ let (maintype, subtype) = imageMimeType src kvs
+ let attr = [("id", ident) | not (null ident)] ++
+ [("mimetype", maintype),
+ ("mime-subtype", subtype),
+ ("xlink:href", src)] ++
+ [("xlink:title", tit) | not (null tit)] ++
+ [(k,v) | (k,v) <- kvs, k `elem` ["baseline-shift",
+ "content-type", "specific-use", "xlink:actuate",
+ "xlink:href", "xlink:role", "xlink:show",
+ "xlink:type"]]
+ return $ selfClosingTag "graphic" attr
+blockToJATS opts (Para lst) =
+ inTagsIndented "p" <$> inlinesToJATS opts lst
+blockToJATS opts (LineBlock lns) =
+ blockToJATS opts $ linesToPara lns
+blockToJATS opts (BlockQuote blocks) =
+ inTagsIndented "disp-quote" <$> blocksToJATS opts blocks
+blockToJATS _ (CodeBlock a str) = return $
+ inTags False tag attr (flush (text (escapeStringForXML str)))
+ where (lang, attr) = codeAttr a
+ tag = if null lang then "preformat" else "code"
+blockToJATS _ (BulletList []) = return empty
+blockToJATS opts (BulletList lst) =
+ inTags True "list" [("list-type", "bullet")] <$>
+ listItemsToJATS opts Nothing lst
+blockToJATS _ (OrderedList _ []) = return empty
+blockToJATS opts (OrderedList (start, numstyle, delimstyle) items) = do
+ let listType = case numstyle of
+ DefaultStyle -> "order"
+ Decimal -> "order"
+ Example -> "order"
+ UpperAlpha -> "alpha-upper"
+ LowerAlpha -> "alpha-lower"
+ UpperRoman -> "roman-upper"
+ LowerRoman -> "roman-lower"
+ let simpleList = start == 1 && (delimstyle == DefaultDelim ||
+ delimstyle == Period)
+ let markers = if simpleList
+ then Nothing
+ else Just $
+ orderedListMarkers (start, numstyle, delimstyle)
+ inTags True "list" [("list-type", listType)] <$>
+ listItemsToJATS opts markers items
+blockToJATS opts (DefinitionList lst) =
+ inTags True "def-list" [] <$> deflistItemsToJATS opts lst
+blockToJATS _ b@(RawBlock f str)
+ | f == "jats" = return $ text str -- raw XML block
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
+blockToJATS _ HorizontalRule = return empty -- not semantic
+blockToJATS opts (Table [] aligns widths headers rows) = do
+ let percent w = show (truncate (100*w) :: Integer) ++ "*"
+ let coltags = vcat $ zipWith (\w al -> selfClosingTag "col"
+ ([("width", percent w) | w > 0] ++
+ [("align", alignmentToString al)])) widths aligns
+ thead <- if all null headers
+ then return empty
+ else inTagsIndented "thead" <$> tableRowToJATS opts True headers
+ tbody <- (inTagsIndented "tbody" . vcat) <$>
+ mapM (tableRowToJATS opts False) rows
+ return $ inTags True "table" [] $ coltags $$ thead $$ tbody
+blockToJATS opts (Table caption aligns widths headers rows) = do
+ captionDoc <- inTagsIndented "caption" <$> blockToJATS opts (Para caption)
+ tbl <- blockToJATS opts (Table [] aligns widths headers rows)
+ return $ inTags True "table-wrap" [] $ captionDoc $$ tbl
+
+alignmentToString :: Alignment -> [Char]
+alignmentToString alignment = case alignment of
+ AlignLeft -> "left"
+ AlignRight -> "right"
+ AlignCenter -> "center"
+ AlignDefault -> "left"
+
+tableRowToJATS :: PandocMonad m
+ => WriterOptions
+ -> Bool
+ -> [[Block]]
+ -> JATS m Doc
+tableRowToJATS opts isHeader cols =
+ (inTagsIndented "tr" . vcat) <$> mapM (tableItemToJATS opts isHeader) cols
+
+tableItemToJATS :: PandocMonad m
+ => WriterOptions
+ -> Bool
+ -> [Block]
+ -> JATS m Doc
+tableItemToJATS opts isHeader [Plain item] =
+ inTags True (if isHeader then "th" else "td") [] <$>
+ inlinesToJATS opts item
+tableItemToJATS opts isHeader item =
+ (inTags True (if isHeader then "th" else "td") [] . vcat) <$>
+ mapM (blockToJATS opts) item
+
+-- | Convert a list of inline elements to JATS.
+inlinesToJATS :: PandocMonad m => WriterOptions -> [Inline] -> JATS m Doc
+inlinesToJATS opts lst = hcat <$> mapM (inlineToJATS opts) lst
+
+-- | Convert an inline element to JATS.
+inlineToJATS :: PandocMonad m => WriterOptions -> Inline -> JATS m Doc
+inlineToJATS _ (Str str) = return $ text $ escapeStringForXML str
+inlineToJATS opts (Emph lst) =
+ inTagsSimple "italic" <$> inlinesToJATS opts lst
+inlineToJATS opts (Strong lst) =
+ inTags False "bold" [("role", "strong")] <$> inlinesToJATS opts lst
+inlineToJATS opts (Strikeout lst) =
+ inTagsSimple "strike" <$> inlinesToJATS opts lst
+inlineToJATS opts (Superscript lst) =
+ inTagsSimple "sup" <$> inlinesToJATS opts lst
+inlineToJATS opts (Subscript lst) =
+ inTagsSimple "sub" <$> inlinesToJATS opts lst
+inlineToJATS opts (SmallCaps lst) =
+ inTags False "sc" [("role", "smallcaps")] <$>
+ inlinesToJATS opts lst
+inlineToJATS opts (Quoted SingleQuote lst) = do
+ contents <- inlinesToJATS opts lst
+ return $ char '‘' <> contents <> char '’'
+inlineToJATS opts (Quoted DoubleQuote lst) = do
+ contents <- inlinesToJATS opts lst
+ return $ char '“' <> contents <> char '”'
+inlineToJATS _ (Code a str) =
+ return $ inTags False tag attr $ text (escapeStringForXML str)
+ where (lang, attr) = codeAttr a
+ tag = if null lang then "monospace" else "code"
+inlineToJATS _ il@(RawInline f x)
+ | f == "jats" = return $ text x
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
+inlineToJATS _ LineBreak = return $ selfClosingTag "break" []
+inlineToJATS _ Space = return space
+inlineToJATS opts SoftBreak
+ | writerWrapText opts == WrapPreserve = return cr
+ | otherwise = return space
+inlineToJATS opts (Note contents) =
+ -- TODO technically only <p> tags are allowed inside
+ inTagsIndented "fn" <$> blocksToJATS opts contents
+inlineToJATS opts (Cite _ lst) =
+ -- TODO revisit this after examining the jats.csl pipeline
+ inlinesToJATS opts lst
+inlineToJATS opts (Span ("",_,[]) ils) = inlinesToJATS opts ils
+inlineToJATS opts (Span (ident,_,kvs) ils) = do
+ contents <- inlinesToJATS opts ils
+ let attr = [("id",ident) | not (null ident)] ++
+ [("xml:lang",l) | ("lang",l) <- kvs] ++
+ [(k,v) | (k,v) <- kvs
+ , k `elem` ["content-type", "rationale",
+ "rid", "specific-use"]]
+ return $ selfClosingTag "milestone-start" attr <> contents <>
+ selfClosingTag "milestone-end" []
+inlineToJATS _ (Math t str) = do
+ let addPref (Xml.Attr q v)
+ | Xml.qName q == "xmlns" = Xml.Attr q{ Xml.qName = "xmlns:mml" } v
+ | otherwise = Xml.Attr q v
+ let fixNS' e = e{ Xml.elName =
+ (Xml.elName e){ Xml.qPrefix = Just "mml" } }
+ let fixNS = everywhere (mkT fixNS') .
+ (\e -> e{ Xml.elAttribs = map addPref (Xml.elAttribs e) })
+ let conf = Xml.useShortEmptyTags (const False) Xml.defaultConfigPP
+ res <- convertMath writeMathML t str
+ let tagtype = case t of
+ DisplayMath -> "disp-formula"
+ InlineMath -> "inline-formula"
+ let rawtex = inTagsSimple "tex-math"
+ $ text "<![CDATA[" <>
+ text str <>
+ text "]]>"
+ return $ inTagsSimple tagtype $
+ case res of
+ Right r -> inTagsSimple "alternatives" $
+ cr <> rawtex $$
+ text (Xml.ppcElement conf $ fixNS r)
+ Left _ -> rawtex
+inlineToJATS _ (Link _attr [Str t] ('m':'a':'i':'l':'t':'o':':':email, _))
+ | escapeURI t == email =
+ return $ inTagsSimple "email" $ text (escapeStringForXML email)
+inlineToJATS opts (Link (ident,_,kvs) txt ('#':src, _)) = do
+ let attr = [("id", ident) | not (null ident)] ++
+ [("alt", stringify txt) | not (null txt)] ++
+ [("rid", src)] ++
+ [(k,v) | (k,v) <- kvs, k `elem` ["ref-type", "specific-use"]]
+ if null txt
+ then return $ selfClosingTag "xref" attr
+ else do
+ contents <- inlinesToJATS opts txt
+ return $ inTags False "xref" attr contents
+inlineToJATS opts (Link (ident,_,kvs) txt (src, tit)) = do
+ let attr = [("id", ident) | not (null ident)] ++
+ [("ext-link-type", "uri"),
+ ("xlink:href", src)] ++
+ [("xlink:title", tit) | not (null tit)] ++
+ [(k,v) | (k,v) <- kvs, k `elem` ["assigning-authority",
+ "specific-use", "xlink:actuate",
+ "xlink:role", "xlink:show",
+ "xlink:type"]]
+ contents <- inlinesToJATS opts txt
+ return $ inTags False "ext-link" attr contents
+inlineToJATS _ (Image (ident,_,kvs) _ (src, tit)) = do
+ let mbMT = getMimeType src
+ let maintype = fromMaybe "image" $
+ lookup "mimetype" kvs `mplus`
+ (takeWhile (/='/') <$> mbMT)
+ let subtype = fromMaybe "" $
+ lookup "mime-subtype" kvs `mplus`
+ ((drop 1 . dropWhile (/='/')) <$> mbMT)
+ let attr = [("id", ident) | not (null ident)] ++
+ [("mimetype", maintype),
+ ("mime-subtype", subtype),
+ ("xlink:href", src)] ++
+ [("xlink:title", tit) | not (null tit)] ++
+ [(k,v) | (k,v) <- kvs, k `elem` ["baseline-shift",
+ "content-type", "specific-use", "xlink:actuate",
+ "xlink:href", "xlink:role", "xlink:show",
+ "xlink:type"]]
+ return $ selfClosingTag "inline-graphic" attr
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index 88934eb44..f61c878e5 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE OverloadedStrings, ScopedTypeVariables,
- PatternGuards #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.LaTeX
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,37 +30,44 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' format into LaTeX.
-}
-module Text.Pandoc.Writers.LaTeX ( writeLaTeX ) where
+module Text.Pandoc.Writers.LaTeX (
+ writeLaTeX
+ , writeBeamer
+ ) where
+import Control.Applicative ((<|>))
+import Control.Monad.State.Strict
+import Data.Aeson (FromJSON, object, (.=))
+import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isPunctuation, ord,
+ toLower)
+import Data.List (foldl', intercalate, intersperse, isInfixOf, nubBy,
+ stripPrefix, (\\))
+import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe, isNothing)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Network.URI (unEscapeString)
+import Text.Pandoc.BCP47 (Lang (..), getLang, renderLang)
+import Text.Pandoc.Class (PandocMonad, report, toLang)
import Text.Pandoc.Definition
-import Text.Pandoc.Walk
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
+import Text.Pandoc.Highlighting (formatLaTeXBlock, formatLaTeXInline, highlight,
+ styleToLaTeX, toListingsLanguage)
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Templates
-import Text.Printf ( printf )
-import Network.URI ( isURI, unEscapeString )
-import Data.Aeson (object, (.=), FromJSON)
-import Data.List ( (\\), isInfixOf, stripPrefix, intercalate, intersperse,
- nub, nubBy, foldl' )
-import Data.Char ( toLower, isPunctuation, isAscii, isLetter, isDigit,
- ord, isAlphaNum )
-import Data.Maybe ( fromMaybe, isJust, catMaybes )
-import qualified Data.Text as T
-import Control.Applicative ((<|>))
-import Control.Monad.State
-import qualified Text.Parsec as P
import Text.Pandoc.Pretty
-import Text.Pandoc.ImageSize
+import Text.Pandoc.Shared
import Text.Pandoc.Slides
-import Text.Pandoc.Highlighting (highlight, styleToLaTeX,
- formatLaTeXInline, formatLaTeXBlock,
- toListingsLanguage)
+import Text.Pandoc.Templates
+import Text.Pandoc.Walk
+import Text.Pandoc.Writers.Shared
+import qualified Text.Parsec as P
+import Text.Printf (printf)
data WriterState =
WriterState { stInNote :: Bool -- true if we're in a note
, stInQuote :: Bool -- true if in a blockquote
, stInMinipage :: Bool -- true if in minipage
, stInHeading :: Bool -- true if in a section heading
+ , stInItem :: Bool -- true if in \item[..]
, stNotes :: [Doc] -- notes in a minipage
, stOLLevel :: Int -- level of ordered list nesting
, stOptions :: WriterOptions -- writer options, so they don't have to be parameter
@@ -74,49 +82,75 @@ data WriterState =
, stHighlighting :: Bool -- true if document has highlighted code
, stIncremental :: Bool -- true if beamer lists should be displayed bit by bit
, stInternalLinks :: [String] -- list of internal link targets
- , stUsesEuro :: Bool -- true if euro symbol used
+ , stBeamer :: Bool -- produce beamer
+ , stEmptyLine :: Bool -- true if no content on line
}
+startingState :: WriterOptions -> WriterState
+startingState options = WriterState {
+ stInNote = False
+ , stInQuote = False
+ , stInMinipage = False
+ , stInHeading = False
+ , stInItem = False
+ , stNotes = []
+ , stOLLevel = 1
+ , stOptions = options
+ , stVerbInNote = False
+ , stTable = False
+ , stStrikeout = False
+ , stUrl = False
+ , stGraphics = False
+ , stLHS = False
+ , stBook = case writerTopLevelDivision options of
+ TopLevelPart -> True
+ TopLevelChapter -> True
+ _ -> False
+ , stCsquotes = False
+ , stHighlighting = False
+ , stIncremental = writerIncremental options
+ , stInternalLinks = []
+ , stBeamer = False
+ , stEmptyLine = True }
+
-- | Convert Pandoc to LaTeX.
-writeLaTeX :: WriterOptions -> Pandoc -> String
+writeLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeLaTeX options document =
- evalState (pandocToLaTeX options document) $
- WriterState { stInNote = False, stInQuote = False,
- stInMinipage = False, stInHeading = False,
- stNotes = [], stOLLevel = 1,
- stOptions = options, stVerbInNote = False,
- stTable = False, stStrikeout = False,
- stUrl = False, stGraphics = False,
- stLHS = False,
- stBook = (case writerTopLevelDivision options of
- TopLevelPart -> True
- TopLevelChapter -> True
- _ -> False),
- stCsquotes = False, stHighlighting = False,
- stIncremental = writerIncremental options,
- stInternalLinks = [], stUsesEuro = False }
-
-pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState String
+ evalStateT (pandocToLaTeX options document) $
+ startingState options
+
+-- | Convert Pandoc to LaTeX Beamer.
+writeBeamer :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeBeamer options document =
+ evalStateT (pandocToLaTeX options document) $
+ (startingState options){ stBeamer = True }
+
+type LW m = StateT WriterState m
+
+pandocToLaTeX :: PandocMonad m
+ => WriterOptions -> Pandoc -> LW m Text
pandocToLaTeX options (Pandoc meta blocks) = do
-- Strip off final 'references' header if --natbib or --biblatex
let method = writerCiteMethod options
let blocks' = if method == Biblatex || method == Natbib
then case reverse blocks of
- (Div (_,["references"],_) _):xs -> reverse xs
- _ -> blocks
+ Div (_,["references"],_) _:xs -> reverse xs
+ _ -> blocks
else blocks
-- see if there are internal links
- let isInternalLink (Link _ _ ('#':xs,_)) = [xs]
- isInternalLink _ = []
+ let isInternalLink (Link _ _ ('#':xs,_)) = [xs]
+ isInternalLink _ = []
modify $ \s -> s{ stInternalLinks = query isInternalLink blocks' }
- let template = maybe "" id $ writerTemplate options
+ let template = fromMaybe "" $ writerTemplate options
-- set stBook depending on documentclass
let colwidth = if writerWrapText options == WrapAuto
then Just $ writerColumns options
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON options
- (fmap (render colwidth) . blockListToLaTeX)
- (fmap (render colwidth) . inlineListToLaTeX)
+ (fmap render' . blockListToLaTeX)
+ (fmap render' . inlineListToLaTeX)
meta
let bookClasses = ["memoir","book","report","scrreprt","scrbook"]
let documentClass = case P.parse pDocumentClass "template" template of
@@ -143,25 +177,38 @@ pandocToLaTeX options (Pandoc meta blocks) = do
else case last blocks' of
Header 1 _ il -> (init blocks', il)
_ -> (blocks', [])
- blocks''' <- if writerBeamer options
+ beamer <- gets stBeamer
+ blocks''' <- if beamer
then toSlides blocks''
else return blocks''
body <- mapM (elementToLaTeX options) $ hierarchicalize blocks'''
- (biblioTitle :: String) <- liftM (render colwidth) $ inlineListToLaTeX lastHeader
- let main = render colwidth $ vsep body
+ (biblioTitle :: Text) <- render' <$> inlineListToLaTeX lastHeader
+ let main = render' $ vsep body
st <- get
titleMeta <- stringToLaTeX TextString $ stringify $ docTitle meta
authorsMeta <- mapM (stringToLaTeX TextString . stringify) $ docAuthors meta
- let docLangs = nub $ query (extract "lang") blocks
+ docLangs <- catMaybes <$>
+ mapM (toLang . Just) (ordNub (query (extract "lang") blocks))
let hasStringValue x = isJust (getField x metadata :: Maybe String)
- let geometryFromMargins = intercalate [','] $ catMaybes $
- map (\(x,y) ->
+ let geometryFromMargins = intercalate [','] $ mapMaybe (\(x,y) ->
((x ++ "=") ++) <$> getField y metadata)
[("lmargin","margin-left")
,("rmargin","margin-right")
,("tmargin","margin-top")
,("bmargin","margin-bottom")
]
+ let toPolyObj lang = object [ "name" .= T.pack name
+ , "options" .= T.pack opts ]
+ where
+ (name, opts) = toPolyglossia lang
+ mblang <- toLang $ case getLang options meta of
+ Just l -> Just l
+ Nothing | null docLangs -> Nothing
+ | otherwise -> Just "en"
+ -- we need a default here since lang is used in template conditionals
+
+ let dirs = query (extract "dir") blocks
+
let context = defField "toc" (writerTableOfContents options) $
defField "toc-depth" (show (writerTOCDepth options -
if stBook st
@@ -170,7 +217,7 @@ pandocToLaTeX options (Pandoc meta blocks) = do
defField "body" main $
defField "title-meta" titleMeta $
defField "author-meta" (intercalate "; " authorsMeta) $
- defField "documentclass" (if writerBeamer options
+ defField "documentclass" (if beamer
then ("beamer" :: String)
else if stBook st
then "book"
@@ -183,12 +230,14 @@ pandocToLaTeX options (Pandoc meta blocks) = do
defField "lhs" (stLHS st) $
defField "graphics" (stGraphics st) $
defField "book-class" (stBook st) $
- defField "euro" (stUsesEuro st) $
defField "listings" (writerListings options || stLHS st) $
- defField "beamer" (writerBeamer options) $
+ defField "beamer" beamer $
(if stHighlighting st
- then defField "highlighting-macros" (styleToLaTeX
- $ writerHighlightStyle options )
+ then case writerHighlightStyle options of
+ Just sty ->
+ defField "highlighting-macros"
+ (styleToLaTeX sty)
+ Nothing -> id
else id) $
(case writerCiteMethod options of
Natbib -> defField "biblio-title" biblioTitle .
@@ -196,26 +245,26 @@ pandocToLaTeX options (Pandoc meta blocks) = do
Biblatex -> defField "biblio-title" biblioTitle .
defField "biblatex" True
_ -> id) $
- -- set lang to something so polyglossia/babel is included
- defField "lang" (if null docLangs then ""::String else "en") $
- defField "otherlangs" docLangs $
defField "colorlinks" (any hasStringValue
["citecolor", "urlcolor", "linkcolor", "toccolor"]) $
- defField "dir" (if (null $ query (extract "dir") blocks)
- then ""::String
- else "ltr") $
+ (if null dirs
+ then id
+ else defField "dir" ("ltr" :: String)) $
defField "section-titles" True $
defField "geometry" geometryFromMargins $
+ (case getField "papersize" metadata of
+ -- uppercase a4, a5, etc.
+ Just (('A':d:ds) :: String)
+ | all isDigit (d:ds) -> resetField "papersize"
+ (('a':d:ds) :: String)
+ _ -> id)
metadata
- let toPolyObj lang = object [ "name" .= T.pack name
- , "options" .= T.pack opts ]
- where
- (name, opts) = toPolyglossia lang
- let lang = maybe [] (splitBy (=='-')) $ getField "lang" context
- otherlangs = maybe [] (map $ splitBy (=='-')) $ getField "otherlangs" context
let context' =
- defField "babel-lang" (toBabel lang)
- $ defField "babel-otherlangs" (map toBabel otherlangs)
+ -- note: lang is used in some conditionals in the template,
+ -- so we need to set it if we have any babel/polyglossia:
+ maybe id (defField "lang" . renderLang) mblang
+ $ maybe id (defField "babel-lang" . toBabel) mblang
+ $ defField "babel-otherlangs" (map toBabel docLangs)
$ defField "babel-newcommands" (concatMap (\(poly, babel) ->
-- \textspanish and \textgalician are already used by babel
-- save them as \oritext... and let babel use that
@@ -227,31 +276,30 @@ pandocToLaTeX options (Pandoc meta blocks) = do
"\\AddBabelHook{" ++ poly ++ "}{afterextras}" ++
"{\\renewcommand{\\text" ++ poly ++ "}[2][]{\\foreignlanguage{"
++ poly ++ "}{##2}}}\n"
- else "\\newcommand{\\text" ++ poly ++ "}[2][]{\\foreignlanguage{"
- ++ babel ++ "}{#2}}\n" ++
- "\\newenvironment{" ++ poly ++ "}[2][]{\\begin{otherlanguage}{"
- ++ babel ++ "}}{\\end{otherlanguage}}\n"
+ else (if poly == "latin" -- see #4161
+ then "\\providecommand{\\textlatin}{}\n\\renewcommand"
+ else "\\newcommand") ++ "{\\text" ++ poly ++
+ "}[2][]{\\foreignlanguage{" ++ babel ++ "}{#2}}\n" ++
+ "\\newenvironment{" ++ poly ++
+ "}[2][]{\\begin{otherlanguage}{" ++
+ babel ++ "}}{\\end{otherlanguage}}\n"
)
-- eliminate duplicates that have same polyglossia name
$ nubBy (\a b -> fst a == fst b)
-- find polyglossia and babel names of languages used in the document
- $ map (\l ->
- let lng = splitBy (=='-') l
- in (fst $ toPolyglossia lng, toBabel lng)
- )
- docLangs )
- $ defField "polyglossia-lang" (toPolyObj lang)
- $ defField "polyglossia-otherlangs" (map toPolyObj otherlangs)
- $ defField "latex-dir-rtl" (case (getField "dir" context)::Maybe String of
- Just "rtl" -> True
- _ -> False)
- $ context
- return $ case writerTemplate options of
- Nothing -> main
- Just tpl -> renderTemplate' tpl context'
+ $ map (\l -> (fst $ toPolyglossia l, toBabel l)) docLangs
+ )
+ $ maybe id (defField "polyglossia-lang" . toPolyObj) mblang
+ $ defField "polyglossia-otherlangs" (map toPolyObj docLangs)
+ $
+ defField "latex-dir-rtl"
+ (getField "dir" context == Just ("rtl" :: String)) context
+ case writerTemplate options of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context'
-- | Convert Elements to LaTeX
-elementToLaTeX :: WriterOptions -> Element -> State WriterState Doc
+elementToLaTeX :: PandocMonad m => WriterOptions -> Element -> LW m Doc
elementToLaTeX _ (Blk block) = blockToLaTeX block
elementToLaTeX opts (Sec level _ (id',classes,_) title' elements) = do
modify $ \s -> s{stInHeading = True}
@@ -266,18 +314,15 @@ data StringContext = TextString
deriving (Eq)
-- escape things as needed for LaTeX
-stringToLaTeX :: StringContext -> String -> State WriterState String
+stringToLaTeX :: PandocMonad m => StringContext -> String -> LW m String
stringToLaTeX _ [] = return ""
stringToLaTeX ctx (x:xs) = do
opts <- gets stOptions
rest <- stringToLaTeX ctx xs
- let ligatures = writerTeXLigatures opts && ctx == TextString
+ let ligatures = isEnabled Ext_smart opts && ctx == TextString
let isUrl = ctx == URLString
- when (x == '€') $
- modify $ \st -> st{ stUsesEuro = True }
return $
case x of
- '€' -> "\\euro{}" ++ rest
'{' -> "\\{" ++ rest
'}' -> "\\}" ++ rest
'`' | ctx == CodeString -> "\\textasciigrave{}" ++ rest
@@ -311,26 +356,30 @@ stringToLaTeX ctx (x:xs) = do
'\x2013' | ligatures -> "--" ++ rest
_ -> x : rest
-toLabel :: String -> State WriterState String
+toLabel :: PandocMonad m => String -> LW m String
toLabel z = go `fmap` stringToLaTeX URLString z
where go [] = ""
go (x:xs)
| (isLetter x || isDigit x) && isAscii x = x:go xs
- | elem x ("_-+=:;." :: String) = x:go xs
+ | x `elem` ("_-+=:;." :: String) = x:go xs
| otherwise = "ux" ++ printf "%x" (ord x) ++ go xs
-- | Puts contents into LaTeX command.
inCmd :: String -> Doc -> Doc
inCmd cmd contents = char '\\' <> text cmd <> braces contents
-toSlides :: [Block] -> State WriterState [Block]
+toSlides :: PandocMonad m => [Block] -> LW m [Block]
toSlides bs = do
opts <- gets stOptions
let slideLevel = fromMaybe (getSlideLevel bs) $ writerSlideLevel opts
let bs' = prepSlides slideLevel bs
- concat `fmap` (mapM (elementToBeamer slideLevel) $ hierarchicalize bs')
+ concat `fmap` mapM (elementToBeamer slideLevel) (hierarchicalize bs')
-elementToBeamer :: Int -> Element -> State WriterState [Block]
+elementToBeamer :: PandocMonad m => Int -> Element -> LW m [Block]
+elementToBeamer _slideLevel (Blk (Div attr bs)) = do
+ -- make sure we support "blocks" inside divs
+ bs' <- concat `fmap` mapM (elementToBeamer 0) (hierarchicalize bs)
+ return [Div attr bs']
elementToBeamer _slideLevel (Blk b) = return [b]
elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts)
| lvl > slideLevel = do
@@ -340,7 +389,7 @@ elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts)
: bs ++ [RawBlock "latex" "\\end{block}"]
| lvl < slideLevel = do
bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts
- return $ (Header lvl (ident,classes,kvs) tit) : bs
+ return $ Header lvl (ident,classes,kvs) tit : bs
| otherwise = do -- lvl == slideLevel
-- note: [fragile] is required or verbatim breaks
let hasCodeBlock (CodeBlock _ _) = [True]
@@ -349,19 +398,28 @@ elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts)
hasCode _ = []
let fragile = "fragile" `elem` classes ||
not (null $ query hasCodeBlock elts ++ query hasCode elts)
- let frameoptions = ["allowdisplaybreaks", "allowframebreaks",
+ let frameoptions = ["allowdisplaybreaks", "allowframebreaks", "fragile",
"b", "c", "t", "environment",
"label", "plain", "shrink", "standout"]
- let optionslist = ["fragile" | fragile] ++
+ let optionslist = ["fragile" | fragile && isNothing (lookup "fragile" kvs)] ++
[k | k <- classes, k `elem` frameoptions] ++
[k ++ "=" ++ v | (k,v) <- kvs, k `elem` frameoptions]
let options = if null optionslist
then ""
else "[" ++ intercalate "," optionslist ++ "]"
- let slideStart = Para $ RawInline "latex" ("\\begin{frame}" ++ options) :
- if tit == [Str "\0"] -- marker for hrule
- then []
- else (RawInline "latex" "{") : tit ++ [RawInline "latex" "}"]
+ let latex = RawInline (Format "latex")
+ slideTitle <-
+ if tit == [Str "\0"] -- marker for hrule
+ then return []
+ else
+ if null ident
+ then return $ latex "{" : tit ++ [latex "}"]
+ else do
+ ref <- toLabel ident
+ return $ latex ("{%\n\\protect\\hypertarget{" ++
+ ref ++ "}{%\n") : tit ++ [latex "}}"]
+ let slideStart = Para $
+ RawInline "latex" ("\\begin{frame}" ++ options) : slideTitle
let slideEnd = RawBlock "latex" "\\end{frame}"
-- now carve up slide into blocks if there are sections inside
bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts
@@ -376,43 +434,89 @@ isListBlock _ = False
isLineBreakOrSpace :: Inline -> Bool
isLineBreakOrSpace LineBreak = True
isLineBreakOrSpace SoftBreak = True
-isLineBreakOrSpace Space = True
-isLineBreakOrSpace _ = False
+isLineBreakOrSpace Space = True
+isLineBreakOrSpace _ = False
-- | Convert Pandoc block element to LaTeX.
-blockToLaTeX :: Block -- ^ Block to convert
- -> State WriterState Doc
+blockToLaTeX :: PandocMonad m
+ => Block -- ^ Block to convert
+ -> LW m Doc
blockToLaTeX Null = return empty
-blockToLaTeX (Div (identifier,classes,kvs) bs) = do
- beamer <- writerBeamer `fmap` gets stOptions
- ref <- toLabel identifier
- let linkAnchor = if null identifier
- then empty
- else "\\hypertarget" <> braces (text ref) <>
- braces empty
- let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
- let wrapDir = case lookup "dir" kvs of
- Just "rtl" -> align "RTL"
- Just "ltr" -> align "LTR"
- _ -> id
- wrapLang txt = case lookup "lang" kvs of
- Just lng -> let (l, o) = toPolyglossiaEnv lng
- ops = if null o
- then ""
- else brackets $ text o
- in inCmd "begin" (text l) <> ops
- $$ blankline <> txt <> blankline
- $$ inCmd "end" (text l)
- Nothing -> txt
- wrapNotes txt = if beamer && "notes" `elem` classes
+blockToLaTeX (Div (identifier,classes,kvs) bs)
+ | "incremental" `elem` classes = do
+ let classes' = filter ("incremental"/=) classes
+ beamer <- gets stBeamer
+ if beamer
+ then do oldIncremental <- gets stIncremental
+ modify $ \s -> s{ stIncremental = True }
+ result <- blockToLaTeX $ Div (identifier,classes',kvs) bs
+ modify $ \s -> s{ stIncremental = oldIncremental }
+ return result
+ else blockToLaTeX $ Div (identifier,classes',kvs) bs
+ | "nonincremental" `elem` classes = do
+ let classes' = filter ("nonincremental"/=) classes
+ beamer <- gets stBeamer
+ if beamer
+ then do oldIncremental <- gets stIncremental
+ modify $ \s -> s{ stIncremental = False }
+ result <- blockToLaTeX $ Div (identifier,classes',kvs) bs
+ modify $ \s -> s{ stIncremental = oldIncremental }
+ return result
+ else blockToLaTeX $ Div (identifier,classes',kvs) bs
+ | otherwise = do
+ beamer <- gets stBeamer
+ linkAnchor' <- hypertarget True identifier empty
+ -- see #2704 for the motivation for adding \leavevmode:
+ let linkAnchor =
+ case bs of
+ Para _ : _
+ | not (isEmpty linkAnchor')
+ -> "\\leavevmode" <> linkAnchor' <> "%"
+ _ -> linkAnchor'
+ let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
+ lang <- toLang $ lookup "lang" kvs
+ let wrapColumns = if "columns" `elem` classes
+ then \contents ->
+ inCmd "begin" "columns" <> brackets "T"
+ $$ contents
+ $$ inCmd "end" "columns"
+ else id
+ wrapColumn = if "column" `elem` classes
+ then \contents ->
+ let fromPct xs =
+ case reverse xs of
+ '%':ds -> '0':'.': reverse ds
+ _ -> xs
+ w = maybe "0.48" fromPct (lookup "width" kvs)
+ in inCmd "begin" "column" <>
+ braces (text w <> "\\textwidth")
+ $$ contents
+ $$ inCmd "end" "column"
+ else id
+ wrapDir = case lookup "dir" kvs of
+ Just "rtl" -> align "RTL"
+ Just "ltr" -> align "LTR"
+ _ -> id
+ wrapLang txt = case lang of
+ Just lng -> let (l, o) = toPolyglossiaEnv lng
+ ops = if null o
+ then ""
+ else brackets $ text o
+ in inCmd "begin" (text l) <> ops
+ $$ blankline <> txt <> blankline
+ $$ inCmd "end" (text l)
+ Nothing -> txt
+ wrapNotes txt = if beamer && "notes" `elem` classes
then "\\note" <> braces txt -- speaker notes
else linkAnchor $$ txt
- fmap (wrapDir . wrapLang . wrapNotes) $ blockListToLaTeX bs
+ (wrapColumns . wrapColumn . wrapDir . wrapLang . wrapNotes)
+ <$> blockListToLaTeX bs
blockToLaTeX (Plain lst) =
inlineListToLaTeX $ dropWhile isLineBreakOrSpace lst
-- title beginning with fig: indicates that the image is a figure
blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,'f':'i':'g':':':tit)]) = do
inNote <- gets stInNote
+ inMinipage <- gets stInMinipage
modify $ \st -> st{ stInMinipage = True, stNotes = [] }
capt <- inlineListToLaTeX txt
notes <- gets stNotes
@@ -426,25 +530,26 @@ blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,'f':'i':'g':':':tit)]) = d
let footnotes = notesToLaTeX notes
lab <- labelFor ident
let caption = "\\caption" <> captForLof <> braces capt <> lab
- figure <- hypertarget ident (cr <>
- "\\begin{figure}" $$ "\\centering" $$ img $$
- caption $$ "\\end{figure}" <> cr)
- return $ if inNote
- -- can't have figures in notes
+ innards <- hypertarget True ident $
+ "\\centering" $$ img $$ caption <> cr
+ let figure = cr <> "\\begin{figure}" $$ innards $$ "\\end{figure}"
+ return $ if inNote || inMinipage
+ -- can't have figures in notes or minipage (here, table cell)
+ -- http://www.tex.ac.uk/FAQ-ouparmd.html
then "\\begin{center}" $$ img $+$ capt $$ "\\end{center}"
else figure $$ footnotes
-- . . . indicates pause in beamer slides
blockToLaTeX (Para [Str ".",Space,Str ".",Space,Str "."]) = do
- beamer <- writerBeamer `fmap` gets stOptions
+ beamer <- gets stBeamer
if beamer
then blockToLaTeX (RawBlock "latex" "\\pause")
else inlineListToLaTeX [Str ".",Space,Str ".",Space,Str "."]
blockToLaTeX (Para lst) =
inlineListToLaTeX $ dropWhile isLineBreakOrSpace lst
-blockToLaTeX (LineBlock lns) = do
+blockToLaTeX (LineBlock lns) =
blockToLaTeX $ linesToPara lns
blockToLaTeX (BlockQuote lst) = do
- beamer <- writerBeamer `fmap` gets stOptions
+ beamer <- gets stBeamer
case lst of
[b] | beamer && isListBlock b -> do
oldIncremental <- gets stIncremental
@@ -460,11 +565,11 @@ blockToLaTeX (BlockQuote lst) = do
return $ "\\begin{quote}" $$ contents $$ "\\end{quote}"
blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do
opts <- gets stOptions
- ref <- toLabel identifier
- let linkAnchor = if null identifier
+ lab <- labelFor identifier
+ linkAnchor' <- hypertarget True identifier lab
+ let linkAnchor = if isEmpty linkAnchor'
then empty
- else "\\hypertarget" <> braces (text ref) <>
- braces ("\\label" <> braces (text ref))
+ else linkAnchor' <> "%"
let lhsCodeBlock = do
modify $ \s -> s{ stLHS = True }
return $ flush (linkAnchor $$ "\\begin{code}" $$ text str $$
@@ -479,6 +584,7 @@ blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do
text str $$ text ("\\end{" ++ env ++ "}")) <> cr
let listingsCodeBlock = do
st <- get
+ ref <- toLabel identifier
let params = if writerListings (stOptions st)
then (case getListingsLanguage classes of
Just l -> [ "language=" ++ mbBraced l ]
@@ -495,9 +601,6 @@ blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do
else [ "label=" ++ ref ])
else []
- mbBraced x = if not (all isAlphaNum x)
- then "{" <> x <> "}"
- else x
printParams
| null params = empty
| otherwise = brackets $ hcat (intersperse ", "
@@ -505,24 +608,34 @@ blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do
return $ flush ("\\begin{lstlisting}" <> printParams $$ text str $$
"\\end{lstlisting}") $$ cr
let highlightedCodeBlock =
- case highlight formatLaTeXBlock ("",classes,keyvalAttr) str of
- Nothing -> rawCodeBlock
- Just h -> modify (\st -> st{ stHighlighting = True }) >>
- return (flush $ linkAnchor $$ text (T.unpack h))
+ case highlight (writerSyntaxMap opts)
+ formatLaTeXBlock ("",classes,keyvalAttr) str of
+ Left msg -> do
+ unless (null msg) $
+ report $ CouldNotHighlight msg
+ rawCodeBlock
+ Right h -> do
+ st <- get
+ when (stInNote st) $ modify (\s -> s{ stVerbInNote = True })
+ modify (\s -> s{ stHighlighting = True })
+ return (flush $ linkAnchor $$ text (T.unpack h))
case () of
_ | isEnabled Ext_literate_haskell opts && "haskell" `elem` classes &&
- "literate" `elem` classes -> lhsCodeBlock
- | writerListings opts -> listingsCodeBlock
- | writerHighlight opts && not (null classes) -> highlightedCodeBlock
- | otherwise -> rawCodeBlock
-blockToLaTeX (RawBlock f x)
+ "literate" `elem` classes -> lhsCodeBlock
+ | writerListings opts -> listingsCodeBlock
+ | not (null classes) && isJust (writerHighlightStyle opts)
+ -> highlightedCodeBlock
+ | otherwise -> rawCodeBlock
+blockToLaTeX b@(RawBlock f x)
| f == Format "latex" || f == Format "tex"
= return $ text x
- | otherwise = return empty
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
blockToLaTeX (BulletList []) = return empty -- otherwise latex error
blockToLaTeX (BulletList lst) = do
incremental <- gets stIncremental
- beamer <- writerBeamer `fmap` gets stOptions
+ beamer <- gets stBeamer
let inc = if beamer && incremental then "[<+->]" else ""
items <- mapM listItemToLaTeX lst
let spacing = if isTightList lst
@@ -538,6 +651,7 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
put $ st {stOLLevel = oldlevel + 1}
items <- mapM listItemToLaTeX lst
modify (\s -> s {stOLLevel = oldlevel})
+ let beamer = stBeamer st
let tostyle x = case numstyle of
Decimal -> "\\arabic" <> braces x
UpperRoman -> "\\Roman" <> braces x
@@ -547,15 +661,24 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
Example -> "\\arabic" <> braces x
DefaultStyle -> "\\arabic" <> braces x
let todelim x = case numdelim of
- OneParen -> x <> ")"
- TwoParens -> parens x
- Period -> x <> "."
- _ -> x <> "."
+ OneParen -> x <> ")"
+ TwoParens -> parens x
+ Period -> x <> "."
+ _ -> x <> "."
+ let exemplar = case numstyle of
+ Decimal -> "1"
+ UpperRoman -> "I"
+ LowerRoman -> "i"
+ UpperAlpha -> "A"
+ LowerAlpha -> "a"
+ Example -> "1"
+ DefaultStyle -> "1"
let enum = text $ "enum" ++ map toLower (toRomanNumeral oldlevel)
- let stylecommand = if numstyle == DefaultStyle && numdelim == DefaultDelim
- then empty
- else "\\def" <> "\\label" <> enum <>
- braces (todelim $ tostyle enum)
+ let stylecommand
+ | numstyle == DefaultStyle && numdelim == DefaultDelim = empty
+ | beamer = brackets (todelim exemplar)
+ | otherwise = "\\def" <> "\\label" <> enum <>
+ braces (todelim $ tostyle enum)
let resetcounter = if start == 1 || oldlevel > 4
then empty
else "\\setcounter" <> braces enum <>
@@ -579,7 +702,8 @@ blockToLaTeX (DefinitionList lst) = do
else empty
return $ text ("\\begin{description}" ++ inc) $$ spacing $$ vcat items $$
"\\end{description}"
-blockToLaTeX HorizontalRule = return $
+blockToLaTeX HorizontalRule =
+ return
"\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}"
blockToLaTeX (Header level (id',classes,_) lst) = do
modify $ \s -> s{stInHeading = True}
@@ -587,33 +711,34 @@ blockToLaTeX (Header level (id',classes,_) lst) = do
modify $ \s -> s{stInHeading = False}
return hdr
blockToLaTeX (Table caption aligns widths heads rows) = do
- headers <- if all null heads
- then return empty
- else do
- contents <- (tableRowToLaTeX True aligns widths) heads
- return ("\\toprule" $$ contents $$ "\\midrule")
- let endhead = if all null heads
- then empty
- else text "\\endhead"
- let endfirsthead = if all null heads
- then empty
- else text "\\endfirsthead"
+ let toHeaders hs = do contents <- tableRowToLaTeX True aligns widths hs
+ return ("\\toprule" $$ contents $$ "\\midrule")
+ let removeNote (Note _) = Span ("", [], []) []
+ removeNote x = x
captionText <- inlineListToLaTeX caption
+ firsthead <- if isEmpty captionText || all null heads
+ then return empty
+ else ($$ text "\\endfirsthead") <$> toHeaders heads
+ head' <- if all null heads
+ then return "\\toprule"
+ -- avoid duplicate notes in head and firsthead:
+ else toHeaders (if isEmpty firsthead
+ then heads
+ else walk removeNote heads)
let capt = if isEmpty captionText
then empty
- else text "\\caption" <> braces captionText <> "\\tabularnewline"
- $$ headers
- $$ endfirsthead
+ else text "\\caption" <>
+ braces captionText <> "\\tabularnewline"
rows' <- mapM (tableRowToLaTeX False aligns widths) rows
- let colDescriptors = text $ concat $ map toColDescriptor aligns
+ let colDescriptors = text $ concatMap toColDescriptor aligns
modify $ \s -> s{ stTable = True }
return $ "\\begin{longtable}[]" <>
braces ("@{}" <> colDescriptors <> "@{}")
-- the @{} removes extra space at beginning and end
$$ capt
- $$ (if all null heads then "\\toprule" else empty)
- $$ headers
- $$ endhead
+ $$ firsthead
+ $$ head'
+ $$ "\\endhead"
$$ vcat rows'
$$ "\\bottomrule"
$$ "\\end{longtable}"
@@ -626,14 +751,16 @@ toColDescriptor align =
AlignCenter -> "c"
AlignDefault -> "l"
-blockListToLaTeX :: [Block] -> State WriterState Doc
-blockListToLaTeX lst = vsep `fmap` mapM blockToLaTeX lst
+blockListToLaTeX :: PandocMonad m => [Block] -> LW m Doc
+blockListToLaTeX lst =
+ vsep `fmap` mapM (\b -> setEmptyLine True >> blockToLaTeX b) lst
-tableRowToLaTeX :: Bool
+tableRowToLaTeX :: PandocMonad m
+ => Bool
-> [Alignment]
-> [Double]
-> [[Block]]
- -> State WriterState Doc
+ -> LW m Doc
tableRowToLaTeX header aligns widths cols = do
-- scale factor compensates for extra space between columns
-- so the whole table isn't larger than columnwidth
@@ -643,9 +770,9 @@ tableRowToLaTeX header aligns widths cols = do
isSimple [] = True
isSimple _ = False
-- simple tables have to have simple cells:
- let widths' = if not (all isSimple cols)
+ let widths' = if all (== 0) widths && not (all isSimple cols)
then replicate (length aligns)
- (0.97 / fromIntegral (length aligns))
+ (scaleFactor / fromIntegral (length aligns))
else map (scaleFactor *) widths
cells <- mapM (tableCellToLaTeX header) $ zip3 widths' aligns cols
return $ hsep (intersperse "&" cells) <> "\\tabularnewline"
@@ -672,10 +799,10 @@ fixLineBreaks' ils = case splitBy (== LineBreak) ils of
-- math breaks in simple tables.
displayMathToInline :: Inline -> Inline
displayMathToInline (Math DisplayMath x) = Math InlineMath x
-displayMathToInline x = x
+displayMathToInline x = x
-tableCellToLaTeX :: Bool -> (Double, Alignment, [Block])
- -> State WriterState Doc
+tableCellToLaTeX :: PandocMonad m => Bool -> (Double, Alignment, [Block])
+ -> LW m Doc
tableCellToLaTeX _ (0, _, blocks) =
blockListToLaTeX $ walk fixLineBreaks $ walk displayMathToInline blocks
tableCellToLaTeX header (width, align, blocks) = do
@@ -691,7 +818,7 @@ tableCellToLaTeX header (width, align, blocks) = do
AlignDefault -> "\\raggedright"
return $ ("\\begin{minipage}" <> valign <>
braces (text (printf "%.2f\\columnwidth" width)) <>
- (halign <> "\\strut" <> cr <> cellContents <> "\\strut" <> cr) <>
+ (halign <> cr <> cellContents <> "\\strut" <> cr) <>
"\\end{minipage}") $$
notesToLaTeX notes
@@ -708,19 +835,22 @@ notesToLaTeX ns = (case length ns of
$ map (\x -> "\\footnotetext" <> braces x)
$ reverse ns)
-listItemToLaTeX :: [Block] -> State WriterState Doc
+listItemToLaTeX :: PandocMonad m => [Block] -> LW m Doc
listItemToLaTeX lst
-- we need to put some text before a header if it's the first
-- element in an item. This will look ugly in LaTeX regardless, but
-- this will keep the typesetter from throwing an error.
- | ((Header _ _ _) :_) <- lst =
- blockListToLaTeX lst >>= return . (text "\\item ~" $$) . (nest 2)
+ | (Header{} :_) <- lst =
+ blockListToLaTeX lst >>= return . (text "\\item ~" $$) . nest 2
| otherwise = blockListToLaTeX lst >>= return . (text "\\item" $$) .
- (nest 2)
+ nest 2
-defListItemToLaTeX :: ([Inline], [[Block]]) -> State WriterState Doc
+defListItemToLaTeX :: PandocMonad m => ([Inline], [[Block]]) -> LW m Doc
defListItemToLaTeX (term, defs) = do
+ -- needed to turn off 'listings' because it breaks inside \item[...]:
+ modify $ \s -> s{stInItem = True}
term' <- inlineListToLaTeX term
+ modify $ \s -> s{stInItem = False}
-- put braces around term if it contains an internal link,
-- since otherwise we get bad bracket interactions: \item[\hyperref[..]
let isInternalLink (Link _ _ ('#':_,_)) = True
@@ -730,32 +860,33 @@ defListItemToLaTeX (term, defs) = do
else term'
def' <- liftM vsep $ mapM blockListToLaTeX defs
return $ case defs of
- (((Header _ _ _) : _) : _) ->
+ ((Header{} : _) : _) ->
"\\item" <> brackets term'' <> " ~ " $$ def'
_ ->
"\\item" <> brackets term'' $$ def'
-- | Craft the section header, inserting the secton reference, if supplied.
-sectionHeader :: Bool -- True for unnumbered
+sectionHeader :: PandocMonad m
+ => Bool -- True for unnumbered
-> [Char]
-> Int
-> [Inline]
- -> State WriterState Doc
+ -> LW m Doc
sectionHeader unnumbered ident level lst = do
txt <- inlineListToLaTeX lst
plain <- stringToLaTeX TextString $ concatMap stringify lst
- let removeInvalidInline (Note _) = []
+ let removeInvalidInline (Note _) = []
removeInvalidInline (Span (id', _, _) _) | not (null id') = []
- removeInvalidInline (Image _ _ _) = []
- removeInvalidInline x = [x]
+ removeInvalidInline Image{} = []
+ removeInvalidInline x = [x]
let lstNoNotes = foldr (mappend . (\x -> walkM removeInvalidInline x)) mempty lst
txtNoNotes <- inlineListToLaTeX lstNoNotes
-- footnotes in sections don't work (except for starred variants)
-- unless you specify an optional argument:
-- \section[mysec]{mysec\footnote{blah}}
- optional <- if unnumbered || lstNoNotes == lst || lstNoNotes == []
+ optional <- if unnumbered || lstNoNotes == lst || null lstNoNotes
then return empty
- else do
+ else
return $ brackets txtNoNotes
let contents = if render Nothing txt == plain
then braces txt
@@ -767,7 +898,8 @@ sectionHeader unnumbered ident level lst = do
let topLevelDivision = if book && writerTopLevelDivision opts == TopLevelDefault
then TopLevelChapter
else writerTopLevelDivision opts
- let level' = if writerBeamer opts &&
+ beamer <- gets stBeamer
+ let level' = if beamer &&
topLevelDivision `elem` [TopLevelPart, TopLevelChapter]
-- beamer has parts but no chapters
then if level == 1 then -1 else level - 1
@@ -794,7 +926,8 @@ sectionHeader unnumbered ident level lst = do
lab <- labelFor ident
let star = if unnumbered && level' < 4 then text "*" else empty
let stuffing = star <> optional <> contents
- stuffing' <- hypertarget ident $ text ('\\':sectionType) <> stuffing <> lab
+ stuffing' <- hypertarget True ident $
+ text ('\\':sectionType) <> stuffing <> lab
return $ if level' > 5
then txt
else prefix $$ stuffing'
@@ -804,28 +937,28 @@ sectionHeader unnumbered ident level lst = do
braces txtNoNotes
else empty
-hypertarget :: String -> Doc -> State WriterState Doc
-hypertarget ident x = do
+hypertarget :: PandocMonad m => Bool -> String -> Doc -> LW m Doc
+hypertarget _ "" x = return x
+hypertarget addnewline ident x = do
ref <- text `fmap` toLabel ident
- internalLinks <- gets stInternalLinks
- return $
- if ident `elem` internalLinks
- then text "\\hypertarget"
+ return $ text "\\hypertarget"
<> braces ref
- <> braces x
- else x
+ <> braces ((if addnewline && not (isEmpty x)
+ then ("%" <> cr)
+ else empty) <> x)
-labelFor :: String -> State WriterState Doc
+labelFor :: PandocMonad m => String -> LW m Doc
labelFor "" = return empty
labelFor ident = do
ref <- text `fmap` toLabel ident
return $ text "\\label" <> braces ref
-- | Convert list of inline elements to LaTeX.
-inlineListToLaTeX :: [Inline] -- ^ Inlines to convert
- -> State WriterState Doc
+inlineListToLaTeX :: PandocMonad m
+ => [Inline] -- ^ Inlines to convert
+ -> LW m Doc
inlineListToLaTeX lst =
- mapM inlineToLaTeX (fixBreaks $ fixLineInitialSpaces lst)
+ mapM inlineToLaTeX (fixLineInitialSpaces lst)
>>= return . hcat
-- nonbreaking spaces (~) in LaTeX don't work after line breaks,
-- so we turn nbsps after hard breaks to \hspace commands.
@@ -837,43 +970,35 @@ inlineListToLaTeX lst =
fixNbsps s = let (ys,zs) = span (=='\160') s
in replicate (length ys) hspace ++ [Str zs]
hspace = RawInline "latex" "\\hspace*{0.333em}"
- -- linebreaks after blank lines cause problems:
- fixBreaks [] = []
- fixBreaks ys@(LineBreak : LineBreak : _) =
- case span (== LineBreak) ys of
- (lbs, rest) -> RawInline "latex"
- ("\\\\[" ++ show (length lbs) ++
- "\\baselineskip]") : fixBreaks rest
- fixBreaks (y:ys) = y : fixBreaks ys
isQuoted :: Inline -> Bool
isQuoted (Quoted _ _) = True
-isQuoted _ = False
+isQuoted _ = False
-- | Convert inline element to LaTeX
-inlineToLaTeX :: Inline -- ^ Inline to convert
- -> State WriterState Doc
+inlineToLaTeX :: PandocMonad m
+ => Inline -- ^ Inline to convert
+ -> LW m Doc
inlineToLaTeX (Span (id',classes,kvs) ils) = do
- ref <- toLabel id'
- let linkAnchor = if null id'
- then empty
- else "\\protect\\hypertarget" <> braces (text ref) <>
- braces empty
+ linkAnchor <- hypertarget False id' empty
+ lang <- toLang $ lookup "lang" kvs
let cmds = ["textup" | "csl-no-emph" `elem` classes] ++
["textnormal" | "csl-no-strong" `elem` classes ||
"csl-no-smallcaps" `elem` classes] ++
["RL" | ("dir", "rtl") `elem` kvs] ++
["LR" | ("dir", "ltr") `elem` kvs] ++
- (case lookup "lang" kvs of
- Just lng -> let (l, o) = toPolyglossia $ splitBy (=='-') lng
+ (case lang of
+ Just lng -> let (l, o) = toPolyglossia lng
ops = if null o then "" else ("[" ++ o ++ "]")
in ["text" ++ l ++ ops]
Nothing -> [])
contents <- inlineListToLaTeX ils
- return $ linkAnchor <>
- if null cmds
- then braces contents
- else foldr inCmd contents cmds
+ return $ (if null id'
+ then empty
+ else "\\protect" <> linkAnchor) <>
+ (if null cmds
+ then braces contents
+ else foldr inCmd contents cmds)
inlineToLaTeX (Emph lst) =
inlineListToLaTeX lst >>= return . inCmd "emph"
inlineToLaTeX (Strong lst) =
@@ -886,7 +1011,7 @@ inlineToLaTeX (Strikeout lst) = do
return $ inCmd "sout" contents
inlineToLaTeX (Superscript lst) =
inlineListToLaTeX lst >>= return . inCmd "textsuperscript"
-inlineToLaTeX (Subscript lst) = do
+inlineToLaTeX (Subscript lst) =
inlineListToLaTeX lst >>= return . inCmd "textsubscript"
inlineToLaTeX (SmallCaps lst) =
inlineListToLaTeX lst >>= return . inCmd "textsc"
@@ -901,26 +1026,39 @@ inlineToLaTeX (Cite cits lst) = do
inlineToLaTeX (Code (_,classes,_) str) = do
opts <- gets stOptions
inHeading <- gets stInHeading
+ inItem <- gets stInItem
+ let listingsCode = do
+ let listingsopt = case getListingsLanguage classes of
+ Just l -> "[language=" ++ mbBraced l ++ "]"
+ Nothing -> ""
+ inNote <- gets stInNote
+ when inNote $ modify $ \s -> s{ stVerbInNote = True }
+ let chr = case "!\"&'()*,-./:;?@_" \\ str of
+ (c:_) -> c
+ [] -> '!'
+ let str' = escapeStringUsing (backslashEscapes "\\{}%~_&") str
+ -- we always put lstinline in a dummy 'passthrough' command
+ -- (defined in the default template) so that we don't have
+ -- to change the way we escape characters depending on whether
+ -- the lstinline is inside another command. See #1629:
+ return $ text $ "\\passthrough{\\lstinline" ++ listingsopt ++ [chr] ++ str' ++ [chr] ++ "}"
+ let rawCode = liftM (text . (\s -> "\\texttt{" ++ escapeSpaces s ++ "}"))
+ $ stringToLaTeX CodeString str
+ where escapeSpaces = concatMap
+ (\c -> if c == ' ' then "\\ " else [c])
+ let highlightCode =
+ case highlight (writerSyntaxMap opts)
+ formatLaTeXInline ("",classes,[]) str of
+ Left msg -> do
+ unless (null msg) $ report $ CouldNotHighlight msg
+ rawCode
+ Right h -> modify (\st -> st{ stHighlighting = True }) >>
+ return (text (T.unpack h))
case () of
- _ | writerListings opts && not inHeading -> listingsCode
- | writerHighlight opts && not (null classes) -> highlightCode
+ _ | writerListings opts && not (inHeading || inItem) -> listingsCode
+ | isJust (writerHighlightStyle opts) && not (null classes)
+ -> highlightCode
| otherwise -> rawCode
- where listingsCode = do
- inNote <- gets stInNote
- when inNote $ modify $ \s -> s{ stVerbInNote = True }
- let chr = case "!\"&'()*,-./:;?@_" \\ str of
- (c:_) -> c
- [] -> '!'
- return $ text $ "\\lstinline" ++ [chr] ++ str ++ [chr]
- highlightCode = do
- case highlight formatLaTeXInline ("",classes,[]) str of
- Nothing -> rawCode
- Just h -> modify (\st -> st{ stHighlighting = True }) >>
- return (text (T.unpack h))
- rawCode = liftM (text . (\s -> "\\texttt{" ++ escapeSpaces s ++ "}"))
- $ stringToLaTeX CodeString str
- where
- escapeSpaces = concatMap (\c -> if c == ' ' then "\\ " else [c])
inlineToLaTeX (Quoted qt lst) = do
contents <- inlineListToLaTeX lst
csquotes <- liftM stCsquotes get
@@ -928,32 +1066,43 @@ inlineToLaTeX (Quoted qt lst) = do
if csquotes
then return $ "\\enquote" <> braces contents
else do
- let s1 = if (not (null lst)) && (isQuoted (head lst))
+ let s1 = if not (null lst) && isQuoted (head lst)
then "\\,"
else empty
- let s2 = if (not (null lst)) && (isQuoted (last lst))
+ let s2 = if not (null lst) && isQuoted (last lst)
then "\\,"
else empty
let inner = s1 <> contents <> s2
return $ case qt of
DoubleQuote ->
- if writerTeXLigatures opts
+ if isEnabled Ext_smart opts
then text "``" <> inner <> text "''"
else char '\x201C' <> inner <> char '\x201D'
SingleQuote ->
- if writerTeXLigatures opts
+ if isEnabled Ext_smart opts
then char '`' <> inner <> char '\''
else char '\x2018' <> inner <> char '\x2019'
-inlineToLaTeX (Str str) = liftM text $ stringToLaTeX TextString str
-inlineToLaTeX (Math InlineMath str) =
+inlineToLaTeX (Str str) = do
+ setEmptyLine False
+ liftM text $ stringToLaTeX TextString str
+inlineToLaTeX (Math InlineMath str) = do
+ setEmptyLine False
return $ "\\(" <> text str <> "\\)"
-inlineToLaTeX (Math DisplayMath str) =
+inlineToLaTeX (Math DisplayMath str) = do
+ setEmptyLine False
return $ "\\[" <> text str <> "\\]"
-inlineToLaTeX (RawInline f str)
+inlineToLaTeX il@(RawInline f str)
| f == Format "latex" || f == Format "tex"
- = return $ text str
- | otherwise = return empty
-inlineToLaTeX (LineBreak) = return $ "\\\\" <> cr
+ = do
+ setEmptyLine False
+ return $ text str
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
+inlineToLaTeX LineBreak = do
+ emptyLine <- gets stEmptyLine
+ setEmptyLine True
+ return $ (if emptyLine then "~" else "") <> "\\\\" <> cr
inlineToLaTeX SoftBreak = do
wrapText <- gets (writerWrapText . stOptions)
case wrapText of
@@ -982,19 +1131,32 @@ inlineToLaTeX (Link _ txt (src, _)) =
src' <- stringToLaTeX URLString (escapeURI src)
return $ text ("\\href{" ++ src' ++ "}{") <>
contents <> char '}'
+inlineToLaTeX il@(Image _ _ ('d':'a':'t':'a':':':_, _)) = do
+ report $ InlineNotRendered il
+ return empty
inlineToLaTeX (Image attr _ (source, _)) = do
+ setEmptyLine False
modify $ \s -> s{ stGraphics = True }
opts <- gets stOptions
let showDim dir = let d = text (show dir) <> "="
- in case (dimension dir attr) of
+ in case dimension dir attr of
Just (Pixel a) ->
[d <> text (showInInch opts (Pixel a)) <> "in"]
Just (Percent a) ->
- [d <> text (showFl (a / 100)) <> "\\textwidth"]
+ [d <> text (showFl (a / 100)) <>
+ case dir of
+ Width -> "\\textwidth"
+ Height -> "\\textheight"
+ ]
Just dim ->
[d <> text (show dim)]
Nothing ->
- []
+ case dir of
+ Width | isJust (dimension Height attr) ->
+ [d <> "\\textwidth"]
+ Height | isJust (dimension Width attr) ->
+ [d <> "\\textheight"]
+ _ -> []
dimList = showDim Width ++ showDim Height
dims = if null dimList
then empty
@@ -1008,6 +1170,7 @@ inlineToLaTeX (Image attr _ (source, _)) = do
(if inHeading then "\\protect\\includegraphics" else "\\includegraphics") <>
dims <> braces (text source'')
inlineToLaTeX (Note contents) = do
+ setEmptyLine False
inMinipage <- gets stInMinipage
modify (\s -> s{stInNote = True})
contents' <- blockListToLaTeX contents
@@ -1016,9 +1179,9 @@ inlineToLaTeX (Note contents) = do
(CodeBlock _ _ : _) -> cr
_ -> empty
let noteContents = nest 2 contents' <> optnl
- opts <- gets stOptions
+ beamer <- gets stBeamer
-- in beamer slides, display footnote from current overlay forward
- let beamerMark = if writerBeamer opts
+ let beamerMark = if beamer
then text "<.->"
else empty
modify $ \st -> st{ stNotes = noteContents : stNotes st }
@@ -1035,8 +1198,12 @@ protectCode (x@(Code _ _) : xs) = ltx "\\mbox{" : x : ltx "}" : xs
where ltx = RawInline (Format "latex")
protectCode (x : xs) = x : protectCode xs
-citationsToNatbib :: [Citation] -> State WriterState Doc
-citationsToNatbib (one:[])
+setEmptyLine :: PandocMonad m => Bool -> LW m ()
+setEmptyLine b = modify $ \st -> st{ stEmptyLine = b }
+
+citationsToNatbib :: PandocMonad m => [Citation] -> LW m Doc
+citationsToNatbib
+ [one]
= citeCommand c p s k
where
Citation { citationId = k
@@ -1046,8 +1213,8 @@ citationsToNatbib (one:[])
}
= one
c = case m of
- AuthorInText -> "citet"
- SuppressAuthor -> "citeyearpar"
+ AuthorInText -> "citet"
+ SuppressAuthor -> "citeyearpar"
NormalCitation -> "citep"
citationsToNatbib cits
@@ -1056,9 +1223,11 @@ citationsToNatbib cits
where
noPrefix = all (null . citationPrefix)
noSuffix = all (null . citationSuffix)
- ismode m = all (((==) m) . citationMode)
- p = citationPrefix $ head $ cits
- s = citationSuffix $ last $ cits
+ ismode m = all ((==) m . citationMode)
+ p = citationPrefix $
+ head cits
+ s = citationSuffix $
+ last cits
ks = intercalate ", " $ map citationId cits
citationsToNatbib (c:cs) | citationMode c == AuthorInText = do
@@ -1082,17 +1251,20 @@ citationsToNatbib cits = do
SuppressAuthor -> citeCommand "citeyear" p s k
NormalCitation -> citeCommand "citealp" p s k
-citeCommand :: String -> [Inline] -> [Inline] -> String -> State WriterState Doc
+citeCommand :: PandocMonad m
+ => String -> [Inline] -> [Inline] -> String -> LW m Doc
citeCommand c p s k = do
args <- citeArguments p s k
return $ text ("\\" ++ c) <> args
-citeArguments :: [Inline] -> [Inline] -> String -> State WriterState Doc
+citeArguments :: PandocMonad m
+ => [Inline] -> [Inline] -> String -> LW m Doc
citeArguments p s k = do
let s' = case s of
- (Str (x:[]) : r) | isPunctuation x -> dropWhile (== Space) r
+ (Str
+ [x] : r) | isPunctuation x -> dropWhile (== Space) r
(Str (x:xs) : r) | isPunctuation x -> Str xs : r
- _ -> s
+ _ -> s
pdoc <- inlineListToLaTeX p
sdoc <- inlineListToLaTeX s'
let optargs = case (isEmpty pdoc, isEmpty sdoc) of
@@ -1101,8 +1273,9 @@ citeArguments p s k = do
(_ , _ ) -> brackets pdoc <> brackets sdoc
return $ optargs <> braces (text k)
-citationsToBiblatex :: [Citation] -> State WriterState Doc
-citationsToBiblatex (one:[])
+citationsToBiblatex :: PandocMonad m => [Citation] -> LW m Doc
+citationsToBiblatex
+ [one]
= citeCommand cmd p s k
where
Citation { citationId = k
@@ -1133,15 +1306,20 @@ citationsToBiblatex _ = return empty
-- Determine listings language from list of class attributes.
getListingsLanguage :: [String] -> Maybe String
-getListingsLanguage [] = Nothing
-getListingsLanguage (x:xs) = toListingsLanguage x <|> getListingsLanguage xs
+getListingsLanguage xs
+ = foldr ((<|>) . toListingsLanguage) Nothing xs
+
+mbBraced :: String -> String
+mbBraced x = if not (all isAlphaNum x)
+ then "{" <> x <> "}"
+ else x
-- Extract a key from divs and spans
extract :: String -> Block -> [String]
extract key (Div attr _) = lookKey key attr
-extract key (Plain ils) = concatMap (extractInline key) ils
-extract key (Para ils) = concatMap (extractInline key) ils
-extract key (Header _ _ ils) = concatMap (extractInline key) ils
+extract key (Plain ils) = query (extractInline key) ils
+extract key (Para ils) = query (extractInline key) ils
+extract key (Header _ _ ils) = query (extractInline key) ils
extract _ _ = []
-- Extract a key from spans
@@ -1154,85 +1332,95 @@ lookKey :: String -> Attr -> [String]
lookKey key (_,_,kvs) = maybe [] words $ lookup key kvs
-- In environments \Arabic instead of \arabic is used
-toPolyglossiaEnv :: String -> (String, String)
+toPolyglossiaEnv :: Lang -> (String, String)
toPolyglossiaEnv l =
- case toPolyglossia $ (splitBy (=='-')) l of
+ case toPolyglossia l of
("arabic", o) -> ("Arabic", o)
x -> x
-- Takes a list of the constituents of a BCP 47 language code and
-- converts it to a Polyglossia (language, options) tuple
-- http://mirrors.ctan.org/macros/latex/contrib/polyglossia/polyglossia.pdf
-toPolyglossia :: [String] -> (String, String)
-toPolyglossia ("ar":"DZ":_) = ("arabic", "locale=algeria")
-toPolyglossia ("ar":"IQ":_) = ("arabic", "locale=mashriq")
-toPolyglossia ("ar":"JO":_) = ("arabic", "locale=mashriq")
-toPolyglossia ("ar":"LB":_) = ("arabic", "locale=mashriq")
-toPolyglossia ("ar":"LY":_) = ("arabic", "locale=libya")
-toPolyglossia ("ar":"MA":_) = ("arabic", "locale=morocco")
-toPolyglossia ("ar":"MR":_) = ("arabic", "locale=mauritania")
-toPolyglossia ("ar":"PS":_) = ("arabic", "locale=mashriq")
-toPolyglossia ("ar":"SY":_) = ("arabic", "locale=mashriq")
-toPolyglossia ("ar":"TN":_) = ("arabic", "locale=tunisia")
-toPolyglossia ("de":"1901":_) = ("german", "spelling=old")
-toPolyglossia ("de":"AT":"1901":_) = ("german", "variant=austrian, spelling=old")
-toPolyglossia ("de":"AT":_) = ("german", "variant=austrian")
-toPolyglossia ("de":"CH":"1901":_) = ("german", "variant=swiss, spelling=old")
-toPolyglossia ("de":"CH":_) = ("german", "variant=swiss")
-toPolyglossia ("de":_) = ("german", "")
-toPolyglossia ("dsb":_) = ("lsorbian", "")
-toPolyglossia ("el":"polyton":_) = ("greek", "variant=poly")
-toPolyglossia ("en":"AU":_) = ("english", "variant=australian")
-toPolyglossia ("en":"CA":_) = ("english", "variant=canadian")
-toPolyglossia ("en":"GB":_) = ("english", "variant=british")
-toPolyglossia ("en":"NZ":_) = ("english", "variant=newzealand")
-toPolyglossia ("en":"UK":_) = ("english", "variant=british")
-toPolyglossia ("en":"US":_) = ("english", "variant=american")
-toPolyglossia ("grc":_) = ("greek", "variant=ancient")
-toPolyglossia ("hsb":_) = ("usorbian", "")
-toPolyglossia ("la":"x":"classic":_) = ("latin", "variant=classic")
-toPolyglossia ("sl":_) = ("slovenian", "")
-toPolyglossia x = (commonFromBcp47 x, "")
+toPolyglossia :: Lang -> (String, String)
+toPolyglossia (Lang "ar" _ "DZ" _) = ("arabic", "locale=algeria")
+toPolyglossia (Lang "ar" _ "IQ" _) = ("arabic", "locale=mashriq")
+toPolyglossia (Lang "ar" _ "JO" _) = ("arabic", "locale=mashriq")
+toPolyglossia (Lang "ar" _ "LB" _) = ("arabic", "locale=mashriq")
+toPolyglossia (Lang "ar" _ "LY" _) = ("arabic", "locale=libya")
+toPolyglossia (Lang "ar" _ "MA" _) = ("arabic", "locale=morocco")
+toPolyglossia (Lang "ar" _ "MR" _) = ("arabic", "locale=mauritania")
+toPolyglossia (Lang "ar" _ "PS" _) = ("arabic", "locale=mashriq")
+toPolyglossia (Lang "ar" _ "SY" _) = ("arabic", "locale=mashriq")
+toPolyglossia (Lang "ar" _ "TN" _) = ("arabic", "locale=tunisia")
+toPolyglossia (Lang "de" _ _ vars)
+ | "1901" `elem` vars = ("german", "spelling=old")
+toPolyglossia (Lang "de" _ "AT" vars)
+ | "1901" `elem` vars = ("german", "variant=austrian, spelling=old")
+toPolyglossia (Lang "de" _ "AT" _) = ("german", "variant=austrian")
+toPolyglossia (Lang "de" _ "CH" vars)
+ | "1901" `elem` vars = ("german", "variant=swiss, spelling=old")
+toPolyglossia (Lang "de" _ "CH" _) = ("german", "variant=swiss")
+toPolyglossia (Lang "de" _ _ _) = ("german", "")
+toPolyglossia (Lang "dsb" _ _ _) = ("lsorbian", "")
+toPolyglossia (Lang "el" _ "polyton" _) = ("greek", "variant=poly")
+toPolyglossia (Lang "en" _ "AU" _) = ("english", "variant=australian")
+toPolyglossia (Lang "en" _ "CA" _) = ("english", "variant=canadian")
+toPolyglossia (Lang "en" _ "GB" _) = ("english", "variant=british")
+toPolyglossia (Lang "en" _ "NZ" _) = ("english", "variant=newzealand")
+toPolyglossia (Lang "en" _ "UK" _) = ("english", "variant=british")
+toPolyglossia (Lang "en" _ "US" _) = ("english", "variant=american")
+toPolyglossia (Lang "grc" _ _ _) = ("greek", "variant=ancient")
+toPolyglossia (Lang "hsb" _ _ _) = ("usorbian", "")
+toPolyglossia (Lang "la" _ _ vars)
+ | "x-classic" `elem` vars = ("latin", "variant=classic")
+toPolyglossia (Lang "sl" _ _ _) = ("slovenian", "")
+toPolyglossia x = (commonFromBcp47 x, "")
-- Takes a list of the constituents of a BCP 47 language code and
-- converts it to a Babel language string.
-- http://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf
-- List of supported languages (slightly outdated):
-- http://tug.ctan.org/language/hyph-utf8/doc/generic/hyph-utf8/hyphenation.pdf
-toBabel :: [String] -> String
-toBabel ("de":"1901":_) = "german"
-toBabel ("de":"AT":"1901":_) = "austrian"
-toBabel ("de":"AT":_) = "naustrian"
-toBabel ("de":"CH":"1901":_) = "swissgerman"
-toBabel ("de":"CH":_) = "nswissgerman"
-toBabel ("de":_) = "ngerman"
-toBabel ("dsb":_) = "lowersorbian"
-toBabel ("el":"polyton":_) = "polutonikogreek"
-toBabel ("en":"AU":_) = "australian"
-toBabel ("en":"CA":_) = "canadian"
-toBabel ("en":"GB":_) = "british"
-toBabel ("en":"NZ":_) = "newzealand"
-toBabel ("en":"UK":_) = "british"
-toBabel ("en":"US":_) = "american"
-toBabel ("fr":"CA":_) = "canadien"
-toBabel ("fra":"aca":_) = "acadian"
-toBabel ("grc":_) = "polutonikogreek"
-toBabel ("hsb":_) = "uppersorbian"
-toBabel ("la":"x":"classic":_) = "classiclatin"
-toBabel ("sl":_) = "slovene"
-toBabel x = commonFromBcp47 x
+toBabel :: Lang -> String
+toBabel (Lang "de" _ "AT" vars)
+ | "1901" `elem` vars = "austrian"
+ | otherwise = "naustrian"
+toBabel (Lang "de" _ "CH" vars)
+ | "1901" `elem` vars = "swissgerman"
+ | otherwise = "nswissgerman"
+toBabel (Lang "de" _ _ vars)
+ | "1901" `elem` vars = "german"
+ | otherwise = "ngerman"
+toBabel (Lang "dsb" _ _ _) = "lowersorbian"
+toBabel (Lang "el" _ _ vars)
+ | "polyton" `elem` vars = "polutonikogreek"
+toBabel (Lang "en" _ "AU" _) = "australian"
+toBabel (Lang "en" _ "CA" _) = "canadian"
+toBabel (Lang "en" _ "GB" _) = "british"
+toBabel (Lang "en" _ "NZ" _) = "newzealand"
+toBabel (Lang "en" _ "UK" _) = "british"
+toBabel (Lang "en" _ "US" _) = "american"
+toBabel (Lang "fr" _ "CA" _) = "canadien"
+toBabel (Lang "fra" _ _ vars)
+ | "aca" `elem` vars = "acadian"
+toBabel (Lang "grc" _ _ _) = "polutonikogreek"
+toBabel (Lang "hsb" _ _ _) = "uppersorbian"
+toBabel (Lang "la" _ _ vars)
+ | "x-classic" `elem` vars = "classiclatin"
+toBabel (Lang "sl" _ _ _) = "slovene"
+toBabel x = commonFromBcp47 x
-- Takes a list of the constituents of a BCP 47 language code
-- and converts it to a string shared by Babel and Polyglossia.
-- https://tools.ietf.org/html/bcp47#section-2.1
-commonFromBcp47 :: [String] -> String
-commonFromBcp47 [] = ""
-commonFromBcp47 ("pt":"BR":_) = "brazil"
+commonFromBcp47 :: Lang -> String
+commonFromBcp47 (Lang "pt" _ "BR" _) = "brazil"
-- Note: documentation says "brazilian" works too, but it doesn't seem to work
-- on some systems. See #2953.
-commonFromBcp47 ("sr":"Cyrl":_) = "serbianc"
-commonFromBcp47 ("zh":"Latn":"pinyin":_) = "pinyin"
-commonFromBcp47 x = fromIso $ head x
+commonFromBcp47 (Lang "sr" "Cyrl" _ _) = "serbianc"
+commonFromBcp47 (Lang "zh" "Latn" _ vars)
+ | "pinyin" `elem` vars = "pinyin"
+commonFromBcp47 (Lang l _ _ _) = fromIso l
where
fromIso "af" = "afrikaans"
fromIso "am" = "amharic"
@@ -1316,10 +1504,6 @@ commonFromBcp47 x = fromIso $ head x
fromIso "vi" = "vietnamese"
fromIso _ = ""
-deNote :: Inline -> Inline
-deNote (Note _) = RawInline (Format "latex") ""
-deNote x = x
-
pDocumentOptions :: P.Parsec String () [String]
pDocumentOptions = do
P.char '['
diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs
index 98b08b08b..1be955fe3 100644
--- a/src/Text/Pandoc/Writers/Man.hs
+++ b/src/Text/Pandoc/Writers/Man.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Man
- Copyright : Copyright (C) 2007-2015 John MacFarlane
+ Copyright : Copyright (C) 2007-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,79 +30,95 @@ Conversion of 'Pandoc' documents to groff man page format.
-}
module Text.Pandoc.Writers.Man ( writeMan) where
+import Control.Monad.State.Strict
+import Data.List (intercalate, intersperse, sort, stripPrefix)
+import qualified Data.Map as Map
+import Data.Maybe (fromMaybe)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.Pandoc.Builder (deleteMeta)
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
-import Text.Pandoc.Templates
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Readers.TeXMath
-import Text.Printf ( printf )
-import Data.List ( stripPrefix, intersperse, intercalate )
-import Data.Maybe (fromMaybe)
import Text.Pandoc.Pretty
-import Text.Pandoc.Builder (deleteMeta)
-import Control.Monad.State
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates
+import Text.Pandoc.Writers.Math
+import Text.Pandoc.Writers.Shared
+import Text.Printf (printf)
type Notes = [[Block]]
-data WriterState = WriterState { stNotes :: Notes
- , stHasTables :: Bool }
+data WriterState = WriterState { stNotes :: Notes
+ , stFontFeatures :: Map.Map Char Bool
+ , stHasTables :: Bool }
+
+defaultWriterState :: WriterState
+defaultWriterState = WriterState { stNotes = []
+ , stFontFeatures = Map.fromList [
+ ('I',False)
+ , ('B',False)
+ , ('C',False)
+ ]
+ , stHasTables = False }
-- | Convert Pandoc to Man.
-writeMan :: WriterOptions -> Pandoc -> String
-writeMan opts document = evalState (pandocToMan opts document) (WriterState [] False)
+writeMan :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeMan opts document =
+ evalStateT (pandocToMan opts document) defaultWriterState
-- | Return groff man representation of document.
-pandocToMan :: WriterOptions -> Pandoc -> State WriterState String
+pandocToMan :: PandocMonad m => WriterOptions -> Pandoc -> StateT WriterState m Text
pandocToMan opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- let render' = render colwidth
+ let render' :: Doc -> Text
+ render' = render colwidth
titleText <- inlineListToMan opts $ docTitle meta
let title' = render' titleText
let setFieldsFromTitle =
- case break (== ' ') title' of
- (cmdName, rest) -> case break (=='(') cmdName of
- (xs, '(':ys) | not (null ys) &&
- last ys == ')' ->
+ case T.break (== ' ') title' of
+ (cmdName, rest) -> case T.break (=='(') cmdName of
+ (xs, ys) | "(" `T.isPrefixOf` ys
+ && ")" `T.isSuffixOf` ys ->
defField "title" xs .
- defField "section" (init ys) .
- case splitBy (=='|') rest of
+ defField "section" (T.init $ T.drop 1 ys) .
+ case T.splitOn "|" rest of
(ft:hds) ->
- defField "footer" (trim ft) .
+ defField "footer" (T.strip ft) .
defField "header"
- (trim $ concat hds)
+ (T.strip $ mconcat hds)
[] -> id
_ -> defField "title" title'
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToMan opts)
- (fmap (render colwidth) . inlineListToMan opts)
+ (fmap render' . blockListToMan opts)
+ (fmap render' . inlineListToMan opts)
$ deleteMeta "title" meta
body <- blockListToMan opts blocks
- notes <- liftM stNotes get
+ notes <- gets stNotes
notes' <- notesToMan opts (reverse notes)
let main = render' $ body $$ notes' $$ text ""
- hasTables <- liftM stHasTables get
+ hasTables <- gets stHasTables
let context = defField "body" main
$ setFieldsFromTitle
$ defField "has-tables" hasTables
$ defField "hyphenate" True
- $ defField "pandoc-version" pandocVersion
- $ metadata
+ $ defField "pandoc-version" pandocVersion metadata
case writerTemplate opts of
Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
-- | Return man representation of notes.
-notesToMan :: WriterOptions -> [[Block]] -> State WriterState Doc
+notesToMan :: PandocMonad m => WriterOptions -> [[Block]] -> StateT WriterState m Doc
notesToMan opts notes =
if null notes
then return empty
- else mapM (\(num, note) -> noteToMan opts num note) (zip [1..] notes) >>=
+ else zipWithM (noteToMan opts) [1..] notes >>=
return . (text ".SH NOTES" $$) . vcat
-- | Return man representation of a note.
-noteToMan :: WriterOptions -> Int -> [Block] -> State WriterState Doc
+noteToMan :: PandocMonad m => WriterOptions -> Int -> [Block] -> StateT WriterState m Doc
noteToMan opts num note = do
contents <- blockListToMan opts note
let marker = cr <> text ".SS " <> brackets (text (show num))
@@ -123,11 +140,11 @@ escapeString = escapeStringUsing manEscapes
-- | Escape a literal (code) section for Man.
escapeCode :: String -> String
-escapeCode = concat . intersperse "\n" . map escapeLine . lines where
+escapeCode = intercalate "\n" . map escapeLine . lines where
escapeLine codeline =
case escapeStringUsing (manEscapes ++ backslashEscapes "\t ") codeline of
a@('.':_) -> "\\&" ++ a
- b -> b
+ b -> b
-- We split inline lists into sentences, and print one sentence per
-- line. groff/troff treats the line-ending period differently.
@@ -139,8 +156,8 @@ breakSentence [] = ([],[])
breakSentence xs =
let isSentenceEndInline (Str ys@(_:_)) | last ys == '.' = True
isSentenceEndInline (Str ys@(_:_)) | last ys == '?' = True
- isSentenceEndInline (LineBreak) = True
- isSentenceEndInline _ = False
+ isSentenceEndInline LineBreak = True
+ isSentenceEndInline _ = False
(as, bs) = break isSentenceEndInline xs
in case bs of
[] -> (as, [])
@@ -160,9 +177,10 @@ splitSentences xs =
in if null rest then [sent] else sent : splitSentences rest
-- | Convert Pandoc block element to man.
-blockToMan :: WriterOptions -- ^ Options
- -> Block -- ^ Block element
- -> State WriterState Doc
+blockToMan :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> Block -- ^ Block element
+ -> StateT WriterState m Doc
blockToMan _ Null = return empty
blockToMan opts (Div _ bs) = blockListToMan opts bs
blockToMan opts (Plain inlines) =
@@ -173,9 +191,11 @@ blockToMan opts (Para inlines) = do
return $ text ".PP" $$ contents
blockToMan opts (LineBlock lns) =
blockToMan opts $ linesToPara lns
-blockToMan _ (RawBlock f str)
+blockToMan _ b@(RawBlock f str)
| f == Format "man" = return $ text str
- | otherwise = return empty
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
blockToMan _ HorizontalRule = return $ text ".PP" $$ text " * * * * *"
blockToMan opts (Header level _ inlines) = do
contents <- inlineListToMan opts inlines
@@ -205,12 +225,12 @@ blockToMan opts (Table caption alignments widths headers rows) =
then repeat ""
else map (printf "w(%0.1fn)" . (70 *)) widths
-- 78n default width - 8n indent = 70n
- let coldescriptions = text $ intercalate " "
+ let coldescriptions = text $ unwords
(zipWith (\align width -> aligncode align ++ width)
alignments iwidths) ++ "."
colheadings <- mapM (blockListToMan opts) headers
let makeRow cols = text "T{" $$
- (vcat $ intersperse (text "T}@T{") cols) $$
+ vcat (intersperse (text "T}@T{") cols) $$
text "T}"
let colheadings' = if all null headers
then empty
@@ -227,7 +247,8 @@ blockToMan opts (BulletList items) = do
return (vcat contents)
blockToMan opts (OrderedList attribs items) = do
let markers = take (length items) $ orderedListMarkers attribs
- let indent = 1 + (maximum $ map length markers)
+ let indent = 1 +
+ maximum (map length markers)
contents <- mapM (\(num, item) -> orderedListItemToMan opts num indent item) $
zip markers items
return (vcat contents)
@@ -236,11 +257,11 @@ blockToMan opts (DefinitionList items) = do
return (vcat contents)
-- | Convert bullet list item (list of blocks) to man.
-bulletListItemToMan :: WriterOptions -> [Block] -> State WriterState Doc
+bulletListItemToMan :: PandocMonad m => WriterOptions -> [Block] -> StateT WriterState m Doc
bulletListItemToMan _ [] = return empty
-bulletListItemToMan opts ((Para first):rest) =
- bulletListItemToMan opts ((Plain first):rest)
-bulletListItemToMan opts ((Plain first):rest) = do
+bulletListItemToMan opts (Para first:rest) =
+ bulletListItemToMan opts (Plain first:rest)
+bulletListItemToMan opts (Plain first:rest) = do
first' <- blockToMan opts (Plain first)
rest' <- blockListToMan opts rest
let first'' = text ".IP \\[bu] 2" $$ first'
@@ -254,14 +275,15 @@ bulletListItemToMan opts (first:rest) = do
return $ text "\\[bu] .RS 2" $$ first' $$ rest' $$ text ".RE"
-- | Convert ordered list item (a list of blocks) to man.
-orderedListItemToMan :: WriterOptions -- ^ options
- -> String -- ^ order marker for list item
- -> Int -- ^ number of spaces to indent
- -> [Block] -- ^ list item (list of blocks)
- -> State WriterState Doc
+orderedListItemToMan :: PandocMonad m
+ => WriterOptions -- ^ options
+ -> String -- ^ order marker for list item
+ -> Int -- ^ number of spaces to indent
+ -> [Block] -- ^ list item (list of blocks)
+ -> StateT WriterState m Doc
orderedListItemToMan _ _ _ [] = return empty
-orderedListItemToMan opts num indent ((Para first):rest) =
- orderedListItemToMan opts num indent ((Plain first):rest)
+orderedListItemToMan opts num indent (Para first:rest) =
+ orderedListItemToMan opts num indent (Plain first:rest)
orderedListItemToMan opts num indent (first:rest) = do
first' <- blockToMan opts first
rest' <- blockListToMan opts rest
@@ -273,44 +295,47 @@ orderedListItemToMan opts num indent (first:rest) = do
return $ first'' $$ rest''
-- | Convert definition list item (label, list of blocks) to man.
-definitionListItemToMan :: WriterOptions
- -> ([Inline],[[Block]])
- -> State WriterState Doc
+definitionListItemToMan :: PandocMonad m
+ => WriterOptions
+ -> ([Inline],[[Block]])
+ -> StateT WriterState m Doc
definitionListItemToMan opts (label, defs) = do
labelText <- inlineListToMan opts label
contents <- if null defs
then return empty
- else liftM vcat $ forM defs $ \blocks -> do
- let (first, rest) = case blocks of
- ((Para x):y) -> (Plain x,y)
- (x:y) -> (x,y)
- [] -> error "blocks is null"
- rest' <- liftM vcat $
- mapM (\item -> blockToMan opts item) rest
- first' <- blockToMan opts first
- return $ first' $$ text ".RS" $$ rest' $$ text ".RE"
+ else liftM vcat $ forM defs $ \blocks ->
+ case blocks of
+ (x:xs) -> do
+ first' <- blockToMan opts $
+ case x of
+ Para y -> Plain y
+ _ -> x
+ rest' <- liftM vcat $ mapM
+ (\item -> blockToMan opts item) xs
+ return $ first' $$
+ text ".RS" $$ rest' $$ text ".RE"
+ [] -> return empty
return $ text ".TP" $$ nowrap (text ".B " <> labelText) $$ contents
-- | Convert list of Pandoc block elements to man.
-blockListToMan :: WriterOptions -- ^ Options
- -> [Block] -- ^ List of block elements
- -> State WriterState Doc
+blockListToMan :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> [Block] -- ^ List of block elements
+ -> StateT WriterState m Doc
blockListToMan opts blocks =
mapM (blockToMan opts) blocks >>= (return . vcat)
-- | Convert list of Pandoc inline elements to man.
-inlineListToMan :: WriterOptions -> [Inline] -> State WriterState Doc
+inlineListToMan :: PandocMonad m => WriterOptions -> [Inline] -> StateT WriterState m Doc
inlineListToMan opts lst = mapM (inlineToMan opts) lst >>= (return . hcat)
-- | Convert Pandoc inline element to man.
-inlineToMan :: WriterOptions -> Inline -> State WriterState Doc
+inlineToMan :: PandocMonad m => WriterOptions -> Inline -> StateT WriterState m Doc
inlineToMan opts (Span _ ils) = inlineListToMan opts ils
-inlineToMan opts (Emph lst) = do
- contents <- inlineListToMan opts lst
- return $ text "\\f[I]" <> contents <> text "\\f[]"
-inlineToMan opts (Strong lst) = do
- contents <- inlineListToMan opts lst
- return $ text "\\f[B]" <> contents <> text "\\f[]"
+inlineToMan opts (Emph lst) =
+ withFontFeature 'I' (inlineListToMan opts lst)
+inlineToMan opts (Strong lst) =
+ withFontFeature 'B' (inlineListToMan opts lst)
inlineToMan opts (Strikeout lst) = do
contents <- inlineListToMan opts lst
return $ text "[STRIKEOUT:" <> contents <> char ']'
@@ -330,22 +355,26 @@ inlineToMan opts (Quoted DoubleQuote lst) = do
inlineToMan opts (Cite _ lst) =
inlineListToMan opts lst
inlineToMan _ (Code _ str) =
- return $ text $ "\\f[C]" ++ escapeCode str ++ "\\f[]"
+ withFontFeature 'C' (return (text $ escapeCode str))
inlineToMan _ (Str str@('.':_)) =
return $ afterBreak "\\&" <> text (escapeString str)
inlineToMan _ (Str str) = return $ text $ escapeString str
inlineToMan opts (Math InlineMath str) =
- inlineListToMan opts $ texMathToInlines InlineMath str
+ lift (texMathToInlines InlineMath str) >>= inlineListToMan opts
inlineToMan opts (Math DisplayMath str) = do
- contents <- inlineListToMan opts $ texMathToInlines DisplayMath str
+ contents <- lift (texMathToInlines DisplayMath str) >>= inlineListToMan opts
return $ cr <> text ".RS" $$ contents $$ text ".RE"
-inlineToMan _ (RawInline f str)
+inlineToMan _ il@(RawInline f str)
| f == Format "man" = return $ text str
- | otherwise = return empty
-inlineToMan _ (LineBreak) = return $
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
+inlineToMan _ LineBreak = return $
cr <> text ".PD 0" $$ text ".P" $$ text ".PD" <> cr
inlineToMan _ SoftBreak = return space
inlineToMan _ Space = return space
+inlineToMan opts (Link _ txt ('#':_, _)) =
+ inlineListToMan opts txt -- skip internal links
inlineToMan opts (Link _ txt (src, _)) = do
linktext <- inlineListToMan opts txt
let srcSuffix = fromMaybe src (stripPrefix "mailto:" src)
@@ -355,7 +384,7 @@ inlineToMan opts (Link _ txt (src, _)) = do
char '<' <> text srcSuffix <> char '>'
_ -> linktext <> text " (" <> text src <> char ')'
inlineToMan opts (Image attr alternate (source, tit)) = do
- let txt = if (null alternate) || (alternate == [Str ""]) ||
+ let txt = if null alternate || (alternate == [Str ""]) ||
(alternate == [Str source]) -- to prevent autolinks
then [Str "image"]
else alternate
@@ -364,6 +393,24 @@ inlineToMan opts (Image attr alternate (source, tit)) = do
inlineToMan _ (Note contents) = do
-- add to notes in state
modify $ \st -> st{ stNotes = contents : stNotes st }
- notes <- liftM stNotes get
- let ref = show $ (length notes)
+ notes <- gets stNotes
+ let ref = show (length notes)
return $ char '[' <> text ref <> char ']'
+
+fontChange :: PandocMonad m => StateT WriterState m Doc
+fontChange = do
+ features <- gets stFontFeatures
+ let filling = sort [c | (c,True) <- Map.toList features]
+ return $ text $ "\\f[" ++ filling ++ "]"
+
+withFontFeature :: PandocMonad m
+ => Char
+ -> StateT WriterState m Doc
+ -> StateT WriterState m Doc
+withFontFeature c action = do
+ modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
+ begin <- fontChange
+ d <- action
+ modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
+ end <- fontChange
+ return $ begin <> d <> end
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
index e3bb3eea0..cdd8f3b66 100644
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -1,6 +1,9 @@
-{-# LANGUAGE OverloadedStrings, TupleSections, ScopedTypeVariables, MultiWayIf #-}
+{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TupleSections #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Markdown
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,47 +34,50 @@ Conversion of 'Pandoc' documents to markdown-formatted plain text.
Markdown: <http://daringfireball.net/projects/markdown/>
-}
module Text.Pandoc.Writers.Markdown (writeMarkdown, writePlain) where
-import Text.Pandoc.Definition
-import Text.Pandoc.Walk
-import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
-import Text.Pandoc.Options
-import Text.Pandoc.Parsing hiding (blankline, blanklines, char, space)
-import Data.Maybe (fromMaybe)
-import Data.Monoid (Any(..))
-import Data.List ( group, stripPrefix, find, intersperse, transpose, sortBy )
-import Data.Char ( isSpace, isPunctuation, ord, chr )
-import Data.Ord ( comparing )
-import Text.Pandoc.Pretty
import Control.Monad.Reader
-import Control.Monad.State
-import Text.Pandoc.Writers.HTML (writeHtmlString)
-import Text.Pandoc.Readers.TeXMath (texMathToInlines)
-import Text.HTML.TagSoup (parseTags, isTagText, Tag(..))
-import Network.URI (isURI)
+import Control.Monad.State.Strict
+import Data.Char (chr, isPunctuation, isSpace, ord, isAlphaNum)
import Data.Default
-import Data.Yaml (Value(Object,String,Array,Bool,Number))
import qualified Data.HashMap.Strict as H
-import qualified Data.Vector as V
-import qualified Data.Text as T
+import Data.List (find, group, intersperse, sortBy, stripPrefix, transpose)
+import qualified Data.Map as M
+import Data.Maybe (fromMaybe)
+import Data.Monoid (Any (..))
+import Data.Ord (comparing)
import qualified Data.Set as Set
-import Network.HTTP ( urlEncode )
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Vector as V
+import Data.Yaml (Value (Array, Bool, Number, Object, String))
+import Network.HTTP (urlEncode)
+import Text.HTML.TagSoup (Tag (..), isTagText, parseTags)
+import Text.Pandoc.Class (PandocMonad, report)
+import Text.Pandoc.Definition
+import Text.Pandoc.Logging
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (blankline, blanklines, char, space)
+import Text.Pandoc.Pretty
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Walk
+import Text.Pandoc.Writers.HTML (writeHtml5String)
+import Text.Pandoc.Writers.Math (texMathToInlines)
+import Text.Pandoc.Writers.Shared
type Notes = [[Block]]
-type Ref = ([Inline], Target, Attr)
+type Ref = (Doc, Target, Attr)
type Refs = [Ref]
-type MD = ReaderT WriterEnv (State WriterState)
+type MD m = ReaderT WriterEnv (StateT WriterState m)
-evalMD :: MD a -> WriterEnv -> WriterState -> a
-evalMD md env st = evalState (runReaderT md env) st
+evalMD :: PandocMonad m => MD m a -> WriterEnv -> WriterState -> m a
+evalMD md env st = evalStateT (runReaderT md env) st
-data WriterEnv = WriterEnv { envInList :: Bool
- , envPlain :: Bool
+data WriterEnv = WriterEnv { envInList :: Bool
+ , envPlain :: Bool
, envRefShortcutable :: Bool
, envBlockLevel :: Int
- , envEscapeSpaces :: Bool
+ , envEscapeSpaces :: Bool
}
instance Default WriterEnv
@@ -82,21 +88,26 @@ instance Default WriterEnv
, envEscapeSpaces = False
}
-data WriterState = WriterState { stNotes :: Notes
- , stRefs :: Refs
- , stIds :: Set.Set String
+data WriterState = WriterState { stNotes :: Notes
+ , stRefs :: Refs
+ , stKeys :: M.Map Key
+ (M.Map (Target, Attr) Int)
+ , stLastIdx :: Int
+ , stIds :: Set.Set String
, stNoteNum :: Int
}
instance Default WriterState
where def = WriterState{ stNotes = []
, stRefs = []
+ , stKeys = M.empty
+ , stLastIdx = 0
, stIds = Set.empty
, stNoteNum = 1
}
-- | Convert Pandoc to Markdown.
-writeMarkdown :: WriterOptions -> Pandoc -> String
+writeMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeMarkdown opts document =
evalMD (pandocToMarkdown opts{
writerWrapText = if isEnabled Ext_hard_line_breaks opts
@@ -106,7 +117,7 @@ writeMarkdown opts document =
-- | Convert Pandoc to plain text (like markdown, but without links,
-- pictures, or inline formatting).
-writePlain :: WriterOptions -> Pandoc -> String
+writePlain :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writePlain opts document =
evalMD (pandocToMarkdown opts document) def{ envPlain = True } def
@@ -155,8 +166,7 @@ jsonToYaml (Object hashmap) =
| otherwise -> (k' <> ":") $$ x
(k', Object _, x) -> (k' <> ":") $$ nest 2 x
(_, String "", _) -> empty
- (k', _, x) | k == "meta-json" -> empty
- | otherwise -> k' <> ":" <> space <> hang 2 "" x)
+ (k', _, x) -> k' <> ":" <> space <> hang 2 "" x)
$ sortBy (comparing fst) $ H.toList hashmap
jsonToYaml (Array vec) =
vcat $ map (\v -> hang 2 "- " (jsonToYaml v)) $ V.toList vec
@@ -171,15 +181,17 @@ jsonToYaml (Number n) = text $ show n
jsonToYaml _ = empty
-- | Return markdown representation of document.
-pandocToMarkdown :: WriterOptions -> Pandoc -> MD String
+pandocToMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> MD m Text
pandocToMarkdown opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
isPlain <- asks envPlain
- metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToMarkdown opts)
- (fmap (render colwidth) . inlineListToMarkdown opts)
+ let render' :: Doc -> Text
+ render' = render colwidth . chomp
+ metadata <- metaToJSON'
+ (fmap render' . blockListToMarkdown opts)
+ (fmap render' . blockToMarkdown opts . Plain)
meta
let title' = maybe empty text $ getField "title" metadata
let authors' = maybe [] (map text) $ getField "author" metadata
@@ -196,49 +208,51 @@ pandocToMarkdown opts (Pandoc meta blocks) = do
| otherwise -> empty
Nothing -> empty
let headerBlocks = filter isHeaderBlock blocks
- let toc = if writerTableOfContents opts
- then tableOfContents opts headerBlocks
- else empty
+ toc <- if writerTableOfContents opts
+ then render' <$> tableOfContents opts headerBlocks
+ else return ""
-- Strip off final 'references' header if markdown citations enabled
let blocks' = if isEnabled Ext_citations opts
then case reverse blocks of
(Div (_,["references"],_) _):xs -> reverse xs
- _ -> blocks
+ _ -> blocks
else blocks
body <- blockListToMarkdown opts blocks'
notesAndRefs' <- notesAndRefs opts
- let render' :: Doc -> String
- render' = render colwidth
let main = render' $ body <> notesAndRefs'
- let context = defField "toc" (render' toc)
+ let context = -- for backwards compatibility we populate toc
+ -- with the contents of the toc, rather than a
+ -- boolean:
+ defField "toc" toc
+ $ defField "table-of-contents" toc
$ defField "body" main
$ (if isNullMeta meta
then id
else defField "titleblock" (render' titleblock))
- $ metadata
+ $ addVariablesToJSON opts metadata
case writerTemplate opts of
Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
-- | Return markdown representation of reference key table.
-refsToMarkdown :: WriterOptions -> Refs -> MD Doc
+refsToMarkdown :: PandocMonad m => WriterOptions -> Refs -> MD m Doc
refsToMarkdown opts refs = mapM (keyToMarkdown opts) refs >>= return . vcat
-- | Return markdown representation of a reference key.
-keyToMarkdown :: WriterOptions
+keyToMarkdown :: PandocMonad m
+ => WriterOptions
-> Ref
- -> MD Doc
-keyToMarkdown opts (label, (src, tit), attr) = do
- label' <- inlineListToMarkdown opts label
+ -> MD m Doc
+keyToMarkdown opts (label', (src, tit), attr) = do
let tit' = if null tit
then empty
else space <> "\"" <> text tit <> "\""
return $ nest 2 $ hang 2
("[" <> label' <> "]:" <> space) (text src <> tit')
- <> linkAttributes opts attr
+ <+> linkAttributes opts attr
-- | Return markdown representation of notes.
-notesToMarkdown :: WriterOptions -> [[Block]] -> MD Doc
+notesToMarkdown :: PandocMonad m => WriterOptions -> [[Block]] -> MD m Doc
notesToMarkdown opts notes = do
n <- gets stNoteNum
notes' <- mapM (\(num, note) -> noteToMarkdown opts num note) (zip [n..] notes)
@@ -246,7 +260,7 @@ notesToMarkdown opts notes = do
return $ vsep notes'
-- | Return markdown representation of a note.
-noteToMarkdown :: WriterOptions -> Int -> [Block] -> MD Doc
+noteToMarkdown :: PandocMonad m => WriterOptions -> Int -> [Block] -> MD m Doc
noteToMarkdown opts num blocks = do
contents <- blockListToMarkdown opts blocks
let num' = text $ writerIdentifierPrefix opts ++ show num
@@ -256,45 +270,65 @@ noteToMarkdown opts num blocks = do
let markerSize = 4 + offset num'
let spacer = case writerTabStop opts - markerSize of
n | n > 0 -> text $ replicate n ' '
- _ -> text " "
+ _ -> text " "
return $ if isEnabled Ext_footnotes opts
then hang (writerTabStop opts) (marker <> spacer) contents
else marker <> spacer <> contents
-- | Escape special characters for Markdown.
escapeString :: WriterOptions -> String -> String
-escapeString opts = escapeStringUsing markdownEscapes
- where markdownEscapes = ('<', "&lt;") : ('>', "&gt;") :
- backslashEscapes specialChars
- specialChars =
- (if isEnabled Ext_superscript opts
- then ('^':)
- else id) .
- (if isEnabled Ext_subscript opts
- then ('~':)
- else id) .
- (if isEnabled Ext_tex_math_dollars opts
- then ('$':)
- else id) $
- "\\`*_[]#"
+escapeString _ [] = []
+escapeString opts (c:cs) =
+ case c of
+ '<' | isEnabled Ext_all_symbols_escapable opts ->
+ '\\' : '<' : escapeString opts cs
+ | otherwise -> "&lt;" ++ escapeString opts cs
+ '>' | isEnabled Ext_all_symbols_escapable opts ->
+ '\\' : '>' : escapeString opts cs
+ | otherwise -> "&gt;" ++ escapeString opts cs
+ '@' | isEnabled Ext_citations opts ->
+ case cs of
+ (d:_)
+ | isAlphaNum d || d == '_'
+ -> '\\':'@':escapeString opts cs
+ _ -> '@':escapeString opts cs
+ _ | c `elem` ['\\','`','*','_','[',']','#'] ->
+ '\\':c:escapeString opts cs
+ '|' | isEnabled Ext_pipe_tables opts -> '\\':'|':escapeString opts cs
+ '^' | isEnabled Ext_superscript opts -> '\\':'^':escapeString opts cs
+ '~' | isEnabled Ext_subscript opts -> '\\':'~':escapeString opts cs
+ '$' | isEnabled Ext_tex_math_dollars opts -> '\\':'$':escapeString opts cs
+ '\'' | isEnabled Ext_smart opts -> '\\':'\'':escapeString opts cs
+ '"' | isEnabled Ext_smart opts -> '\\':'"':escapeString opts cs
+ '-' | isEnabled Ext_smart opts ->
+ case cs of
+ '-':_ -> '\\':'-':escapeString opts cs
+ _ -> '-':escapeString opts cs
+ '.' | isEnabled Ext_smart opts ->
+ case cs of
+ '.':'.':rest -> '\\':'.':'.':'.':escapeString opts rest
+ _ -> '.':escapeString opts cs
+ _ -> c : escapeString opts cs
-- | Construct table of contents from list of header blocks.
-tableOfContents :: WriterOptions -> [Block] -> Doc
-tableOfContents opts headers =
- let opts' = opts { writerIgnoreNotes = True }
- contents = BulletList $ map (elementToListItem opts) $ hierarchicalize headers
- in evalMD (blockToMarkdown opts' contents) def def
+tableOfContents :: PandocMonad m => WriterOptions -> [Block] -> MD m Doc
+tableOfContents opts headers = do
+ contents <- BulletList <$> mapM (elementToListItem opts) (hierarchicalize headers)
+ blockToMarkdown opts contents
-- | Converts an Element to a list item for a table of contents,
-elementToListItem :: WriterOptions -> Element -> [Block]
+elementToListItem :: PandocMonad m => WriterOptions -> Element -> MD m [Block]
elementToListItem opts (Sec lev _nums (ident,_,_) headerText subsecs)
- = Plain headerLink :
- [ BulletList (map (elementToListItem opts) subsecs) |
- not (null subsecs) && lev < writerTOCDepth opts ]
- where headerLink = if null ident
- then headerText
- else [Link nullAttr headerText ('#':ident, "")]
-elementToListItem _ (Blk _) = []
+ = do isPlain <- asks envPlain
+ let headerLink = if null ident || isPlain
+ then walk deNote headerText
+ else [Link nullAttr (walk deNote headerText)
+ ('#':ident, "")]
+ listContents <- if null subsecs || lev >= writerTOCDepth opts
+ then return []
+ else mapM (elementToListItem opts) subsecs
+ return [Plain headerLink, BulletList listContents]
+elementToListItem _ (Blk _) = return []
attrsToMarkdown :: Attr -> Doc
attrsToMarkdown attribs = braces $ hsep [attribId, attribClasses, attribKeys]
@@ -331,10 +365,10 @@ olMarker = do (start, style', delim) <- anyOrderedListMarker
beginsWithOrderedListMarker :: String -> Bool
beginsWithOrderedListMarker str =
case runParser olMarker defaultParserState "para start" (take 10 str) of
- Left _ -> False
- Right _ -> True
+ Left _ -> False
+ Right _ -> True
-notesAndRefs :: WriterOptions -> MD Doc
+notesAndRefs :: PandocMonad m => WriterOptions -> MD m Doc
notesAndRefs opts = do
notes' <- reverse <$> gets stNotes >>= notesToMarkdown opts
modify $ \s -> s { stNotes = [] }
@@ -345,16 +379,17 @@ notesAndRefs opts = do
if | writerReferenceLocation opts == EndOfDocument -> empty
| isEmpty notes' && isEmpty refs' -> empty
| otherwise -> blankline
-
+
return $
(if isEmpty notes' then empty else blankline <> notes') <>
(if isEmpty refs' then empty else blankline <> refs') <>
endSpacing
-- | Convert Pandoc block element to markdown.
-blockToMarkdown :: WriterOptions -- ^ Options
+blockToMarkdown :: PandocMonad m
+ => WriterOptions -- ^ Options
-> Block -- ^ Block element
- -> MD Doc
+ -> MD m Doc
blockToMarkdown opts blk =
local (\env -> env {envBlockLevel = envBlockLevel env + 1}) $
do doc <- blockToMarkdown' opts blk
@@ -363,17 +398,26 @@ blockToMarkdown opts blk =
then notesAndRefs opts >>= (\d -> return $ doc <> d)
else return doc
-blockToMarkdown' :: WriterOptions -- ^ Options
- -> Block -- ^ Block element
- -> MD Doc
+blockToMarkdown' :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> Block -- ^ Block element
+ -> MD m Doc
blockToMarkdown' _ Null = return empty
blockToMarkdown' opts (Div attrs ils) = do
contents <- blockListToMarkdown opts ils
- return $ if isEnabled Ext_raw_html opts &&
- isEnabled Ext_markdown_in_html_blocks opts
- then tagWithAttrs "div" attrs <> blankline <>
- contents <> blankline <> "</div>" <> blankline
- else contents <> blankline
+ return $
+ case () of
+ _ | isEnabled Ext_fenced_divs opts &&
+ attrs /= nullAttr ->
+ nowrap (text ":::" <+> attrsToMarkdown attrs) $$
+ chomp contents $$
+ text ":::" <> blankline
+ | isEnabled Ext_native_divs opts ||
+ (isEnabled Ext_raw_html opts &&
+ isEnabled Ext_markdown_in_html_blocks opts) ->
+ tagWithAttrs "div" attrs <> blankline <>
+ contents <> blankline <> "</div>" <> blankline
+ | otherwise -> contents <> blankline
blockToMarkdown' opts (Plain inlines) = do
contents <- inlineListToMarkdown opts inlines
-- escape if para starts with ordered list marker
@@ -382,13 +426,28 @@ blockToMarkdown' opts (Plain inlines) = do
then Just $ writerColumns opts
else Nothing
let rendered = render colwidth contents
- let escapeDelimiter (x:xs) | x `elem` (".()" :: String) = '\\':x:xs
- | otherwise = x : escapeDelimiter xs
- escapeDelimiter [] = []
- let contents' = if isEnabled Ext_all_symbols_escapable opts &&
- not isPlain && beginsWithOrderedListMarker rendered
- then text $ escapeDelimiter rendered
- else contents
+ let escapeMarker (x:xs) | x `elem` (".()" :: String) = '\\':x:xs
+ | otherwise = x : escapeMarker xs
+ escapeMarker [] = []
+ let contents' =
+ case rendered of
+ '%':_ | isEnabled Ext_pandoc_title_block opts &&
+ isEnabled Ext_all_symbols_escapable opts ->
+ "\\" <> contents
+ '+':s:_ | not isPlain && isSpace s -> "\\" <> contents
+ '*':s:_ | not isPlain && isSpace s -> "\\" <> contents
+ '-':s:_ | not isPlain && isSpace s -> "\\" <> contents
+ '+':[] | not isPlain -> "\\" <> contents
+ '*':[] | not isPlain -> "\\" <> contents
+ '-':[] | not isPlain -> "\\" <> contents
+ '|':_ | (isEnabled Ext_line_blocks opts ||
+ isEnabled Ext_pipe_tables opts)
+ && isEnabled Ext_all_symbols_escapable opts
+ -> "\\" <> contents
+ _ | not isPlain && beginsWithOrderedListMarker rendered
+ && isEnabled Ext_all_symbols_escapable opts
+ -> text $ escapeMarker rendered
+ | otherwise -> contents
return $ contents' <> cr
-- title beginning with fig: indicates figure
blockToMarkdown' opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) =
@@ -401,9 +460,11 @@ blockToMarkdown' opts (LineBlock lns) =
mdLines <- mapM (inlineListToMarkdown opts) lns
return $ (vcat $ map (hang 2 (text "| ")) mdLines) <> blankline
else blockToMarkdown opts $ linesToPara lns
-blockToMarkdown' opts (RawBlock f str)
- | f == "markdown" = return $ text str <> text "\n"
- | f == "html" && isEnabled Ext_raw_html opts = do
+blockToMarkdown' opts b@(RawBlock f str)
+ | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
+ "markdown_mmd", "markdown_strict"]
+ = return $ text str <> text "\n"
+ | f `elem` ["html", "html5", "html4"] && isEnabled Ext_raw_html opts = do
plain <- asks envPlain
return $ if plain
then empty
@@ -415,7 +476,9 @@ blockToMarkdown' opts (RawBlock f str)
return $ if plain
then empty
else text str <> text "\n"
- | otherwise = return empty
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
blockToMarkdown' opts HorizontalRule = do
return $ blankline <> text (replicate (writerColumns opts) '-') <> blankline
blockToMarkdown' opts (Header level attr inlines) = do
@@ -442,6 +505,8 @@ blockToMarkdown' opts (Header level attr inlines) = do
space <> attrsToMarkdown attr
| otherwise -> empty
contents <- inlineListToMarkdown opts $
+ -- ensure no newlines; see #3736
+ walk lineBreakToSpace $
if level == 1 && plain
then capitalize inlines
else inlines
@@ -497,39 +562,70 @@ blockToMarkdown' opts (BlockQuote blocks) = do
contents <- blockListToMarkdown opts blocks
return $ (prefixed leader contents) <> blankline
blockToMarkdown' opts t@(Table caption aligns widths headers rows) = do
+ let numcols = maximum (length aligns : length widths :
+ map length (headers:rows))
caption' <- inlineListToMarkdown opts caption
let caption'' = if null caption || not (isEnabled Ext_table_captions opts)
- then empty
- else blankline <> ": " <> caption' <> blankline
- rawHeaders <- mapM (blockListToMarkdown opts) headers
- rawRows <- mapM (mapM (blockListToMarkdown opts)) rows
+ then blankline
+ else blankline $$ (": " <> caption') $$ blankline
let isLineBreak LineBreak = Any True
isLineBreak _ = Any False
- let isSimple = all (==0) widths &&
- not ( getAny (query isLineBreak (headers:rows)) )
+ let hasLineBreak = getAny . query isLineBreak
+ let isSimpleCell [Plain ils] = not (hasLineBreak ils)
+ isSimpleCell [Para ils ] = not (hasLineBreak ils)
+ isSimpleCell [] = True
+ isSimpleCell _ = False
+ let hasSimpleCells = all isSimpleCell (concat (headers:rows))
+ let isSimple = hasSimpleCells && all (==0) widths
let isPlainBlock (Plain _) = True
isPlainBlock _ = False
let hasBlocks = not (all isPlainBlock $ concat . concat $ headers:rows)
- (nst,tbl) <- case True of
- _ | isSimple &&
- isEnabled Ext_simple_tables opts -> fmap (nest 2,) $
- pandocTable opts (all null headers) aligns widths
- rawHeaders rawRows
- | isSimple &&
- isEnabled Ext_pipe_tables opts -> fmap (id,) $
- pipeTable (all null headers) aligns rawHeaders rawRows
- | not hasBlocks &&
- isEnabled Ext_multiline_tables opts -> fmap (nest 2,) $
- pandocTable opts (all null headers) aligns widths
- rawHeaders rawRows
- | isEnabled Ext_grid_tables opts -> fmap (id,) $
- gridTable opts (all null headers) aligns widths
- rawHeaders rawRows
- | isEnabled Ext_raw_html opts -> fmap (id,) $
- return $ text $ writeHtmlString def
- $ Pandoc nullMeta [t]
- | otherwise -> return $ (id, text "[TABLE]")
- return $ nst $ tbl $$ blankline $$ caption'' $$ blankline
+ let padRow r = case numcols - length r of
+ x | x > 0 -> r ++ replicate x empty
+ | otherwise -> r
+ let aligns' = case numcols - length aligns of
+ x | x > 0 -> aligns ++ replicate x AlignDefault
+ | otherwise -> aligns
+ let widths' = case numcols - length widths of
+ x | x > 0 -> widths ++ replicate x 0.0
+ | otherwise -> widths
+ (nst,tbl) <-
+ case True of
+ _ | isSimple &&
+ isEnabled Ext_simple_tables opts -> do
+ rawHeaders <- padRow <$> mapM (blockListToMarkdown opts) headers
+ rawRows <- mapM (fmap padRow . mapM (blockListToMarkdown opts))
+ rows
+ (nest 2,) <$> pandocTable opts False (all null headers)
+ aligns' widths' rawHeaders rawRows
+ | isSimple &&
+ isEnabled Ext_pipe_tables opts -> do
+ rawHeaders <- padRow <$> mapM (blockListToMarkdown opts) headers
+ rawRows <- mapM (fmap padRow . mapM (blockListToMarkdown opts))
+ rows
+ (id,) <$> pipeTable (all null headers) aligns' rawHeaders rawRows
+ | not hasBlocks &&
+ isEnabled Ext_multiline_tables opts -> do
+ rawHeaders <- padRow <$> mapM (blockListToMarkdown opts) headers
+ rawRows <- mapM (fmap padRow . mapM (blockListToMarkdown opts))
+ rows
+ (nest 2,) <$> pandocTable opts True (all null headers)
+ aligns' widths' rawHeaders rawRows
+ | isEnabled Ext_grid_tables opts &&
+ writerColumns opts >= 8 * numcols -> (id,) <$>
+ gridTable opts blockListToMarkdown
+ (all null headers) aligns' widths' headers rows
+ | isEnabled Ext_raw_html opts -> fmap (id,) $
+ (text . T.unpack) <$>
+ (writeHtml5String def $ Pandoc nullMeta [t])
+ | hasSimpleCells &&
+ isEnabled Ext_pipe_tables opts -> do
+ rawHeaders <- padRow <$> mapM (blockListToMarkdown opts) headers
+ rawRows <- mapM (fmap padRow . mapM (blockListToMarkdown opts))
+ rows
+ (id,) <$> pipeTable (all null headers) aligns' rawHeaders rawRows
+ | otherwise -> return $ (id, text "[TABLE]")
+ return $ nst $ tbl $$ caption'' $$ blankline
blockToMarkdown' opts (BulletList items) = do
contents <- inList $ mapM (bulletListItemToMarkdown opts) items
return $ cat contents <> blankline
@@ -550,7 +646,7 @@ blockToMarkdown' opts (DefinitionList items) = do
contents <- inList $ mapM (definitionListItemToMarkdown opts) items
return $ cat contents <> blankline
-inList :: MD a -> MD a
+inList :: Monad m => MD m a -> MD m a
inList p = local (\env -> env {envInList = True}) p
addMarkdownAttribute :: String -> String
@@ -562,7 +658,7 @@ addMarkdownAttribute s =
x /= "markdown"]
_ -> s
-pipeTable :: Bool -> [Alignment] -> [Doc] -> [[Doc]] -> MD Doc
+pipeTable :: PandocMonad m => Bool -> [Alignment] -> [Doc] -> [[Doc]] -> MD m Doc
pipeTable headless aligns rawHeaders rawRows = do
let sp = text " "
let blockFor AlignLeft x y = lblock (x + 2) (sp <> y) <> lblock 0 empty
@@ -590,9 +686,10 @@ pipeTable headless aligns rawHeaders rawRows = do
let body = vcat $ map torow rawRows
return $ header $$ border $$ body
-pandocTable :: WriterOptions -> Bool -> [Alignment] -> [Double]
- -> [Doc] -> [[Doc]] -> MD Doc
-pandocTable opts headless aligns widths rawHeaders rawRows = do
+pandocTable :: PandocMonad m
+ => WriterOptions -> Bool -> Bool -> [Alignment] -> [Double]
+ -> [Doc] -> [[Doc]] -> MD m Doc
+pandocTable opts multiline headless aligns widths rawHeaders rawRows = do
let isSimple = all (==0) widths
let alignHeader alignment = case alignment of
AlignLeft -> lblock
@@ -609,23 +706,21 @@ pandocTable opts headless aligns widths rawHeaders rawRows = do
let minNumChars = (+ 2) . maximum . map minOffset
let columns = transpose (rawHeaders : rawRows)
-- minimal column width without wrapping a single word
- let noWordWrapWidth
- | writerWrapText opts == WrapAuto
- = fromIntegral $ maximum (map minNumChars columns)
- | otherwise = fromIntegral $ maximum (map numChars columns)
- let relWidth w = floor $ max (fromIntegral (writerColumns opts) * w)
- (noWordWrapWidth * w / minimum widths)
+ let relWidth w col =
+ max (floor $ fromIntegral (writerColumns opts - 1) * w)
+ (if writerWrapText opts == WrapAuto
+ then minNumChars col
+ else numChars col)
let widthsInChars
| isSimple = map numChars columns
- | otherwise = map relWidth widths
+ | otherwise = zipWith relWidth widths columns
let makeRow = hcat . intersperse (lblock 1 (text " ")) .
(zipWith3 alignHeader aligns widthsInChars)
let rows' = map makeRow rawRows
let head' = makeRow rawHeaders
- let maxRowHeight = maximum $ map height (head':rows')
let underline = cat $ intersperse (text " ") $
map (\width -> text (replicate width '-')) widthsInChars
- let border = if maxRowHeight > 1
+ let border = if multiline
then text (replicate (sum widthsInChars +
length widthsInChars - 1) '-')
else if headless
@@ -634,7 +729,7 @@ pandocTable opts headless aligns widths rawHeaders rawRows = do
let head'' = if headless
then empty
else border <> cr <> head'
- let body = if maxRowHeight > 1
+ let body = if multiline
then vsep rows'
else vcat rows'
let bottom = if headless
@@ -642,62 +737,15 @@ pandocTable opts headless aligns widths rawHeaders rawRows = do
else border
return $ head'' $$ underline $$ body $$ bottom
-gridTable :: WriterOptions -> Bool -> [Alignment] -> [Double]
- -> [Doc] -> [[Doc]] -> MD Doc
-gridTable opts headless aligns widths headers' rawRows = do
- let numcols = length headers'
- let widths' = if all (==0) widths
- then replicate numcols (1.0 / fromIntegral numcols)
- else widths
- let widthsInChars = map
- ((\x -> x - 3) . floor . (fromIntegral (writerColumns opts) *)) widths'
- let hpipeBlocks blocks = hcat [beg, middle, end]
- where h = maximum (1 : map height blocks)
- sep' = lblock 3 $ vcat (map text $ replicate h " | ")
- beg = lblock 2 $ vcat (map text $ replicate h "| ")
- end = lblock 2 $ vcat (map text $ replicate h " |")
- middle = chomp $ hcat $ intersperse sep' blocks
- let makeRow = hpipeBlocks . zipWith lblock widthsInChars
- let head' = makeRow headers'
- let rows' = map (makeRow . map chomp) rawRows
- let borderpart ch align widthInChars =
- let widthInChars' = if widthInChars < 1 then 1 else widthInChars
- in (if (align == AlignLeft || align == AlignCenter)
- then char ':'
- else char ch) <>
- text (replicate widthInChars' ch) <>
- (if (align == AlignRight || align == AlignCenter)
- then char ':'
- else char ch)
- let border ch aligns' widthsInChars' =
- char '+' <>
- hcat (intersperse (char '+') (zipWith (borderpart ch)
- aligns' widthsInChars')) <> char '+'
- let body = vcat $ intersperse (border '-' (repeat AlignDefault) widthsInChars)
- rows'
- let head'' = if headless
- then empty
- else head' $$ border '=' aligns widthsInChars
- if headless
- then return $
- border '-' aligns widthsInChars $$
- body $$
- border '-' (repeat AlignDefault) widthsInChars
- else return $
- border '-' (repeat AlignDefault) widthsInChars $$
- head'' $$
- body $$
- border '-' (repeat AlignDefault) widthsInChars
-
itemEndsWithTightList :: [Block] -> Bool
itemEndsWithTightList bs =
case bs of
[Plain _, BulletList xs] -> isTightList xs
[Plain _, OrderedList _ xs] -> isTightList xs
- _ -> False
+ _ -> False
-- | Convert bullet list item (list of blocks) to markdown.
-bulletListItemToMarkdown :: WriterOptions -> [Block] -> MD Doc
+bulletListItemToMarkdown :: PandocMonad m => WriterOptions -> [Block] -> MD m Doc
bulletListItemToMarkdown opts bs = do
contents <- blockListToMarkdown opts bs
let sps = replicate (writerTabStop opts - 2) ' '
@@ -709,15 +757,16 @@ bulletListItemToMarkdown opts bs = do
return $ hang (writerTabStop opts) start $ contents' <> cr
-- | Convert ordered list item (a list of blocks) to markdown.
-orderedListItemToMarkdown :: WriterOptions -- ^ options
+orderedListItemToMarkdown :: PandocMonad m
+ => WriterOptions -- ^ options
-> String -- ^ list item marker
-> [Block] -- ^ list item (list of blocks)
- -> MD Doc
+ -> MD m Doc
orderedListItemToMarkdown opts marker bs = do
contents <- blockListToMarkdown opts bs
let sps = case length marker - writerTabStop opts of
n | n > 0 -> text $ replicate n ' '
- _ -> text " "
+ _ -> text " "
let start = text marker <> sps
-- remove trailing blank line if item ends with a tight list
let contents' = if itemEndsWithTightList bs
@@ -726,9 +775,10 @@ orderedListItemToMarkdown opts marker bs = do
return $ hang (writerTabStop opts) start $ contents' <> cr
-- | Convert definition list item (label, list of blocks) to markdown.
-definitionListItemToMarkdown :: WriterOptions
+definitionListItemToMarkdown :: PandocMonad m
+ => WriterOptions
-> ([Inline],[[Block]])
- -> MD Doc
+ -> MD m Doc
definitionListItemToMarkdown opts (label, defs) = do
labelText <- inlineListToMarkdown opts label
defs' <- mapM (mapM (blockToMarkdown opts)) defs
@@ -739,7 +789,7 @@ definitionListItemToMarkdown opts (label, defs) = do
let leader = if isPlain then " " else ": "
let sps = case writerTabStop opts - 3 of
n | n > 0 -> text $ replicate n ' '
- _ -> text " "
+ _ -> text " "
if isEnabled Ext_compact_definition_lists opts
then do
let contents = vcat $ map (\d -> hang tabStop (leader <> sps)
@@ -750,7 +800,7 @@ definitionListItemToMarkdown opts (label, defs) = do
$ vcat d <> cr) defs'
let isTight = case defs of
((Plain _ : _): _) -> True
- _ -> False
+ _ -> False
return $ blankline <> nowrap labelText <>
(if isTight then cr else blankline) <> contents <> blankline
else do
@@ -758,75 +808,129 @@ definitionListItemToMarkdown opts (label, defs) = do
vsep (map vsep defs') <> blankline
-- | Convert list of Pandoc block elements to markdown.
-blockListToMarkdown :: WriterOptions -- ^ Options
+blockListToMarkdown :: PandocMonad m
+ => WriterOptions -- ^ Options
-> [Block] -- ^ List of block elements
- -> MD Doc
-blockListToMarkdown opts blocks =
+ -> MD m Doc
+blockListToMarkdown opts blocks = do
+ inlist <- asks envInList
+ isPlain <- asks envPlain
+ -- a) insert comment between list and indented code block, or the
+ -- code block will be treated as a list continuation paragraph
+ -- b) change Plain to Para unless it's followed by a RawBlock
+ -- or has a list as its parent (#3487)
+ let fixBlocks (b : CodeBlock attr x : rest)
+ | (not (isEnabled Ext_fenced_code_blocks opts) || attr == nullAttr)
+ && isListBlock b = b : commentSep : CodeBlock attr x :
+ fixBlocks rest
+ fixBlocks (b1@(BulletList _) : b2@(BulletList _) : bs) =
+ b1 : commentSep : fixBlocks (b2:bs)
+ fixBlocks (b1@(OrderedList _ _) : b2@(OrderedList _ _) : bs) =
+ b1 : commentSep : fixBlocks (b2:bs)
+ fixBlocks (b1@(DefinitionList _) : b2@(DefinitionList _) : bs) =
+ b1 : commentSep : fixBlocks (b2:bs)
+ fixBlocks (Plain ils : bs@(RawBlock{}:_)) =
+ Plain ils : fixBlocks bs
+ fixBlocks (Plain ils : bs) | inlist =
+ Plain ils : fixBlocks bs
+ fixBlocks (Plain ils : bs) =
+ Para ils : fixBlocks bs
+ fixBlocks (x : xs) = x : fixBlocks xs
+ fixBlocks [] = []
+ isListBlock (BulletList _) = True
+ isListBlock (OrderedList _ _) = True
+ isListBlock (DefinitionList _) = True
+ isListBlock _ = False
+ commentSep = if isPlain
+ then Null
+ else if isEnabled Ext_raw_html opts
+ then RawBlock "html" "<!-- -->\n"
+ else RawBlock "markdown" "&nbsp;\n"
mapM (blockToMarkdown opts) (fixBlocks blocks) >>= return . cat
- -- insert comment between list and indented code block, or the
- -- code block will be treated as a list continuation paragraph
- where fixBlocks (b : CodeBlock attr x : rest)
- | (not (isEnabled Ext_fenced_code_blocks opts) || attr == nullAttr)
- && isListBlock b = b : commentSep : CodeBlock attr x :
- fixBlocks rest
- fixBlocks (b1@(BulletList _) : b2@(BulletList _) : bs) =
- b1 : commentSep : fixBlocks (b2:bs)
- fixBlocks (b1@(OrderedList _ _) : b2@(OrderedList _ _) : bs) =
- b1 : commentSep : fixBlocks (b2:bs)
- fixBlocks (b1@(DefinitionList _) : b2@(DefinitionList _) : bs) =
- b1 : commentSep : fixBlocks (b2:bs)
- fixBlocks (x : xs) = x : fixBlocks xs
- fixBlocks [] = []
- isListBlock (BulletList _) = True
- isListBlock (OrderedList _ _) = True
- isListBlock (DefinitionList _) = True
- isListBlock _ = False
- commentSep = if isEnabled Ext_raw_html opts
- then RawBlock "html" "<!-- -->\n"
- else RawBlock "markdown" "&nbsp;"
+
+getKey :: Doc -> Key
+getKey = toKey . render Nothing
-- | Get reference for target; if none exists, create unique one and return.
-- Prefer label if possible; otherwise, generate a unique key.
-getReference :: Attr -> [Inline] -> Target -> MD [Inline]
+getReference :: PandocMonad m => Attr -> Doc -> Target -> MD m Doc
getReference attr label target = do
- st <- get
- case find (\(_,t,a) -> t == target && a == attr) (stRefs st) of
+ refs <- gets stRefs
+ case find (\(_,t,a) -> t == target && a == attr) refs of
Just (ref, _, _) -> return ref
Nothing -> do
- let label' = case find (\(l,_,_) -> l == label) (stRefs st) of
- Just _ -> -- label is used; generate numerical label
- case find (\n -> notElem [Str (show n)]
- (map (\(l,_,_) -> l) (stRefs st)))
- [1..(10000 :: Integer)] of
- Just x -> [Str (show x)]
- Nothing -> error "no unique label"
- Nothing -> label
- modify (\s -> s{ stRefs = (label', target, attr) : stRefs st })
- return label'
+ keys <- gets stKeys
+ case M.lookup (getKey label) keys of
+ Nothing -> do -- no other refs with this label
+ (lab', idx) <- if isEmpty label
+ then do
+ i <- (+ 1) <$> gets stLastIdx
+ modify $ \s -> s{ stLastIdx = i }
+ return (text (show i), i)
+ else return (label, 0)
+ modify (\s -> s{
+ stRefs = (lab', target, attr) : refs,
+ stKeys = M.insert (getKey label)
+ (M.insert (target, attr) idx mempty)
+ (stKeys s) })
+ return lab'
+
+ Just km -> do -- we have refs with this label
+ case M.lookup (target, attr) km of
+ Just i -> do
+ let lab' = label <> if i == 0
+ then mempty
+ else text (show i)
+ -- make sure it's in stRefs; it may be
+ -- a duplicate that was printed in a previous
+ -- block:
+ when ((lab', target, attr) `notElem` refs) $
+ modify (\s -> s{
+ stRefs = (lab', target, attr) : refs })
+ return lab'
+ Nothing -> do -- but this one is to a new target
+ i <- (+ 1) <$> gets stLastIdx
+ modify $ \s -> s{ stLastIdx = i }
+ let lab' = text (show i)
+ modify (\s -> s{
+ stRefs = (lab', target, attr) : refs,
+ stKeys = M.insert (getKey label)
+ (M.insert (target, attr) i km)
+ (stKeys s) })
+ return lab'
-- | Convert list of Pandoc inline elements to markdown.
-inlineListToMarkdown :: WriterOptions -> [Inline] -> MD Doc
+inlineListToMarkdown :: PandocMonad m => WriterOptions -> [Inline] -> MD m Doc
inlineListToMarkdown opts lst = do
inlist <- asks envInList
go (if inlist then avoidBadWrapsInList lst else lst)
where go [] = return empty
go (i:is) = case i of
(Link _ _ _) -> case is of
- -- If a link is followed by another link or '[' we don't shortcut
- (Link _ _ _):_ -> unshortcutable
- Space:(Link _ _ _):_ -> unshortcutable
- Space:(Str('[':_)):_ -> unshortcutable
- Space:(RawInline _ ('[':_)):_ -> unshortcutable
- Space:(Cite _ _):_ -> unshortcutable
- SoftBreak:(Link _ _ _):_ -> unshortcutable
- SoftBreak:(Str('[':_)):_ -> unshortcutable
+ -- If a link is followed by another link, or '[', '(' or ':'
+ -- then we don't shortcut
+ (Link _ _ _):_ -> unshortcutable
+ Space:(Link _ _ _):_ -> unshortcutable
+ Space:(Str('[':_)):_ -> unshortcutable
+ Space:(RawInline _ ('[':_)):_ -> unshortcutable
+ Space:(Cite _ _):_ -> unshortcutable
+ SoftBreak:(Link _ _ _):_ -> unshortcutable
+ SoftBreak:(Str('[':_)):_ -> unshortcutable
SoftBreak:(RawInline _ ('[':_)):_ -> unshortcutable
- SoftBreak:(Cite _ _):_ -> unshortcutable
- (Cite _ _):_ -> unshortcutable
- Str ('[':_):_ -> unshortcutable
- (RawInline _ ('[':_)):_ -> unshortcutable
- (RawInline _ (' ':'[':_)):_ -> unshortcutable
- _ -> shortcutable
+ SoftBreak:(Cite _ _):_ -> unshortcutable
+ LineBreak:(Link _ _ _):_ -> unshortcutable
+ LineBreak:(Str('[':_)):_ -> unshortcutable
+ LineBreak:(RawInline _ ('[':_)):_ -> unshortcutable
+ LineBreak:(Cite _ _):_ -> unshortcutable
+ (Cite _ _):_ -> unshortcutable
+ Str ('[':_):_ -> unshortcutable
+ Str ('(':_):_ -> unshortcutable
+ Str (':':_):_ -> unshortcutable
+ (RawInline _ ('[':_)):_ -> unshortcutable
+ (RawInline _ ('(':_)):_ -> unshortcutable
+ (RawInline _ (':':_)):_ -> unshortcutable
+ (RawInline _ (' ':'[':_)):_ -> unshortcutable
+ _ -> shortcutable
_ -> shortcutable
where shortcutable = liftM2 (<>) (inlineToMarkdown opts i) (go is)
unshortcutable = do
@@ -836,9 +940,9 @@ inlineListToMarkdown opts lst = do
fmap (iMark <>) (go is)
isSp :: Inline -> Bool
-isSp Space = True
+isSp Space = True
isSp SoftBreak = True
-isSp _ = False
+isSp _ = False
avoidBadWrapsInList :: [Inline] -> [Inline]
avoidBadWrapsInList [] = []
@@ -857,7 +961,7 @@ avoidBadWrapsInList (s:Str cs:[])
avoidBadWrapsInList (x:xs) = x : avoidBadWrapsInList xs
isOrderedListMarker :: String -> Bool
-isOrderedListMarker xs = (last xs `elem` ['.',')']) &&
+isOrderedListMarker xs = not (null xs) && (last xs `elem` ['.',')']) &&
isRight (runParser (anyOrderedListMarker >> eof)
defaultParserState "" xs)
@@ -866,27 +970,30 @@ isRight (Right _) = True
isRight (Left _) = False
-- | Convert Pandoc inline element to markdown.
-inlineToMarkdown :: WriterOptions -> Inline -> MD Doc
+inlineToMarkdown :: PandocMonad m => WriterOptions -> Inline -> MD m Doc
inlineToMarkdown opts (Span attrs ils) = do
plain <- asks envPlain
contents <- inlineListToMarkdown opts ils
return $ case plain of
True -> contents
- False | isEnabled Ext_bracketed_spans opts ->
- "[" <> contents <> "]" <>
- if attrs == nullAttr
- then "{}"
- else linkAttributes opts attrs
+ False | attrs == nullAttr -> contents
+ | isEnabled Ext_bracketed_spans opts ->
+ let attrs' = if attrs /= nullAttr
+ then attrsToMarkdown attrs
+ else empty
+ in "[" <> contents <> "]" <> attrs'
| isEnabled Ext_raw_html opts ||
isEnabled Ext_native_spans opts ->
tagWithAttrs "span" attrs <> contents <> text "</span>"
| otherwise -> contents
+inlineToMarkdown _ (Emph []) = return empty
inlineToMarkdown opts (Emph lst) = do
plain <- asks envPlain
contents <- inlineListToMarkdown opts lst
return $ if plain
then "_" <> contents <> "_"
else "*" <> contents <> "*"
+inlineToMarkdown _ (Strong []) = return empty
inlineToMarkdown opts (Strong lst) = do
plain <- asks envPlain
if plain
@@ -894,6 +1001,7 @@ inlineToMarkdown opts (Strong lst) = do
else do
contents <- inlineListToMarkdown opts lst
return $ "**" <> contents <> "**"
+inlineToMarkdown _ (Strikeout []) = return empty
inlineToMarkdown opts (Strikeout lst) = do
contents <- inlineListToMarkdown opts lst
return $ if isEnabled Ext_strikeout opts
@@ -901,6 +1009,7 @@ inlineToMarkdown opts (Strikeout lst) = do
else if isEnabled Ext_raw_html opts
then "<s>" <> contents <> "</s>"
else contents
+inlineToMarkdown _ (Superscript []) = return empty
inlineToMarkdown opts (Superscript lst) =
local (\env -> env {envEscapeSpaces = True}) $ do
contents <- inlineListToMarkdown opts lst
@@ -908,14 +1017,12 @@ inlineToMarkdown opts (Superscript lst) =
then "^" <> contents <> "^"
else if isEnabled Ext_raw_html opts
then "<sup>" <> contents <> "</sup>"
- else case (render Nothing contents) of
- ds | all (\d -> d >= '0' && d <= '9') ds
- -> text (map toSuperscript ds)
- _ -> contents
- where toSuperscript '1' = '\x00B9'
- toSuperscript '2' = '\x00B2'
- toSuperscript '3' = '\x00B3'
- toSuperscript c = chr (0x2070 + (ord c - 48))
+ else
+ let rendered = render Nothing contents
+ in case mapM toSuperscript rendered of
+ Just r -> text r
+ Nothing -> text $ "^(" ++ rendered ++ ")"
+inlineToMarkdown _ (Subscript []) = return empty
inlineToMarkdown opts (Subscript lst) =
local (\env -> env {envEscapeSpaces = True}) $ do
contents <- inlineListToMarkdown opts lst
@@ -923,27 +1030,27 @@ inlineToMarkdown opts (Subscript lst) =
then "~" <> contents <> "~"
else if isEnabled Ext_raw_html opts
then "<sub>" <> contents <> "</sub>"
- else case (render Nothing contents) of
- ds | all (\d -> d >= '0' && d <= '9') ds
- -> text (map toSubscript ds)
- _ -> contents
- where toSubscript c = chr (0x2080 + (ord c - 48))
+ else
+ let rendered = render Nothing contents
+ in case mapM toSubscript rendered of
+ Just r -> text r
+ Nothing -> text $ "_(" ++ rendered ++ ")"
inlineToMarkdown opts (SmallCaps lst) = do
plain <- asks envPlain
if not plain &&
(isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
- then do
- contents <- inlineListToMarkdown opts lst
- return $ tagWithAttrs "span"
- ("",[],[("style","font-variant:small-caps;")])
- <> contents <> text "</span>"
+ then inlineToMarkdown opts (Span ("",["smallcaps"],[]) lst)
else inlineListToMarkdown opts $ capitalize lst
inlineToMarkdown opts (Quoted SingleQuote lst) = do
contents <- inlineListToMarkdown opts lst
- return $ "‘" <> contents <> "’"
+ return $ if isEnabled Ext_smart opts
+ then "'" <> contents <> "'"
+ else "‘" <> contents <> "’"
inlineToMarkdown opts (Quoted DoubleQuote lst) = do
contents <- inlineListToMarkdown opts lst
- return $ "“" <> contents <> "”"
+ return $ if isEnabled Ext_smart opts
+ then "\"" <> contents <> "\""
+ else "“" <> contents <> "”"
inlineToMarkdown opts (Code attr str) = do
let tickGroups = filter (\s -> '`' `elem` s) $ group str
let longest = if null tickGroups
@@ -960,14 +1067,17 @@ inlineToMarkdown opts (Code attr str) = do
else return $ text (marker ++ spacer ++ str ++ spacer ++ marker) <> attrs
inlineToMarkdown opts (Str str) = do
isPlain <- asks envPlain
- if isPlain
- then return $ text str
- else return $ text $ escapeString opts str
+ let str' = (if isEnabled Ext_smart opts
+ then unsmartify opts
+ else id) $
+ if isPlain
+ then str
+ else escapeString opts str
+ return $ text str'
inlineToMarkdown opts (Math InlineMath str) =
case writerHTMLMathMethod opts of
- WebTeX url ->
- inlineToMarkdown opts (Image nullAttr [Str str]
- (url ++ urlEncode str, str))
+ WebTeX url -> inlineToMarkdown opts
+ (Image nullAttr [Str str] (url ++ urlEncode str, str))
_ | isEnabled Ext_tex_math_dollars opts ->
return $ "$" <> text str <> "$"
| isEnabled Ext_tex_math_single_backslash opts ->
@@ -976,9 +1086,9 @@ inlineToMarkdown opts (Math InlineMath str) =
return $ "\\\\(" <> text str <> "\\\\)"
| otherwise -> do
plain <- asks envPlain
- inlineListToMarkdown opts $
- (if plain then makeMathPlainer else id) $
- texMathToInlines InlineMath str
+ texMathToInlines InlineMath str >>=
+ inlineListToMarkdown opts .
+ (if plain then makeMathPlainer else id)
inlineToMarkdown opts (Math DisplayMath str) =
case writerHTMLMathMethod opts of
WebTeX url -> (\x -> blankline <> x <> blankline) `fmap`
@@ -991,15 +1101,19 @@ inlineToMarkdown opts (Math DisplayMath str) =
| isEnabled Ext_tex_math_double_backslash opts ->
return $ "\\\\[" <> text str <> "\\\\]"
| otherwise -> (\x -> cr <> x <> cr) `fmap`
- inlineListToMarkdown opts (texMathToInlines DisplayMath str)
-inlineToMarkdown opts (RawInline f str) = do
+ (texMathToInlines DisplayMath str >>= inlineListToMarkdown opts)
+inlineToMarkdown opts il@(RawInline f str) = do
plain <- asks envPlain
- if not plain &&
- ( f == "markdown" ||
+ if (plain && f == "plain") || (not plain &&
+ ( f `elem` ["markdown", "markdown_github", "markdown_phpextra",
+ "markdown_mmd", "markdown_strict"] ||
(isEnabled Ext_raw_tex opts && (f == "latex" || f == "tex")) ||
- (isEnabled Ext_raw_html opts && f == "html") )
+ (isEnabled Ext_raw_html opts && f `elem` ["html", "html4", "html5"])
+ ))
then return $ text str
- else return empty
+ else do
+ report $ InlineNotRendered il
+ return empty
inlineToMarkdown opts (LineBreak) = do
plain <- asks envPlain
if plain || isEnabled Ext_hard_line_breaks opts
@@ -1052,7 +1166,8 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
- return $ text $ trim $ writeHtmlString def $ Pandoc nullMeta [Plain [lnk]]
+ (text . T.unpack . T.strip) <$>
+ writeHtml5String def (Pandoc nullMeta [Plain [lnk]])
| otherwise = do
plain <- asks envPlain
linktext <- inlineListToMarkdown opts txt
@@ -1063,20 +1178,20 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
let useAuto = isURI src &&
case txt of
[Str s] | escapeURI s == srcSuffix -> True
- _ -> False
+ _ -> False
let useRefLinks = writerReferenceLinks opts && not useAuto
shortcutable <- asks envRefShortcutable
let useShortcutRefLinks = shortcutable &&
isEnabled Ext_shortcut_reference_links opts
- ref <- if useRefLinks then getReference attr txt (src, tit) else return []
- reftext <- inlineListToMarkdown opts ref
+ reftext <- if useRefLinks then getReference attr linktext (src, tit)
+ else return empty
return $ if useAuto
then if plain
then text srcSuffix
else "<" <> text srcSuffix <> ">"
else if useRefLinks
then let first = "[" <> linktext <> "]"
- second = if txt == ref
+ second = if getKey linktext == getKey reftext
then if useShortcutRefLinks
then ""
else "[]"
@@ -1091,7 +1206,8 @@ inlineToMarkdown opts img@(Image attr alternate (source, tit))
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
- return $ text $ trim $ writeHtmlString def $ Pandoc nullMeta [Plain [img]]
+ (text . T.unpack . T.strip) <$>
+ writeHtml5String def (Pandoc nullMeta [Plain [img]])
| otherwise = do
plain <- asks envPlain
let txt = if null alternate || alternate == [Str source]
@@ -1114,4 +1230,36 @@ makeMathPlainer :: [Inline] -> [Inline]
makeMathPlainer = walk go
where
go (Emph xs) = Span nullAttr xs
- go x = x
+ go x = x
+
+toSuperscript :: Char -> Maybe Char
+toSuperscript '1' = Just '\x00B9'
+toSuperscript '2' = Just '\x00B2'
+toSuperscript '3' = Just '\x00B3'
+toSuperscript '+' = Just '\x207A'
+toSuperscript '-' = Just '\x207B'
+toSuperscript '=' = Just '\x207C'
+toSuperscript '(' = Just '\x207D'
+toSuperscript ')' = Just '\x207E'
+toSuperscript c
+ | c >= '0' && c <= '9' =
+ Just $ chr (0x2070 + (ord c - 48))
+ | isSpace c = Just c
+ | otherwise = Nothing
+
+toSubscript :: Char -> Maybe Char
+toSubscript '+' = Just '\x208A'
+toSubscript '-' = Just '\x208B'
+toSubscript '=' = Just '\x208C'
+toSubscript '(' = Just '\x208D'
+toSubscript ')' = Just '\x208E'
+toSubscript c
+ | c >= '0' && c <= '9' =
+ Just $ chr (0x2080 + (ord c - 48))
+ | isSpace c = Just c
+ | otherwise = Nothing
+
+lineBreakToSpace :: Inline -> Inline
+lineBreakToSpace LineBreak = Space
+lineBreakToSpace SoftBreak = Space
+lineBreakToSpace x = x
diff --git a/src/Text/Pandoc/Writers/Math.hs b/src/Text/Pandoc/Writers/Math.hs
new file mode 100644
index 000000000..477f5a0b1
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Math.hs
@@ -0,0 +1,56 @@
+module Text.Pandoc.Writers.Math
+ ( texMathToInlines
+ , convertMath
+ , defaultMathJaxURL
+ , defaultKaTeXURL
+ )
+where
+
+import Text.Pandoc.Class
+import Text.Pandoc.Definition
+import Text.Pandoc.Logging
+import Text.TeXMath (DisplayType (..), Exp, readTeX, writePandoc)
+
+-- | Converts a raw TeX math formula to a list of 'Pandoc' inlines.
+-- Defaults to raw formula between @$@ or @$$@ characters if entire formula
+-- can't be converted.
+texMathToInlines :: PandocMonad m
+ => MathType
+ -> String -- ^ String to parse (assumes @'\n'@ line endings)
+ -> m [Inline]
+texMathToInlines mt inp = do
+ res <- convertMath writePandoc mt inp
+ case res of
+ Right (Just ils) -> return ils
+ Right Nothing -> do
+ report $ CouldNotConvertTeXMath inp ""
+ return [mkFallback mt inp]
+ Left il -> return [il]
+
+mkFallback :: MathType -> String -> Inline
+mkFallback mt str = Str (delim ++ str ++ delim)
+ where delim = case mt of
+ DisplayMath -> "$$"
+ InlineMath -> "$"
+
+-- | Converts a raw TeX math formula using a writer function,
+-- issuing a warning and producing a fallback (a raw string)
+-- on failure.
+convertMath :: PandocMonad m
+ => (DisplayType -> [Exp] -> a) -> MathType -> String
+ -> m (Either Inline a)
+convertMath writer mt str =
+ case writer dt <$> readTeX str of
+ Right r -> return (Right r)
+ Left e -> do
+ report $ CouldNotConvertTeXMath str e
+ return (Left $ mkFallback mt str)
+ where dt = case mt of
+ DisplayMath -> DisplayBlock
+ InlineMath -> DisplayInline
+
+defaultMathJaxURL :: String
+defaultMathJaxURL = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/"
+
+defaultKaTeXURL :: String
+defaultKaTeXURL = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/"
diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs
index 78d4651e7..2470d9200 100644
--- a/src/Text/Pandoc/Writers/MediaWiki.hs
+++ b/src/Text/Pandoc/Writers/MediaWiki.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.MediaWiki
- Copyright : Copyright (C) 2008-2015 John MacFarlane
+ Copyright : Copyright (C) 2008-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,41 +30,44 @@ Conversion of 'Pandoc' documents to MediaWiki markup.
MediaWiki: <http://www.mediawiki.org/wiki/MediaWiki>
-}
module Text.Pandoc.Writers.MediaWiki ( writeMediaWiki ) where
+import Control.Monad.Reader
+import Control.Monad.State.Strict
+import Data.List (intercalate)
+import qualified Data.Set as Set
+import Data.Text (Text, pack)
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
import Text.Pandoc.Pretty (render)
-import Text.Pandoc.ImageSize
+import Text.Pandoc.Shared
import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.XML ( escapeStringForXML )
-import Data.List ( intersect, intercalate )
-import Network.URI ( isURI )
-import Control.Monad.Reader
-import Control.Monad.State
+import Text.Pandoc.Writers.Shared
+import Text.Pandoc.XML (escapeStringForXML)
data WriterState = WriterState {
- stNotes :: Bool -- True if there are notes
- , stOptions :: WriterOptions -- writer options
+ stNotes :: Bool -- True if there are notes
+ , stOptions :: WriterOptions -- writer options
}
data WriterReader = WriterReader {
- options :: WriterOptions -- Writer options
- , listLevel :: String -- String at beginning of list items, e.g. "**"
- , useTags :: Bool -- True if we should use HTML tags because we're in a complex list
+ options :: WriterOptions -- Writer options
+ , listLevel :: String -- String at beginning of list items, e.g. "**"
+ , useTags :: Bool -- True if we should use HTML tags because we're in a complex list
}
-type MediaWikiWriter = ReaderT WriterReader (State WriterState)
+type MediaWikiWriter m = ReaderT WriterReader (StateT WriterState m)
-- | Convert Pandoc to MediaWiki.
-writeMediaWiki :: WriterOptions -> Pandoc -> String
+writeMediaWiki :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeMediaWiki opts document =
let initialState = WriterState { stNotes = False, stOptions = opts }
env = WriterReader { options = opts, listLevel = [], useTags = False }
- in evalState (runReaderT (pandocToMediaWiki document) env) initialState
+ in evalStateT (runReaderT (pandocToMediaWiki document) env) initialState
-- | Return MediaWiki representation of document.
-pandocToMediaWiki :: Pandoc -> MediaWikiWriter String
+pandocToMediaWiki :: PandocMonad m => Pandoc -> MediaWikiWriter m Text
pandocToMediaWiki (Pandoc meta blocks) = do
opts <- asks options
metadata <- metaToJSON opts
@@ -79,8 +82,8 @@ pandocToMediaWiki (Pandoc meta blocks) = do
let main = body ++ notes
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts) metadata
- return $ case writerTemplate opts of
- Nothing -> main
+ pack <$> case writerTemplate opts of
+ Nothing -> return main
Just tpl -> renderTemplate' tpl context
-- | Escape special characters for MediaWiki.
@@ -88,8 +91,9 @@ escapeString :: String -> String
escapeString = escapeStringForXML
-- | Convert Pandoc block element to MediaWiki.
-blockToMediaWiki :: Block -- ^ Block element
- -> MediaWikiWriter String
+blockToMediaWiki :: PandocMonad m
+ => Block -- ^ Block element
+ -> MediaWikiWriter m String
blockToMediaWiki Null = return ""
@@ -123,10 +127,10 @@ blockToMediaWiki (Para inlines) = do
blockToMediaWiki (LineBlock lns) =
blockToMediaWiki $ linesToPara lns
-blockToMediaWiki (RawBlock f str)
+blockToMediaWiki b@(RawBlock f str)
| f == Format "mediawiki" = return str
| f == Format "html" = return str
- | otherwise = return ""
+ | otherwise = "" <$ report (BlockNotRendered b)
blockToMediaWiki HorizontalRule = return "\n-----\n"
@@ -136,23 +140,15 @@ blockToMediaWiki (Header level _ inlines) = do
return $ eqs ++ " " ++ contents ++ " " ++ eqs ++ "\n"
blockToMediaWiki (CodeBlock (_,classes,_) str) = do
- let at = classes `intersect` ["actionscript", "ada", "apache", "applescript", "asm", "asp",
- "autoit", "bash", "blitzbasic", "bnf", "c", "c_mac", "caddcl", "cadlisp", "cfdg", "cfm",
- "cpp", "cpp-qt", "csharp", "css", "d", "delphi", "diff", "div", "dos", "eiffel", "fortran",
- "freebasic", "gml", "groovy", "html4strict", "idl", "ini", "inno", "io", "java", "java5",
- "javascript", "latex", "lisp", "lua", "matlab", "mirc", "mpasm", "mysql", "nsis", "objc",
- "ocaml", "ocaml-brief", "oobas", "oracle8", "pascal", "perl", "php", "php-brief", "plsql",
- "python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic",
- "smalltalk", "smarty", "sql", "tcl", "", "thinbasic", "tsql", "vb", "vbnet", "vhdl",
- "visualfoxpro", "winbatch", "xml", "xpp", "z80"]
+ let at = Set.fromList classes `Set.intersection` highlightingLangs
return $
- if null at
- then "<pre" ++ (if null classes
- then ">"
- else " class=\"" ++ unwords classes ++ "\">") ++
- escapeString str ++ "</pre>"
- else "<source lang=\"" ++ head at ++ "\">" ++ str ++ "</source>"
- -- note: no escape!
+ case Set.toList at of
+ [] -> "<pre" ++ (if null classes
+ then ">"
+ else " class=\"" ++ unwords classes ++ "\">") ++
+ escapeString str ++ "</pre>"
+ (l:_) -> "<source lang=\"" ++ l ++ "\">" ++ str ++ "</source>"
+ -- note: no escape! even for <!
blockToMediaWiki (BlockQuote blocks) = do
contents <- blockListToMediaWiki blocks
@@ -218,7 +214,7 @@ listAttribsToString (startnum, numstyle, _) =
else "")
-- | Convert bullet or ordered list item (list of blocks) to MediaWiki.
-listItemToMediaWiki :: [Block] -> MediaWikiWriter String
+listItemToMediaWiki :: PandocMonad m => [Block] -> MediaWikiWriter m String
listItemToMediaWiki items = do
contents <- blockListToMediaWiki items
tags <- asks useTags
@@ -229,8 +225,9 @@ listItemToMediaWiki items = do
return $ marker ++ " " ++ contents
-- | Convert definition list item (label, list of blocks) to MediaWiki.
-definitionListItemToMediaWiki :: ([Inline],[[Block]])
- -> MediaWikiWriter String
+definitionListItemToMediaWiki :: PandocMonad m
+ => ([Inline],[[Block]])
+ -> MediaWikiWriter m String
definitionListItemToMediaWiki (label, items) = do
labelText <- inlineListToMediaWiki label
contents <- mapM blockListToMediaWiki items
@@ -259,18 +256,18 @@ isSimpleListItem :: [Block] -> Bool
isSimpleListItem [] = True
isSimpleListItem [x] =
case x of
- Plain _ -> True
- Para _ -> True
- BulletList _ -> isSimpleList x
- OrderedList _ _ -> isSimpleList x
- DefinitionList _ -> isSimpleList x
- _ -> False
+ Plain _ -> True
+ Para _ -> True
+ BulletList _ -> isSimpleList x
+ OrderedList _ _ -> isSimpleList x
+ DefinitionList _ -> isSimpleList x
+ _ -> False
isSimpleListItem [x, y] | isPlainOrPara x =
case y of
- BulletList _ -> isSimpleList y
- OrderedList _ _ -> isSimpleList y
- DefinitionList _ -> isSimpleList y
- _ -> False
+ BulletList _ -> isSimpleList y
+ OrderedList _ _ -> isSimpleList y
+ DefinitionList _ -> isSimpleList y
+ _ -> False
isSimpleListItem _ = False
isPlainOrPara :: Block -> Bool
@@ -284,20 +281,22 @@ vcat = intercalate "\n"
-- Auxiliary functions for tables:
-tableRowToMediaWiki :: Bool
+tableRowToMediaWiki :: PandocMonad m
+ => Bool
-> [Alignment]
-> [Double]
-> (Int, [[Block]])
- -> MediaWikiWriter String
+ -> MediaWikiWriter m String
tableRowToMediaWiki headless alignments widths (rownum, cells) = do
cells' <- mapM (tableCellToMediaWiki headless rownum)
$ zip3 alignments widths cells
return $ unlines cells'
-tableCellToMediaWiki :: Bool
+tableCellToMediaWiki :: PandocMonad m
+ => Bool
-> Int
-> (Alignment, Double, [Block])
- -> MediaWikiWriter String
+ -> MediaWikiWriter m String
tableCellToMediaWiki headless rownum (alignment, width, bs) = do
contents <- blockListToMediaWiki bs
let marker = if rownum == 1 && not headless then "!" else "|"
@@ -322,13 +321,13 @@ alignmentToString alignment = case alignment of
AlignCenter -> "center"
AlignDefault -> "left"
-imageToMediaWiki :: Attr -> MediaWikiWriter String
+imageToMediaWiki :: PandocMonad m => Attr -> MediaWikiWriter m String
imageToMediaWiki attr = do
opts <- gets stOptions
let (_, cls, _) = attr
toPx = fmap (showInPixel opts) . checkPct
checkPct (Just (Percent _)) = Nothing
- checkPct maybeDim = maybeDim
+ checkPct maybeDim = maybeDim
go (Just w) Nothing = '|':w ++ "px"
go (Just w) (Just h) = '|':w ++ "x" ++ h ++ "px"
go Nothing (Just h) = "|x" ++ h ++ "px"
@@ -340,18 +339,19 @@ imageToMediaWiki attr = do
return $ dims ++ classes
-- | Convert list of Pandoc block elements to MediaWiki.
-blockListToMediaWiki :: [Block] -- ^ List of block elements
- -> MediaWikiWriter String
+blockListToMediaWiki :: PandocMonad m
+ => [Block] -- ^ List of block elements
+ -> MediaWikiWriter m String
blockListToMediaWiki blocks =
fmap vcat $ mapM blockToMediaWiki blocks
-- | Convert list of Pandoc inline elements to MediaWiki.
-inlineListToMediaWiki :: [Inline] -> MediaWikiWriter String
+inlineListToMediaWiki :: PandocMonad m => [Inline] -> MediaWikiWriter m String
inlineListToMediaWiki lst =
fmap concat $ mapM inlineToMediaWiki lst
-- | Convert Pandoc inline element to MediaWiki.
-inlineToMediaWiki :: Inline -> MediaWikiWriter String
+inlineToMediaWiki :: PandocMonad m => Inline -> MediaWikiWriter m String
inlineToMediaWiki (Span attrs ils) = do
contents <- inlineListToMediaWiki ils
@@ -394,22 +394,28 @@ inlineToMediaWiki (Code _ str) =
inlineToMediaWiki (Str str) = return $ escapeString str
-inlineToMediaWiki (Math _ str) = return $ "<math>" ++ str ++ "</math>"
- -- note: str should NOT be escaped
+inlineToMediaWiki (Math mt str) = return $
+ "<math display=\"" ++
+ (if mt == DisplayMath then "block" else "inline") ++
+ "\">" ++ str ++ "</math>"
+ -- note: str should NOT be escaped
-inlineToMediaWiki (RawInline f str)
+inlineToMediaWiki il@(RawInline f str)
| f == Format "mediawiki" = return str
| f == Format "html" = return str
- | otherwise = return ""
+ | otherwise = "" <$ report (InlineNotRendered il)
-inlineToMediaWiki (LineBreak) = return "<br />\n"
+inlineToMediaWiki LineBreak = return "<br />\n"
inlineToMediaWiki SoftBreak = do
wrapText <- gets (writerWrapText . stOptions)
+ listlevel <- asks listLevel
case wrapText of
WrapAuto -> return " "
WrapNone -> return " "
- WrapPreserve -> return "\n"
+ WrapPreserve -> if null listlevel
+ then return "\n"
+ else return " "
inlineToMediaWiki Space = return " "
@@ -437,5 +443,636 @@ inlineToMediaWiki (Image attr alt (source, tit)) = do
inlineToMediaWiki (Note contents) = do
contents' <- blockListToMediaWiki contents
modify (\s -> s { stNotes = True })
- return $ "<ref>" ++ contents' ++ "</ref>"
- -- note - may not work for notes with multiple blocks
+ return $ "<ref>" ++ stripTrailingNewlines contents' ++ "</ref>"
+ -- note - does not work for notes with multiple blocks
+
+highlightingLangs :: Set.Set String
+highlightingLangs = Set.fromList [
+ "abap",
+ "abl",
+ "abnf",
+ "aconf",
+ "actionscript",
+ "actionscript3",
+ "ada",
+ "ada2005",
+ "ada95",
+ "adl",
+ "agda",
+ "ahk",
+ "alloy",
+ "ambienttalk",
+ "ambienttalk/2",
+ "antlr",
+ "antlr-actionscript",
+ "antlr-as",
+ "antlr-c#",
+ "antlr-cpp",
+ "antlr-csharp",
+ "antlr-java",
+ "antlr-objc",
+ "antlr-perl",
+ "antlr-python",
+ "antlr-rb",
+ "antlr-ruby",
+ "apache",
+ "apacheconf",
+ "apl",
+ "applescript",
+ "arduino",
+ "arexx",
+ "as",
+ "as3",
+ "asm",
+ "aspectj",
+ "aspx-cs",
+ "aspx-vb",
+ "asy",
+ "asymptote",
+ "at",
+ "autohotkey",
+ "autoit",
+ "awk",
+ "b3d",
+ "basemake",
+ "bash",
+ "basic",
+ "bat",
+ "batch",
+ "bbcode",
+ "because",
+ "befunge",
+ "bf",
+ "blitzbasic",
+ "blitzmax",
+ "bmax",
+ "bnf",
+ "boo",
+ "boogie",
+ "bplus",
+ "brainfuck",
+ "bro",
+ "bsdmake",
+ "bugs",
+ "c",
+ "c#",
+ "c++",
+ "c++-objdumb",
+ "c-objdump",
+ "ca65",
+ "cadl",
+ "camkes",
+ "cbmbas",
+ "ceylon",
+ "cf3",
+ "cfc",
+ "cfengine3",
+ "cfg",
+ "cfm",
+ "cfs",
+ "chai",
+ "chaiscript",
+ "chapel",
+ "cheetah",
+ "chpl",
+ "cirru",
+ "cl",
+ "clay",
+ "clipper",
+ "clj",
+ "cljs",
+ "clojure",
+ "clojurescript",
+ "cmake",
+ "cobol",
+ "cobolfree",
+ "coffee",
+ "coffee-script",
+ "coffeescript",
+ "common-lisp",
+ "componentpascal",
+ "console",
+ "control",
+ "coq",
+ "cp",
+ "cpp",
+ "cpp-objdump",
+ "cpsa",
+ "crmsh",
+ "croc",
+ "cry",
+ "cryptol",
+ "csh",
+ "csharp",
+ "csound",
+ "csound-csd",
+ "csound-document",
+ "csound-orc",
+ "csound-sco",
+ "csound-score",
+ "css",
+ "css+django",
+ "css+erb",
+ "css+genshi",
+ "css+genshitext",
+ "css+jinja",
+ "css+lasso",
+ "css+mako",
+ "css+mozpreproc",
+ "css+myghty",
+ "css+php",
+ "css+ruby",
+ "css+smarty",
+ "cu",
+ "cucumber",
+ "cuda",
+ "cxx-objdump",
+ "cypher",
+ "cython",
+ "d",
+ "d-objdump",
+ "dart",
+ "debcontrol",
+ "debsources",
+ "delphi",
+ "dg",
+ "diff",
+ "django",
+ "docker",
+ "dockerfile",
+ "dosbatch",
+ "doscon",
+ "dosini",
+ "dpatch",
+ "dtd",
+ "duby",
+ "duel",
+ "dylan",
+ "dylan-console",
+ "dylan-lid",
+ "dylan-repl",
+ "earl-grey",
+ "earlgrey",
+ "easytrieve",
+ "ebnf",
+ "ec",
+ "ecl",
+ "eg",
+ "eiffel",
+ "elisp",
+ "elixir",
+ "elm",
+ "emacs",
+ "erb",
+ "erl",
+ "erlang",
+ "evoque",
+ "ex",
+ "exs",
+ "ezhil",
+ "factor",
+ "fan",
+ "fancy",
+ "felix",
+ "fish",
+ "fishshell",
+ "flx",
+ "fortran",
+ "fortranfixed",
+ "foxpro",
+ "fsharp",
+ "fy",
+ "gap",
+ "gas",
+ "gawk",
+ "genshi",
+ "genshitext",
+ "gherkin",
+ "glsl",
+ "gnuplot",
+ "go",
+ "golo",
+ "gooddata-cl",
+ "gosu",
+ "groff",
+ "groovy",
+ "gst",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "haxeml",
+ "hexdump",
+ "hs",
+ "html",
+ "html+cheetah",
+ "html+django",
+ "html+erb",
+ "html+evoque",
+ "html+genshi",
+ "html+handlebars",
+ "html+jinja",
+ "html+kid",
+ "html+lasso",
+ "html+mako",
+ "html+myghty",
+ "html+php",
+ "html+ruby",
+ "html+smarty",
+ "html+spitfire",
+ "html+twig",
+ "html+velocity",
+ "htmlcheetah",
+ "htmldjango",
+ "http",
+ "hx",
+ "hxml",
+ "hxsl",
+ "hy",
+ "hybris",
+ "hylang",
+ "i6",
+ "i6t",
+ "i7",
+ "idl",
+ "idl4",
+ "idr",
+ "idris",
+ "iex",
+ "igor",
+ "igorpro",
+ "ik",
+ "inform6",
+ "inform7",
+ "ini",
+ "io",
+ "ioke",
+ "irb",
+ "irc",
+ "isabelle",
+ "j",
+ "jade",
+ "jags",
+ "jasmin",
+ "jasminxt",
+ "java",
+ "javascript",
+ "javascript+cheetah",
+ "javascript+django",
+ "javascript+erb",
+ "javascript+genshi",
+ "javascript+genshitext",
+ "javascript+jinja",
+ "javascript+lasso",
+ "javascript+mako",
+ "javascript+mozpreproc",
+ "javascript+myghty",
+ "javascript+php",
+ "javascript+ruby",
+ "javascript+smarty",
+ "javascript+spitfire",
+ "jbst",
+ "jcl",
+ "jinja",
+ "jl",
+ "jlcon",
+ "jproperties",
+ "js",
+ "js+cheetah",
+ "js+django",
+ "js+erb",
+ "js+genshi",
+ "js+genshitext",
+ "js+jinja",
+ "js+lasso",
+ "js+mako",
+ "js+myghty",
+ "js+php",
+ "js+ruby",
+ "js+smarty",
+ "js+spitfire",
+ "json",
+ "json-ld",
+ "jsonld",
+ "jsonml+bst",
+ "jsp",
+ "julia",
+ "kal",
+ "kconfig",
+ "kernel-config",
+ "kid",
+ "koka",
+ "kotlin",
+ "ksh",
+ "lagda",
+ "lasso",
+ "lassoscript",
+ "latex",
+ "lcry",
+ "lcryptol",
+ "lean",
+ "less",
+ "lhaskell",
+ "lhs",
+ "lid",
+ "lidr",
+ "lidris",
+ "lighttpd",
+ "lighty",
+ "limbo",
+ "linux-config",
+ "liquid",
+ "lisp",
+ "literate-agda",
+ "literate-cryptol",
+ "literate-haskell",
+ "literate-idris",
+ "live-script",
+ "livescript",
+ "llvm",
+ "logos",
+ "logtalk",
+ "lsl",
+ "lua",
+ "m2",
+ "make",
+ "makefile",
+ "mako",
+ "man",
+ "maql",
+ "mask",
+ "mason",
+ "mathematica",
+ "matlab",
+ "matlabsession",
+ "mawk",
+ "menuconfig",
+ "mf",
+ "minid",
+ "mma",
+ "modelica",
+ "modula2",
+ "moin",
+ "monkey",
+ "moo",
+ "moocode",
+ "moon",
+ "moonscript",
+ "mozhashpreproc",
+ "mozpercentpreproc",
+ "mq4",
+ "mq5",
+ "mql",
+ "mql4",
+ "mql5",
+ "msc",
+ "mscgen",
+ "mupad",
+ "mxml",
+ "myghty",
+ "mysql",
+ "nasm",
+ "nawk",
+ "nb",
+ "nemerle",
+ "nesc",
+ "newlisp",
+ "newspeak",
+ "nginx",
+ "nim",
+ "nimrod",
+ "nit",
+ "nix",
+ "nixos",
+ "nroff",
+ "nsh",
+ "nsi",
+ "nsis",
+ "numpy",
+ "obj-c",
+ "obj-c++",
+ "obj-j",
+ "objc",
+ "objc++",
+ "objdump",
+ "objdump-nasm",
+ "objective-c",
+ "objective-c++",
+ "objective-j",
+ "objectivec",
+ "objectivec++",
+ "objectivej",
+ "objectpascal",
+ "objj",
+ "ocaml",
+ "octave",
+ "odin",
+ "ooc",
+ "opa",
+ "openbugs",
+ "openedge",
+ "pacmanconf",
+ "pan",
+ "parasail",
+ "pas",
+ "pascal",
+ "pawn",
+ "pcmk",
+ "perl",
+ "perl6",
+ "php",
+ "php3",
+ "php4",
+ "php5",
+ "pig",
+ "pike",
+ "pkgconfig",
+ "pl",
+ "pl6",
+ "plpgsql",
+ "po",
+ "posh",
+ "postgres",
+ "postgres-console",
+ "postgresql",
+ "postgresql-console",
+ "postscr",
+ "postscript",
+ "pot",
+ "pov",
+ "powershell",
+ "praat",
+ "progress",
+ "prolog",
+ "properties",
+ "proto",
+ "protobuf",
+ "ps1",
+ "ps1con",
+ "psm1",
+ "psql",
+ "puppet",
+ "py",
+ "py3",
+ "py3tb",
+ "pycon",
+ "pypy",
+ "pypylog",
+ "pyrex",
+ "pytb",
+ "python",
+ "python3",
+ "pyx",
+ "qbasic",
+ "qbs",
+ "qml",
+ "qvt",
+ "qvto",
+ "r",
+ "racket",
+ "ragel",
+ "ragel-c",
+ "ragel-cpp",
+ "ragel-d",
+ "ragel-em",
+ "ragel-java",
+ "ragel-objc",
+ "ragel-rb",
+ "ragel-ruby",
+ "raw",
+ "rb",
+ "rbcon",
+ "rconsole",
+ "rd",
+ "rebol",
+ "red",
+ "red/system",
+ "redcode",
+ "registry",
+ "resource",
+ "resourcebundle",
+ "rest",
+ "restructuredtext",
+ "rexx",
+ "rhtml",
+ "rkt",
+ "roboconf-graph",
+ "roboconf-instances",
+ "robotframework",
+ "rout",
+ "rql",
+ "rsl",
+ "rst",
+ "rts",
+ "ruby",
+ "rust",
+ "s",
+ "sage",
+ "salt",
+ "sass",
+ "sc",
+ "scala",
+ "scaml",
+ "scheme",
+ "scilab",
+ "scm",
+ "scss",
+ "sh",
+ "shell",
+ "shell-session",
+ "shen",
+ "slim",
+ "sls",
+ "smali",
+ "smalltalk",
+ "smarty",
+ "sml",
+ "snobol",
+ "sources.list",
+ "sourceslist",
+ "sp",
+ "sparql",
+ "spec",
+ "spitfire",
+ "splus",
+ "sql",
+ "sqlite3",
+ "squeak",
+ "squid",
+ "squid.conf",
+ "squidconf",
+ "ssp",
+ "st",
+ "stan",
+ "supercollider",
+ "sv",
+ "swift",
+ "swig",
+ "systemverilog",
+ "tads3",
+ "tap",
+ "tcl",
+ "tcsh",
+ "tcshcon",
+ "tea",
+ "termcap",
+ "terminfo",
+ "terraform",
+ "tex",
+ "text",
+ "tf",
+ "thrift",
+ "todotxt",
+ "trac-wiki",
+ "trafficscript",
+ "treetop",
+ "ts",
+ "turtle",
+ "twig",
+ "typescript",
+ "udiff",
+ "urbiscript",
+ "v",
+ "vala",
+ "vapi",
+ "vb.net",
+ "vbnet",
+ "vctreestatus",
+ "velocity",
+ "verilog",
+ "vfp",
+ "vgl",
+ "vhdl",
+ "vim",
+ "winbatch",
+ "winbugs",
+ "x10",
+ "xbase",
+ "xml",
+ "xml+cheetah",
+ "xml+django",
+ "xml+erb",
+ "xml+evoque",
+ "xml+genshi",
+ "xml+jinja",
+ "xml+kid",
+ "xml+lasso",
+ "xml+mako",
+ "xml+myghty",
+ "xml+php",
+ "xml+ruby",
+ "xml+smarty",
+ "xml+spitfire",
+ "xml+velocity",
+ "xq",
+ "xql",
+ "xqm",
+ "xquery",
+ "xqy",
+ "xslt",
+ "xten",
+ "xtend",
+ "xul+mozpreproc",
+ "yaml",
+ "yaml+jinja",
+ "zephir" ]
diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs
new file mode 100644
index 000000000..83d80cd4a
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Ms.hs
@@ -0,0 +1,639 @@
+{-
+Copyright (C) 2007-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Ms
+ Copyright : Copyright (C) 2007-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to groff ms format.
+
+TODO:
+
+[ ] use base URL to construct absolute URLs from relative ones for external
+ links
+[ ] is there a better way to do strikeout?
+[ ] tight/loose list distinction
+-}
+
+module Text.Pandoc.Writers.Ms ( writeMs ) where
+import Control.Monad.State.Strict
+import Data.Char (isLower, isUpper, toUpper)
+import Data.List (intercalate, intersperse, sort)
+import qualified Data.Map as Map
+import Data.Maybe (catMaybes, fromMaybe)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Network.URI (escapeURIString, isAllowedInURI)
+import Skylighting
+import System.FilePath (takeExtension)
+import Text.Pandoc.Class (PandocMonad, report)
+import Text.Pandoc.Definition
+import Text.Pandoc.Highlighting
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
+import Text.Pandoc.Options
+import Text.Pandoc.Pretty
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates
+import Text.Pandoc.Writers.Math
+import Text.Pandoc.Writers.Shared
+import Text.Printf (printf)
+import Text.TeXMath (writeEqn)
+
+data WriterState = WriterState { stHasInlineMath :: Bool
+ , stFirstPara :: Bool
+ , stNotes :: [Note]
+ , stSmallCaps :: Bool
+ , stHighlighting :: Bool
+ , stFontFeatures :: Map.Map Char Bool
+ }
+
+defaultWriterState :: WriterState
+defaultWriterState = WriterState{ stHasInlineMath = False
+ , stFirstPara = True
+ , stNotes = []
+ , stSmallCaps = False
+ , stHighlighting = False
+ , stFontFeatures = Map.fromList [
+ ('I',False)
+ , ('B',False)
+ , ('C',False)
+ ]
+ }
+
+type Note = [Block]
+
+type MS = StateT WriterState
+
+-- | Convert Pandoc to Ms.
+writeMs :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeMs opts document =
+ evalStateT (pandocToMs opts document) defaultWriterState
+
+-- | Return groff ms representation of document.
+pandocToMs :: PandocMonad m => WriterOptions -> Pandoc -> MS m Text
+pandocToMs opts (Pandoc meta blocks) = do
+ let colwidth = if writerWrapText opts == WrapAuto
+ then Just $ writerColumns opts
+ else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
+ metadata <- metaToJSON opts
+ (fmap render' . blockListToMs opts)
+ (fmap render' . inlineListToMs' opts)
+ meta
+ body <- blockListToMs opts blocks
+ let main = render' body
+ hasInlineMath <- gets stHasInlineMath
+ let titleMeta = (escapeString . stringify) $ docTitle meta
+ let authorsMeta = map (escapeString . stringify) $ docAuthors meta
+ hasHighlighting <- gets stHighlighting
+ let highlightingMacros = if hasHighlighting
+ then case writerHighlightStyle opts of
+ Nothing -> mempty
+ Just sty -> render' $ styleToMs sty
+ else mempty
+
+ let context = defField "body" main
+ $ defField "has-inline-math" hasInlineMath
+ $ defField "hyphenate" True
+ $ defField "pandoc-version" pandocVersion
+ $ defField "toc" (writerTableOfContents opts)
+ $ defField "title-meta" titleMeta
+ $ defField "author-meta" (intercalate "; " authorsMeta)
+ $ defField "highlighting-macros" highlightingMacros metadata
+ case writerTemplate opts of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
+
+-- | Association list of characters to escape.
+msEscapes :: Map.Map Char String
+msEscapes = Map.fromList
+ [ ('\160', "\\~")
+ , ('\'', "\\[aq]")
+ , ('`', "\\`")
+ , ('\8217', "'")
+ , ('"', "\\[dq]")
+ , ('\x2014', "\\[em]")
+ , ('\x2013', "\\[en]")
+ , ('\x2026', "\\&...")
+ , ('~', "\\[ti]")
+ , ('^', "\\[ha]")
+ , ('-', "\\-")
+ , ('@', "\\@")
+ , ('\\', "\\\\")
+ ]
+
+escapeChar :: Char -> String
+escapeChar c = fromMaybe [c] (Map.lookup c msEscapes)
+
+-- | Escape | character, used to mark inline math, inside math.
+escapeBar :: String -> String
+escapeBar = concatMap go
+ where go '|' = "\\[u007C]"
+ go c = [c]
+
+-- | Escape special characters for Ms.
+escapeString :: String -> String
+escapeString = concatMap escapeChar
+
+escapeUri :: String -> String
+escapeUri = escapeURIString (\c -> c /= '@' && isAllowedInURI c)
+
+toSmallCaps :: String -> String
+toSmallCaps [] = []
+toSmallCaps (c:cs)
+ | isLower c = let (lowers,rest) = span isLower (c:cs)
+ in "\\s-2" ++ escapeString (map toUpper lowers) ++
+ "\\s0" ++ toSmallCaps rest
+ | isUpper c = let (uppers,rest) = span isUpper (c:cs)
+ in escapeString uppers ++ toSmallCaps rest
+ | otherwise = escapeChar c ++ toSmallCaps cs
+
+-- | Escape a literal (code) section for Ms.
+escapeCode :: String -> String
+escapeCode = intercalate "\n" . map escapeLine . lines
+ where escapeCodeChar ' ' = "\\ "
+ escapeCodeChar '\t' = "\\\t"
+ escapeCodeChar c = escapeChar c
+ escapeLine codeline =
+ case concatMap escapeCodeChar codeline of
+ a@('.':_) -> "\\&" ++ a
+ b -> b
+
+-- We split inline lists into sentences, and print one sentence per
+-- line. groff/troff treats the line-ending period differently.
+-- See http://code.google.com/p/pandoc/issues/detail?id=148.
+
+-- | Returns the first sentence in a list of inlines, and the rest.
+breakSentence :: [Inline] -> ([Inline], [Inline])
+breakSentence [] = ([],[])
+breakSentence xs =
+ let isSentenceEndInline (Str ys@(_:_)) | last ys == '.' = True
+ isSentenceEndInline (Str ys@(_:_)) | last ys == '?' = True
+ isSentenceEndInline LineBreak = True
+ isSentenceEndInline _ = False
+ (as, bs) = break isSentenceEndInline xs
+ in case bs of
+ [] -> (as, [])
+ [c] -> (as ++ [c], [])
+ (c:Space:cs) -> (as ++ [c], cs)
+ (c:SoftBreak:cs) -> (as ++ [c], cs)
+ (Str ".":Str (')':ys):cs) -> (as ++ [Str ".", Str (')':ys)], cs)
+ (x@(Str ('.':')':_)):cs) -> (as ++ [x], cs)
+ (LineBreak:x@(Str ('.':_)):cs) -> (as ++[LineBreak], x:cs)
+ (c:cs) -> (as ++ [c] ++ ds, es)
+ where (ds, es) = breakSentence cs
+
+-- | Split a list of inlines into sentences.
+splitSentences :: [Inline] -> [[Inline]]
+splitSentences xs =
+ let (sent, rest) = breakSentence xs
+ in if null rest then [sent] else sent : splitSentences rest
+
+blockToMs :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> Block -- ^ Block element
+ -> MS m Doc
+blockToMs _ Null = return empty
+blockToMs opts (Div _ bs) = do
+ setFirstPara
+ res <- blockListToMs opts bs
+ setFirstPara
+ return res
+blockToMs opts (Plain inlines) =
+ liftM vcat $ mapM (inlineListToMs' opts) $ splitSentences inlines
+blockToMs opts (Para [Image attr alt (src,_tit)])
+ | let ext = takeExtension src in (ext == ".ps" || ext == ".eps") = do
+ let (mbW,mbH) = (inPoints opts <$> dimension Width attr,
+ inPoints opts <$> dimension Height attr)
+ let sizeAttrs = case (mbW, mbH) of
+ (Just wp, Nothing) -> space <> doubleQuotes
+ (text (show (floor wp :: Int) ++ "p"))
+ (Just wp, Just hp) -> space <> doubleQuotes
+ (text (show (floor wp :: Int) ++ "p")) <>
+ space <>
+ doubleQuotes (text (show (floor hp :: Int)))
+ _ -> empty
+ capt <- inlineListToMs' opts alt
+ return $ nowrap (text ".PSPIC -C " <>
+ doubleQuotes (text (escapeString src)) <>
+ sizeAttrs) $$
+ text ".ce 1000" $$
+ capt $$
+ text ".ce 0"
+blockToMs opts (Para inlines) = do
+ firstPara <- gets stFirstPara
+ resetFirstPara
+ contents <- liftM vcat $ mapM (inlineListToMs' opts) $
+ splitSentences inlines
+ return $ text (if firstPara then ".LP" else ".PP") $$ contents
+blockToMs _ b@(RawBlock f str)
+ | f == Format "ms" = return $ text str
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
+blockToMs _ HorizontalRule = do
+ resetFirstPara
+ return $ text ".HLINE"
+blockToMs opts (Header level (ident,classes,_) inlines) = do
+ setFirstPara
+ contents <- inlineListToMs' opts $ map breakToSpace inlines
+ let (heading, secnum) = if writerNumberSections opts &&
+ "unnumbered" `notElem` classes
+ then (".NH", "\\*[SN]")
+ else (".SH", "")
+ let anchor = if null ident
+ then empty
+ else nowrap $
+ text ".pdfhref M " <> doubleQuotes (text ident)
+ let bookmark = text ".pdfhref O " <> text (show level ++ " ") <>
+ doubleQuotes (text $ secnum ++
+ (if null secnum
+ then ""
+ else " ") ++
+ escapeString (stringify inlines))
+ let backlink = nowrap (text ".pdfhref L -D " <>
+ doubleQuotes (text ident) <> space <> text "\\") <> cr <>
+ text " -- "
+ let tocEntry = if writerTableOfContents opts &&
+ level <= writerTOCDepth opts
+ then text ".XS"
+ $$ backlink <> doubleQuotes (
+ nowrap (text (replicate level '\t') <>
+ (if null secnum
+ then empty
+ else text secnum <> text "\\~\\~")
+ <> contents))
+ $$ text ".XE"
+ else empty
+ modify $ \st -> st{ stFirstPara = True }
+ return $ (text heading <> space <> text (show level)) $$
+ contents $$
+ bookmark $$
+ anchor $$
+ tocEntry
+blockToMs opts (CodeBlock attr str) = do
+ hlCode <- highlightCode opts attr str
+ setFirstPara
+ return $
+ text ".IP" $$
+ text ".nf" $$
+ text "\\f[C]" $$
+ hlCode $$
+ text "\\f[]" $$
+ text ".fi"
+blockToMs opts (LineBlock ls) = do
+ resetFirstPara
+ blockToMs opts $ Para $ intercalate [LineBreak] ls
+blockToMs opts (BlockQuote blocks) = do
+ setFirstPara
+ contents <- blockListToMs opts blocks
+ setFirstPara
+ return $ text ".RS" $$ contents $$ text ".RE"
+blockToMs opts (Table caption alignments widths headers rows) =
+ let aligncode AlignLeft = "l"
+ aligncode AlignRight = "r"
+ aligncode AlignCenter = "c"
+ aligncode AlignDefault = "l"
+ in do
+ caption' <- inlineListToMs' opts caption
+ let iwidths = if all (== 0) widths
+ then repeat ""
+ else map (printf "w(%0.1fn)" . (70 *)) widths
+ -- 78n default width - 8n indent = 70n
+ let coldescriptions = text $ unwords
+ (zipWith (\align width -> aligncode align ++ width)
+ alignments iwidths) ++ "."
+ colheadings <- mapM (blockListToMs opts) headers
+ let makeRow cols = text "T{" $$
+ vcat (intersperse (text "T}\tT{") cols) $$
+ text "T}"
+ let colheadings' = if all null headers
+ then empty
+ else makeRow colheadings $$ char '_'
+ body <- mapM (\row -> do
+ cols <- mapM (blockListToMs opts) row
+ return $ makeRow cols) rows
+ setFirstPara
+ return $ text ".PP" $$ caption' $$
+ text ".TS" $$ text "delim(@@) tab(\t);" $$ coldescriptions $$
+ colheadings' $$ vcat body $$ text ".TE"
+
+blockToMs opts (BulletList items) = do
+ contents <- mapM (bulletListItemToMs opts) items
+ setFirstPara
+ return (vcat contents)
+blockToMs opts (OrderedList attribs items) = do
+ let markers = take (length items) $ orderedListMarkers attribs
+ let indent = 2 +
+ maximum (map length markers)
+ contents <- mapM (\(num, item) -> orderedListItemToMs opts num indent item) $
+ zip markers items
+ setFirstPara
+ return (vcat contents)
+blockToMs opts (DefinitionList items) = do
+ contents <- mapM (definitionListItemToMs opts) items
+ setFirstPara
+ return (vcat contents)
+
+-- | Convert bullet list item (list of blocks) to ms.
+bulletListItemToMs :: PandocMonad m => WriterOptions -> [Block] -> MS m Doc
+bulletListItemToMs _ [] = return empty
+bulletListItemToMs opts (Para first:rest) =
+ bulletListItemToMs opts (Plain first:rest)
+bulletListItemToMs opts (Plain first:rest) = do
+ first' <- blockToMs opts (Plain first)
+ rest' <- blockListToMs opts rest
+ let first'' = text ".IP \\[bu] 3" $$ first'
+ let rest'' = if null rest
+ then empty
+ else text ".RS 3" $$ rest' $$ text ".RE"
+ return (first'' $$ rest'')
+bulletListItemToMs opts (first:rest) = do
+ first' <- blockToMs opts first
+ rest' <- blockListToMs opts rest
+ return $ text "\\[bu] .RS 3" $$ first' $$ rest' $$ text ".RE"
+
+-- | Convert ordered list item (a list of blocks) to ms.
+orderedListItemToMs :: PandocMonad m
+ => WriterOptions -- ^ options
+ -> String -- ^ order marker for list item
+ -> Int -- ^ number of spaces to indent
+ -> [Block] -- ^ list item (list of blocks)
+ -> MS m Doc
+orderedListItemToMs _ _ _ [] = return empty
+orderedListItemToMs opts num indent (Para first:rest) =
+ orderedListItemToMs opts num indent (Plain first:rest)
+orderedListItemToMs opts num indent (first:rest) = do
+ first' <- blockToMs opts first
+ rest' <- blockListToMs opts rest
+ let num' = printf ("%" ++ show (indent - 1) ++ "s") num
+ let first'' = text (".IP \"" ++ num' ++ "\" " ++ show indent) $$ first'
+ let rest'' = if null rest
+ then empty
+ else text ".RS " <> text (show indent) $$
+ rest' $$ text ".RE"
+ return $ first'' $$ rest''
+
+-- | Convert definition list item (label, list of blocks) to ms.
+definitionListItemToMs :: PandocMonad m
+ => WriterOptions
+ -> ([Inline],[[Block]])
+ -> MS m Doc
+definitionListItemToMs opts (label, defs) = do
+ labelText <- inlineListToMs' opts $ map breakToSpace label
+ contents <- if null defs
+ then return empty
+ else liftM vcat $ forM defs $ \blocks -> do
+ let (first, rest) = case blocks of
+ (Para x:y) -> (Plain x,y)
+ (x:y) -> (x,y)
+ [] -> (Plain [], [])
+ -- should not happen
+ rest' <- liftM vcat $
+ mapM (\item -> blockToMs opts item) rest
+ first' <- blockToMs opts first
+ return $ first' $$ text ".RS" $$ rest' $$ text ".RE"
+ return $ nowrap (text ".IP " <> doubleQuotes labelText) $$ contents
+
+-- | Convert list of Pandoc block elements to ms.
+blockListToMs :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> [Block] -- ^ List of block elements
+ -> MS m Doc
+blockListToMs opts blocks =
+ mapM (blockToMs opts) blocks >>= (return . vcat)
+
+-- | Convert list of Pandoc inline elements to ms.
+inlineListToMs :: PandocMonad m => WriterOptions -> [Inline] -> MS m Doc
+-- if list starts with ., insert a zero-width character \& so it
+-- won't be interpreted as markup if it falls at the beginning of a line.
+inlineListToMs opts lst = hcat <$> mapM (inlineToMs opts) lst
+
+-- This version to be used when there is no further inline content;
+-- forces a note at the end.
+inlineListToMs' :: PandocMonad m => WriterOptions -> [Inline] -> MS m Doc
+inlineListToMs' opts lst = do
+ x <- hcat <$> mapM (inlineToMs opts) lst
+ y <- handleNotes opts empty
+ return $ x <> y
+
+-- | Convert Pandoc inline element to ms.
+inlineToMs :: PandocMonad m => WriterOptions -> Inline -> MS m Doc
+inlineToMs opts (Span _ ils) = inlineListToMs opts ils
+inlineToMs opts (Emph lst) =
+ withFontFeature 'I' (inlineListToMs opts lst)
+inlineToMs opts (Strong lst) =
+ withFontFeature 'B' (inlineListToMs opts lst)
+inlineToMs opts (Strikeout lst) = do
+ contents <- inlineListToMs opts lst
+ -- we use grey color instead of strikeout, which seems quite
+ -- hard to do in groff for arbitrary bits of text
+ return $ text "\\m[strikecolor]" <> contents <> text "\\m[]"
+inlineToMs opts (Superscript lst) = do
+ contents <- inlineListToMs opts lst
+ return $ text "\\*{" <> contents <> text "\\*}"
+inlineToMs opts (Subscript lst) = do
+ contents <- inlineListToMs opts lst
+ return $ text "\\*<" <> contents <> text "\\*>"
+inlineToMs opts (SmallCaps lst) = do
+ -- see https://lists.gnu.org/archive/html/groff/2015-01/msg00016.html
+ modify $ \st -> st{ stSmallCaps = not (stSmallCaps st) }
+ res <- inlineListToMs opts lst
+ modify $ \st -> st{ stSmallCaps = not (stSmallCaps st) }
+ return res
+inlineToMs opts (Quoted SingleQuote lst) = do
+ contents <- inlineListToMs opts lst
+ return $ char '`' <> contents <> char '\''
+inlineToMs opts (Quoted DoubleQuote lst) = do
+ contents <- inlineListToMs opts lst
+ return $ text "\\[lq]" <> contents <> text "\\[rq]"
+inlineToMs opts (Cite _ lst) =
+ inlineListToMs opts lst
+inlineToMs opts (Code attr str) = do
+ hlCode <- highlightCode opts attr str
+ withFontFeature 'C' (return hlCode)
+inlineToMs _ (Str str) = do
+ let shim = case str of
+ '.':_ -> afterBreak "\\&"
+ _ -> empty
+ smallcaps <- gets stSmallCaps
+ if smallcaps
+ then return $ shim <> text (toSmallCaps str)
+ else return $ shim <> text (escapeString str)
+inlineToMs opts (Math InlineMath str) = do
+ modify $ \st -> st{ stHasInlineMath = True }
+ res <- convertMath writeEqn InlineMath str
+ case res of
+ Left il -> inlineToMs opts il
+ Right r -> return $ text "@" <> text (escapeBar r) <> text "@"
+inlineToMs opts (Math DisplayMath str) = do
+ res <- convertMath writeEqn InlineMath str
+ case res of
+ Left il -> do
+ contents <- inlineToMs opts il
+ return $ cr <> text ".RS" $$ contents $$ text ".RE"
+ Right r -> return $
+ cr <> text ".EQ" $$ text (escapeBar r) $$ text ".EN"
+inlineToMs _ il@(RawInline f str)
+ | f == Format "ms" = return $ text str
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
+inlineToMs _ LineBreak = return $ cr <> text ".br" <> cr
+inlineToMs opts SoftBreak =
+ handleNotes opts $
+ case writerWrapText opts of
+ WrapAuto -> space
+ WrapNone -> space
+ WrapPreserve -> cr
+inlineToMs opts Space = handleNotes opts space
+inlineToMs opts (Link _ txt ('#':ident, _)) = do
+ -- internal link
+ contents <- inlineListToMs' opts $ map breakToSpace txt
+ return $ text "\\c" <> cr <> nowrap (text ".pdfhref L -D " <>
+ doubleQuotes (text ident) <> text " -A " <>
+ doubleQuotes (text "\\c") <> space <> text "\\") <> cr <>
+ text " -- " <> doubleQuotes (nowrap contents) <> cr <> text "\\&"
+inlineToMs opts (Link _ txt (src, _)) = do
+ -- external link
+ contents <- inlineListToMs' opts $ map breakToSpace txt
+ return $ text "\\c" <> cr <> nowrap (text ".pdfhref W -D " <>
+ doubleQuotes (text (escapeUri src)) <> text " -A " <>
+ doubleQuotes (text "\\c") <> space <> text "\\") <> cr <>
+ text " -- " <> doubleQuotes (nowrap contents) <> cr <> text "\\&"
+inlineToMs _ (Image _ alternate (_, _)) =
+ return $ char '[' <> text "IMAGE: " <>
+ text (escapeString (stringify alternate)) <> char ']'
+inlineToMs _ (Note contents) = do
+ modify $ \st -> st{ stNotes = contents : stNotes st }
+ return $ text "\\**"
+
+handleNotes :: PandocMonad m => WriterOptions -> Doc -> MS m Doc
+handleNotes opts fallback = do
+ notes <- gets stNotes
+ if null notes
+ then return fallback
+ else do
+ modify $ \st -> st{ stNotes = [] }
+ vcat <$> mapM (handleNote opts) notes
+
+handleNote :: PandocMonad m => WriterOptions -> Note -> MS m Doc
+handleNote opts bs = do
+ -- don't start with Paragraph or we'll get a spurious blank
+ -- line after the note ref:
+ let bs' = case bs of
+ (Para ils : rest) -> Plain ils : rest
+ _ -> bs
+ contents <- blockListToMs opts bs'
+ return $ cr <> text ".FS" $$ contents $$ text ".FE" <> cr
+
+fontChange :: PandocMonad m => MS m Doc
+fontChange = do
+ features <- gets stFontFeatures
+ let filling = sort [c | (c,True) <- Map.toList features]
+ return $ text $ "\\f[" ++ filling ++ "]"
+
+withFontFeature :: PandocMonad m => Char -> MS m Doc -> MS m Doc
+withFontFeature c action = do
+ modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
+ begin <- fontChange
+ d <- action
+ modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
+ end <- fontChange
+ return $ begin <> d <> end
+
+setFirstPara :: PandocMonad m => MS m ()
+setFirstPara = modify $ \st -> st{ stFirstPara = True }
+
+resetFirstPara :: PandocMonad m => MS m ()
+resetFirstPara = modify $ \st -> st{ stFirstPara = False }
+
+breakToSpace :: Inline -> Inline
+breakToSpace SoftBreak = Space
+breakToSpace LineBreak = Space
+breakToSpace x = x
+
+-- Highlighting
+
+styleToMs :: Style -> Doc
+styleToMs sty = vcat $ colordefs ++ map (toMacro sty) alltoktypes
+ where alltoktypes = enumFromTo KeywordTok NormalTok
+ colordefs = map toColorDef allcolors
+ toColorDef c = text (".defcolor " ++
+ hexColor c ++ " rgb #" ++ hexColor c)
+ allcolors = catMaybes $ ordNub $
+ [defaultColor sty, backgroundColor sty,
+ lineNumberColor sty, lineNumberBackgroundColor sty] ++
+ concatMap (colorsForToken. snd) (Map.toList (tokenStyles sty))
+ colorsForToken ts = [tokenColor ts, tokenBackground ts]
+
+hexColor :: Color -> String
+hexColor (RGB r g b) = printf "%02x%02x%02x" r g b
+
+toMacro :: Style -> TokenType -> Doc
+toMacro sty toktype =
+ nowrap (text ".ds " <> text (show toktype) <> text " " <>
+ setbg <> setcolor <> setfont <>
+ text "\\\\$1" <>
+ resetfont <> resetcolor <> resetbg)
+ where setcolor = maybe empty fgcol tokCol
+ resetcolor = maybe empty (const $ text "\\\\m[]") tokCol
+ setbg = empty -- maybe empty bgcol tokBg
+ resetbg = empty -- maybe empty (const $ text "\\\\M[]") tokBg
+ fgcol c = text $ "\\\\m[" ++ hexColor c ++ "]"
+ -- bgcol c = text $ "\\\\M[" ++ hexColor c ++ "]"
+ setfont = if tokBold || tokItalic
+ then text $ "\\\\f[C" ++ ['B' | tokBold] ++
+ ['I' | tokItalic] ++ "]"
+ else empty
+ resetfont = if tokBold || tokItalic
+ then text "\\\\f[C]"
+ else empty
+ tokSty = Map.lookup toktype (tokenStyles sty)
+ tokCol = (tokSty >>= tokenColor) `mplus` defaultColor sty
+ -- tokBg = (tokSty >>= tokenBackground) `mplus` backgroundColor sty
+ tokBold = fromMaybe False (tokenBold <$> tokSty)
+ tokItalic = fromMaybe False (tokenItalic <$> tokSty)
+ -- tokUnderline = fromMaybe False (tokSty >>= tokUnderline)
+ -- lnColor = lineNumberColor sty
+ -- lnBkgColor = lineNumberBackgroundColor sty
+
+msFormatter :: FormatOptions -> [SourceLine] -> Doc
+msFormatter _fmtopts =
+ vcat . map fmtLine
+ where fmtLine = hcat . map fmtToken
+ fmtToken (toktype, tok) = text "\\*" <>
+ brackets (text (show toktype) <> text " \""
+ <> text (escapeCode (T.unpack tok)) <> text "\"")
+
+highlightCode :: PandocMonad m => WriterOptions -> Attr -> String -> MS m Doc
+highlightCode opts attr str =
+ case highlight (writerSyntaxMap opts) msFormatter attr str of
+ Left msg -> do
+ unless (null msg) $ report $ CouldNotHighlight msg
+ return $ text (escapeCode str)
+ Right h -> do
+ modify (\st -> st{ stHighlighting = True })
+ return h
diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs
new file mode 100644
index 000000000..ad67e489d
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Muse.hs
@@ -0,0 +1,408 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-
+Copyright (C) 2017-2018 Alexander Krotov <ilabdsf@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Muse
+ Copyright : Copyright (C) 2017-2018 Alexander Krotov
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Alexander Krotov <ilabdsf@gmail.com>
+ Stability : stable
+ Portability : portable
+
+Conversion of 'Pandoc' documents to Muse.
+
+This module is mostly intended for <https://amusewiki.org/ Amusewiki> markup support,
+as described by <https://amusewiki.org/library/manual Text::Amuse markup manual>.
+Original <https://www.gnu.org/software/emacs-muse/ Emacs Muse> markup support
+is a secondary goal.
+
+Where Text::Amuse markup
+<https://metacpan.org/pod/Text::Amuse#DIFFERENCES-WITH-THE-ORIGINAL-EMACS-MUSE-MARKUP differs>
+from <https://www.gnu.org/software/emacs-muse/manual/ Emacs Muse markup>,
+Text::Amuse markup is supported.
+For example, native tables are always used instead of Org Mode tables.
+However, @\<literal style="html">@ tag is used for HTML raw blocks
+even though it is supported only in Emacs Muse.
+-}
+module Text.Pandoc.Writers.Muse (writeMuse) where
+import Control.Monad.State.Strict
+import Data.Text (Text)
+import Data.List (intersperse, transpose, isInfixOf)
+import System.FilePath (takeExtension)
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Definition
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Options
+import Text.Pandoc.Pretty
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Math
+import Text.Pandoc.Writers.Shared
+import qualified Data.Set as Set
+
+type Notes = [[Block]]
+data WriterState =
+ WriterState { stNotes :: Notes
+ , stOptions :: WriterOptions
+ , stTopLevel :: Bool
+ , stInsideBlock :: Bool
+ , stIds :: Set.Set String
+ }
+
+-- | Convert Pandoc to Muse.
+writeMuse :: PandocMonad m
+ => WriterOptions
+ -> Pandoc
+ -> m Text
+writeMuse opts document =
+ let st = WriterState { stNotes = []
+ , stOptions = opts
+ , stTopLevel = True
+ , stInsideBlock = False
+ , stIds = Set.empty
+ }
+ in evalStateT (pandocToMuse document) st
+
+-- | Return Muse representation of document.
+pandocToMuse :: PandocMonad m
+ => Pandoc
+ -> StateT WriterState m Text
+pandocToMuse (Pandoc meta blocks) = do
+ opts <- gets stOptions
+ let colwidth = if writerWrapText opts == WrapAuto
+ then Just $ writerColumns opts
+ else Nothing
+ let render' :: Doc -> Text
+ render' = render Nothing
+ metadata <- metaToJSON opts
+ (fmap render' . blockListToMuse)
+ (fmap render' . inlineListToMuse)
+ meta
+ body <- blockListToMuse blocks
+ notes <- liftM (reverse . stNotes) get >>= notesToMuse
+ let main = render colwidth $ body $+$ notes
+ let context = defField "body" main metadata
+ case writerTemplate opts of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
+
+-- | Helper function for flatBlockListToMuse
+-- | Render all blocks and insert blank lines between the first two
+catWithBlankLines :: PandocMonad m
+ => [Block] -- ^ List of block elements
+ -> Int -- ^ Number of blank lines
+ -> StateT WriterState m Doc
+catWithBlankLines (b : bs) n = do
+ b' <- blockToMuse b
+ bs' <- flatBlockListToMuse bs
+ return $ b' <> blanklines n <> bs'
+catWithBlankLines _ _ = error "Expected at least one block"
+
+-- | Convert list of Pandoc block elements to Muse
+-- | without setting stTopLevel.
+flatBlockListToMuse :: PandocMonad m
+ => [Block] -- ^ List of block elements
+ -> StateT WriterState m Doc
+flatBlockListToMuse bs@(BulletList _ : BulletList _ : _) = catWithBlankLines bs 2
+flatBlockListToMuse bs@(OrderedList (_, style1, _) _ : OrderedList (_, style2, _) _ : _) =
+ catWithBlankLines bs (if style1' == style2' then 2 else 0)
+ where
+ style1' = normalizeStyle style1
+ style2' = normalizeStyle style2
+ normalizeStyle DefaultStyle = Decimal
+ normalizeStyle s = s
+flatBlockListToMuse bs@(DefinitionList _ : DefinitionList _ : _) = catWithBlankLines bs 2
+flatBlockListToMuse bs@(_ : _) = catWithBlankLines bs 0
+flatBlockListToMuse [] = return mempty
+
+-- | Convert list of Pandoc block elements to Muse.
+blockListToMuse :: PandocMonad m
+ => [Block] -- ^ List of block elements
+ -> StateT WriterState m Doc
+blockListToMuse blocks = do
+ oldState <- get
+ modify $ \s -> s { stTopLevel = not $ stInsideBlock s
+ , stInsideBlock = True
+ }
+ result <- flatBlockListToMuse blocks
+ modify $ \s -> s { stTopLevel = stTopLevel oldState
+ , stInsideBlock = stInsideBlock oldState
+ }
+ return result
+
+-- | Convert Pandoc block element to Muse.
+blockToMuse :: PandocMonad m
+ => Block -- ^ Block element
+ -> StateT WriterState m Doc
+blockToMuse (Plain inlines) = inlineListToMuse inlines
+blockToMuse (Para inlines) = do
+ contents <- inlineListToMuse inlines
+ return $ contents <> blankline
+blockToMuse (LineBlock lns) = do
+ lns' <- mapM inlineListToMuse lns
+ return $ nowrap $ vcat (map (text "> " <>) lns') <> blankline
+blockToMuse (CodeBlock (_,_,_) str) =
+ return $ "<example>" $$ text str $$ "</example>" $$ blankline
+blockToMuse (RawBlock (Format format) str) =
+ return $ blankline $$ "<literal style=\"" <> text format <> "\">" $$
+ text str $$ "</literal>" $$ blankline
+blockToMuse (BlockQuote blocks) = do
+ contents <- flatBlockListToMuse blocks
+ return $ blankline
+ <> "<quote>"
+ $$ nest 0 contents -- nest 0 to remove trailing blank lines
+ $$ "</quote>"
+ <> blankline
+blockToMuse (OrderedList (start, style, _) items) = do
+ let markers = take (length items) $ orderedListMarkers
+ (start, style, Period)
+ let maxMarkerLength = maximum $ map length markers
+ let markers' = map (\m -> let s = maxMarkerLength - length m
+ in m ++ replicate s ' ') markers
+ contents <- zipWithM orderedListItemToMuse markers' items
+ -- ensure that sublists have preceding blank line
+ topLevel <- gets stTopLevel
+ return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
+ where orderedListItemToMuse :: PandocMonad m
+ => String -- ^ marker for list item
+ -> [Block] -- ^ list item (list of blocks)
+ -> StateT WriterState m Doc
+ orderedListItemToMuse marker item = do
+ contents <- blockListToMuse item
+ return $ hang (length marker + 1) (text marker <> space) contents
+blockToMuse (BulletList items) = do
+ contents <- mapM bulletListItemToMuse items
+ -- ensure that sublists have preceding blank line
+ topLevel <- gets stTopLevel
+ return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
+ where bulletListItemToMuse :: PandocMonad m
+ => [Block]
+ -> StateT WriterState m Doc
+ bulletListItemToMuse item = do
+ contents <- blockListToMuse item
+ return $ hang 2 "- " contents
+blockToMuse (DefinitionList items) = do
+ contents <- mapM definitionListItemToMuse items
+ -- ensure that sublists have preceding blank line
+ topLevel <- gets stTopLevel
+ return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
+ where definitionListItemToMuse :: PandocMonad m
+ => ([Inline], [[Block]])
+ -> StateT WriterState m Doc
+ definitionListItemToMuse (label, defs) = do
+ label' <- inlineListToMuse label
+ contents <- liftM vcat $ mapM descriptionToMuse defs
+ let ind = offset label'
+ return $ hang ind label' contents
+ descriptionToMuse :: PandocMonad m
+ => [Block]
+ -> StateT WriterState m Doc
+ descriptionToMuse desc = hang 4 " :: " <$> blockListToMuse desc
+blockToMuse (Header level (ident,_,_) inlines) = do
+ opts <- gets stOptions
+ contents <- inlineListToMuse inlines
+
+ ids <- gets stIds
+ let autoId = uniqueIdent inlines ids
+ modify $ \st -> st{ stIds = Set.insert autoId ids }
+
+ let attr' = if null ident || (isEnabled Ext_auto_identifiers opts && ident == autoId)
+ then empty
+ else "#" <> text ident <> cr
+ let header' = text $ replicate level '*'
+ return $ blankline <> nowrap (header' <> space <> contents)
+ $$ attr' <> blankline
+-- https://www.gnu.org/software/emacs-muse/manual/muse.html#Horizontal-Rules-and-Anchors
+blockToMuse HorizontalRule = return $ blankline $$ "----" $$ blankline
+blockToMuse (Table caption _ _ headers rows) = do
+ caption' <- inlineListToMuse caption
+ headers' <- mapM blockListToMuse headers
+ rows' <- mapM (mapM blockListToMuse) rows
+ let noHeaders = all null headers
+
+ let numChars = maximum . map offset
+ -- FIXME: width is not being used.
+ let widthsInChars =
+ map numChars $ transpose (headers' : rows')
+ -- FIXME: Muse doesn't allow blocks with height more than 1.
+ let hpipeBlocks sep blocks = hcat $ intersperse sep' blocks
+ where h = maximum (1 : map height blocks)
+ sep' = lblock (length sep) $ vcat (replicate h (text sep))
+ let makeRow sep = (" " <>) . hpipeBlocks sep . zipWith lblock widthsInChars
+ let head' = makeRow " || " headers'
+ let rowSeparator = if noHeaders then " | " else " | "
+ rows'' <- mapM (\row -> do cols <- mapM blockListToMuse row
+ return $ makeRow rowSeparator cols) rows
+ let body = vcat rows''
+ return $ (if noHeaders then empty else head')
+ $$ body
+ $$ (if null caption then empty else " |+ " <> caption' <> " +|")
+ $$ blankline
+blockToMuse (Div _ bs) = flatBlockListToMuse bs
+blockToMuse Null = return empty
+
+-- | Return Muse representation of notes.
+notesToMuse :: PandocMonad m
+ => Notes
+ -> StateT WriterState m Doc
+notesToMuse notes = liftM vsep (zipWithM noteToMuse [1 ..] notes)
+
+-- | Return Muse representation of a note.
+noteToMuse :: PandocMonad m
+ => Int
+ -> [Block]
+ -> StateT WriterState m Doc
+noteToMuse num note = do
+ contents <- blockListToMuse note
+ let marker = "[" ++ show num ++ "] "
+ return $ hang (length marker) (text marker) contents
+
+-- | Escape special characters for Muse.
+escapeString :: String -> String
+escapeString s =
+ "<verbatim>" ++
+ substitute "</verbatim>" "<</verbatim><verbatim>/verbatim>" s ++
+ "</verbatim>"
+
+-- | Escape special characters for Muse if needed.
+conditionalEscapeString :: String -> String
+conditionalEscapeString s =
+ if any (`elem` ("#*<=>[]|" :: String)) s ||
+ "::" `isInfixOf` s ||
+ "----" `isInfixOf` s ||
+ "~~" `isInfixOf` s
+ then escapeString s
+ else s
+
+normalizeInlineList :: [Inline] -> [Inline]
+normalizeInlineList (x : Str "" : xs)
+ = normalizeInlineList (x:xs)
+normalizeInlineList (Str x1 : Str x2 : xs)
+ = normalizeInlineList $ Str (x1 ++ x2) : xs
+normalizeInlineList (Emph x1 : Emph x2 : ils)
+ = normalizeInlineList $ Emph (x1 ++ x2) : ils
+normalizeInlineList (Strong x1 : Strong x2 : ils)
+ = normalizeInlineList $ Strong (x1 ++ x2) : ils
+normalizeInlineList (Strikeout x1 : Strikeout x2 : ils)
+ = normalizeInlineList $ Strikeout (x1 ++ x2) : ils
+normalizeInlineList (Superscript x1 : Superscript x2 : ils)
+ = normalizeInlineList $ Superscript (x1 ++ x2) : ils
+normalizeInlineList (Subscript x1 : Subscript x2 : ils)
+ = normalizeInlineList $ Subscript (x1 ++ x2) : ils
+normalizeInlineList (SmallCaps x1 : SmallCaps x2 : ils)
+ = normalizeInlineList $ SmallCaps (x1 ++ x2) : ils
+normalizeInlineList (Code _ x1 : Code _ x2 : ils)
+ = normalizeInlineList $ Code nullAttr (x1 ++ x2) : ils
+normalizeInlineList (RawInline f1 x1 : RawInline f2 x2 : ils) | f1 == f2
+ = normalizeInlineList $ RawInline f1 (x1 ++ x2) : ils
+normalizeInlineList (Span a1 x1 : Span a2 x2 : ils) | a1 == a2
+ = normalizeInlineList $ Span a1 (x1 ++ x2) : ils
+normalizeInlineList (x:xs) = x : normalizeInlineList xs
+normalizeInlineList [] = []
+
+fixNotes :: [Inline] -> [Inline]
+fixNotes [] = []
+fixNotes (Space : n@Note{} : rest) = Str " " : n : fixNotes rest
+fixNotes (SoftBreak : n@Note{} : rest) = Str " " : n : fixNotes rest
+fixNotes (x:xs) = x : fixNotes xs
+
+-- | Convert list of Pandoc inline elements to Muse.
+inlineListToMuse :: PandocMonad m
+ => [Inline]
+ -> StateT WriterState m Doc
+inlineListToMuse lst = hcat <$> mapM inlineToMuse (fixNotes $ normalizeInlineList lst)
+
+-- | Convert Pandoc inline element to Muse.
+inlineToMuse :: PandocMonad m
+ => Inline
+ -> StateT WriterState m Doc
+inlineToMuse (Str str) = return $ text $ conditionalEscapeString str
+inlineToMuse (Emph lst) = do
+ contents <- inlineListToMuse lst
+ return $ "<em>" <> contents <> "</em>"
+inlineToMuse (Strong lst) = do
+ contents <- inlineListToMuse lst
+ return $ "<strong>" <> contents <> "</strong>"
+inlineToMuse (Strikeout lst) = do
+ contents <- inlineListToMuse lst
+ return $ "<del>" <> contents <> "</del>"
+inlineToMuse (Superscript lst) = do
+ contents <- inlineListToMuse lst
+ return $ "<sup>" <> contents <> "</sup>"
+inlineToMuse (Subscript lst) = do
+ contents <- inlineListToMuse lst
+ return $ "<sub>" <> contents <> "</sub>"
+inlineToMuse (SmallCaps lst) = inlineListToMuse lst
+inlineToMuse (Quoted SingleQuote lst) = do
+ contents <- inlineListToMuse lst
+ return $ "‘" <> contents <> "’"
+inlineToMuse (Quoted DoubleQuote lst) = do
+ contents <- inlineListToMuse lst
+ return $ "“" <> contents <> "”"
+-- Amusewiki does not support <cite> tag,
+-- and Emacs Muse citation support is limited
+-- (https://www.gnu.org/software/emacs-muse/manual/html_node/Citations.html#Citation)
+-- so just fallback to expanding inlines.
+inlineToMuse (Cite _ lst) = inlineListToMuse lst
+inlineToMuse (Code _ str) = return $
+ "<code>" <> text (substitute "</code>" "<</code><code>/code>" str) <> "</code>"
+inlineToMuse (Math t str) =
+ lift (texMathToInlines t str) >>= inlineListToMuse
+inlineToMuse (RawInline (Format f) str) =
+ return $ "<literal style=\"" <> text f <> "\">" <> text str <> "</literal>"
+inlineToMuse LineBreak = return $ "<br>" <> cr
+inlineToMuse Space = return space
+inlineToMuse SoftBreak = do
+ wrapText <- gets $ writerWrapText . stOptions
+ return $ if wrapText == WrapPreserve then cr else space
+inlineToMuse (Link _ txt (src, _)) =
+ case txt of
+ [Str x] | escapeURI x == src ->
+ return $ "[[" <> text (escapeLink x) <> "]]"
+ _ -> do contents <- inlineListToMuse txt
+ return $ "[[" <> text (escapeLink src) <> "][" <> contents <> "]]"
+ where escapeLink lnk = if isImageUrl lnk then "URL:" ++ lnk else lnk
+ -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el
+ imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"]
+ isImageUrl = (`elem` imageExtensions) . takeExtension
+inlineToMuse (Image attr alt (source,'f':'i':'g':':':title)) =
+ inlineToMuse (Image attr alt (source,title))
+inlineToMuse (Image attr inlines (source, title)) = do
+ opts <- gets stOptions
+ alt <- inlineListToMuse inlines
+ let title' = if null title
+ then if null inlines
+ then ""
+ else "[" <> alt <> "]"
+ else "[" <> text title <> "]"
+ let width = case dimension Width attr of
+ Just (Percent x) | isEnabled Ext_amuse opts -> " " ++ show (round x :: Integer)
+ _ -> ""
+ return $ "[[" <> text (source ++ width) <> "]" <> title' <> "]"
+inlineToMuse (Note contents) = do
+ -- add to notes in state
+ notes <- gets stNotes
+ modify $ \st -> st { stNotes = contents:notes }
+ let ref = show $ length notes + 1
+ return $ "[" <> text ref <> "]"
+inlineToMuse (Span (_,name:_,_) inlines) = do
+ contents <- inlineListToMuse inlines
+ return $ "<class name=\"" <> text name <> "\">" <> contents <> "</class>"
+inlineToMuse (Span _ lst) = inlineListToMuse lst
diff --git a/src/Text/Pandoc/Writers/Native.hs b/src/Text/Pandoc/Writers/Native.hs
index 87e23aeeb..f852bad96 100644
--- a/src/Text/Pandoc/Writers/Native.hs
+++ b/src/Text/Pandoc/Writers/Native.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Native
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,14 +30,17 @@ Conversion of a 'Pandoc' document to a string representation.
-}
module Text.Pandoc.Writers.Native ( writeNative )
where
-import Text.Pandoc.Options ( WriterOptions(..), WrapOption(..) )
-import Data.List ( intersperse )
+import Data.List (intersperse)
+import Data.Text (Text)
+import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
+import Text.Pandoc.Options (WrapOption (..), WriterOptions (..))
import Text.Pandoc.Pretty
prettyList :: [Doc] -> Doc
prettyList ds =
- "[" <> (cat $ intersperse (cr <> ",") $ map (nest 1) ds) <> "]"
+ "[" <>
+ cat (intersperse (cr <> ",") $ map (nest 1) ds) <> "]"
-- | Prettyprint Pandoc block element.
prettyBlock :: Block -> Doc
@@ -47,12 +50,12 @@ prettyBlock (BlockQuote blocks) =
"BlockQuote" $$ prettyList (map prettyBlock blocks)
prettyBlock (OrderedList attribs blockLists) =
"OrderedList" <> space <> text (show attribs) $$
- (prettyList $ map (prettyList . map prettyBlock) blockLists)
+ prettyList (map (prettyList . map prettyBlock) blockLists)
prettyBlock (BulletList blockLists) =
"BulletList" $$
- (prettyList $ map (prettyList . map prettyBlock) blockLists)
+ prettyList (map (prettyList . map prettyBlock) blockLists)
prettyBlock (DefinitionList items) = "DefinitionList" $$
- (prettyList $ map deflistitem items)
+ prettyList (map deflistitem items)
where deflistitem (term, defs) = "(" <> text (show term) <> "," <> cr <>
nest 1 (prettyList $ map (prettyList . map prettyBlock) defs) <> ")"
prettyBlock (Table caption aligns widths header rows) =
@@ -66,8 +69,8 @@ prettyBlock (Div attr blocks) =
prettyBlock block = text $ show block
-- | Prettyprint Pandoc document.
-writeNative :: WriterOptions -> Pandoc -> String
-writeNative opts (Pandoc meta blocks) =
+writeNative :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeNative opts (Pandoc meta blocks) = return $
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs
index ce4d456a3..63a3f915a 100644
--- a/src/Text/Pandoc/Writers/ODT.hs
+++ b/src/Text/Pandoc/Writers/ODT.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.ODT
- Copyright : Copyright (C) 2008-2015 John MacFarlane
+ Copyright : Copyright (C) 2008-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,49 +29,70 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to ODT.
-}
module Text.Pandoc.Writers.ODT ( writeODT ) where
-import Data.IORef
-import Data.List ( isPrefixOf )
-import Data.Maybe ( fromMaybe )
-import Text.XML.Light.Output
-import Text.TeXMath
-import qualified Data.ByteString.Lazy as B
-import Text.Pandoc.UTF8 ( fromStringLazy )
import Codec.Archive.Zip
-import Text.Pandoc.Options ( WriterOptions(..), WrapOption(..) )
-import Text.Pandoc.Shared ( stringify, fetchItem', warn,
- getDefaultReferenceODT )
-import Text.Pandoc.ImageSize
-import Text.Pandoc.MIME ( getMimeType, extensionFromMimeType )
+import Control.Monad.Except (catchError)
+import Control.Monad.State.Strict
+import qualified Data.ByteString.Lazy as B
+import Data.Generics (everywhere', mkT)
+import Data.List (isPrefixOf)
+import Data.Maybe (fromMaybe)
+import qualified Data.Text.Lazy as TL
+import System.FilePath (takeDirectory, takeExtension, (<.>))
+import Text.Pandoc.BCP47 (Lang (..), getLang, renderLang)
+import Text.Pandoc.Class (PandocMonad, report, toLang)
+import qualified Text.Pandoc.Class as P
import Text.Pandoc.Definition
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
+import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
+import Text.Pandoc.Options (WrapOption (..), WriterOptions (..))
+import Text.Pandoc.Pretty
+import Text.Pandoc.Shared (stringify)
+import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toStringLazy)
import Text.Pandoc.Walk
-import Text.Pandoc.Writers.Shared ( fixDisplayMath )
-import Text.Pandoc.Writers.OpenDocument ( writeOpenDocument )
-import Control.Monad (liftM)
+import Text.Pandoc.Writers.OpenDocument (writeOpenDocument)
+import Text.Pandoc.Writers.Shared (fixDisplayMath)
import Text.Pandoc.XML
-import Text.Pandoc.Pretty
-import qualified Control.Exception as E
-import Data.Time.Clock.POSIX ( getPOSIXTime )
-import System.FilePath ( takeExtension, takeDirectory, (<.>))
+import Text.TeXMath
+import Text.XML.Light
+
+newtype ODTState = ODTState { stEntries :: [Entry]
+ }
+
+type O m = StateT ODTState m
-- | Produce an ODT file from a Pandoc document.
-writeODT :: WriterOptions -- ^ Writer options
+writeODT :: PandocMonad m
+ => WriterOptions -- ^ Writer options
-> Pandoc -- ^ Document to convert
- -> IO B.ByteString
-writeODT opts doc@(Pandoc meta _) = do
- let datadir = writerUserDataDir opts
+ -> m B.ByteString
+writeODT opts doc =
+ let initState = ODTState{ stEntries = []
+ }
+ in
+ evalStateT (pandocToODT opts doc) initState
+
+-- | Produce an ODT file from a Pandoc document.
+pandocToODT :: PandocMonad m
+ => WriterOptions -- ^ Writer options
+ -> Pandoc -- ^ Document to convert
+ -> O m B.ByteString
+pandocToODT opts doc@(Pandoc meta _) = do
let title = docTitle meta
+ lang <- toLang (getLang opts meta)
refArchive <-
- case writerReferenceODT opts of
- Just f -> liftM toArchive $ B.readFile f
- Nothing -> getDefaultReferenceODT datadir
+ case writerReferenceDoc opts of
+ Just f -> liftM toArchive $ lift $ P.readFileLazy f
+ Nothing -> lift $ (toArchive . B.fromStrict) <$>
+ P.readDataFile "reference.odt"
-- handle formulas and pictures
- picEntriesRef <- newIORef ([] :: [Entry])
- doc' <- walkM (transformPicMath opts picEntriesRef) $ walk fixDisplayMath doc
- let newContents = writeOpenDocument opts{writerWrapText = WrapNone} doc'
- epochtime <- floor `fmap` getPOSIXTime
+ -- picEntriesRef <- P.newIORef ([] :: [Entry])
+ doc' <- walkM (transformPicMath opts) $ walk fixDisplayMath doc
+ newContents <- lift $ writeOpenDocument opts{writerWrapText = WrapNone} doc'
+ epochtime <- floor `fmap` lift P.getPOSIXTime
let contentEntry = toEntry "content.xml" epochtime
- $ fromStringLazy newContents
- picEntries <- readIORef picEntriesRef
+ $ fromTextLazy $ TL.fromStrict newContents
+ picEntries <- gets stEntries
let archive = foldr addEntryToArchive refArchive
$ contentEntry : picEntries
-- construct META-INF/manifest.xml based on archive
@@ -90,14 +111,13 @@ writeODT opts doc@(Pandoc meta _) = do
$ fromStringLazy $ render Nothing
$ text "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
$$
- ( inTags True "manifest:manifest"
+ (inTags True "manifest:manifest"
[("xmlns:manifest","urn:oasis:names:tc:opendocument:xmlns:manifest:1.0")
- ,("manifest:version","1.2")]
- $ ( selfClosingTag "manifest:file-entry"
+ ,("manifest:version","1.2")] ( selfClosingTag "manifest:file-entry"
[("manifest:media-type","application/vnd.oasis.opendocument.text")
,("manifest:full-path","/")]
- $$ vcat ( map toFileEntry $ files )
- $$ vcat ( map toFileEntry $ formulas )
+ $$ vcat ( map toFileEntry files )
+ $$ vcat ( map toFileEntry formulas )
)
)
let archive' = addEntryToArchive manifestEntry archive
@@ -105,88 +125,138 @@ writeODT opts doc@(Pandoc meta _) = do
$ fromStringLazy $ render Nothing
$ text "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
$$
- ( inTags True "office:document-meta"
+ (inTags True "office:document-meta"
[("xmlns:office","urn:oasis:names:tc:opendocument:xmlns:office:1.0")
,("xmlns:xlink","http://www.w3.org/1999/xlink")
,("xmlns:dc","http://purl.org/dc/elements/1.1/")
,("xmlns:meta","urn:oasis:names:tc:opendocument:xmlns:meta:1.0")
,("xmlns:ooo","http://openoffice.org/2004/office")
,("xmlns:grddl","http://www.w3.org/2003/g/data-view#")
- ,("office:version","1.2")]
- $ ( inTagsSimple "office:meta"
- $ ( inTagsSimple "dc:title" (text $ escapeStringForXML (stringify title))
- )
+ ,("office:version","1.2")] ( inTagsSimple "office:meta" $
+ ( inTagsSimple "dc:title"
+ (text $ escapeStringForXML (stringify title))
+ $$
+ case lang of
+ Just l -> inTagsSimple "dc:language"
+ (text (escapeStringForXML (renderLang l)))
+ Nothing -> empty
+ )
)
)
-- make sure mimetype is first
let mimetypeEntry = toEntry "mimetype" epochtime
$ fromStringLazy "application/vnd.oasis.opendocument.text"
- let archive'' = addEntryToArchive mimetypeEntry
+ archive'' <- updateStyleWithLang lang
+ $ addEntryToArchive mimetypeEntry
$ addEntryToArchive metaEntry archive'
return $ fromArchive archive''
+updateStyleWithLang :: PandocMonad m => Maybe Lang -> Archive -> O m Archive
+updateStyleWithLang Nothing arch = return arch
+updateStyleWithLang (Just lang) arch = do
+ epochtime <- floor `fmap` lift P.getPOSIXTime
+ return arch{ zEntries = [if eRelativePath e == "styles.xml"
+ then case parseXMLDoc
+ (toStringLazy (fromEntry e)) of
+ Nothing -> e
+ Just d ->
+ toEntry "styles.xml" epochtime
+ ( fromStringLazy
+ . ppTopElement
+ . addLang lang $ d )
+ else e
+ | e <- zEntries arch] }
+
+addLang :: Lang -> Element -> Element
+addLang lang = everywhere' (mkT updateLangAttr)
+ where updateLangAttr (Attr n@(QName "language" _ (Just "fo")) _)
+ = Attr n (langLanguage lang)
+ updateLangAttr (Attr n@(QName "country" _ (Just "fo")) _)
+ = Attr n (langRegion lang)
+ updateLangAttr x = x
+
-- | transform both Image and Math elements
-transformPicMath :: WriterOptions -> IORef [Entry] -> Inline -> IO Inline
-transformPicMath opts entriesRef (Image attr@(id', cls, _) lab (src,t)) = do
- res <- fetchItem' (writerMediaBag opts) (writerSourceURL opts) src
- case res of
- Left (_ :: E.SomeException) -> do
- warn $ "Could not find image `" ++ src ++ "', skipping..."
- return $ Emph lab
- Right (img, mbMimeType) -> do
- (ptX, ptY) <- case imageSize img of
+transformPicMath :: PandocMonad m => WriterOptions ->Inline -> O m Inline
+transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = catchError
+ (do (img, mbMimeType) <- P.fetchItem src
+ (ptX, ptY) <- case imageSize opts img of
Right s -> return $ sizeInPoints s
Left msg -> do
- warn $ "Could not determine image size in `" ++
- src ++ "': " ++ msg
+ report $ CouldNotDetermineImageSize src msg
return (100, 100)
let dims =
case (getDim Width, getDim Height) of
(Just w, Just h) -> [("width", show w), ("height", show h)]
- (Just w@(Percent _), Nothing) -> [("width", show w), ("style:rel-height", "scale")]
- (Nothing, Just h@(Percent _)) -> [("style:rel-width", "scale"), ("height", show h)]
+ (Just w@(Percent p), Nothing) -> [("width", show w), ("height", show (p / ratio) ++ "%")]
+ (Nothing, Just h@(Percent p)) -> [("width", show (p * ratio) ++ "%"), ("height", show h)]
(Just w@(Inch i), Nothing) -> [("width", show w), ("height", show (i / ratio) ++ "in")]
(Nothing, Just h@(Inch i)) -> [("width", show (i * ratio) ++ "in"), ("height", show h)]
_ -> [("width", show ptX ++ "pt"), ("height", show ptY ++ "pt")]
where
ratio = ptX / ptY
- getDim dir = case (dimension dir attr) of
+ getDim dir = case dimension dir attr of
Just (Percent i) -> Just $ Percent i
Just dim -> Just $ Inch $ inInch opts dim
Nothing -> Nothing
let newattr = (id', cls, dims)
- entries <- readIORef entriesRef
+ entries <- gets stEntries
let extension = fromMaybe (takeExtension $ takeWhile (/='?') src)
(mbMimeType >>= extensionFromMimeType)
let newsrc = "Pictures/" ++ show (length entries) <.> extension
let toLazy = B.fromChunks . (:[])
- epochtime <- floor `fmap` getPOSIXTime
+ epochtime <- floor `fmap` lift P.getPOSIXTime
let entry = toEntry newsrc epochtime $ toLazy img
- modifyIORef entriesRef (entry:)
- return $ Image newattr lab (newsrc, t)
-transformPicMath _ entriesRef (Math t math) = do
- entries <- readIORef entriesRef
+ modify $ \st -> st{ stEntries = entry : entries }
+ return $ Image newattr lab (newsrc, t))
+ (\e -> do
+ report $ CouldNotFetchResource src (show e)
+ return $ Emph lab)
+
+transformPicMath _ (Math t math) = do
+ entries <- gets stEntries
let dt = if t == InlineMath then DisplayInline else DisplayBlock
case writeMathML dt <$> readTeX math of
Left _ -> return $ Math t math
Right r -> do
let conf = useShortEmptyTags (const False) defaultConfigPP
let mathml = ppcTopElement conf r
- epochtime <- floor `fmap` getPOSIXTime
+ epochtime <- floor `fmap` (lift P.getPOSIXTime)
let dirname = "Formula-" ++ show (length entries) ++ "/"
let fname = dirname ++ "content.xml"
let entry = toEntry fname epochtime (fromStringLazy mathml)
- modifyIORef entriesRef (entry:)
+ let fname' = dirname ++ "settings.xml"
+ let entry' = toEntry fname' epochtime $ documentSettings (t == InlineMath)
+ modify $ \st -> st{ stEntries = entry' : (entry : entries) }
return $ RawInline (Format "opendocument") $ render Nothing $
- inTags False "draw:frame" [("text:anchor-type",
- if t == DisplayMath
- then "paragraph"
- else "as-char")
- ,("style:vertical-pos", "middle")
- ,("style:vertical-rel", "text")] $
+ inTags False "draw:frame" (if t == DisplayMath
+ then [("draw:style-name","fr2")
+ -- `draw:frame` does not support either
+ -- `style:vertical-pos` or `style:vertical-rel`,
+ -- therefore those attributes must go into the
+ -- `style:style` element
+ ,("text:anchor-type","paragraph")]
+ else [("draw:style-name","fr1")
+ ,("text:anchor-type","as-char")]) $
selfClosingTag "draw:object" [("xlink:href", dirname)
, ("xlink:type", "simple")
, ("xlink:show", "embed")
, ("xlink:actuate", "onLoad")]
-transformPicMath _ _ x = return x
+transformPicMath _ x = return x
+
+documentSettings :: Bool -> B.ByteString
+documentSettings isTextMode = fromStringLazy $ render Nothing
+ $ text "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ $$
+ (inTags True "office:document-settings"
+ [("xmlns:office","urn:oasis:names:tc:opendocument:xmlns:office:1.0")
+ ,("xmlns:xlink","http://www.w3.org/1999/xlink")
+ ,("xmlns:config","urn:oasis:names:tc:opendocument:xmlns:config:1.0")
+ ,("xmlns:ooo","http://openoffice.org/2004/office")
+ ,("office:version","1.2")] $
+ inTagsSimple "office:settings" $
+ inTags False "config:config-item-set"
+ [("config:name", "ooo:configuration-settings")] $
+ inTags False "config:config-item" [("config:name", "IsTextMode")
+ ,("config:type", "boolean")] $
+ text $ if isTextMode then "true" else "false")
diff --git a/src/Text/Pandoc/Writers/OOXML.hs b/src/Text/Pandoc/Writers/OOXML.hs
new file mode 100644
index 000000000..30d8d72dd
--- /dev/null
+++ b/src/Text/Pandoc/Writers/OOXML.hs
@@ -0,0 +1,108 @@
+{-
+Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.OOXML
+ Copyright : Copyright (C) 2012-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Functions common to OOXML writers (Docx and Powerpoint)
+-}
+module Text.Pandoc.Writers.OOXML ( mknode
+ , nodename
+ , toLazy
+ , renderXml
+ , parseXml
+ , elemToNameSpaces
+ , elemName
+ , isElem
+ , NameSpaces
+ , fitToPage
+ ) where
+
+import Codec.Archive.Zip
+import Control.Monad.Reader
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.ByteString.Lazy.Char8 as BL8
+import Data.Maybe (mapMaybe)
+import Data.Monoid ((<>))
+import Text.Pandoc.Class (PandocMonad)
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.XML.Light as XML
+
+mknode :: Node t => String -> [(String,String)] -> t -> Element
+mknode s attrs =
+ add_attrs (map (\(k,v) -> Attr (nodename k) v) attrs) . node (nodename s)
+
+nodename :: String -> QName
+nodename s = QName{ qName = name, qURI = Nothing, qPrefix = prefix }
+ where (name, prefix) = case break (==':') s of
+ (xs,[]) -> (xs, Nothing)
+ (ys, _:zs) -> (zs, Just ys)
+
+toLazy :: B.ByteString -> BL.ByteString
+toLazy = BL.fromChunks . (:[])
+
+renderXml :: Element -> BL.ByteString
+renderXml elt = BL8.pack "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" <>
+ UTF8.fromStringLazy (showElement elt)
+
+parseXml :: (PandocMonad m) => Archive -> Archive -> String -> m Element
+parseXml refArchive distArchive relpath =
+ case findEntryByPath relpath refArchive `mplus`
+ findEntryByPath relpath distArchive of
+ Nothing -> fail $ relpath ++ " missing in reference file"
+ Just e -> case parseXMLDoc . UTF8.toStringLazy . fromEntry $ e of
+ Nothing -> fail $ relpath ++ " corrupt in reference file"
+ Just d -> return d
+
+-- Copied from Util
+
+attrToNSPair :: XML.Attr -> Maybe (String, String)
+attrToNSPair (XML.Attr (QName s _ (Just "xmlns")) val) = Just (s, val)
+attrToNSPair _ = Nothing
+
+
+elemToNameSpaces :: Element -> NameSpaces
+elemToNameSpaces = mapMaybe attrToNSPair . elAttribs
+
+elemName :: NameSpaces -> String -> String -> QName
+elemName ns prefix name =
+ QName name (lookup prefix ns) (if null prefix then Nothing else Just prefix)
+
+isElem :: NameSpaces -> String -> String -> Element -> Bool
+isElem ns prefix name element =
+ let ns' = ns ++ elemToNameSpaces element
+ in qName (elName element) == name &&
+ qURI (elName element) == lookup prefix ns'
+
+type NameSpaces = [(String, String)]
+
+-- | Scales the image to fit the page
+-- sizes are passed in emu
+fitToPage :: (Double, Double) -> Integer -> (Integer, Integer)
+fitToPage (x, y) pageWidth
+ -- Fixes width to the page width and scales the height
+ | x > fromIntegral pageWidth =
+ (pageWidth, floor $ (fromIntegral pageWidth / x) * y)
+ | otherwise = (floor x, floor y)
diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs
index 20c2c5cbc..29e1bc80c 100644
--- a/src/Text/Pandoc/Writers/OPML.hs
+++ b/src/Text/Pandoc/Writers/OPML.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE CPP #-}
{-
-Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.OPML
- Copyright : Copyright (C) 2013-2015 John MacFarlane
+ Copyright : Copyright (C) 2013-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,40 +29,45 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to OPML XML.
-}
module Text.Pandoc.Writers.OPML ( writeOPML) where
+import Control.Monad.Except (throwError)
+import Data.Text (Text, unpack)
+import qualified Data.Text as T
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Compat.Time
import Text.Pandoc.Definition
-import Text.Pandoc.XML
-import Text.Pandoc.Writers.Shared
-import Text.Pandoc.Shared
+import Text.Pandoc.Error
import Text.Pandoc.Options
+import Text.Pandoc.Pretty
+import Text.Pandoc.Shared
import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.Writers.HTML (writeHtmlString)
+import Text.Pandoc.Writers.HTML (writeHtml5String)
import Text.Pandoc.Writers.Markdown (writeMarkdown)
-import Text.Pandoc.Pretty
-import Text.Pandoc.Compat.Time
-import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Writers.Shared
+import Text.Pandoc.XML
-- | Convert Pandoc document to string in OPML format.
-writeOPML :: WriterOptions -> Pandoc -> String
-writeOPML opts (Pandoc meta blocks) =
+writeOPML :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeOPML opts (Pandoc meta blocks) = do
let elements = hierarchicalize blocks
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
meta' = B.setMeta "date" (B.str $ convertDate $ docDate meta) meta
- Just metadata = metaToJSON opts
- (Just . writeMarkdown def . Pandoc nullMeta)
- (Just . trimr . writeMarkdown def . Pandoc nullMeta .
- (\ils -> [Plain ils]))
- meta'
- main = render colwidth $ vcat (map (elementToOPML opts) elements)
- context = defField "body" main metadata
- in case writerTemplate opts of
- Nothing -> main
- Just tpl -> renderTemplate' tpl context
+ metadata <- metaToJSON opts
+ (writeMarkdown def . Pandoc nullMeta)
+ (\ils -> T.stripEnd <$> writeMarkdown def (Pandoc nullMeta [Plain ils]))
+ meta'
+ main <- (render colwidth . vcat) <$> mapM (elementToOPML opts) elements
+ let context = defField "body" main metadata
+ case writerTemplate opts of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
-writeHtmlInlines :: [Inline] -> String
-writeHtmlInlines ils = trim $ writeHtmlString def
- $ Pandoc nullMeta [Plain ils]
+
+writeHtmlInlines :: PandocMonad m => [Inline] -> m Text
+writeHtmlInlines ils =
+ T.strip <$> writeHtml5String def (Pandoc nullMeta [Plain ils])
-- date format: RFC 822: Thu, 14 Jul 2005 23:41:05 GMT
showDateTimeRFC822 :: UTCTime -> String
@@ -75,20 +80,27 @@ convertDate ils = maybe "" showDateTimeRFC822 $
#else
parseTime
#endif
- defaultTimeLocale "%F" =<< (normalizeDate $ stringify ils)
+ defaultTimeLocale "%F" =<< normalizeDate (stringify ils)
-- | Convert an Element to OPML.
-elementToOPML :: WriterOptions -> Element -> Doc
-elementToOPML _ (Blk _) = empty
-elementToOPML opts (Sec _ _num _ title elements) =
- let isBlk (Blk _) = True
- isBlk _ = False
- fromBlk (Blk x) = x
- fromBlk _ = error "fromBlk called on non-block"
+elementToOPML :: PandocMonad m => WriterOptions -> Element -> m Doc
+elementToOPML _ (Blk _) = return empty
+elementToOPML opts (Sec _ _num _ title elements) = do
+ let isBlk :: Element -> Bool
+ isBlk (Blk _) = True
+ isBlk _ = False
+
+ fromBlk :: PandocMonad m => Element -> m Block
+ fromBlk (Blk x) = return x
+ fromBlk _ = throwError $ PandocSomeError "fromBlk called on non-block"
+
(blocks, rest) = span isBlk elements
- attrs = [("text", writeHtmlInlines title)] ++
- [("_note", writeMarkdown def (Pandoc nullMeta
- (map fromBlk blocks)))
- | not (null blocks)]
- in inTags True "outline" attrs $
- vcat (map (elementToOPML opts) rest)
+ htmlIls <- writeHtmlInlines title
+ md <- if null blocks
+ then return mempty
+ else do blks <- mapM fromBlk blocks
+ writeMarkdown def $ Pandoc nullMeta blks
+ let attrs = ("text", unpack htmlIls) :
+ [("_note", unpack md) | not (null blocks)]
+ o <- mapM (elementToOPML opts) rest
+ return $ inTags True "outline" attrs $ vcat o
diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs
index 8f0e037c5..17edc0cbd 100644
--- a/src/Text/Pandoc/Writers/OpenDocument.hs
+++ b/src/Text/Pandoc/Writers/OpenDocument.hs
@@ -1,6 +1,8 @@
-{-# LANGUAGE PatternGuards, OverloadedStrings, FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2008-2015 Andrea Rossato <andrea.rossato@ing.unitn.it>
+Copyright (C) 2008-2018 Andrea Rossato <andrea.rossato@ing.unitn.it>
and John MacFarlane.
This program is free software; you can redistribute it and/or modify
@@ -20,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.OpenDocument
- Copyright : Copyright (C) 2008-2015 Andrea Rossato and John MacFarlane
+ Copyright : Copyright (C) 2008-2018 Andrea Rossato and John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Andrea Rossato <andrea.rossato@ing.unitn.it>
@@ -30,32 +32,38 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to OpenDocument XML.
-}
module Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) where
+import Control.Arrow ((***), (>>>))
+import Control.Monad.State.Strict hiding (when)
+import Data.Char (chr)
+import Data.List (sortBy)
+import qualified Data.Map as Map
+import Data.Ord (comparing)
+import qualified Data.Set as Set
+import Data.Text (Text)
+import Text.Pandoc.BCP47 (Lang (..), parseBCP47)
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.XML
+import Text.Pandoc.Pretty
import Text.Pandoc.Shared (linesToPara)
import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.Readers.TeXMath
-import Text.Pandoc.Pretty
-import Text.Printf ( printf )
-import Control.Arrow ( (***), (>>>) )
-import Control.Monad.State hiding ( when )
-import Data.Char (chr)
-import qualified Data.Set as Set
-import qualified Data.Map as Map
+import Text.Pandoc.Writers.Math
import Text.Pandoc.Writers.Shared
-import Data.List (sortBy)
-import Data.Ord (comparing)
+import Text.Pandoc.XML
+import Text.Printf (printf)
-- | Auxiliary function to convert Plain block to Para.
plainToPara :: Block -> Block
plainToPara (Plain x) = Para x
-plainToPara x = x
+plainToPara x = x
--
-- OpenDocument writer
--
+type OD m = StateT WriterState m
+
data WriterState =
WriterState { stNotes :: [Doc]
, stTableStyles :: [Doc]
@@ -88,46 +96,45 @@ defaultWriterState =
when :: Bool -> Doc -> Doc
when p a = if p then a else empty
-addTableStyle :: Doc -> State WriterState ()
+addTableStyle :: PandocMonad m => Doc -> OD m ()
addTableStyle i = modify $ \s -> s { stTableStyles = i : stTableStyles s }
-addNote :: Doc -> State WriterState ()
+addNote :: PandocMonad m => Doc -> OD m ()
addNote i = modify $ \s -> s { stNotes = i : stNotes s }
-addParaStyle :: Doc -> State WriterState ()
+addParaStyle :: PandocMonad m => Doc -> OD m ()
addParaStyle i = modify $ \s -> s { stParaStyles = i : stParaStyles s }
-addTextStyle :: Set.Set TextStyle -> (String, Doc) -> State WriterState ()
+addTextStyle :: PandocMonad m => Set.Set TextStyle -> (String, Doc) -> OD m ()
addTextStyle attrs i = modify $ \s ->
s { stTextStyles = Map.insert attrs i (stTextStyles s) }
-addTextStyleAttr :: TextStyle -> State WriterState ()
+addTextStyleAttr :: PandocMonad m => TextStyle -> OD m ()
addTextStyleAttr t = modify $ \s ->
s { stTextStyleAttr = Set.insert t (stTextStyleAttr s) }
-increaseIndent :: State WriterState ()
+increaseIndent :: PandocMonad m => OD m ()
increaseIndent = modify $ \s -> s { stIndentPara = 1 + stIndentPara s }
-resetIndent :: State WriterState ()
-resetIndent = modify $ \s -> s { stIndentPara = (stIndentPara s) - 1 }
+resetIndent :: PandocMonad m => OD m ()
+resetIndent = modify $ \s -> s { stIndentPara = stIndentPara s - 1 }
-inTightList :: State WriterState a -> State WriterState a
+inTightList :: PandocMonad m => OD m a -> OD m a
inTightList f = modify (\s -> s { stTight = True }) >> f >>= \r ->
modify (\s -> s { stTight = False }) >> return r
-setInDefinitionList :: Bool -> State WriterState ()
+setInDefinitionList :: PandocMonad m => Bool -> OD m ()
setInDefinitionList b = modify $ \s -> s { stInDefinition = b }
-setFirstPara :: State WriterState ()
+setFirstPara :: PandocMonad m => OD m ()
setFirstPara = modify $ \s -> s { stFirstPara = True }
-inParagraphTags :: Doc -> State WriterState Doc
-inParagraphTags d | isEmpty d = return empty
+inParagraphTags :: PandocMonad m => Doc -> OD m Doc
inParagraphTags d = do
b <- gets stFirstPara
a <- if b
then do modify $ \st -> st { stFirstPara = False }
- return $ [("text:style-name", "First_20_paragraph")]
+ return [("text:style-name", "First_20_paragraph")]
else return [("text:style-name", "Text_20_body")]
return $ inTags False "text:p" a d
@@ -137,7 +144,7 @@ inParagraphTagsWithStyle sty = inTags False "text:p" [("text:style-name", sty)]
inSpanTags :: String -> Doc -> Doc
inSpanTags s = inTags False "text:span" [("text:style-name",s)]
-withTextStyle :: TextStyle -> State WriterState a -> State WriterState a
+withTextStyle :: PandocMonad m => TextStyle -> OD m a -> OD m a
withTextStyle s f = do
oldTextStyleAttr <- gets stTextStyleAttr
addTextStyleAttr s
@@ -145,7 +152,7 @@ withTextStyle s f = do
modify $ \st -> st{ stTextStyleAttr = oldTextStyleAttr }
return res
-inTextStyle :: Doc -> State WriterState Doc
+inTextStyle :: PandocMonad m => Doc -> OD m Doc
inTextStyle d = do
at <- gets stTextStyleAttr
if Set.null at
@@ -161,12 +168,30 @@ inTextStyle d = do
inTags False "style:style"
[("style:name", styleName)
,("style:family", "text")]
- $ selfClosingTag "style:text-properties"
- (concatMap textStyleAttr (Set.toList at)))
+ $ selfClosingTag "style:text-properties"
+ (concatMap textStyleAttr (Set.toList at)))
return $ inTags False
"text:span" [("text:style-name",styleName)] d
-inHeaderTags :: Int -> Doc -> State WriterState Doc
+formulaStyles :: [Doc]
+formulaStyles = [formulaStyle InlineMath, formulaStyle DisplayMath]
+
+formulaStyle :: MathType -> Doc
+formulaStyle mt = inTags False "style:style"
+ [("style:name", if mt == InlineMath then "fr1" else "fr2")
+ ,("style:family", "graphic")
+ ,("style:parent-style-name", "Formula")]
+ $ selfClosingTag "style:graphic-properties" $ if mt == InlineMath then
+ [("style:vertical-pos", "middle")
+ ,("style:vertical-rel", "text")]
+ else
+ [("style:vertical-pos", "middle")
+ ,("style:vertical-rel", "paragraph-content")
+ ,("style:horizontal-pos", "center")
+ ,("style:horizontal-rel", "paragraph-content")
+ ,("style:wrap", "none")]
+
+inHeaderTags :: PandocMonad m => Int -> Doc -> OD m Doc
inHeaderTags i d =
return $ inTags False "text:h" [ ("text:style-name", "Heading_20_" ++ show i)
, ("text:outline-level", show i)] d
@@ -189,64 +214,67 @@ handleSpaces s
rm [] = empty
-- | Convert Pandoc document to string in OpenDocument format.
-writeOpenDocument :: WriterOptions -> Pandoc -> String
-writeOpenDocument opts (Pandoc meta blocks) =
+writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeOpenDocument opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ let render' :: Doc -> Text
render' = render colwidth
- ((body, metadata),s) = flip runState
+ ((body, metadata),s) <- flip runStateT
defaultWriterState $ do
m <- metaToJSON opts
- (fmap (render colwidth) . blocksToOpenDocument opts)
- (fmap (render colwidth) . inlinesToOpenDocument opts)
+ (fmap render' . blocksToOpenDocument opts)
+ (fmap render' . inlinesToOpenDocument opts)
meta
b <- render' `fmap` blocksToOpenDocument opts blocks
return (b, m)
- styles = stTableStyles s ++ stParaStyles s ++
- map snd (reverse $ sortBy (comparing fst) $
- Map.elems (stTextStyles s))
+ let styles = stTableStyles s ++ stParaStyles s ++ formulaStyles ++
+ map snd (sortBy (flip (comparing fst)) (
+ Map.elems (stTextStyles s)))
listStyle (n,l) = inTags True "text:list-style"
[("style:name", "L" ++ show n)] (vcat l)
- listStyles = map listStyle (stListStyles s)
- automaticStyles = vcat $ reverse $ styles ++ listStyles
- context = defField "body" body
- $ defField "automatic-styles" (render' automaticStyles)
- $ metadata
- in case writerTemplate opts of
- Nothing -> body
- Just tpl -> renderTemplate' tpl context
-
-withParagraphStyle :: WriterOptions -> String -> [Block] -> State WriterState Doc
+ let listStyles = map listStyle (stListStyles s)
+ let automaticStyles = vcat $ reverse $ styles ++ listStyles
+ let context = defField "body" body
+ $ defField "toc" (writerTableOfContents opts)
+ $defField "automatic-styles" (render' automaticStyles) metadata
+ case writerTemplate opts of
+ Nothing -> return body
+ Just tpl -> renderTemplate' tpl context
+
+withParagraphStyle :: PandocMonad m
+ => WriterOptions -> String -> [Block] -> OD m Doc
withParagraphStyle o s (b:bs)
| Para l <- b = go =<< inParagraphTagsWithStyle s <$> inlinesToOpenDocument o l
| otherwise = go =<< blockToOpenDocument o b
where go i = (<>) i <$> withParagraphStyle o s bs
withParagraphStyle _ _ [] = return empty
-inPreformattedTags :: String -> State WriterState Doc
+inPreformattedTags :: PandocMonad m => String -> OD m Doc
inPreformattedTags s = do
n <- paraStyle [("style:parent-style-name","Preformatted_20_Text")]
return . inParagraphTagsWithStyle ("P" ++ show n) . handleSpaces $ s
-orderedListToOpenDocument :: WriterOptions -> Int -> [[Block]] -> State WriterState Doc
+orderedListToOpenDocument :: PandocMonad m
+ => WriterOptions -> Int -> [[Block]] -> OD m Doc
orderedListToOpenDocument o pn bs =
vcat . map (inTagsIndented "text:list-item") <$>
mapM (orderedItemToOpenDocument o pn . map plainToPara) bs
-orderedItemToOpenDocument :: WriterOptions -> Int -> [Block] -> State WriterState Doc
-orderedItemToOpenDocument o n (b:bs)
- | OrderedList a l <- b = newLevel a l
- | Para l <- b = go =<< inParagraphTagsWithStyle ("P" ++ show n) <$> inlinesToOpenDocument o l
- | otherwise = go =<< blockToOpenDocument o b
- where
- go i = ($$) i <$> orderedItemToOpenDocument o n bs
- newLevel a l = do
- nn <- length <$> gets stParaStyles
- ls <- head <$> gets stListStyles
- modify $ \s -> s { stListStyles = orderedListLevelStyle a ls : tail (stListStyles s) }
- inTagsIndented "text:list" <$> orderedListToOpenDocument o nn l
-orderedItemToOpenDocument _ _ [] = return empty
+orderedItemToOpenDocument :: PandocMonad m
+ => WriterOptions -> Int -> [Block] -> OD m Doc
+orderedItemToOpenDocument o n bs = vcat <$> mapM go bs
+ where go (OrderedList a l) = newLevel a l
+ go (Para l) = inParagraphTagsWithStyle ("P" ++ show n) <$>
+ inlinesToOpenDocument o l
+ go b = blockToOpenDocument o b
+ newLevel a l = do
+ nn <- length <$> gets stParaStyles
+ ls <- head <$> gets stListStyles
+ modify $ \s -> s { stListStyles = orderedListLevelStyle a ls :
+ drop 1 (stListStyles s) }
+ inTagsIndented "text:list" <$> orderedListToOpenDocument o nn l
isTightList :: [[Block]] -> Bool
isTightList [] = False
@@ -254,7 +282,8 @@ isTightList (b:_)
| Plain {} : _ <- b = True
| otherwise = False
-newOrderedListStyle :: Bool -> ListAttributes -> State WriterState (Int,Int)
+newOrderedListStyle :: PandocMonad m
+ => Bool -> ListAttributes -> OD m (Int,Int)
newOrderedListStyle b a = do
ln <- (+) 1 . length <$> gets stListStyles
let nbs = orderedListLevelStyle a (ln, [])
@@ -262,7 +291,8 @@ newOrderedListStyle b a = do
modify $ \s -> s { stListStyles = nbs : stListStyles s }
return (ln,pn)
-bulletListToOpenDocument :: WriterOptions -> [[Block]] -> State WriterState Doc
+bulletListToOpenDocument :: PandocMonad m
+ => WriterOptions -> [[Block]] -> OD m Doc
bulletListToOpenDocument o b = do
ln <- (+) 1 . length <$> gets stListStyles
(pn,ns) <- if isTightList b then inTightList (bulletListStyle ln) else bulletListStyle ln
@@ -270,48 +300,53 @@ bulletListToOpenDocument o b = do
is <- listItemsToOpenDocument ("P" ++ show pn) o b
return $ inTags True "text:list" [("text:style-name", "L" ++ show ln)] is
-listItemsToOpenDocument :: String -> WriterOptions -> [[Block]] -> State WriterState Doc
+listItemsToOpenDocument :: PandocMonad m
+ => String -> WriterOptions -> [[Block]] -> OD m Doc
listItemsToOpenDocument s o is =
vcat . map (inTagsIndented "text:list-item") <$> mapM (withParagraphStyle o s . map plainToPara) is
-deflistItemToOpenDocument :: WriterOptions -> ([Inline],[[Block]]) -> State WriterState Doc
+deflistItemToOpenDocument :: PandocMonad m
+ => WriterOptions -> ([Inline],[[Block]]) -> OD m Doc
deflistItemToOpenDocument o (t,d) = do
let ts = if isTightList d
then "Definition_20_Term_20_Tight" else "Definition_20_Term"
ds = if isTightList d
then "Definition_20_Definition_20_Tight" else "Definition_20_Definition"
t' <- withParagraphStyle o ts [Para t]
- d' <- liftM vcat $ mapM (withParagraphStyle o ds . (map plainToPara)) d
+ d' <- liftM vcat $ mapM (withParagraphStyle o ds . map plainToPara) d
return $ t' $$ d'
-inBlockQuote :: WriterOptions -> Int -> [Block] -> State WriterState Doc
+inBlockQuote :: PandocMonad m
+ => WriterOptions -> Int -> [Block] -> OD m Doc
inBlockQuote o i (b:bs)
| BlockQuote l <- b = do increaseIndent
ni <- paraStyle
[("style:parent-style-name","Quotations")]
go =<< inBlockQuote o ni (map plainToPara l)
- | Para l <- b = do go =<< inParagraphTagsWithStyle ("P" ++ show i) <$> inlinesToOpenDocument o l
- | otherwise = do go =<< blockToOpenDocument o b
+ | Para l <- b = go =<< inParagraphTagsWithStyle ("P" ++ show i) <$> inlinesToOpenDocument o l
+ | otherwise = go =<< blockToOpenDocument o b
where go block = ($$) block <$> inBlockQuote o i bs
inBlockQuote _ _ [] = resetIndent >> return empty
-- | Convert a list of Pandoc blocks to OpenDocument.
-blocksToOpenDocument :: WriterOptions -> [Block] -> State WriterState Doc
+blocksToOpenDocument :: PandocMonad m => WriterOptions -> [Block] -> OD m Doc
blocksToOpenDocument o b = vcat <$> mapM (blockToOpenDocument o) b
-- | Convert a Pandoc block element to OpenDocument.
-blockToOpenDocument :: WriterOptions -> Block -> State WriterState Doc
+blockToOpenDocument :: PandocMonad m => WriterOptions -> Block -> OD m Doc
blockToOpenDocument o bs
| Plain b <- bs = if null b
then return empty
else inParagraphTags =<< inlinesToOpenDocument o b
| Para [Image attr c (s,'f':'i':'g':':':t)] <- bs
= figure attr c s t
- | Para b <- bs = if null b
+ | Para b <- bs = if null b &&
+ not (isEnabled Ext_empty_paragraphs o)
then return empty
else inParagraphTags =<< inlinesToOpenDocument o b
| LineBlock b <- bs = blockToOpenDocument o $ linesToPara b
- | Div _ xs <- bs = blocksToOpenDocument o xs
+ | Div attr xs <- bs = withLangFromAttr attr
+ (blocksToOpenDocument o xs)
| Header i _ b <- bs = setFirstPara >>
(inHeaderTags i =<< inlinesToOpenDocument o b)
| BlockQuote b <- bs = setFirstPara >> mkBlockQuote b
@@ -324,7 +359,9 @@ blockToOpenDocument o bs
[ ("text:style-name", "Horizontal_20_Line") ])
| RawBlock f s <- bs = if f == Format "opendocument"
then return $ text s
- else return empty
+ else do
+ report $ BlockNotRendered bs
+ return empty
| Null <- bs = return empty
| otherwise = return empty
where
@@ -370,17 +407,23 @@ blockToOpenDocument o bs
captionDoc <- withParagraphStyle o "FigureCaption" [Para caption]
return $ imageDoc $$ captionDoc
-colHeadsToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc
+colHeadsToOpenDocument :: PandocMonad m
+ => WriterOptions -> String -> [String] -> [[Block]]
+ -> OD m Doc
colHeadsToOpenDocument o tn ns hs =
inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$>
mapM (tableItemToOpenDocument o tn) (zip ns hs)
-tableRowToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc
+tableRowToOpenDocument :: PandocMonad m
+ => WriterOptions -> String -> [String] -> [[Block]]
+ -> OD m Doc
tableRowToOpenDocument o tn ns cs =
inTagsIndented "table:table-row" . vcat <$>
mapM (tableItemToOpenDocument o tn) (zip ns cs)
-tableItemToOpenDocument :: WriterOptions -> String -> (String,[Block])-> State WriterState Doc
+tableItemToOpenDocument :: PandocMonad m
+ => WriterOptions -> String -> (String,[Block])
+ -> OD m Doc
tableItemToOpenDocument o tn (n,i) =
let a = [ ("table:style-name" , tn ++ ".A1" )
, ("office:value-type", "string" )
@@ -389,10 +432,10 @@ tableItemToOpenDocument o tn (n,i) =
withParagraphStyle o n (map plainToPara i)
-- | Convert a list of inline elements to OpenDocument.
-inlinesToOpenDocument :: WriterOptions -> [Inline] -> State WriterState Doc
+inlinesToOpenDocument :: PandocMonad m => WriterOptions -> [Inline] -> OD m Doc
inlinesToOpenDocument o l = hcat <$> toChunks o l
-toChunks :: WriterOptions -> [Inline] -> State WriterState [Doc]
+toChunks :: PandocMonad m => WriterOptions -> [Inline] -> OD m [Doc]
toChunks _ [] = return []
toChunks o (x : xs)
| isChunkable x = do
@@ -407,21 +450,21 @@ toChunks o (x : xs)
where (ys, zs) = span isChunkable xs
isChunkable :: Inline -> Bool
-isChunkable (Str _) = True
-isChunkable Space = True
+isChunkable (Str _) = True
+isChunkable Space = True
isChunkable SoftBreak = True
-isChunkable _ = False
+isChunkable _ = False
-- | Convert an inline element to OpenDocument.
-inlineToOpenDocument :: WriterOptions -> Inline -> State WriterState Doc
+inlineToOpenDocument :: PandocMonad m => WriterOptions -> Inline -> OD m Doc
inlineToOpenDocument o ils
= case ils of
Space -> return space
SoftBreak
| writerWrapText o == WrapPreserve
-> return $ preformatted "\n"
- | otherwise -> return $ space
- Span _ xs -> inlinesToOpenDocument o xs
+ | otherwise ->return space
+ Span attr xs -> withLangFromAttr attr (inlinesToOpenDocument o xs)
LineBreak -> return $ selfClosingTag "text:line-break" []
Str s -> return $ handleSpaces $ escapeStringForXML s
Emph l -> withTextStyle Italic $ inlinesToOpenDocument o l
@@ -432,11 +475,14 @@ inlineToOpenDocument o ils
SmallCaps l -> withTextStyle SmallC $ inlinesToOpenDocument o l
Quoted t l -> inQuotes t <$> inlinesToOpenDocument o l
Code _ s -> inlinedCode $ preformatted s
- Math t s -> inlinesToOpenDocument o (texMathToInlines t s)
+ Math t s -> lift (texMathToInlines t s) >>=
+ inlinesToOpenDocument o
Cite _ l -> inlinesToOpenDocument o l
RawInline f s -> if f == Format "opendocument"
then return $ text s
- else return empty
+ else do
+ report $ InlineNotRendered ils
+ return empty
Link _ l (s,t) -> mkLink s t <$> inlinesToOpenDocument o l
Image attr _ (s,t) -> mkImg attr s t
Note l -> mkNote l
@@ -453,8 +499,6 @@ inlineToOpenDocument o ils
let getDims [] = []
getDims (("width", w) :xs) = ("svg:width", w) : getDims xs
getDims (("height", h):xs) = ("svg:height", h) : getDims xs
- getDims (x@("style:rel-width", _) :xs) = x : getDims xs
- getDims (x@("style:rel-height", _):xs) = x : getDims xs
getDims (_:xs) = getDims xs
return $ inTags False "draw:frame"
(("draw:name", "img" ++ show id') : getDims kvs) $
@@ -473,18 +517,18 @@ inlineToOpenDocument o ils
addNote nn
return nn
-bulletListStyle :: Int -> State WriterState (Int,(Int,[Doc]))
-bulletListStyle l =
- let doStyles i = inTags True "text:list-level-style-bullet"
- [ ("text:level" , show (i + 1) )
- , ("text:style-name" , "Bullet_20_Symbols")
- , ("style:num-suffix", "." )
- , ("text:bullet-char", [bulletList !! i] )
- ] (listLevelStyle (1 + i))
- bulletList = map chr $ cycle [8226,8227,8259]
- listElStyle = map doStyles [0..9]
- in do pn <- paraListStyle l
- return (pn, (l, listElStyle))
+bulletListStyle :: PandocMonad m => Int -> OD m (Int,(Int,[Doc]))
+bulletListStyle l = do
+ let doStyles i = inTags True "text:list-level-style-bullet"
+ [ ("text:level" , show (i + 1) )
+ , ("text:style-name" , "Bullet_20_Symbols")
+ , ("style:num-suffix", "." )
+ , ("text:bullet-char", [bulletList !! i] )
+ ] (listLevelStyle (1 + i))
+ bulletList = map chr $ cycle [8226,9702,9642]
+ listElStyle = map doStyles [0..9]
+ pn <- paraListStyle l
+ return (pn, (l, listElStyle))
orderedListLevelStyle :: ListAttributes -> (Int, [Doc]) -> (Int,[Doc])
orderedListLevelStyle (s,n, d) (l,ls) =
@@ -494,11 +538,11 @@ orderedListLevelStyle (s,n, d) (l,ls) =
,("style:num-suffix", ")")]
_ -> [("style:num-suffix", ".")]
format = case n of
- UpperAlpha -> "A"
- LowerAlpha -> "a"
- UpperRoman -> "I"
- LowerRoman -> "i"
- _ -> "1"
+ UpperAlpha -> "A"
+ LowerAlpha -> "a"
+ UpperRoman -> "I"
+ LowerRoman -> "i"
+ _ -> "1"
listStyle = inTags True "text:list-level-style-number"
([ ("text:level" , show $ 1 + length ls )
, ("text:style-name" , "Numbering_20_Symbols")
@@ -509,10 +553,10 @@ orderedListLevelStyle (s,n, d) (l,ls) =
listLevelStyle :: Int -> Doc
listLevelStyle i =
- let indent = show (0.25 * fromIntegral i :: Double) in
+ let indent = show (0.4 * fromIntegral (i - 1) :: Double) in
selfClosingTag "style:list-level-properties"
[ ("text:space-before" , indent ++ "in")
- , ("text:min-label-width", "0.25in")]
+ , ("text:min-label-width", "0.4in")]
tableStyle :: Int -> [(Char,Double)] -> Doc
tableStyle num wcs =
@@ -529,7 +573,7 @@ tableStyle num wcs =
[ ("style:name" , tableId ++ "." ++ [c])
, ("style:family", "table-column" )] $
selfClosingTag "style:table-column-properties"
- [("style:rel-column-width", printf "%d*" $ (floor $ w * 65535 :: Integer))]
+ [("style:rel-column-width", printf "%d*" (floor $ w * 65535 :: Integer))]
cellStyle = inTags True "style:style"
[ ("style:name" , tableId ++ ".A1")
, ("style:family", "table-cell" )] $
@@ -538,31 +582,33 @@ tableStyle num wcs =
columnStyles = map colStyle wcs
in table $$ vcat columnStyles $$ cellStyle
-paraStyle :: [(String,String)] -> State WriterState Int
+paraStyle :: PandocMonad m => [(String,String)] -> OD m Int
paraStyle attrs = do
pn <- (+) 1 . length <$> gets stParaStyles
- i <- (*) 0.5 . fromIntegral <$> gets stIndentPara :: State WriterState Double
+ i <- (*) (0.5 :: Double) . fromIntegral <$> gets stIndentPara
b <- gets stInDefinition
t <- gets stTight
let styleAttr = [ ("style:name" , "P" ++ show pn)
, ("style:family" , "paragraph" )]
- indentVal = flip (++) "in" . show $ if b then (max 0.5 i) else i
+ indentVal = flip (++) "in" . show $ if b then max 0.5 i else i
tight = if t then [ ("fo:margin-top" , "0in" )
, ("fo:margin-bottom" , "0in" )]
else []
- indent = if (i /= 0 || b)
+ indent = if i /= 0 || b
then [ ("fo:margin-left" , indentVal)
, ("fo:margin-right" , "0in" )
, ("fo:text-indent" , "0in" )
, ("style:auto-text-indent" , "false" )]
else []
attributes = indent ++ tight
- paraProps = when (not $ null attributes) $
- selfClosingTag "style:paragraph-properties" attributes
+ paraProps = if null attributes
+ then mempty
+ else selfClosingTag
+ "style:paragraph-properties" attributes
addParaStyle $ inTags True "style:style" (styleAttr ++ attrs) paraProps
return pn
-paraListStyle :: Int -> State WriterState Int
+paraListStyle :: PandocMonad m => Int -> OD m Int
paraListStyle l = paraStyle
[("style:parent-style-name","Text_20_body")
,("style:list-style-name", "L" ++ show l )]
@@ -582,7 +628,14 @@ paraTableStyles t s (a:xs)
[ ("fo:text-align", x)
, ("style:justify-single-word", "false")]
-data TextStyle = Italic | Bold | Strike | Sub | Sup | SmallC | Pre
+data TextStyle = Italic
+ | Bold
+ | Strike
+ | Sub
+ | Sup
+ | SmallC
+ | Pre
+ | Language Lang
deriving ( Eq,Ord )
textStyleAttr :: TextStyle -> [(String,String)]
@@ -600,4 +653,18 @@ textStyleAttr s
| Pre <- s = [("style:font-name" ,"Courier New")
,("style:font-name-asian" ,"Courier New")
,("style:font-name-complex" ,"Courier New")]
+ | Language lang <- s
+ = [("fo:language" ,langLanguage lang)
+ ,("fo:country" ,langRegion lang)]
| otherwise = []
+
+withLangFromAttr :: PandocMonad m => Attr -> OD m a -> OD m a
+withLangFromAttr (_,_,kvs) action =
+ case lookup "lang" kvs of
+ Nothing -> action
+ Just l ->
+ case parseBCP47 l of
+ Right lang -> withTextStyle (Language lang) action
+ Left _ -> do
+ report $ InvalidLang l
+ action
diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs
index 4302459cc..2307204a5 100644
--- a/src/Text/Pandoc/Writers/Org.hs
+++ b/src/Text/Pandoc/Writers/Org.hs
@@ -1,8 +1,8 @@
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
- Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>,
- and John MacFarlane <jgm@berkeley.edu>
+ 2010-2018 John MacFarlane <jgm@berkeley.edu>
+ 2016-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,10 +21,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Org
- Copyright : Copyright (C) 2010-2015 Puneeth Chaganti and John MacFarlane
+ Copyright : © 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
+ 2010-2018 John MacFarlane <jgm@berkeley.edu>
+ 2016-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
License : GNU GPL, version 2 or above
- Maintainer : Puneeth Chaganti <punchagan@gmail.com>
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
Stability : alpha
Portability : portable
@@ -32,64 +34,67 @@ Conversion of 'Pandoc' documents to Emacs Org-Mode.
Org-Mode: <http://orgmode.org>
-}
-module Text.Pandoc.Writers.Org ( writeOrg) where
+module Text.Pandoc.Writers.Org (writeOrg) where
+import Control.Monad.State.Strict
+import Data.Char (isAlphaNum, toLower)
+import Data.List (intersect, intersperse, isPrefixOf, partition, transpose)
+import Data.Text (Text)
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
import Text.Pandoc.Pretty
+import Text.Pandoc.Shared
import Text.Pandoc.Templates (renderTemplate')
-import Data.Char ( isAlphaNum, toLower )
-import Data.List ( isPrefixOf, intersect, intersperse, partition, transpose )
-import Control.Monad.State
+import Text.Pandoc.Writers.Shared
data WriterState =
- WriterState { stNotes :: [[Block]]
- , stLinks :: Bool
- , stImages :: Bool
- , stHasMath :: Bool
- , stOptions :: WriterOptions
+ WriterState { stNotes :: [[Block]]
+ , stHasMath :: Bool
+ , stOptions :: WriterOptions
}
+type Org = StateT WriterState
+
-- | Convert Pandoc to Org.
-writeOrg :: WriterOptions -> Pandoc -> String
-writeOrg opts document =
- let st = WriterState { stNotes = [], stLinks = False,
- stImages = False, stHasMath = False,
+writeOrg :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeOrg opts document = do
+ let st = WriterState { stNotes = [],
+ stHasMath = False,
stOptions = opts }
- in evalState (pandocToOrg document) st
+ evalStateT (pandocToOrg document) st
-- | Return Org representation of document.
-pandocToOrg :: Pandoc -> State WriterState String
+pandocToOrg :: PandocMonad m => Pandoc -> Org m Text
pandocToOrg (Pandoc meta blocks) = do
- opts <- liftM stOptions get
+ opts <- gets stOptions
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToOrg)
- (fmap (render colwidth) . inlineListToOrg)
+ (fmap render' . blockListToOrg)
+ (fmap render' . inlineListToOrg)
meta
body <- blockListToOrg blocks
- notes <- liftM (reverse . stNotes) get >>= notesToOrg
- -- note that the notes may contain refs, so we do them first
- hasMath <- liftM stHasMath get
- let main = render colwidth $ foldl ($+$) empty $ [body, notes]
+ notes <- gets (reverse . stNotes) >>= notesToOrg
+ hasMath <- gets stHasMath
+ let main = render colwidth . foldl ($+$) empty $ [body, notes]
let context = defField "body" main
- $ defField "math" hasMath
+ . defField "math" hasMath
$ metadata
case writerTemplate opts of
Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
-- | Return Org representation of notes.
-notesToOrg :: [[Block]] -> State WriterState Doc
+notesToOrg :: PandocMonad m => [[Block]] -> Org m Doc
notesToOrg notes =
- mapM (\(num, note) -> noteToOrg num note) (zip [1..] notes) >>=
- return . vsep
+ vsep <$> zipWithM noteToOrg [1..] notes
-- | Return Org representation of a note.
-noteToOrg :: Int -> [Block] -> State WriterState Doc
+noteToOrg :: PandocMonad m => Int -> [Block] -> Org m Doc
noteToOrg num note = do
contents <- blockListToOrg note
let marker = "[fn:" ++ show num ++ "] "
@@ -109,8 +114,9 @@ isRawFormat f =
f == Format "latex" || f == Format "tex" || f == Format "org"
-- | Convert Pandoc block element to Org.
-blockToOrg :: Block -- ^ Block element
- -> State WriterState Doc
+blockToOrg :: PandocMonad m
+ => Block -- ^ Block element
+ -> Org m Doc
blockToOrg Null = return empty
blockToOrg (Div (_,classes@(cls:_),kvs) bs) | "drawer" `elem` classes = do
contents <- blockListToOrg bs
@@ -123,36 +129,25 @@ blockToOrg (Div (_,classes@(cls:_),kvs) bs) | "drawer" `elem` classes = do
blankline $$ contents $$
blankline $$ drawerEndTag $$
blankline
-blockToOrg (Div attrs bs) = do
+blockToOrg (Div (ident, classes, kv) bs) = do
contents <- blockListToOrg bs
+ -- if one class looks like the name of a greater block then output as such:
+ -- The ID, if present, is added via the #+NAME keyword; other classes and
+ -- key-value pairs are kept as #+ATTR_HTML attributes.
let isGreaterBlockClass = (`elem` ["center", "quote"]) . map toLower
- return $ case attrs of
- ("", [], []) ->
- -- nullAttr, treat contents as if it wasn't wrapped
- blankline $$ contents $$ blankline
- (ident, [], []) ->
- -- only an id: add id as an anchor, unwrap the rest
- blankline $$ "<<" <> text ident <> ">>" $$ contents $$ blankline
- (ident, classes, kv) ->
- -- if one class looks like the name of a greater block then output as
- -- such: The ID, if present, is added via the #+NAME keyword; other
- -- classes and key-value pairs are kept as #+ATTR_HTML attributes.
- let
- (blockTypeCand, classes') = partition isGreaterBlockClass classes
- in case blockTypeCand of
- (blockType:classes'') ->
- blankline $$ attrHtml (ident, classes'' <> classes', kv) $$
- "#+BEGIN_" <> text blockType $$ contents $$
- "#+END_" <> text blockType $$ blankline
- _ ->
- -- fallback: wrap in div tags
- let
- startTag = tagWithAttrs "div" attrs
- endTag = text "</div>"
- in blankline $$ "#+BEGIN_HTML" $$
- nest 2 startTag $$ "#+END_HTML" $$ blankline $$
- contents $$ blankline $$ "#+BEGIN_HTML" $$
- nest 2 endTag $$ "#+END_HTML" $$ blankline
+ (blockTypeCand, classes') = partition isGreaterBlockClass classes
+ return $ case blockTypeCand of
+ (blockType:classes'') ->
+ blankline $$ attrHtml (ident, classes'' <> classes', kv) $$
+ "#+BEGIN_" <> text blockType $$ contents $$
+ "#+END_" <> text blockType $$ blankline
+ _ ->
+ -- fallback with id: add id as an anchor if present, discard classes and
+ -- key-value pairs, unwrap the content.
+ let contents' = if not (null ident)
+ then "<<" <> text ident <> ">>" $$ contents
+ else contents
+ in blankline $$ contents' $$ blankline
blockToOrg (Plain inlines) = inlineListToOrg inlines
-- title beginning with fig: indicates that the image is a figure
blockToOrg (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
@@ -167,20 +162,22 @@ blockToOrg (Para inlines) = do
blockToOrg (LineBlock lns) = do
let splitStanza [] = []
splitStanza xs = case break (== mempty) xs of
- (l, []) -> l : []
+ (l, []) -> [l]
(l, _:r) -> l : splitStanza r
let joinWithLinefeeds = nowrap . mconcat . intersperse cr
let joinWithBlankLines = mconcat . intersperse blankline
- let prettyfyStanza ls = joinWithLinefeeds <$> mapM inlineListToOrg ls
- contents <- joinWithBlankLines <$> mapM prettyfyStanza (splitStanza lns)
+ let prettifyStanza ls = joinWithLinefeeds <$> mapM inlineListToOrg ls
+ contents <- joinWithBlankLines <$> mapM prettifyStanza (splitStanza lns)
return $ blankline $$ "#+BEGIN_VERSE" $$
nest 2 contents $$ "#+END_VERSE" <> blankline
blockToOrg (RawBlock "html" str) =
return $ blankline $$ "#+BEGIN_HTML" $$
nest 2 (text str) $$ "#+END_HTML" $$ blankline
-blockToOrg (RawBlock f str) | isRawFormat f =
- return $ text str
-blockToOrg (RawBlock _ _) = return empty
+blockToOrg b@(RawBlock f str)
+ | isRawFormat f = return $ text str
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
blockToOrg HorizontalRule = return $ blankline $$ "--------------" $$ blankline
blockToOrg (Header level attr inlines) = do
contents <- inlineListToOrg inlines
@@ -190,7 +187,7 @@ blockToOrg (Header level attr inlines) = do
else cr <> nest (level + 1) (propertiesDrawer attr)
return $ headerStr <> " " <> contents <> drawerStr <> blankline
blockToOrg (CodeBlock (_,classes,_) str) = do
- opts <- stOptions <$> get
+ opts <- gets stOptions
let tabstop = writerTabStop opts
let at = map pandocLangToOrg classes `intersect` orgLangIdentifiers
let (beg, end) = case at of
@@ -205,7 +202,7 @@ blockToOrg (Table caption' _ _ headers rows) = do
caption'' <- inlineListToOrg caption'
let caption = if null caption'
then empty
- else ("#+CAPTION: " <> caption'')
+ else "#+CAPTION: " <> caption''
headers' <- mapM blockListToOrg headers
rawRows <- mapM (mapM blockListToOrg) rows
let numChars = maximum . map offset
@@ -215,16 +212,16 @@ blockToOrg (Table caption' _ _ headers rows) = do
-- FIXME: Org doesn't allow blocks with height more than 1.
let hpipeBlocks blocks = hcat [beg, middle, end]
where h = maximum (1 : map height blocks)
- sep' = lblock 3 $ vcat (map text $ replicate h " | ")
- beg = lblock 2 $ vcat (map text $ replicate h "| ")
- end = lblock 2 $ vcat (map text $ replicate h " |")
+ sep' = lblock 3 $ vcat (replicate h (text " | "))
+ beg = lblock 2 $ vcat (replicate h (text "| "))
+ end = lblock 2 $ vcat (replicate h (text " |"))
middle = hcat $ intersperse sep' blocks
let makeRow = hpipeBlocks . zipWith lblock widthsInChars
let head' = makeRow headers'
rows' <- mapM (\row -> do cols <- mapM blockListToOrg row
return $ makeRow cols) rows
let border ch = char '|' <> char ch <>
- (hcat $ intersperse (char ch <> char '+' <> char ch) $
+ (hcat . intersperse (char ch <> char '+' <> char ch) $
map (\l -> text $ replicate l ch) widthsInChars) <>
char ch <> char '|'
let body = vcat rows'
@@ -245,8 +242,7 @@ blockToOrg (OrderedList (start, _, delim) items) = do
let maxMarkerLength = maximum $ map length markers
let markers' = map (\m -> let s = maxMarkerLength - length m
in m ++ replicate s ' ') markers
- contents <- mapM (\(item, num) -> orderedListItemToOrg item num) $
- zip markers' items
+ contents <- zipWithM orderedListItemToOrg markers' items
-- ensure that sublists have preceding blank line
return $ blankline $$ vcat contents $$ blankline
blockToOrg (DefinitionList items) = do
@@ -254,25 +250,27 @@ blockToOrg (DefinitionList items) = do
return $ vcat contents $$ blankline
-- | Convert bullet list item (list of blocks) to Org.
-bulletListItemToOrg :: [Block] -> State WriterState Doc
+bulletListItemToOrg :: PandocMonad m => [Block] -> Org m Doc
bulletListItemToOrg items = do
contents <- blockListToOrg items
- return $ hang 3 "- " (contents <> cr)
+ return $ hang 2 "- " (contents <> cr)
-- | Convert ordered list item (a list of blocks) to Org.
-orderedListItemToOrg :: String -- ^ marker for list item
+orderedListItemToOrg :: PandocMonad m
+ => String -- ^ marker for list item
-> [Block] -- ^ list item (list of blocks)
- -> State WriterState Doc
+ -> Org m Doc
orderedListItemToOrg marker items = do
contents <- blockListToOrg items
return $ hang (length marker + 1) (text marker <> space) (contents <> cr)
-- | Convert defintion list item (label, list of blocks) to Org.
-definitionListItemToOrg :: ([Inline], [[Block]]) -> State WriterState Doc
+definitionListItemToOrg :: PandocMonad m
+ => ([Inline], [[Block]]) -> Org m Doc
definitionListItemToOrg (label, defs) = do
label' <- inlineListToOrg label
- contents <- liftM vcat $ mapM blockListToOrg defs
- return $ hang 3 "- " $ label' <> " :: " <> (contents <> cr)
+ contents <- vcat <$> mapM blockListToOrg defs
+ return . hang 2 "- " $ label' <> " :: " <> (contents <> cr)
-- | Convert list of key/value pairs to Org :PROPERTIES: drawer.
propertiesDrawer :: Attr -> Doc
@@ -280,8 +278,8 @@ propertiesDrawer (ident, classes, kv) =
let
drawerStart = text ":PROPERTIES:"
drawerEnd = text ":END:"
- kv' = if (classes == mempty) then kv else ("CLASS", unwords classes):kv
- kv'' = if (ident == mempty) then kv' else ("CUSTOM_ID", ident):kv'
+ kv' = if classes == mempty then kv else ("CLASS", unwords classes):kv
+ kv'' = if ident == mempty then kv' else ("CUSTOM_ID", ident):kv'
properties = vcat $ map kvToOrgProperty kv''
in
drawerStart <> cr <> properties <> cr <> drawerEnd
@@ -294,23 +292,37 @@ attrHtml :: Attr -> Doc
attrHtml ("" , [] , []) = mempty
attrHtml (ident, classes, kvs) =
let
- name = if (null ident) then mempty else "#+NAME: " <> text ident <> cr
+ name = if null ident then mempty else "#+NAME: " <> text ident <> cr
keyword = "#+ATTR_HTML"
classKv = ("class", unwords classes)
kvStrings = map (\(k,v) -> ":" <> k <> " " <> v) (classKv:kvs)
in name <> keyword <> ": " <> text (unwords kvStrings) <> cr
-- | Convert list of Pandoc block elements to Org.
-blockListToOrg :: [Block] -- ^ List of block elements
- -> State WriterState Doc
-blockListToOrg blocks = mapM blockToOrg blocks >>= return . vcat
+blockListToOrg :: PandocMonad m
+ => [Block] -- ^ List of block elements
+ -> Org m Doc
+blockListToOrg blocks = vcat <$> mapM blockToOrg blocks
-- | Convert list of Pandoc inline elements to Org.
-inlineListToOrg :: [Inline] -> State WriterState Doc
-inlineListToOrg lst = mapM inlineToOrg lst >>= return . hcat
+inlineListToOrg :: PandocMonad m
+ => [Inline]
+ -> Org m Doc
+inlineListToOrg lst = hcat <$> mapM inlineToOrg (fixMarkers lst)
+ where fixMarkers [] = [] -- prevent note refs and list markers from wrapping, see #4171
+ fixMarkers (Space : x : rest) | shouldFix x =
+ Str " " : x : fixMarkers rest
+ fixMarkers (SoftBreak : x : rest) | shouldFix x =
+ Str " " : x : fixMarkers rest
+ fixMarkers (x : rest) = x : fixMarkers rest
+
+ shouldFix Note{} = True -- Prevent footnotes
+ shouldFix (Str "-") = True -- Prevent bullet list items
+ -- TODO: prevent ordered list items
+ shouldFix _ = False
-- | Convert Pandoc inline element to Org.
-inlineToOrg :: Inline -> State WriterState Doc
+inlineToOrg :: PandocMonad m => Inline -> Org m Doc
inlineToOrg (Span (uid, [], []) []) =
return $ "<<" <> text uid <> ">>"
inlineToOrg (Span _ lst) =
@@ -339,50 +351,48 @@ inlineToOrg (Quoted DoubleQuote lst) = do
return $ "\"" <> contents <> "\""
inlineToOrg (Cite _ lst) = inlineListToOrg lst
inlineToOrg (Code _ str) = return $ "=" <> text str <> "="
-inlineToOrg (Str str) = return $ text $ escapeString str
+inlineToOrg (Str str) = return . text $ escapeString str
inlineToOrg (Math t str) = do
modify $ \st -> st{ stHasMath = True }
return $ if t == InlineMath
then "$" <> text str <> "$"
else "$$" <> text str <> "$$"
-inlineToOrg (RawInline f@(Format f') str) =
- return $ if isRawFormat f
- then text str
- else "@@" <> text f' <> ":" <> text str <> "@@"
-inlineToOrg (LineBreak) = return (text "\\\\" <> cr)
+inlineToOrg il@(RawInline f str)
+ | isRawFormat f = return $ text str
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
+inlineToOrg LineBreak = return (text "\\\\" <> cr)
inlineToOrg Space = return space
inlineToOrg SoftBreak = do
wrapText <- gets (writerWrapText . stOptions)
case wrapText of
- WrapPreserve -> return cr
- WrapAuto -> return space
- WrapNone -> return space
-inlineToOrg (Link _ txt (src, _)) = do
+ WrapPreserve -> return cr
+ WrapAuto -> return space
+ WrapNone -> return space
+inlineToOrg (Link _ txt (src, _)) =
case txt of
[Str x] | escapeURI x == src -> -- autolink
- do modify $ \s -> s{ stLinks = True }
- return $ "[[" <> text (orgPath x) <> "]]"
+ return $ "[[" <> text (orgPath x) <> "]]"
_ -> do contents <- inlineListToOrg txt
- modify $ \s -> s{ stLinks = True }
return $ "[[" <> text (orgPath src) <> "][" <> contents <> "]]"
-inlineToOrg (Image _ _ (source, _)) = do
- modify $ \s -> s{ stImages = True }
+inlineToOrg (Image _ _ (source, _)) =
return $ "[[" <> text (orgPath source) <> "]]"
inlineToOrg (Note contents) = do
-- add to notes in state
- notes <- get >>= (return . stNotes)
+ notes <- gets stNotes
modify $ \st -> st { stNotes = contents:notes }
- let ref = show $ (length notes) + 1
+ let ref = show $ length notes + 1
return $ "[fn:" <> text ref <> "]"
orgPath :: String -> String
orgPath src =
case src of
- [] -> mempty -- wiki link
- ('#':xs) -> xs -- internal link
- _ | isUrl src -> src
- _ | isFilePath src -> src
- _ -> "file:" <> src
+ [] -> mempty -- wiki link
+ ('#':_) -> src -- internal link
+ _ | isUrl src -> src
+ _ | isFilePath src -> src
+ _ -> "file:" <> src
where
isFilePath :: String -> Bool
isFilePath cs = any (`isPrefixOf` cs) ["/", "./", "../", "file:"]
diff --git a/src/Text/Pandoc/Writers/Powerpoint.hs b/src/Text/Pandoc/Writers/Powerpoint.hs
new file mode 100644
index 000000000..645a4cb86
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Powerpoint.hs
@@ -0,0 +1,63 @@
+
+
+{-
+Copyright (C) 2017-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Powerpoint
+ Copyright : Copyright (C) 2017-2018 Jesse Rosenthal
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to powerpoint (pptx). -}
+
+{-
+This is a wrapper around two modules:
+
+ - Text.Pandoc.Writers.Powerpoint.Presentation (which converts a
+ pandoc document into a Presentation datatype), and
+
+ - Text.Pandoc.Writers.Powerpoint.Output (which converts a
+ Presentation into a zip archive, which can be output).
+-}
+
+module Text.Pandoc.Writers.Powerpoint (writePowerpoint) where
+
+import Codec.Archive.Zip
+import Text.Pandoc.Definition
+import Text.Pandoc.Walk
+import Text.Pandoc.Class (PandocMonad, report)
+import Text.Pandoc.Options (WriterOptions)
+import Text.Pandoc.Writers.Shared (fixDisplayMath)
+import Text.Pandoc.Writers.Powerpoint.Presentation (documentToPresentation)
+import Text.Pandoc.Writers.Powerpoint.Output (presentationToArchive)
+import qualified Data.ByteString.Lazy as BL
+
+writePowerpoint :: (PandocMonad m)
+ => WriterOptions -- ^ Writer options
+ -> Pandoc -- ^ Document to convert
+ -> m BL.ByteString
+writePowerpoint opts (Pandoc meta blks) = do
+ let blks' = walk fixDisplayMath blks
+ let (pres, logMsgs) = documentToPresentation opts (Pandoc meta blks')
+ mapM_ report logMsgs
+ archv <- presentationToArchive opts pres
+ return $ fromArchive archv
diff --git a/src/Text/Pandoc/Writers/Powerpoint/Output.hs b/src/Text/Pandoc/Writers/Powerpoint/Output.hs
new file mode 100644
index 000000000..410b6c20c
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Powerpoint/Output.hs
@@ -0,0 +1,1834 @@
+{-# LANGUAGE PatternGuards #-}
+
+{-
+Copyright (C) 2017-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Powerpoint.Output
+ Copyright : Copyright (C) 2017-2018 Jesse Rosenthal
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of Presentation datatype (defined in
+Text.Pandoc.Writers.Powerpoint.Presentation) to a zip archive.
+-}
+
+module Text.Pandoc.Writers.Powerpoint.Output ( presentationToArchive
+ ) where
+
+import Control.Monad.Except (throwError, catchError)
+import Control.Monad.Reader
+import Control.Monad.State
+import Codec.Archive.Zip
+import Data.Char (toUpper)
+import Data.List (intercalate, stripPrefix, nub, union, isPrefixOf, intersperse)
+import Data.Default
+import Text.Pandoc.Compat.Time (formatTime, defaultTimeLocale)
+import Data.Time.Clock (UTCTime)
+import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime)
+import System.FilePath.Posix (splitDirectories, splitExtension, takeExtension)
+import Text.XML.Light
+import Text.Pandoc.Definition
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Error (PandocError(..))
+import qualified Text.Pandoc.Class as P
+import Text.Pandoc.Options
+import Text.Pandoc.MIME
+import qualified Data.ByteString.Lazy as BL
+import Text.Pandoc.Writers.OOXML
+import qualified Data.Map as M
+import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, isJust, maybeToList, catMaybes)
+import Text.Pandoc.ImageSize
+import Control.Applicative ((<|>))
+import System.FilePath.Glob
+import Text.TeXMath
+import Text.Pandoc.Writers.Math (convertMath)
+import Text.Pandoc.Writers.Powerpoint.Presentation
+import Skylighting (fromColor)
+
+-- This populates the global ids map with images already in the
+-- template, so the ids won't be used by images introduced by the
+-- user.
+initialGlobalIds :: Archive -> Archive -> M.Map FilePath Int
+initialGlobalIds refArchive distArchive =
+ let archiveFiles = filesInArchive refArchive `union` filesInArchive distArchive
+ mediaPaths = filter (isPrefixOf "ppt/media/image") archiveFiles
+
+ go :: FilePath -> Maybe (FilePath, Int)
+ go fp = do
+ s <- stripPrefix "ppt/media/image" $ fst $ splitExtension fp
+ (n, _) <- listToMaybe $ reads s
+ return (fp, n)
+ in
+ M.fromList $ mapMaybe go mediaPaths
+
+getPresentationSize :: Archive -> Archive -> Maybe (Integer, Integer)
+getPresentationSize refArchive distArchive = do
+ entry <- findEntryByPath "ppt/presentation.xml" refArchive `mplus`
+ findEntryByPath "ppt/presentation.xml" distArchive
+ presElement <- parseXMLDoc $ UTF8.toStringLazy $ fromEntry entry
+ let ns = elemToNameSpaces presElement
+ sldSize <- findChild (elemName ns "p" "sldSz") presElement
+ cxS <- findAttr (QName "cx" Nothing Nothing) sldSize
+ cyS <- findAttr (QName "cy" Nothing Nothing) sldSize
+ (cx, _) <- listToMaybe $ reads cxS :: Maybe (Integer, String)
+ (cy, _) <- listToMaybe $ reads cyS :: Maybe (Integer, String)
+ return (cx `div` 12700, cy `div` 12700)
+
+data WriterEnv = WriterEnv { envRefArchive :: Archive
+ , envDistArchive :: Archive
+ , envUTCTime :: UTCTime
+ , envOpts :: WriterOptions
+ , envPresentationSize :: (Integer, Integer)
+ , envSlideHasHeader :: Bool
+ , envInList :: Bool
+ , envInNoteSlide :: Bool
+ , envCurSlideId :: Int
+ -- the difference between the number at
+ -- the end of the slide file name and
+ -- the rId number
+ , envSlideIdOffset :: Int
+ , envContentType :: ContentType
+ , envSlideIdMap :: M.Map SlideId Int
+ -- maps the slide number to the
+ -- corresponding notes id number. If there
+ -- are no notes for a slide, there will be
+ -- no entry in the map for it.
+ , envSpeakerNotesIdMap :: M.Map Int Int
+ }
+ deriving (Show)
+
+instance Default WriterEnv where
+ def = WriterEnv { envRefArchive = emptyArchive
+ , envDistArchive = emptyArchive
+ , envUTCTime = posixSecondsToUTCTime 0
+ , envOpts = def
+ , envPresentationSize = (720, 540)
+ , envSlideHasHeader = False
+ , envInList = False
+ , envInNoteSlide = False
+ , envCurSlideId = 1
+ , envSlideIdOffset = 1
+ , envContentType = NormalContent
+ , envSlideIdMap = mempty
+ , envSpeakerNotesIdMap = mempty
+ }
+
+data ContentType = NormalContent
+ | TwoColumnLeftContent
+ | TwoColumnRightContent
+ deriving (Show, Eq)
+
+data MediaInfo = MediaInfo { mInfoFilePath :: FilePath
+ , mInfoLocalId :: Int
+ , mInfoGlobalId :: Int
+ , mInfoMimeType :: Maybe MimeType
+ , mInfoExt :: Maybe String
+ , mInfoCaption :: Bool
+ } deriving (Show, Eq)
+
+data WriterState = WriterState { stLinkIds :: M.Map Int (M.Map Int LinkTarget)
+ -- (FP, Local ID, Global ID, Maybe Mime)
+ , stMediaIds :: M.Map Int [MediaInfo]
+ , stMediaGlobalIds :: M.Map FilePath Int
+ } deriving (Show, Eq)
+
+instance Default WriterState where
+ def = WriterState { stLinkIds = mempty
+ , stMediaIds = mempty
+ , stMediaGlobalIds = mempty
+ }
+
+type P m = ReaderT WriterEnv (StateT WriterState m)
+
+runP :: Monad m => WriterEnv -> WriterState -> P m a -> m a
+runP env st p = evalStateT (runReaderT p env) st
+
+--------------------------------------------------------------------
+
+copyFileToArchive :: PandocMonad m => Archive -> FilePath -> P m Archive
+copyFileToArchive arch fp = do
+ refArchive <- asks envRefArchive
+ distArchive <- asks envDistArchive
+ case findEntryByPath fp refArchive `mplus` findEntryByPath fp distArchive of
+ Nothing -> fail $ fp ++ " missing in reference file"
+ Just e -> return $ addEntryToArchive e arch
+
+alwaysInheritedPatterns :: [Pattern]
+alwaysInheritedPatterns =
+ map compile [ "docProps/app.xml"
+ , "ppt/slideLayouts/slideLayout*.xml"
+ , "ppt/slideLayouts/_rels/slideLayout*.xml.rels"
+ , "ppt/slideMasters/slideMaster1.xml"
+ , "ppt/slideMasters/_rels/slideMaster1.xml.rels"
+ , "ppt/theme/theme1.xml"
+ , "ppt/theme/_rels/theme1.xml.rels"
+ , "ppt/presProps.xml"
+ , "ppt/viewProps.xml"
+ , "ppt/tableStyles.xml"
+ , "ppt/media/image*"
+ ]
+
+-- We only look for these under special conditions
+contingentInheritedPatterns :: Presentation -> [Pattern]
+contingentInheritedPatterns pres = [] ++
+ if presHasSpeakerNotes pres
+ then map compile [ "ppt/notesMasters/notesMaster*.xml"
+ , "ppt/notesMasters/_rels/notesMaster*.xml.rels"
+ , "ppt/theme/theme2.xml"
+ , "ppt/theme/_rels/theme2.xml.rels"
+ ]
+ else []
+
+inheritedPatterns :: Presentation -> [Pattern]
+inheritedPatterns pres =
+ alwaysInheritedPatterns ++ contingentInheritedPatterns pres
+
+patternToFilePaths :: PandocMonad m => Pattern -> P m [FilePath]
+patternToFilePaths pat = do
+ refArchive <- asks envRefArchive
+ distArchive <- asks envDistArchive
+
+ let archiveFiles = filesInArchive refArchive `union` filesInArchive distArchive
+ return $ filter (match pat) archiveFiles
+
+patternsToFilePaths :: PandocMonad m => [Pattern] -> P m [FilePath]
+patternsToFilePaths pats = concat <$> mapM patternToFilePaths pats
+
+-- Here are the files we'll require to make a Powerpoint document. If
+-- any of these are missing, we should error out of our build.
+requiredFiles :: [FilePath]
+requiredFiles = [ "docProps/app.xml"
+ , "ppt/presProps.xml"
+ , "ppt/slideLayouts/slideLayout1.xml"
+ , "ppt/slideLayouts/_rels/slideLayout1.xml.rels"
+ , "ppt/slideLayouts/slideLayout2.xml"
+ , "ppt/slideLayouts/_rels/slideLayout2.xml.rels"
+ , "ppt/slideLayouts/slideLayout3.xml"
+ , "ppt/slideLayouts/_rels/slideLayout3.xml.rels"
+ , "ppt/slideLayouts/slideLayout4.xml"
+ , "ppt/slideLayouts/_rels/slideLayout4.xml.rels"
+ , "ppt/slideMasters/slideMaster1.xml"
+ , "ppt/slideMasters/_rels/slideMaster1.xml.rels"
+ , "ppt/theme/theme1.xml"
+ , "ppt/viewProps.xml"
+ , "ppt/tableStyles.xml"
+ ]
+
+presentationToArchiveP :: PandocMonad m => Presentation -> P m Archive
+presentationToArchiveP p@(Presentation docProps slides) = do
+ filePaths <- patternsToFilePaths $ inheritedPatterns p
+
+ -- make sure all required files are available:
+ let missingFiles = filter (\fp -> not (fp `elem` filePaths)) requiredFiles
+ unless (null missingFiles)
+ (throwError $
+ PandocSomeError $
+ "The following required files are missing:\n" ++
+ (unlines $ map (" " ++) missingFiles)
+ )
+
+ newArch' <- foldM copyFileToArchive emptyArchive filePaths
+ -- we make a docProps/core.xml entry out of the presentation docprops
+ docPropsEntry <- docPropsToEntry docProps
+ -- we make this ourself in case there's something unexpected in the
+ -- one in the reference doc.
+ relsEntry <- topLevelRelsEntry
+ -- presentation entry and rels. We have to do the rels first to make
+ -- sure we know the correct offset for the rIds.
+ presEntry <- presentationToPresEntry p
+ presRelsEntry <- presentationToRelsEntry p
+ slideEntries <- mapM slideToEntry slides
+ slideRelEntries <- mapM slideToSlideRelEntry slides
+ spkNotesEntries <- catMaybes <$> mapM slideToSpeakerNotesEntry slides
+ spkNotesRelEntries <- catMaybes <$> mapM slideToSpeakerNotesRelEntry slides
+ -- These have to come after everything, because they need the info
+ -- built up in the state.
+ mediaEntries <- makeMediaEntries
+ contentTypesEntry <- presentationToContentTypes p >>= contentTypesToEntry
+ -- fold everything into our inherited archive and return it.
+ return $ foldr addEntryToArchive newArch' $
+ slideEntries ++
+ slideRelEntries ++
+ spkNotesEntries ++
+ spkNotesRelEntries ++
+ mediaEntries ++
+ [contentTypesEntry, docPropsEntry, relsEntry, presEntry, presRelsEntry]
+
+makeSlideIdMap :: Presentation -> M.Map SlideId Int
+makeSlideIdMap (Presentation _ slides) =
+ M.fromList $ (map slideId slides) `zip` [1..]
+
+makeSpeakerNotesMap :: Presentation -> M.Map Int Int
+makeSpeakerNotesMap (Presentation _ slides) =
+ M.fromList $ (mapMaybe f $ slides `zip` [1..]) `zip` [1..]
+ where f (Slide _ _ Nothing, _) = Nothing
+ f (Slide _ _ (Just _), n) = Just n
+
+presentationToArchive :: PandocMonad m => WriterOptions -> Presentation -> m Archive
+presentationToArchive opts pres = do
+ distArchive <- (toArchive . BL.fromStrict) <$>
+ P.readDefaultDataFile "reference.pptx"
+ refArchive <- case writerReferenceDoc opts of
+ Just f -> toArchive <$> P.readFileLazy f
+ Nothing -> (toArchive . BL.fromStrict) <$>
+ P.readDataFile "reference.pptx"
+
+ utctime <- P.getCurrentTime
+
+ presSize <- case getPresentationSize refArchive distArchive of
+ Just sz -> return sz
+ Nothing -> throwError $
+ PandocSomeError $
+ "Could not determine presentation size"
+
+ let env = def { envRefArchive = refArchive
+ , envDistArchive = distArchive
+ , envUTCTime = utctime
+ , envOpts = opts
+ , envPresentationSize = presSize
+ , envSlideIdMap = makeSlideIdMap pres
+ , envSpeakerNotesIdMap = makeSpeakerNotesMap pres
+ }
+
+ let st = def { stMediaGlobalIds = initialGlobalIds refArchive distArchive
+ }
+
+ runP env st $ presentationToArchiveP pres
+
+
+
+--------------------------------------------------
+
+-- Check to see if the presentation has speaker notes. This will
+-- influence whether we import the notesMaster template.
+presHasSpeakerNotes :: Presentation -> Bool
+presHasSpeakerNotes (Presentation _ slides) = any isJust $ map slideSpeakerNotes slides
+
+curSlideHasSpeakerNotes :: PandocMonad m => P m Bool
+curSlideHasSpeakerNotes = do
+ sldId <- asks envCurSlideId
+ notesIdMap <- asks envSpeakerNotesIdMap
+ return $ isJust $ M.lookup sldId notesIdMap
+
+--------------------------------------------------
+
+getLayout :: PandocMonad m => Layout -> P m Element
+getLayout layout = do
+ let layoutpath = case layout of
+ (MetadataSlide _ _ _ _) -> "ppt/slideLayouts/slideLayout1.xml"
+ (TitleSlide _) -> "ppt/slideLayouts/slideLayout3.xml"
+ (ContentSlide _ _) -> "ppt/slideLayouts/slideLayout2.xml"
+ (TwoColumnSlide _ _ _) -> "ppt/slideLayouts/slideLayout4.xml"
+ distArchive <- asks envDistArchive
+ root <- case findEntryByPath layoutpath distArchive of
+ Just e -> case parseXMLDoc $ UTF8.toStringLazy $ fromEntry e of
+ Just element -> return $ element
+ Nothing -> throwError $
+ PandocSomeError $
+ layoutpath ++ " corrupt in reference file"
+ Nothing -> throwError $
+ PandocSomeError $
+ layoutpath ++ " missing in reference file"
+ return root
+
+shapeHasId :: NameSpaces -> String -> Element -> Bool
+shapeHasId ns ident element
+ | Just nvSpPr <- findChild (elemName ns "p" "nvSpPr") element
+ , Just cNvPr <- findChild (elemName ns "p" "cNvPr") nvSpPr
+ , Just nm <- findAttr (QName "id" Nothing Nothing) cNvPr =
+ nm == ident
+ | otherwise = False
+
+-- The content shape in slideLayout2 (Title/Content) has id=3 In
+-- slideLayout4 (two column) the left column is id=3, and the right
+-- column is id=4.
+getContentShape :: PandocMonad m => NameSpaces -> Element -> P m Element
+getContentShape ns spTreeElem
+ | isElem ns "p" "spTree" spTreeElem = do
+ contentType <- asks envContentType
+ let idx = case contentType of
+ NormalContent -> "1"
+ TwoColumnLeftContent -> "1"
+ TwoColumnRightContent -> "2"
+ case getShapeByPlaceHolderIndex ns spTreeElem idx of
+ Just e -> return e
+ Nothing -> throwError $
+ PandocSomeError $
+ "Could not find shape for Powerpoint content"
+getContentShape _ _ = throwError $
+ PandocSomeError $
+ "Attempted to find content on non shapeTree"
+
+getShapeDimensions :: NameSpaces
+ -> Element
+ -> Maybe ((Integer, Integer), (Integer, Integer))
+getShapeDimensions ns element
+ | isElem ns "p" "sp" element = do
+ spPr <- findChild (elemName ns "p" "spPr") element
+ xfrm <- findChild (elemName ns "a" "xfrm") spPr
+ off <- findChild (elemName ns "a" "off") xfrm
+ xS <- findAttr (QName "x" Nothing Nothing) off
+ yS <- findAttr (QName "y" Nothing Nothing) off
+ ext <- findChild (elemName ns "a" "ext") xfrm
+ cxS <- findAttr (QName "cx" Nothing Nothing) ext
+ cyS <- findAttr (QName "cy" Nothing Nothing) ext
+ (x, _) <- listToMaybe $ reads xS
+ (y, _) <- listToMaybe $ reads yS
+ (cx, _) <- listToMaybe $ reads cxS
+ (cy, _) <- listToMaybe $ reads cyS
+ return $ ((x `div` 12700, y `div` 12700), (cx `div` 12700, cy `div` 12700))
+ | otherwise = Nothing
+
+
+getMasterShapeDimensionsById :: String
+ -> Element
+ -> Maybe ((Integer, Integer), (Integer, Integer))
+getMasterShapeDimensionsById ident master = do
+ let ns = elemToNameSpaces master
+ cSld <- findChild (elemName ns "p" "cSld") master
+ spTree <- findChild (elemName ns "p" "spTree") cSld
+ sp <- filterChild (\e -> (isElem ns "p" "sp" e) && (shapeHasId ns ident e)) spTree
+ getShapeDimensions ns sp
+
+getContentShapeSize :: PandocMonad m
+ => NameSpaces
+ -> Element
+ -> Element
+ -> P m ((Integer, Integer), (Integer, Integer))
+getContentShapeSize ns layout master
+ | isElem ns "p" "sldLayout" layout
+ , Just cSld <- findChild (elemName ns "p" "cSld") layout
+ , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
+ sp <- getContentShape ns spTree
+ case getShapeDimensions ns sp of
+ Just sz -> return sz
+ Nothing -> do let mbSz =
+ findChild (elemName ns "p" "nvSpPr") sp >>=
+ findChild (elemName ns "p" "cNvPr") >>=
+ findAttr (QName "id" Nothing Nothing) >>=
+ flip getMasterShapeDimensionsById master
+ case mbSz of
+ Just sz' -> return sz'
+ Nothing -> throwError $
+ PandocSomeError $
+ "Couldn't find necessary content shape size"
+getContentShapeSize _ _ _ = throwError $
+ PandocSomeError $
+ "Attempted to find content shape size in non-layout"
+
+replaceNamedChildren :: NameSpaces
+ -> String
+ -> String
+ -> [Element]
+ -> Element
+ -> Element
+replaceNamedChildren ns prefix name newKids element =
+ element { elContent = concat $ fun True $ elContent element }
+ where
+ fun :: Bool -> [Content] -> [[Content]]
+ fun _ [] = []
+ fun switch ((Elem e) : conts) | isElem ns prefix name e =
+ if switch
+ then (map Elem $ newKids) : fun False conts
+ else fun False conts
+ fun switch (cont : conts) = [cont] : fun switch conts
+
+----------------------------------------------------------------
+
+registerLink :: PandocMonad m => LinkTarget -> P m Int
+registerLink link = do
+ curSlideId <- asks envCurSlideId
+ linkReg <- gets stLinkIds
+ mediaReg <- gets stMediaIds
+ hasSpeakerNotes <- curSlideHasSpeakerNotes
+ let maxLinkId = case M.lookup curSlideId linkReg of
+ Just mp -> case M.keys mp of
+ [] -> if hasSpeakerNotes then 2 else 1
+ ks -> maximum ks
+ Nothing -> if hasSpeakerNotes then 2 else 1
+ maxMediaId = case M.lookup curSlideId mediaReg of
+ Just [] -> if hasSpeakerNotes then 2 else 1
+ Just mInfos -> maximum $ map mInfoLocalId mInfos
+ Nothing -> if hasSpeakerNotes then 2 else 1
+ maxId = max maxLinkId maxMediaId
+ slideLinks = case M.lookup curSlideId linkReg of
+ Just mp -> M.insert (maxId + 1) link mp
+ Nothing -> M.singleton (maxId + 1) link
+ modify $ \st -> st{ stLinkIds = M.insert curSlideId slideLinks linkReg}
+ return $ maxId + 1
+
+registerMedia :: PandocMonad m => FilePath -> [ParaElem] -> P m MediaInfo
+registerMedia fp caption = do
+ curSlideId <- asks envCurSlideId
+ linkReg <- gets stLinkIds
+ mediaReg <- gets stMediaIds
+ globalIds <- gets stMediaGlobalIds
+ hasSpeakerNotes <- curSlideHasSpeakerNotes
+ let maxLinkId = case M.lookup curSlideId linkReg of
+ Just mp -> case M.keys mp of
+ [] -> if hasSpeakerNotes then 2 else 1
+ ks -> maximum ks
+ Nothing -> if hasSpeakerNotes then 2 else 1
+ maxMediaId = case M.lookup curSlideId mediaReg of
+ Just [] -> if hasSpeakerNotes then 2 else 1
+ Just mInfos -> maximum $ map mInfoLocalId mInfos
+ Nothing -> if hasSpeakerNotes then 2 else 1
+ maxLocalId = max maxLinkId maxMediaId
+
+ maxGlobalId = case M.elems globalIds of
+ [] -> 0
+ ids -> maximum ids
+
+ (imgBytes, mbMt) <- P.fetchItem fp
+ let imgExt = (mbMt >>= extensionFromMimeType >>= (\x -> return $ '.':x))
+ <|>
+ case imageType imgBytes of
+ Just Png -> Just ".png"
+ Just Jpeg -> Just ".jpeg"
+ Just Gif -> Just ".gif"
+ Just Pdf -> Just ".pdf"
+ Just Eps -> Just ".eps"
+ Just Svg -> Just ".svg"
+ Just Emf -> Just ".emf"
+ Nothing -> Nothing
+
+ let newGlobalId = case M.lookup fp globalIds of
+ Just ident -> ident
+ Nothing -> maxGlobalId + 1
+
+ let newGlobalIds = M.insert fp newGlobalId globalIds
+
+ let mediaInfo = MediaInfo { mInfoFilePath = fp
+ , mInfoLocalId = maxLocalId + 1
+ , mInfoGlobalId = newGlobalId
+ , mInfoMimeType = mbMt
+ , mInfoExt = imgExt
+ , mInfoCaption = (not . null) caption
+ }
+
+ let slideMediaInfos = case M.lookup curSlideId mediaReg of
+ Just minfos -> mediaInfo : minfos
+ Nothing -> [mediaInfo]
+
+
+ modify $ \st -> st{ stMediaIds = M.insert curSlideId slideMediaInfos mediaReg
+ , stMediaGlobalIds = newGlobalIds
+ }
+ return mediaInfo
+
+makeMediaEntry :: PandocMonad m => MediaInfo -> P m Entry
+makeMediaEntry mInfo = do
+ epochtime <- (floor . utcTimeToPOSIXSeconds) <$> asks envUTCTime
+ (imgBytes, _) <- P.fetchItem (mInfoFilePath mInfo)
+ let ext = case mInfoExt mInfo of
+ Just e -> e
+ Nothing -> ""
+ let fp = "ppt/media/image" ++ (show $ mInfoGlobalId mInfo) ++ ext
+ return $ toEntry fp epochtime $ BL.fromStrict imgBytes
+
+makeMediaEntries :: PandocMonad m => P m [Entry]
+makeMediaEntries = do
+ mediaInfos <- gets stMediaIds
+ let allInfos = mconcat $ M.elems mediaInfos
+ mapM makeMediaEntry allInfos
+
+-- -- | Scales the image to fit the page
+-- -- sizes are passed in emu
+-- fitToPage' :: (Double, Double) -- image size in emu
+-- -> Integer -- pageWidth
+-- -> Integer -- pageHeight
+-- -> (Integer, Integer) -- imagesize
+-- fitToPage' (x, y) pageWidth pageHeight
+-- -- Fixes width to the page width and scales the height
+-- | x <= fromIntegral pageWidth && y <= fromIntegral pageHeight =
+-- (floor x, floor y)
+-- | x / fromIntegral pageWidth > y / fromIntegral pageWidth =
+-- (pageWidth, floor $ ((fromIntegral pageWidth) / x) * y)
+-- | otherwise =
+-- (floor $ ((fromIntegral pageHeight) / y) * x, pageHeight)
+
+-- positionImage :: (Double, Double) -> Integer -> Integer -> (Integer, Integer)
+-- positionImage (x, y) pageWidth pageHeight =
+-- let (x', y') = fitToPage' (x, y) pageWidth pageHeight
+-- in
+-- ((pageWidth - x') `div` 2, (pageHeight - y') `div` 2)
+
+getMaster :: PandocMonad m => P m Element
+getMaster = do
+ refArchive <- asks envRefArchive
+ distArchive <- asks envDistArchive
+ parseXml refArchive distArchive "ppt/slideMasters/slideMaster1.xml"
+
+-- We want to get the header dimensions, so we can make sure that the
+-- image goes underneath it. We only use this in a content slide if it
+-- has a header.
+
+-- getHeaderSize :: PandocMonad m => P m ((Integer, Integer), (Integer, Integer))
+-- getHeaderSize = do
+-- master <- getMaster
+-- let ns = elemToNameSpaces master
+-- sps = [master] >>=
+-- findChildren (elemName ns "p" "cSld") >>=
+-- findChildren (elemName ns "p" "spTree") >>=
+-- findChildren (elemName ns "p" "sp")
+-- mbXfrm =
+-- listToMaybe (filter (shapeHasName ns "Title Placeholder 1") sps) >>=
+-- findChild (elemName ns "p" "spPr") >>=
+-- findChild (elemName ns "a" "xfrm")
+-- xoff = mbXfrm >>=
+-- findChild (elemName ns "a" "off") >>=
+-- findAttr (QName "x" Nothing Nothing) >>=
+-- (listToMaybe . (\s -> reads s :: [(Integer, String)]))
+-- yoff = mbXfrm >>=
+-- findChild (elemName ns "a" "off") >>=
+-- findAttr (QName "y" Nothing Nothing) >>=
+-- (listToMaybe . (\s -> reads s :: [(Integer, String)]))
+-- xext = mbXfrm >>=
+-- findChild (elemName ns "a" "ext") >>=
+-- findAttr (QName "cx" Nothing Nothing) >>=
+-- (listToMaybe . (\s -> reads s :: [(Integer, String)]))
+-- yext = mbXfrm >>=
+-- findChild (elemName ns "a" "ext") >>=
+-- findAttr (QName "cy" Nothing Nothing) >>=
+-- (listToMaybe . (\s -> reads s :: [(Integer, String)]))
+-- off = case xoff of
+-- Just (xoff', _) | Just (yoff',_) <- yoff -> (xoff', yoff')
+-- _ -> (1043490, 1027664)
+-- ext = case xext of
+-- Just (xext', _) | Just (yext',_) <- yext -> (xext', yext')
+-- _ -> (7024744, 1143000)
+-- return $ (off, ext)
+
+-- Hard-coded for now
+-- captionPosition :: ((Integer, Integer), (Integer, Integer))
+-- captionPosition = ((457200, 6061972), (8229600, 527087))
+
+captionHeight :: Integer
+captionHeight = 40
+
+createCaption :: PandocMonad m
+ => ((Integer, Integer), (Integer, Integer))
+ -> [ParaElem]
+ -> P m Element
+createCaption contentShapeDimensions paraElements = do
+ let para = Paragraph def{pPropAlign = Just AlgnCenter} paraElements
+ elements <- mapM paragraphToElement [para]
+ let ((x, y), (cx, cy)) = contentShapeDimensions
+ let txBody = mknode "p:txBody" [] $
+ [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] ++ elements
+ return $
+ mknode "p:sp" [] [ mknode "p:nvSpPr" []
+ [ mknode "p:cNvPr" [("id","1"), ("name","TextBox 3")] ()
+ , mknode "p:cNvSpPr" [("txBox", "1")] ()
+ , mknode "p:nvPr" [] ()
+ ]
+ , mknode "p:spPr" []
+ [ mknode "a:xfrm" []
+ [ mknode "a:off" [("x", show $ 12700 * x),
+ ("y", show $ 12700 * (y + cy - captionHeight))] ()
+ , mknode "a:ext" [("cx", show $ 12700 * cx),
+ ("cy", show $ 12700 * captionHeight)] ()
+ ]
+ , mknode "a:prstGeom" [("prst", "rect")]
+ [ mknode "a:avLst" [] ()
+ ]
+ , mknode "a:noFill" [] ()
+ ]
+ , txBody
+ ]
+
+makePicElements :: PandocMonad m
+ => Element
+ -> PicProps
+ -> MediaInfo
+ -> [ParaElem]
+ -> P m [Element]
+makePicElements layout picProps mInfo alt = do
+ opts <- asks envOpts
+ (pageWidth, pageHeight) <- asks envPresentationSize
+ -- hasHeader <- asks envSlideHasHeader
+ let hasCaption = mInfoCaption mInfo
+ (imgBytes, _) <- P.fetchItem (mInfoFilePath mInfo)
+ let (pxX, pxY) = case imageSize opts imgBytes of
+ Right sz -> sizeInPixels $ sz
+ Left _ -> sizeInPixels $ def
+ master <- getMaster
+ let ns = elemToNameSpaces layout
+ ((x, y), (cx, cytmp)) <- getContentShapeSize ns layout master
+ `catchError`
+ (\_ -> return ((0, 0), (pageWidth, pageHeight)))
+
+ let cy = if hasCaption then cytmp - captionHeight else cytmp
+
+ let imgRatio = fromIntegral pxX / fromIntegral pxY :: Double
+ boxRatio = fromIntegral cx / fromIntegral cy :: Double
+ (dimX, dimY) = if imgRatio > boxRatio
+ then (fromIntegral cx, fromIntegral cx / imgRatio)
+ else (fromIntegral cy * imgRatio, fromIntegral cy)
+
+ (dimX', dimY') = (round dimX * 12700, round dimY * 12700) :: (Integer, Integer)
+ (xoff, yoff) = (fromIntegral x + (fromIntegral cx - dimX) / 2,
+ fromIntegral y + (fromIntegral cy - dimY) / 2)
+ (xoff', yoff') = (round xoff * 12700, round yoff * 12700) :: (Integer, Integer)
+
+ let cNvPicPr = mknode "p:cNvPicPr" [] $
+ mknode "a:picLocks" [("noGrp","1")
+ ,("noChangeAspect","1")] ()
+ -- cNvPr will contain the link information so we do that separately,
+ -- and register the link if necessary.
+ let cNvPrAttr = [("descr", mInfoFilePath mInfo), ("id","0"),("name","Picture 1")]
+ cNvPr <- case picPropLink picProps of
+ Just link -> do idNum <- registerLink link
+ return $ mknode "p:cNvPr" cNvPrAttr $
+ mknode "a:hlinkClick" [("r:id", "rId" ++ show idNum)] ()
+ Nothing -> return $ mknode "p:cNvPr" cNvPrAttr ()
+ let nvPicPr = mknode "p:nvPicPr" []
+ [ cNvPr
+ , cNvPicPr
+ , mknode "p:nvPr" [] ()]
+ let blipFill = mknode "p:blipFill" []
+ [ mknode "a:blip" [("r:embed", "rId" ++ (show $ mInfoLocalId mInfo))] ()
+ , mknode "a:stretch" [] $
+ mknode "a:fillRect" [] () ]
+ let xfrm = mknode "a:xfrm" []
+ [ mknode "a:off" [("x",show xoff'), ("y",show yoff')] ()
+ , mknode "a:ext" [("cx",show dimX')
+ ,("cy",show dimY')] () ]
+ let prstGeom = mknode "a:prstGeom" [("prst","rect")] $
+ mknode "a:avLst" [] ()
+ let ln = mknode "a:ln" [("w","9525")]
+ [ mknode "a:noFill" [] ()
+ , mknode "a:headEnd" [] ()
+ , mknode "a:tailEnd" [] () ]
+ let spPr = mknode "p:spPr" [("bwMode","auto")]
+ [xfrm, prstGeom, mknode "a:noFill" [] (), ln]
+
+ let picShape = mknode "p:pic" []
+ [ nvPicPr
+ , blipFill
+ , spPr ]
+
+ -- And now, maybe create the caption:
+ if hasCaption
+ then do cap <- createCaption ((x, y), (cx, cytmp)) alt
+ return [picShape, cap]
+ else return [picShape]
+
+
+paraElemToElement :: PandocMonad m => ParaElem -> P m Element
+paraElemToElement Break = return $ mknode "a:br" [] ()
+paraElemToElement (Run rpr s) = do
+ let sizeAttrs = case rPropForceSize rpr of
+ Just n -> [("sz", (show $ n * 100))]
+ Nothing -> if rPropCode rpr
+ -- hardcoded size for code for now
+ then [("sz", "1800")]
+ else []
+ attrs = sizeAttrs ++
+ (if rPropBold rpr then [("b", "1")] else []) ++
+ (if rPropItalics rpr then [("i", "1")] else []) ++
+ (if rPropUnderline rpr then [("u", "sng")] else []) ++
+ (case rStrikethrough rpr of
+ Just NoStrike -> [("strike", "noStrike")]
+ Just SingleStrike -> [("strike", "sngStrike")]
+ Just DoubleStrike -> [("strike", "dblStrike")]
+ Nothing -> []) ++
+ (case rBaseline rpr of
+ Just n -> [("baseline", show n)]
+ Nothing -> []) ++
+ (case rCap rpr of
+ Just NoCapitals -> [("cap", "none")]
+ Just SmallCapitals -> [("cap", "small")]
+ Just AllCapitals -> [("cap", "all")]
+ Nothing -> []) ++
+ []
+ linkProps <- case rLink rpr of
+ Just link -> do
+ idNum <- registerLink link
+ -- first we have to make sure that if it's an
+ -- anchor, it's in the anchor map. If not, there's
+ -- no link.
+ return $ case link of
+ InternalTarget _ ->
+ let linkAttrs =
+ [ ("r:id", "rId" ++ show idNum)
+ , ("action", "ppaction://hlinksldjump")
+ ]
+ in [mknode "a:hlinkClick" linkAttrs ()]
+ -- external
+ ExternalTarget _ ->
+ let linkAttrs =
+ [ ("r:id", "rId" ++ show idNum)
+ ]
+ in [mknode "a:hlinkClick" linkAttrs ()]
+ Nothing -> return []
+ let colorContents = case rSolidFill rpr of
+ Just color ->
+ case fromColor color of
+ '#':hx -> [mknode "a:solidFill" []
+ [mknode "a:srgbClr" [("val", map toUpper hx)] ()]
+ ]
+ _ -> []
+ Nothing -> []
+ let codeContents = if rPropCode rpr
+ then [mknode "a:latin" [("typeface", "Courier")] ()]
+ else []
+ let propContents = linkProps ++ colorContents ++ codeContents
+ return $ mknode "a:r" [] [ mknode "a:rPr" attrs $ propContents
+ , mknode "a:t" [] s
+ ]
+paraElemToElement (MathElem mathType texStr) = do
+ res <- convertMath writeOMML mathType (unTeXString texStr)
+ case res of
+ Right r -> return $ mknode "a14:m" [] $ addMathInfo r
+ Left (Str s) -> paraElemToElement (Run def s)
+ Left _ -> throwError $ PandocShouldNeverHappenError "non-string math fallback"
+
+-- This is a bit of a kludge -- really requires adding an option to
+-- TeXMath, but since that's a different package, we'll do this one
+-- step at a time.
+addMathInfo :: Element -> Element
+addMathInfo element =
+ let mathspace = Attr { attrKey = (QName "m" Nothing (Just "xmlns"))
+ , attrVal = "http://schemas.openxmlformats.org/officeDocument/2006/math"
+ }
+ in add_attr mathspace element
+
+-- We look through the element to see if it contains an a14:m
+-- element. If so, we surround it. This is a bit ugly, but it seems
+-- more dependable than looking through shapes for math. Plus this is
+-- an xml implementation detail, so it seems to make sense to do it at
+-- the xml level.
+surroundWithMathAlternate :: Element -> Element
+surroundWithMathAlternate element =
+ case findElement (QName "m" Nothing (Just "a14")) element of
+ Just _ ->
+ mknode "mc:AlternateContent"
+ [("xmlns:mc", "http://schemas.openxmlformats.org/markup-compatibility/2006")
+ ] [ mknode "mc:Choice"
+ [ ("xmlns:a14", "http://schemas.microsoft.com/office/drawing/2010/main")
+ , ("Requires", "a14")] [ element ]
+ ]
+ Nothing -> element
+
+paragraphToElement :: PandocMonad m => Paragraph -> P m Element
+paragraphToElement par = do
+ let
+ attrs = [("lvl", show $ pPropLevel $ paraProps par)] ++
+ (case pPropMarginLeft (paraProps par) of
+ Just px -> [("marL", show $ 12700 * px), ("indent", "0")]
+ Nothing -> []
+ ) ++
+ (case pPropAlign (paraProps par) of
+ Just AlgnLeft -> [("algn", "l")]
+ Just AlgnRight -> [("algn", "r")]
+ Just AlgnCenter -> [("algn", "ctr")]
+ Nothing -> []
+ )
+ props = [] ++
+ (case pPropSpaceBefore $ paraProps par of
+ Just px -> [mknode "a:spcBef" [] [
+ mknode "a:spcPts" [("val", show $ 100 * px)] ()
+ ]
+ ]
+ Nothing -> []
+ ) ++
+ (case pPropBullet $ paraProps par of
+ Just Bullet -> []
+ Just (AutoNumbering attrs') ->
+ [mknode "a:buAutoNum" [("type", autoNumberingToType attrs')] ()]
+ Nothing -> [mknode "a:buNone" [] ()]
+ )
+ paras <- mapM paraElemToElement (paraElems par)
+ return $ mknode "a:p" [] $ [mknode "a:pPr" attrs props] ++ paras
+
+shapeToElement :: PandocMonad m => Element -> Shape -> P m Element
+shapeToElement layout (TextBox paras)
+ | ns <- elemToNameSpaces layout
+ , Just cSld <- findChild (elemName ns "p" "cSld") layout
+ , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
+ sp <- getContentShape ns spTree
+ elements <- mapM paragraphToElement paras
+ let txBody = mknode "p:txBody" [] $
+ [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] ++ elements
+ emptySpPr = mknode "p:spPr" [] ()
+ return $
+ surroundWithMathAlternate $
+ replaceNamedChildren ns "p" "txBody" [txBody] $
+ replaceNamedChildren ns "p" "spPr" [emptySpPr] $
+ sp
+-- GraphicFrame and Pic should never reach this.
+shapeToElement _ _ = return $ mknode "p:sp" [] ()
+
+shapeToElements :: PandocMonad m => Element -> Shape -> P m [Element]
+shapeToElements layout (Pic picProps fp alt) = do
+ mInfo <- registerMedia fp alt
+ case mInfoExt mInfo of
+ Just _ -> do
+ makePicElements layout picProps mInfo alt
+ Nothing -> shapeToElements layout $ TextBox [Paragraph def alt]
+shapeToElements layout (GraphicFrame tbls cptn) =
+ graphicFrameToElements layout tbls cptn
+shapeToElements layout shp = do
+ element <- shapeToElement layout shp
+ return [element]
+
+shapesToElements :: PandocMonad m => Element -> [Shape] -> P m [Element]
+shapesToElements layout shps = do
+ concat <$> mapM (shapeToElements layout) shps
+
+graphicFrameToElements :: PandocMonad m => Element -> [Graphic] -> [ParaElem] -> P m [Element]
+graphicFrameToElements layout tbls caption = do
+ -- get the sizing
+ master <- getMaster
+ (pageWidth, pageHeight) <- asks envPresentationSize
+ let ns = elemToNameSpaces layout
+ ((x, y), (cx, cytmp)) <- getContentShapeSize ns layout master
+ `catchError`
+ (\_ -> return ((0, 0), (pageWidth, pageHeight)))
+
+ let cy = if (not $ null caption) then cytmp - captionHeight else cytmp
+
+ elements <- mapM (graphicToElement cx) tbls
+ let graphicFrameElts =
+ mknode "p:graphicFrame" [] $
+ [ mknode "p:nvGraphicFramePr" [] $
+ [ mknode "p:cNvPr" [("id", "6"), ("name", "Content Placeholder 5")] ()
+ , mknode "p:cNvGraphicFramePr" [] $
+ [mknode "a:graphicFrameLocks" [("noGrp", "1")] ()]
+ , mknode "p:nvPr" [] $
+ [mknode "p:ph" [("idx", "1")] ()]
+ ]
+ , mknode "p:xfrm" [] $
+ [ mknode "a:off" [("x", show $ 12700 * x), ("y", show $ 12700 * y)] ()
+ , mknode "a:ext" [("cx", show $ 12700 * cx), ("cy", show $ 12700 * cy)] ()
+ ]
+ ] ++ elements
+
+ if (not $ null caption)
+ then do capElt <- createCaption ((x, y), (cx, cytmp)) caption
+ return [graphicFrameElts, capElt]
+ else return [graphicFrameElts]
+
+getDefaultTableStyle :: PandocMonad m => P m (Maybe String)
+getDefaultTableStyle = do
+ refArchive <- asks envRefArchive
+ distArchive <- asks envDistArchive
+ tblStyleLst <- parseXml refArchive distArchive "ppt/tableStyles.xml"
+ return $ findAttr (QName "def" Nothing Nothing) tblStyleLst
+
+graphicToElement :: PandocMonad m => Integer -> Graphic -> P m Element
+graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
+ let colWidths = if null hdrCells
+ then case rows of
+ r : _ | not (null r) -> replicate (length r) $
+ (tableWidth `div` (toInteger $ length r))
+ -- satisfy the compiler. This is the same as
+ -- saying that rows is empty, but the compiler
+ -- won't understand that `[]` exhausts the
+ -- alternatives.
+ _ -> []
+ else replicate (length hdrCells) $
+ (tableWidth `div` (toInteger $ length hdrCells))
+
+ let cellToOpenXML paras =
+ do elements <- mapM paragraphToElement paras
+ let elements' = if null elements
+ then [mknode "a:p" [] [mknode "a:endParaRPr" [] ()]]
+ else elements
+ return $
+ [mknode "a:txBody" [] $
+ ([ mknode "a:bodyPr" [] ()
+ , mknode "a:lstStyle" [] ()]
+ ++ elements')]
+ headers' <- mapM cellToOpenXML hdrCells
+ rows' <- mapM (mapM cellToOpenXML) rows
+ let borderProps = mknode "a:tcPr" [] ()
+ let emptyCell = [mknode "a:p" [] [mknode "a:pPr" [] ()]]
+ let mkcell border contents = mknode "a:tc" []
+ $ (if null contents
+ then emptyCell
+ else contents) ++ [ borderProps | border ]
+ let mkrow border cells = mknode "a:tr" [("h", "0")] $ map (mkcell border) cells
+
+ let mkgridcol w = mknode "a:gridCol"
+ [("w", show ((12700 * w) :: Integer))] ()
+ let hasHeader = not (all null hdrCells)
+
+ mbDefTblStyle <- getDefaultTableStyle
+ let tblPrElt = mknode "a:tblPr"
+ [ ("firstRow", if tblPrFirstRow tblPr then "1" else "0")
+ , ("bandRow", if tblPrBandRow tblPr then "1" else "0")
+ ] (case mbDefTblStyle of
+ Nothing -> []
+ Just sty -> [mknode "a:tableStyleId" [] sty])
+
+ return $ mknode "a:graphic" [] $
+ [mknode "a:graphicData" [("uri", "http://schemas.openxmlformats.org/drawingml/2006/table")] $
+ [mknode "a:tbl" [] $
+ [ tblPrElt
+ , mknode "a:tblGrid" [] (if all (==0) colWidths
+ then []
+ else map mkgridcol colWidths)
+ ]
+ ++ [ mkrow True headers' | hasHeader ] ++ map (mkrow False) rows'
+ ]
+ ]
+
+getShapeByPlaceHolderType :: NameSpaces -> Element -> String -> Maybe Element
+getShapeByPlaceHolderType ns spTreeElem phType
+ | isElem ns "p" "spTree" spTreeElem =
+ let findPhType element = isElem ns "p" "sp" element &&
+ Just phType == (Just element >>=
+ findChild (elemName ns "p" "nvSpPr") >>=
+ findChild (elemName ns "p" "nvPr") >>=
+ findChild (elemName ns "p" "ph") >>=
+ findAttr (QName "type" Nothing Nothing))
+ in
+ filterChild findPhType spTreeElem
+ | otherwise = Nothing
+
+getShapeByPlaceHolderIndex :: NameSpaces -> Element -> String -> Maybe Element
+getShapeByPlaceHolderIndex ns spTreeElem phIdx
+ | isElem ns "p" "spTree" spTreeElem =
+ let findPhType element = isElem ns "p" "sp" element &&
+ Just phIdx == (Just element >>=
+ findChild (elemName ns "p" "nvSpPr") >>=
+ findChild (elemName ns "p" "nvPr") >>=
+ findChild (elemName ns "p" "ph") >>=
+ findAttr (QName "idx" Nothing Nothing))
+ in
+ filterChild findPhType spTreeElem
+ | otherwise = Nothing
+
+
+nonBodyTextToElement :: PandocMonad m => Element -> String -> [ParaElem] -> P m Element
+nonBodyTextToElement layout phType paraElements
+ | ns <- elemToNameSpaces layout
+ , Just cSld <- findChild (elemName ns "p" "cSld") layout
+ , Just spTree <- findChild (elemName ns "p" "spTree") cSld
+ , Just sp <- getShapeByPlaceHolderType ns spTree phType = do
+ let hdrPara = Paragraph def paraElements
+ element <- paragraphToElement hdrPara
+ let txBody = mknode "p:txBody" [] $
+ [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] ++
+ [element]
+ return $ replaceNamedChildren ns "p" "txBody" [txBody] sp
+ -- XXX: TODO
+ | otherwise = return $ mknode "p:sp" [] ()
+
+contentToElement :: PandocMonad m => Element -> [ParaElem] -> [Shape] -> P m Element
+contentToElement layout hdrShape shapes
+ | ns <- elemToNameSpaces layout
+ , Just cSld <- findChild (elemName ns "p" "cSld") layout
+ , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
+ element <- nonBodyTextToElement layout "title" hdrShape
+ let hdrShapeElements = if null hdrShape
+ then []
+ else [element]
+ contentElements <- local
+ (\env -> env {envContentType = NormalContent})
+ (shapesToElements layout shapes)
+ return $
+ replaceNamedChildren ns "p" "sp"
+ (hdrShapeElements ++ contentElements)
+ spTree
+contentToElement _ _ _ = return $ mknode "p:sp" [] ()
+
+twoColumnToElement :: PandocMonad m => Element -> [ParaElem] -> [Shape] -> [Shape] -> P m Element
+twoColumnToElement layout hdrShape shapesL shapesR
+ | ns <- elemToNameSpaces layout
+ , Just cSld <- findChild (elemName ns "p" "cSld") layout
+ , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
+ element <- nonBodyTextToElement layout "title" hdrShape
+ let hdrShapeElements = if null hdrShape
+ then []
+ else [element]
+ contentElementsL <- local
+ (\env -> env {envContentType =TwoColumnLeftContent})
+ (shapesToElements layout shapesL)
+ contentElementsR <- local
+ (\env -> env {envContentType =TwoColumnRightContent})
+ (shapesToElements layout shapesR)
+ -- let contentElementsL' = map (setIdx ns "1") contentElementsL
+ -- contentElementsR' = map (setIdx ns "2") contentElementsR
+ return $
+ replaceNamedChildren ns "p" "sp"
+ (hdrShapeElements ++ contentElementsL ++ contentElementsR)
+ spTree
+twoColumnToElement _ _ _ _= return $ mknode "p:sp" [] ()
+
+
+titleToElement :: PandocMonad m => Element -> [ParaElem] -> P m Element
+titleToElement layout titleElems
+ | ns <- elemToNameSpaces layout
+ , Just cSld <- findChild (elemName ns "p" "cSld") layout
+ , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
+ element <- nonBodyTextToElement layout "title" titleElems
+ let titleShapeElements = if null titleElems
+ then []
+ else [element]
+ return $ replaceNamedChildren ns "p" "sp" titleShapeElements spTree
+titleToElement _ _ = return $ mknode "p:sp" [] ()
+
+metadataToElement :: PandocMonad m => Element -> [ParaElem] -> [ParaElem] -> [[ParaElem]] -> [ParaElem] -> P m Element
+metadataToElement layout titleElems subtitleElems authorsElems dateElems
+ | ns <- elemToNameSpaces layout
+ , Just cSld <- findChild (elemName ns "p" "cSld") layout
+ , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
+ titleShapeElements <- if null titleElems
+ then return []
+ else sequence [nonBodyTextToElement layout "ctrTitle" titleElems]
+ let combinedAuthorElems = intercalate [Break] authorsElems
+ subtitleAndAuthorElems = intercalate [Break, Break] [subtitleElems, combinedAuthorElems]
+ subtitleShapeElements <- if null subtitleAndAuthorElems
+ then return []
+ else sequence [nonBodyTextToElement layout "subTitle" subtitleAndAuthorElems]
+ dateShapeElements <- if null dateElems
+ then return []
+ else sequence [nonBodyTextToElement layout "dt" dateElems]
+ return $ replaceNamedChildren ns "p" "sp"
+ (titleShapeElements ++ subtitleShapeElements ++ dateShapeElements)
+ spTree
+metadataToElement _ _ _ _ _ = return $ mknode "p:sp" [] ()
+
+slideToElement :: PandocMonad m => Slide -> P m Element
+slideToElement (Slide _ l@(ContentSlide hdrElems shapes) _ )= do
+ layout <- getLayout l
+ spTree <- local (\env -> if null hdrElems
+ then env
+ else env{envSlideHasHeader=True}) $
+ contentToElement layout hdrElems shapes
+ return $ mknode "p:sld"
+ [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main"),
+ ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"),
+ ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
+ ] [mknode "p:cSld" [] [spTree]]
+slideToElement (Slide _ l@(TwoColumnSlide hdrElems shapesL shapesR) _) = do
+ layout <- getLayout l
+ spTree <- local (\env -> if null hdrElems
+ then env
+ else env{envSlideHasHeader=True}) $
+ twoColumnToElement layout hdrElems shapesL shapesR
+ return $ mknode "p:sld"
+ [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main"),
+ ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"),
+ ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
+ ] [mknode "p:cSld" [] [spTree]]
+slideToElement (Slide _ l@(TitleSlide hdrElems) _) = do
+ layout <- getLayout l
+ spTree <- titleToElement layout hdrElems
+ return $ mknode "p:sld"
+ [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main"),
+ ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"),
+ ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
+ ] [mknode "p:cSld" [] [spTree]]
+slideToElement (Slide _ l@(MetadataSlide titleElems subtitleElems authorElems dateElems) _) = do
+ layout <- getLayout l
+ spTree <- metadataToElement layout titleElems subtitleElems authorElems dateElems
+ return $ mknode "p:sld"
+ [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main"),
+ ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"),
+ ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
+ ] [mknode "p:cSld" [] [spTree]]
+
+
+--------------------------------------------------------------------
+-- Notes:
+
+getNotesMaster :: PandocMonad m => P m Element
+getNotesMaster = do
+ let notesMasterPath = "ppt/notesMasters/notesMaster1.xml"
+ distArchive <- asks envDistArchive
+ root <- case findEntryByPath notesMasterPath distArchive of
+ Just e -> case parseXMLDoc $ UTF8.toStringLazy $ fromEntry e of
+ Just element -> return $ element
+ Nothing -> throwError $
+ PandocSomeError $
+ notesMasterPath ++ " corrupt in reference file"
+ Nothing -> throwError $
+ PandocSomeError $
+ notesMasterPath ++ " missing in reference file"
+ return root
+
+getSlideNumberFieldId :: PandocMonad m => Element -> P m String
+getSlideNumberFieldId notesMaster
+ | ns <- elemToNameSpaces notesMaster
+ , Just cSld <- findChild (elemName ns "p" "cSld") notesMaster
+ , Just spTree <- findChild (elemName ns "p" "spTree") cSld
+ , Just sp <- getShapeByPlaceHolderType ns spTree "sldNum"
+ , Just txBody <- findChild (elemName ns "p" "txBody") sp
+ , Just p <- findChild (elemName ns "a" "p") txBody
+ , Just fld <- findChild (elemName ns "a" "fld") p
+ , Just fldId <- findAttr (QName "id" Nothing Nothing) fld =
+ return fldId
+ | otherwise = throwError $
+ PandocSomeError $
+ "No field id for slide numbers in notesMaster.xml"
+
+speakerNotesSlideImage :: Element
+speakerNotesSlideImage =
+ mknode "p:sp" [] $
+ [ mknode "p:nvSpPr" [] $
+ [ mknode "p:cNvPr" [ ("id", "2")
+ , ("name", "Slide Image Placeholder 1")
+ ] ()
+ , mknode "p:cNvSpPr" [] $
+ [ mknode "a:spLocks" [ ("noGrp", "1")
+ , ("noRot", "1")
+ , ("noChangeAspect", "1")
+ ] ()
+ ]
+ , mknode "p:nvPr" [] $
+ [ mknode "p:ph" [("type", "sldImg")] ()]
+ ]
+ , mknode "p:spPr" [] ()
+ ]
+
+-- we want to wipe links from the speaker notes in the
+-- paragraphs. Powerpoint doesn't allow you to input them, and it
+-- would provide extra complications.
+removeParaLinks :: Paragraph -> Paragraph
+removeParaLinks paragraph = paragraph{paraElems = map f (paraElems paragraph)}
+ where f (Run rProps s) = Run rProps{rLink=Nothing} s
+ f pe = pe
+
+-- put an empty paragraph between paragraphs for more expected spacing.
+spaceParas :: [Paragraph] -> [Paragraph]
+spaceParas = intersperse (Paragraph def [])
+
+speakerNotesBody :: PandocMonad m => [Paragraph] -> P m Element
+speakerNotesBody paras = do
+ elements <- mapM paragraphToElement $ spaceParas $ map removeParaLinks paras
+ let txBody = mknode "p:txBody" [] $
+ [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] ++ elements
+ return $
+ mknode "p:sp" [] $
+ [ mknode "p:nvSpPr" [] $
+ [ mknode "p:cNvPr" [ ("id", "3")
+ , ("name", "Notes Placeholder 2")
+ ] ()
+ , mknode "p:cNvSpPr" [] $
+ [ mknode "a:spLocks" [("noGrp", "1")] ()]
+ , mknode "p:nvPr" [] $
+ [ mknode "p:ph" [("type", "body"), ("idx", "1")] ()]
+ ]
+ , mknode "p:spPr" [] ()
+ , txBody
+ ]
+
+speakerNotesSlideNumber :: Int -> String -> Element
+speakerNotesSlideNumber pgNum fieldId =
+ mknode "p:sp" [] $
+ [ mknode "p:nvSpPr" [] $
+ [ mknode "p:cNvPr" [ ("id", "4")
+ , ("name", "Slide Number Placeholder 3")
+ ] ()
+ , mknode "p:cNvSpPr" [] $
+ [ mknode "a:spLocks" [("noGrp", "1")] ()]
+ , mknode "p:nvPr" [] $
+ [ mknode "p:ph" [ ("type", "sldNum")
+ , ("sz", "quarter")
+ , ("idx", "10")
+ ] ()
+ ]
+ ]
+ , mknode "p:spPr" [] ()
+ , mknode "p:txBody" [] $
+ [ mknode "a:bodyPr" [] ()
+ , mknode "a:lstStyle" [] ()
+ , mknode "a:p" [] $
+ [ mknode "a:fld" [ ("id", fieldId)
+ , ("type", "slidenum")
+ ]
+ [ mknode "a:rPr" [("lang", "en-US")] ()
+ , mknode "a:t" [] (show pgNum)
+ ]
+ , mknode "a:endParaRPr" [("lang", "en-US")] ()
+ ]
+ ]
+ ]
+
+slideToSpeakerNotesElement :: PandocMonad m => Slide -> P m (Maybe Element)
+slideToSpeakerNotesElement slide
+ | Slide _ _ mbNotes <- slide
+ , Just (SpeakerNotes paras) <- mbNotes = do
+ master <- getNotesMaster
+ fieldId <- getSlideNumberFieldId master
+ num <- slideNum slide
+ let imgShape = speakerNotesSlideImage
+ sldNumShape = speakerNotesSlideNumber num fieldId
+ bodyShape <- speakerNotesBody paras
+ return $ Just $
+ mknode "p:notes"
+ [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main")
+ , ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")
+ , ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
+ ] [ mknode "p:cSld" []
+ [ mknode "p:spTree" []
+ [ mknode "p:nvGrpSpPr" []
+ [ mknode "p:cNvPr" [("id", "1"), ("name", "")] ()
+ , mknode "p:cNvGrpSpPr" [] ()
+ , mknode "p:nvPr" [] ()
+ ]
+ , mknode "p:grpSpPr" []
+ [ mknode "a:xfrm" []
+ [ mknode "a:off" [("x", "0"), ("y", "0")] ()
+ , mknode "a:ext" [("cx", "0"), ("cy", "0")] ()
+ , mknode "a:chOff" [("x", "0"), ("y", "0")] ()
+ , mknode "a:chExt" [("cx", "0"), ("cy", "0")] ()
+ ]
+ ]
+ , imgShape
+ , bodyShape
+ , sldNumShape
+ ]
+ ]
+ ]
+slideToSpeakerNotesElement _ = return Nothing
+
+-----------------------------------------------------------------------
+
+getSlideIdNum :: PandocMonad m => SlideId -> P m Int
+getSlideIdNum sldId = do
+ slideIdMap <- asks envSlideIdMap
+ case M.lookup sldId slideIdMap of
+ Just n -> return n
+ Nothing -> throwError $
+ PandocShouldNeverHappenError $
+ "Slide Id " ++ (show sldId) ++ " not found."
+
+slideNum :: PandocMonad m => Slide -> P m Int
+slideNum slide = getSlideIdNum $ slideId slide
+
+idNumToFilePath :: Int -> FilePath
+idNumToFilePath idNum = "slide" ++ (show $ idNum) ++ ".xml"
+
+slideToFilePath :: PandocMonad m => Slide -> P m FilePath
+slideToFilePath slide = do
+ idNum <- slideNum slide
+ return $ "slide" ++ (show $ idNum) ++ ".xml"
+
+slideToRelId :: PandocMonad m => Slide -> P m String
+slideToRelId slide = do
+ n <- slideNum slide
+ offset <- asks envSlideIdOffset
+ return $ "rId" ++ (show $ n + offset)
+
+
+data Relationship = Relationship { relId :: Int
+ , relType :: MimeType
+ , relTarget :: FilePath
+ } deriving (Show, Eq)
+
+elementToRel :: Element -> Maybe Relationship
+elementToRel element
+ | elName element == QName "Relationship" (Just "http://schemas.openxmlformats.org/package/2006/relationships") Nothing =
+ do rId <- findAttr (QName "Id" Nothing Nothing) element
+ numStr <- stripPrefix "rId" rId
+ num <- case reads numStr :: [(Int, String)] of
+ (n, _) : _ -> Just n
+ [] -> Nothing
+ type' <- findAttr (QName "Type" Nothing Nothing) element
+ target <- findAttr (QName "Target" Nothing Nothing) element
+ return $ Relationship num type' target
+ | otherwise = Nothing
+
+slideToPresRel :: PandocMonad m => Slide -> P m Relationship
+slideToPresRel slide = do
+ idNum <- slideNum slide
+ n <- asks envSlideIdOffset
+ let rId = idNum + n
+ fp = "slides/" ++ idNumToFilePath idNum
+ return $ Relationship { relId = rId
+ , relType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide"
+ , relTarget = fp
+ }
+
+getRels :: PandocMonad m => P m [Relationship]
+getRels = do
+ refArchive <- asks envRefArchive
+ distArchive <- asks envDistArchive
+ relsElem <- parseXml refArchive distArchive "ppt/_rels/presentation.xml.rels"
+ let globalNS = "http://schemas.openxmlformats.org/package/2006/relationships"
+ let relElems = findChildren (QName "Relationship" (Just globalNS) Nothing) relsElem
+ return $ mapMaybe elementToRel relElems
+
+presentationToRels :: PandocMonad m => Presentation -> P m [Relationship]
+presentationToRels pres@(Presentation _ slides) = do
+ mySlideRels <- mapM slideToPresRel slides
+ let notesMasterRels =
+ if presHasSpeakerNotes pres
+ then [Relationship { relId = length mySlideRels + 2
+ , relType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster"
+ , relTarget = "notesMasters/notesMaster1.xml"
+ }]
+ else []
+ insertedRels = mySlideRels ++ notesMasterRels
+ rels <- getRels
+ -- we remove the slide rels and the notesmaster (if it's
+ -- there). We'll put these back in ourselves, if necessary.
+ let relsWeKeep = filter
+ (\r -> relType r /= "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" &&
+ relType r /= "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")
+ rels
+ -- We want to make room for the slides in the id space. The slides
+ -- will start at Id2 (since Id1 is for the slide master). There are
+ -- two slides in the data file, but that might change in the future,
+ -- so we will do this:
+ --
+ -- 1. We look to see what the minimum relWithoutSlide id (greater than 1) is.
+ -- 2. We add the difference between this and the number of slides to
+ -- all relWithoutSlide rels (unless they're 1)
+ -- 3. If we have a notesmaster slide, we make space for that as well.
+
+ let minRelNotOne = case filter (1<) $ map relId relsWeKeep of
+ [] -> 0 -- doesn't matter in this case, since
+ -- there will be nothing to map the
+ -- function over
+ l -> minimum l
+
+ modifyRelNum :: Int -> Int
+ modifyRelNum 1 = 1
+ modifyRelNum n = n - minRelNotOne + 2 + length insertedRels
+
+ relsWeKeep' = map (\r -> r{relId = modifyRelNum $ relId r}) relsWeKeep
+
+ return $ insertedRels ++ relsWeKeep'
+
+-- We make this ourselves, in case there's a thumbnail in the one from
+-- the template.
+topLevelRels :: [Relationship]
+topLevelRels =
+ [ Relationship { relId = 1
+ , relType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
+ , relTarget = "ppt/presentation.xml"
+ }
+ , Relationship { relId = 2
+ , relType = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"
+ , relTarget = "docProps/core.xml"
+ }
+ , Relationship { relId = 3
+ , relType = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/extended-properties"
+ , relTarget = "docProps/app.xml"
+ }
+ ]
+
+topLevelRelsEntry :: PandocMonad m => P m Entry
+topLevelRelsEntry = elemToEntry "_rels/.rels" $ relsToElement topLevelRels
+
+relToElement :: Relationship -> Element
+relToElement rel = mknode "Relationship" [ ("Id", "rId" ++ (show $ relId rel))
+ , ("Type", relType rel)
+ , ("Target", relTarget rel) ] ()
+
+relsToElement :: [Relationship] -> Element
+relsToElement rels = mknode "Relationships"
+ [("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships")]
+ (map relToElement rels)
+
+presentationToRelsEntry :: PandocMonad m => Presentation -> P m Entry
+presentationToRelsEntry pres = do
+ rels <- presentationToRels pres
+ elemToEntry "ppt/_rels/presentation.xml.rels" $ relsToElement rels
+
+elemToEntry :: PandocMonad m => FilePath -> Element -> P m Entry
+elemToEntry fp element = do
+ epochtime <- (floor . utcTimeToPOSIXSeconds) <$> asks envUTCTime
+ return $ toEntry fp epochtime $ renderXml element
+
+slideToEntry :: PandocMonad m => Slide -> P m Entry
+slideToEntry slide = do
+ idNum <- slideNum slide
+ local (\env -> env{envCurSlideId = idNum}) $ do
+ element <- slideToElement slide
+ elemToEntry ("ppt/slides/" ++ idNumToFilePath idNum) element
+
+slideToSpeakerNotesEntry :: PandocMonad m => Slide -> P m (Maybe Entry)
+slideToSpeakerNotesEntry slide = do
+ idNum <- slideNum slide
+ local (\env -> env{envCurSlideId = idNum}) $ do
+ mbElement <- slideToSpeakerNotesElement slide
+ mbNotesIdNum <- do mp <- asks envSpeakerNotesIdMap
+ return $ M.lookup idNum mp
+ case mbElement of
+ Just element | Just notesIdNum <- mbNotesIdNum ->
+ Just <$>
+ elemToEntry
+ ("ppt/notesSlides/notesSlide" ++ show notesIdNum ++ ".xml")
+ element
+ _ -> return Nothing
+
+slideToSpeakerNotesRelElement :: PandocMonad m => Slide -> P m (Maybe Element)
+slideToSpeakerNotesRelElement slide
+ | Slide _ _ mbNotes <- slide
+ , Just _ <- mbNotes = do
+ idNum <- slideNum slide
+ return $ Just $
+ mknode "Relationships"
+ [("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships")]
+ [ mknode "Relationship" [ ("Id", "rId2")
+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide")
+ , ("Target", "../slides/slide" ++ show idNum ++ ".xml")
+ ] ()
+ , mknode "Relationship" [ ("Id", "rId1")
+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")
+ , ("Target", "../notesMasters/notesMaster1.xml")
+ ] ()
+ ]
+slideToSpeakerNotesRelElement _ = return Nothing
+
+slideToSpeakerNotesRelEntry :: PandocMonad m => Slide -> P m (Maybe Entry)
+slideToSpeakerNotesRelEntry slide = do
+ idNum <- slideNum slide
+ mbElement <- slideToSpeakerNotesRelElement slide
+ mp <- asks envSpeakerNotesIdMap
+ let mbNotesIdNum = M.lookup idNum mp
+ case mbElement of
+ Just element | Just notesIdNum <- mbNotesIdNum ->
+ Just <$>
+ elemToEntry
+ ("ppt/notesSlides/_rels/notesSlide" ++ show notesIdNum ++ ".xml.rels")
+ element
+ _ -> return Nothing
+
+slideToSlideRelEntry :: PandocMonad m => Slide -> P m Entry
+slideToSlideRelEntry slide = do
+ idNum <- slideNum slide
+ element <- slideToSlideRelElement slide
+ elemToEntry ("ppt/slides/_rels/" ++ idNumToFilePath idNum ++ ".rels") element
+
+linkRelElement :: PandocMonad m => Int -> LinkTarget -> P m Element
+linkRelElement rIdNum (InternalTarget targetId) = do
+ targetIdNum <- getSlideIdNum targetId
+ return $
+ mknode "Relationship" [ ("Id", "rId" ++ show rIdNum)
+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide")
+ , ("Target", "slide" ++ show targetIdNum ++ ".xml")
+ ] ()
+linkRelElement rIdNum (ExternalTarget (url, _)) = do
+ return $
+ mknode "Relationship" [ ("Id", "rId" ++ show rIdNum)
+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")
+ , ("Target", url)
+ , ("TargetMode", "External")
+ ] ()
+
+linkRelElements :: PandocMonad m => M.Map Int LinkTarget -> P m [Element]
+linkRelElements mp = mapM (\(n, lnk) -> linkRelElement n lnk) (M.toList mp)
+
+mediaRelElement :: MediaInfo -> Element
+mediaRelElement mInfo =
+ let ext = case mInfoExt mInfo of
+ Just e -> e
+ Nothing -> ""
+ in
+ mknode "Relationship" [ ("Id", "rId" ++ (show $ mInfoLocalId mInfo))
+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image")
+ , ("Target", "../media/image" ++ (show $ mInfoGlobalId mInfo) ++ ext)
+ ] ()
+
+speakerNotesSlideRelElement :: PandocMonad m => Slide -> P m (Maybe Element)
+speakerNotesSlideRelElement slide = do
+ idNum <- slideNum slide
+ mp <- asks envSpeakerNotesIdMap
+ return $ case M.lookup idNum mp of
+ Nothing -> Nothing
+ Just n ->
+ let target = "../notesSlides/notesSlide" ++ show n ++ ".xml"
+ in Just $
+ mknode "Relationship" [ ("Id", "rId2")
+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide")
+ , ("Target", target)
+ ] ()
+
+slideToSlideRelElement :: PandocMonad m => Slide -> P m Element
+slideToSlideRelElement slide = do
+ idNum <- slideNum slide
+ let target = case slide of
+ (Slide _ (MetadataSlide _ _ _ _) _) -> "../slideLayouts/slideLayout1.xml"
+ (Slide _ (TitleSlide _) _) -> "../slideLayouts/slideLayout3.xml"
+ (Slide _ (ContentSlide _ _) _) -> "../slideLayouts/slideLayout2.xml"
+ (Slide _ (TwoColumnSlide _ _ _) _) -> "../slideLayouts/slideLayout4.xml"
+
+ speakerNotesRels <- maybeToList <$> speakerNotesSlideRelElement slide
+
+ linkIds <- gets stLinkIds
+ mediaIds <- gets stMediaIds
+
+ linkRels <- case M.lookup idNum linkIds of
+ Just mp -> linkRelElements mp
+ Nothing -> return []
+ let mediaRels = case M.lookup idNum mediaIds of
+ Just mInfos -> map mediaRelElement mInfos
+ Nothing -> []
+
+ return $
+ mknode "Relationships"
+ [("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships")]
+ ([mknode "Relationship" [ ("Id", "rId1")
+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout")
+ , ("Target", target)] ()
+ ] ++ speakerNotesRels ++ linkRels ++ mediaRels)
+
+slideToSldIdElement :: PandocMonad m => Slide -> P m Element
+slideToSldIdElement slide = do
+ n <- slideNum slide
+ let id' = show $ n + 255
+ rId <- slideToRelId slide
+ return $ mknode "p:sldId" [("id", id'), ("r:id", rId)] ()
+
+presentationToSldIdLst :: PandocMonad m => Presentation -> P m Element
+presentationToSldIdLst (Presentation _ slides) = do
+ ids <- mapM slideToSldIdElement slides
+ return $ mknode "p:sldIdLst" [] ids
+
+presentationToPresentationElement :: PandocMonad m => Presentation -> P m Element
+presentationToPresentationElement pres@(Presentation _ slds) = do
+ refArchive <- asks envRefArchive
+ distArchive <- asks envDistArchive
+ element <- parseXml refArchive distArchive "ppt/presentation.xml"
+ sldIdLst <- presentationToSldIdLst pres
+
+ let modifySldIdLst :: Content -> Content
+ modifySldIdLst (Elem e) = case elName e of
+ (QName "sldIdLst" _ _) -> Elem sldIdLst
+ _ -> Elem e
+ modifySldIdLst ct = ct
+
+ notesMasterRId = length slds + 2
+
+ notesMasterElem = mknode "p:notesMasterIdLst" []
+ [ mknode
+ "p:NotesMasterId"
+ [("r:id", "rId" ++ show notesMasterRId)]
+ ()
+ ]
+
+ -- if there's a notesMasterIdLst in the presentation.xml file,
+ -- we want to remove it. We then want to put our own, if
+ -- necessary, after the slideMasterIdLst element.
+
+ removeNotesMaster' :: Content -> [Content]
+ removeNotesMaster' (Elem e) = case elName e of
+ (QName "notesMasterIdLst" _ _) -> []
+ _ -> [Elem e]
+ removeNotesMaster' ct = [ct]
+
+ removeNotesMaster :: [Content] -> [Content]
+ removeNotesMaster = concatMap removeNotesMaster'
+
+ insertNotesMaster' :: Content -> [Content]
+ insertNotesMaster' (Elem e) = case elName e of
+ (QName "sldMasterIdLst" _ _) -> [Elem e, Elem notesMasterElem]
+ _ -> [Elem e]
+ insertNotesMaster' ct = [ct]
+
+ insertNotesMaster :: [Content] -> [Content]
+ insertNotesMaster = if presHasSpeakerNotes pres
+ then concatMap insertNotesMaster'
+ else id
+
+ newContent = insertNotesMaster $
+ removeNotesMaster $
+ map modifySldIdLst $
+ elContent element
+
+ return $ element{elContent = newContent}
+
+presentationToPresEntry :: PandocMonad m => Presentation -> P m Entry
+presentationToPresEntry pres = presentationToPresentationElement pres >>=
+ elemToEntry "ppt/presentation.xml"
+
+-- adapted from the Docx writer
+docPropsElement :: PandocMonad m => DocProps -> P m Element
+docPropsElement docProps = do
+ utctime <- asks envUTCTime
+ let keywords = case dcKeywords docProps of
+ Just xs -> intercalate "," xs
+ Nothing -> ""
+ return $
+ mknode "cp:coreProperties"
+ [("xmlns:cp","http://schemas.openxmlformats.org/package/2006/metadata/core-properties")
+ ,("xmlns:dc","http://purl.org/dc/elements/1.1/")
+ ,("xmlns:dcterms","http://purl.org/dc/terms/")
+ ,("xmlns:dcmitype","http://purl.org/dc/dcmitype/")
+ ,("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")]
+ $ (mknode "dc:title" [] $ fromMaybe "" $ dcTitle docProps)
+ : (mknode "dc:creator" [] $ fromMaybe "" $ dcCreator docProps)
+ : (mknode "cp:keywords" [] keywords)
+ : (\x -> [ mknode "dcterms:created" [("xsi:type","dcterms:W3CDTF")] x
+ , mknode "dcterms:modified" [("xsi:type","dcterms:W3CDTF")] x
+ ]) (formatTime defaultTimeLocale "%FT%XZ" utctime)
+
+docPropsToEntry :: PandocMonad m => DocProps -> P m Entry
+docPropsToEntry docProps = docPropsElement docProps >>=
+ elemToEntry "docProps/core.xml"
+
+
+defaultContentTypeToElem :: DefaultContentType -> Element
+defaultContentTypeToElem dct =
+ mknode "Default"
+ [("Extension", defContentTypesExt dct),
+ ("ContentType", defContentTypesType dct)]
+ ()
+
+overrideContentTypeToElem :: OverrideContentType -> Element
+overrideContentTypeToElem oct =
+ mknode "Override"
+ [("PartName", overrideContentTypesPart oct),
+ ("ContentType", overrideContentTypesType oct)]
+ ()
+
+contentTypesToElement :: ContentTypes -> Element
+contentTypesToElement ct =
+ let ns = "http://schemas.openxmlformats.org/package/2006/content-types"
+ in
+ mknode "Types" [("xmlns", ns)] $
+ (map defaultContentTypeToElem $ contentTypesDefaults ct) ++
+ (map overrideContentTypeToElem $ contentTypesOverrides ct)
+
+data DefaultContentType = DefaultContentType
+ { defContentTypesExt :: String
+ , defContentTypesType:: MimeType
+ }
+ deriving (Show, Eq)
+
+data OverrideContentType = OverrideContentType
+ { overrideContentTypesPart :: FilePath
+ , overrideContentTypesType :: MimeType
+ }
+ deriving (Show, Eq)
+
+data ContentTypes = ContentTypes { contentTypesDefaults :: [DefaultContentType]
+ , contentTypesOverrides :: [OverrideContentType]
+ }
+ deriving (Show, Eq)
+
+contentTypesToEntry :: PandocMonad m => ContentTypes -> P m Entry
+contentTypesToEntry ct = elemToEntry "[Content_Types].xml" $ contentTypesToElement ct
+
+pathToOverride :: FilePath -> Maybe OverrideContentType
+pathToOverride fp = OverrideContentType ("/" ++ fp) <$> (getContentType fp)
+
+mediaFileContentType :: FilePath -> Maybe DefaultContentType
+mediaFileContentType fp = case takeExtension fp of
+ '.' : ext -> Just $
+ DefaultContentType { defContentTypesExt = ext
+ , defContentTypesType =
+ case getMimeType fp of
+ Just mt -> mt
+ Nothing -> "application/octet-stream"
+ }
+ _ -> Nothing
+
+mediaContentType :: MediaInfo -> Maybe DefaultContentType
+mediaContentType mInfo
+ | Just ('.' : ext) <- mInfoExt mInfo =
+ Just $ DefaultContentType { defContentTypesExt = ext
+ , defContentTypesType =
+ case mInfoMimeType mInfo of
+ Just mt -> mt
+ Nothing -> "application/octet-stream"
+ }
+ | otherwise = Nothing
+
+getSpeakerNotesFilePaths :: PandocMonad m => P m [FilePath]
+getSpeakerNotesFilePaths = do
+ mp <- asks envSpeakerNotesIdMap
+ let notesIdNums = M.elems mp
+ return $ map (\n -> "ppt/notesSlides/notesSlide" ++ show n ++ ".xml") notesIdNums
+
+presentationToContentTypes :: PandocMonad m => Presentation -> P m ContentTypes
+presentationToContentTypes p@(Presentation _ slides) = do
+ mediaInfos <- (mconcat . M.elems) <$> gets stMediaIds
+ filePaths <- patternsToFilePaths $ inheritedPatterns p
+ let mediaFps = filter (match (compile "ppt/media/image*")) filePaths
+ let defaults = [ DefaultContentType "xml" "application/xml"
+ , DefaultContentType "rels" "application/vnd.openxmlformats-package.relationships+xml"
+ ]
+ mediaDefaults = nub $
+ (mapMaybe mediaContentType $ mediaInfos) ++
+ (mapMaybe mediaFileContentType $ mediaFps)
+
+ inheritedOverrides = mapMaybe pathToOverride filePaths
+ docPropsOverride = mapMaybe pathToOverride ["docProps/core.xml"]
+ presOverride = mapMaybe pathToOverride ["ppt/presentation.xml"]
+ relativePaths <- mapM slideToFilePath slides
+ let slideOverrides = mapMaybe
+ (\fp -> pathToOverride $ "ppt/slides/" ++ fp)
+ relativePaths
+ speakerNotesOverrides <- (mapMaybe pathToOverride) <$> getSpeakerNotesFilePaths
+ return $ ContentTypes
+ (defaults ++ mediaDefaults)
+ (inheritedOverrides ++ docPropsOverride ++ presOverride ++ slideOverrides ++ speakerNotesOverrides)
+
+presML :: String
+presML = "application/vnd.openxmlformats-officedocument.presentationml"
+
+noPresML :: String
+noPresML = "application/vnd.openxmlformats-officedocument"
+
+getContentType :: FilePath -> Maybe MimeType
+getContentType fp
+ | fp == "ppt/presentation.xml" = Just $ presML ++ ".presentation.main+xml"
+ | fp == "ppt/presProps.xml" = Just $ presML ++ ".presProps+xml"
+ | fp == "ppt/viewProps.xml" = Just $ presML ++ ".viewProps+xml"
+ | fp == "ppt/tableStyles.xml" = Just $ presML ++ ".tableStyles+xml"
+ | fp == "docProps/core.xml" = Just $ "application/vnd.openxmlformats-package.core-properties+xml"
+ | fp == "docProps/app.xml" = Just $ noPresML ++ ".extended-properties+xml"
+ | "ppt" : "slideMasters" : f : [] <- splitDirectories fp
+ , (_, ".xml") <- splitExtension f =
+ Just $ presML ++ ".slideMaster+xml"
+ | "ppt" : "slides" : f : [] <- splitDirectories fp
+ , (_, ".xml") <- splitExtension f =
+ Just $ presML ++ ".slide+xml"
+ | "ppt" : "notesMasters" : f : [] <- splitDirectories fp
+ , (_, ".xml") <- splitExtension f =
+ Just $ presML ++ ".notesMaster+xml"
+ | "ppt" : "notesSlides" : f : [] <- splitDirectories fp
+ , (_, ".xml") <- splitExtension f =
+ Just $ presML ++ ".notesSlide+xml"
+ | "ppt" : "theme" : f : [] <- splitDirectories fp
+ , (_, ".xml") <- splitExtension f =
+ Just $ noPresML ++ ".theme+xml"
+ | "ppt" : "slideLayouts" : _ : [] <- splitDirectories fp=
+ Just $ presML ++ ".slideLayout+xml"
+ | otherwise = Nothing
+
+autoNumberingToType :: ListAttributes -> String
+autoNumberingToType (_, numStyle, numDelim) =
+ typeString ++ delimString
+ where
+ typeString = case numStyle of
+ Decimal -> "arabic"
+ UpperAlpha -> "alphaUc"
+ LowerAlpha -> "alphaLc"
+ UpperRoman -> "romanUc"
+ LowerRoman -> "romanLc"
+ _ -> "arabic"
+ delimString = case numDelim of
+ Period -> "Period"
+ OneParen -> "ParenR"
+ TwoParens -> "ParenBoth"
+ _ -> "Period"
diff --git a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
new file mode 100644
index 000000000..396469edd
--- /dev/null
+++ b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
@@ -0,0 +1,987 @@
+{-# LANGUAGE PatternGuards #-}
+
+{-
+Copyright (C) 2017-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.Powerpoint.Presentation
+ Copyright : Copyright (C) 2017-2018 Jesse Rosenthal
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
+ Stability : alpha
+ Portability : portable
+
+Definition of Presentation datatype, modeling a MS Powerpoint (pptx)
+document, and functions for converting a Pandoc document to
+Presentation.
+-}
+
+module Text.Pandoc.Writers.Powerpoint.Presentation ( documentToPresentation
+ , Presentation(..)
+ , DocProps(..)
+ , Slide(..)
+ , Layout(..)
+ , SpeakerNotes(..)
+ , SlideId(..)
+ , Shape(..)
+ , Graphic(..)
+ , BulletType(..)
+ , Algnment(..)
+ , Paragraph(..)
+ , ParaElem(..)
+ , ParaProps(..)
+ , RunProps(..)
+ , TableProps(..)
+ , Strikethrough(..)
+ , Capitals(..)
+ , PicProps(..)
+ , URL
+ , TeXString(..)
+ , LinkTarget(..)
+ ) where
+
+
+import Control.Monad.Reader
+import Control.Monad.State
+import Data.List (intercalate)
+import Data.Default
+import Text.Pandoc.Definition
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Slides (getSlideLevel)
+import Text.Pandoc.Options
+import Text.Pandoc.Logging
+import Text.Pandoc.Walk
+import Text.Pandoc.Compat.Time (UTCTime)
+import qualified Text.Pandoc.Shared as Shared -- so we don't overlap "Element"
+import Text.Pandoc.Writers.Shared (metaValueToInlines)
+import qualified Data.Map as M
+import qualified Data.Set as S
+import Data.Maybe (maybeToList, fromMaybe)
+import Text.Pandoc.Highlighting
+import qualified Data.Text as T
+import Control.Applicative ((<|>))
+import Skylighting
+
+data WriterEnv = WriterEnv { envMetadata :: Meta
+ , envRunProps :: RunProps
+ , envParaProps :: ParaProps
+ , envSlideLevel :: Int
+ , envOpts :: WriterOptions
+ , envSlideHasHeader :: Bool
+ , envInList :: Bool
+ , envInNoteSlide :: Bool
+ , envCurSlideId :: SlideId
+ , envInSpeakerNotes :: Bool
+ }
+ deriving (Show)
+
+instance Default WriterEnv where
+ def = WriterEnv { envMetadata = mempty
+ , envRunProps = def
+ , envParaProps = def
+ , envSlideLevel = 2
+ , envOpts = def
+ , envSlideHasHeader = False
+ , envInList = False
+ , envInNoteSlide = False
+ , envCurSlideId = SlideId "Default"
+ , envInSpeakerNotes = False
+ }
+
+
+data WriterState = WriterState { stNoteIds :: M.Map Int [Block]
+ -- associate anchors with slide id
+ , stAnchorMap :: M.Map String SlideId
+ , stSlideIdSet :: S.Set SlideId
+ , stLog :: [LogMessage]
+ , stSpeakerNotesMap :: M.Map SlideId [[Paragraph]]
+ } deriving (Show, Eq)
+
+instance Default WriterState where
+ def = WriterState { stNoteIds = mempty
+ , stAnchorMap = mempty
+ -- we reserve this s
+ , stSlideIdSet = reservedSlideIds
+ , stLog = []
+ , stSpeakerNotesMap = mempty
+ }
+
+metadataSlideId :: SlideId
+metadataSlideId = SlideId "Metadata"
+
+tocSlideId :: SlideId
+tocSlideId = SlideId "TOC"
+
+endNotesSlideId :: SlideId
+endNotesSlideId = SlideId "EndNotes"
+
+reservedSlideIds :: S.Set SlideId
+reservedSlideIds = S.fromList [ metadataSlideId
+ , tocSlideId
+ , endNotesSlideId
+ ]
+
+uniqueSlideId' :: Integer -> S.Set SlideId -> String -> SlideId
+uniqueSlideId' n idSet s =
+ let s' = if n == 0 then s else s ++ "-" ++ show n
+ in if SlideId s' `S.member` idSet
+ then uniqueSlideId' (n+1) idSet s
+ else SlideId s'
+
+uniqueSlideId :: S.Set SlideId -> String -> SlideId
+uniqueSlideId = uniqueSlideId' 0
+
+runUniqueSlideId :: String -> Pres SlideId
+runUniqueSlideId s = do
+ idSet <- gets stSlideIdSet
+ let sldId = uniqueSlideId idSet s
+ modify $ \st -> st{stSlideIdSet = S.insert sldId idSet}
+ return sldId
+
+addLogMessage :: LogMessage -> Pres ()
+addLogMessage msg = modify $ \st -> st{stLog = msg : stLog st}
+
+type Pres = ReaderT WriterEnv (State WriterState)
+
+runPres :: WriterEnv -> WriterState -> Pres a -> (a, [LogMessage])
+runPres env st p = (pres, reverse $ stLog finalSt)
+ where (pres, finalSt) = runState (runReaderT p env) st
+
+-- GHC 7.8 will still complain about concat <$> mapM unless we specify
+-- Functor. We can get rid of this when we stop supporting GHC 7.8.
+concatMapM :: (Monad m) => (a -> m [b]) -> [a] -> m [b]
+concatMapM f xs = liftM concat (mapM f xs)
+
+type Pixels = Integer
+
+data Presentation = Presentation DocProps [Slide]
+ deriving (Show)
+
+data DocProps = DocProps { dcTitle :: Maybe String
+ , dcSubject :: Maybe String
+ , dcCreator :: Maybe String
+ , dcKeywords :: Maybe [String]
+ , dcCreated :: Maybe UTCTime
+ } deriving (Show, Eq)
+
+
+data Slide = Slide { slideId :: SlideId
+ , slideLayout :: Layout
+ , slideSpeakerNotes :: Maybe SpeakerNotes
+ } deriving (Show, Eq)
+
+newtype SlideId = SlideId String
+ deriving (Show, Eq, Ord)
+
+-- In theory you could have anything on a notes slide but it seems
+-- designed mainly for one textbox, so we'll just put in the contents
+-- of that textbox, to avoid other shapes that won't work as well.
+newtype SpeakerNotes = SpeakerNotes {fromSpeakerNotes :: [Paragraph]}
+ deriving (Show, Eq)
+
+data Layout = MetadataSlide { metadataSlideTitle :: [ParaElem]
+ , metadataSlideSubtitle :: [ParaElem]
+ , metadataSlideAuthors :: [[ParaElem]]
+ , metadataSlideDate :: [ParaElem]
+ }
+ | TitleSlide { titleSlideHeader :: [ParaElem]}
+ | ContentSlide { contentSlideHeader :: [ParaElem]
+ , contentSlideContent :: [Shape]
+ }
+ | TwoColumnSlide { twoColumnSlideHeader :: [ParaElem]
+ , twoColumnSlideLeft :: [Shape]
+ , twoColumnSlideRight :: [Shape]
+ }
+ deriving (Show, Eq)
+
+data Shape = Pic PicProps FilePath [ParaElem]
+ | GraphicFrame [Graphic] [ParaElem]
+ | TextBox [Paragraph]
+ deriving (Show, Eq)
+
+type Cell = [Paragraph]
+
+data TableProps = TableProps { tblPrFirstRow :: Bool
+ , tblPrBandRow :: Bool
+ } deriving (Show, Eq)
+
+data Graphic = Tbl TableProps [Cell] [[Cell]]
+ deriving (Show, Eq)
+
+
+data Paragraph = Paragraph { paraProps :: ParaProps
+ , paraElems :: [ParaElem]
+ } deriving (Show, Eq)
+
+data BulletType = Bullet
+ | AutoNumbering ListAttributes
+ deriving (Show, Eq)
+
+data Algnment = AlgnLeft | AlgnRight | AlgnCenter
+ deriving (Show, Eq)
+
+data ParaProps = ParaProps { pPropMarginLeft :: Maybe Pixels
+ , pPropMarginRight :: Maybe Pixels
+ , pPropLevel :: Int
+ , pPropBullet :: Maybe BulletType
+ , pPropAlign :: Maybe Algnment
+ , pPropSpaceBefore :: Maybe Pixels
+ } deriving (Show, Eq)
+
+instance Default ParaProps where
+ def = ParaProps { pPropMarginLeft = Just 0
+ , pPropMarginRight = Just 0
+ , pPropLevel = 0
+ , pPropBullet = Nothing
+ , pPropAlign = Nothing
+ , pPropSpaceBefore = Nothing
+ }
+
+newtype TeXString = TeXString {unTeXString :: String}
+ deriving (Eq, Show)
+
+data ParaElem = Break
+ | Run RunProps String
+ -- It would be more elegant to have native TeXMath
+ -- Expressions here, but this allows us to use
+ -- `convertmath` from T.P.Writers.Math. Will perhaps
+ -- revisit in the future.
+ | MathElem MathType TeXString
+ deriving (Show, Eq)
+
+data Strikethrough = NoStrike | SingleStrike | DoubleStrike
+ deriving (Show, Eq)
+
+data Capitals = NoCapitals | SmallCapitals | AllCapitals
+ deriving (Show, Eq)
+
+type URL = String
+
+data LinkTarget = ExternalTarget (URL, String)
+ | InternalTarget SlideId
+ deriving (Show, Eq)
+
+data RunProps = RunProps { rPropBold :: Bool
+ , rPropItalics :: Bool
+ , rStrikethrough :: Maybe Strikethrough
+ , rBaseline :: Maybe Int
+ , rCap :: Maybe Capitals
+ , rLink :: Maybe LinkTarget
+ , rPropCode :: Bool
+ , rPropBlockQuote :: Bool
+ , rPropForceSize :: Maybe Pixels
+ , rSolidFill :: Maybe Color
+ -- TODO: Make a full underline data type with
+ -- the different options.
+ , rPropUnderline :: Bool
+ } deriving (Show, Eq)
+
+instance Default RunProps where
+ def = RunProps { rPropBold = False
+ , rPropItalics = False
+ , rStrikethrough = Nothing
+ , rBaseline = Nothing
+ , rCap = Nothing
+ , rLink = Nothing
+ , rPropCode = False
+ , rPropBlockQuote = False
+ , rPropForceSize = Nothing
+ , rSolidFill = Nothing
+ , rPropUnderline = False
+ }
+
+data PicProps = PicProps { picPropLink :: Maybe LinkTarget
+ , picWidth :: Maybe Dimension
+ , picHeight :: Maybe Dimension
+ } deriving (Show, Eq)
+
+instance Default PicProps where
+ def = PicProps { picPropLink = Nothing
+ , picWidth = Nothing
+ , picHeight = Nothing
+ }
+
+--------------------------------------------------
+
+inlinesToParElems :: [Inline] -> Pres [ParaElem]
+inlinesToParElems ils = concatMapM inlineToParElems ils
+
+inlineToParElems :: Inline -> Pres [ParaElem]
+inlineToParElems (Str s) = do
+ pr <- asks envRunProps
+ return [Run pr s]
+inlineToParElems (Emph ils) =
+ local (\r -> r{envRunProps = (envRunProps r){rPropItalics=True}}) $
+ inlinesToParElems ils
+inlineToParElems (Strong ils) =
+ local (\r -> r{envRunProps = (envRunProps r){rPropBold=True}}) $
+ inlinesToParElems ils
+inlineToParElems (Strikeout ils) =
+ local (\r -> r{envRunProps = (envRunProps r){rStrikethrough=Just SingleStrike}}) $
+ inlinesToParElems ils
+inlineToParElems (Superscript ils) =
+ local (\r -> r{envRunProps = (envRunProps r){rBaseline=Just 30000}}) $
+ inlinesToParElems ils
+inlineToParElems (Subscript ils) =
+ local (\r -> r{envRunProps = (envRunProps r){rBaseline=Just (-25000)}}) $
+ inlinesToParElems ils
+inlineToParElems (SmallCaps ils) =
+ local (\r -> r{envRunProps = (envRunProps r){rCap = Just SmallCapitals}}) $
+ inlinesToParElems ils
+inlineToParElems Space = inlineToParElems (Str " ")
+inlineToParElems SoftBreak = inlineToParElems (Str " ")
+inlineToParElems LineBreak = return [Break]
+inlineToParElems (Link _ ils (url, title)) =
+ local (\r ->r{envRunProps = (envRunProps r){rLink = Just $ ExternalTarget (url, title)}}) $
+ inlinesToParElems ils
+inlineToParElems (Code _ str) =
+ local (\r ->r{envRunProps = (envRunProps r){rPropCode = True}}) $
+ inlineToParElems $ Str str
+inlineToParElems (Math mathtype str) =
+ return [MathElem mathtype (TeXString str)]
+-- We ignore notes if we're in a speaker notes div. Otherwise this
+-- would add an entry to the endnotes slide, which would put speaker
+-- notes in the public presentation. In the future, we can entertain a
+-- way of adding a speakernotes-specific note that would just add
+-- paragraphs to the bottom of the notes page.
+inlineToParElems (Note blks) = do
+ inSpNotes <- asks envInSpeakerNotes
+ if inSpNotes
+ then return []
+ else do
+ notes <- gets stNoteIds
+ let maxNoteId = case M.keys notes of
+ [] -> 0
+ lst -> maximum lst
+ curNoteId = maxNoteId + 1
+ modify $ \st -> st { stNoteIds = M.insert curNoteId blks notes }
+ local (\env -> env{envRunProps = (envRunProps env){rLink = Just $ InternalTarget endNotesSlideId}}) $
+ inlineToParElems $ Superscript [Str $ show curNoteId]
+inlineToParElems (Span _ ils) = concatMapM inlineToParElems ils
+inlineToParElems (RawInline _ _) = return []
+inlineToParElems _ = return []
+
+isListType :: Block -> Bool
+isListType (OrderedList _ _) = True
+isListType (BulletList _) = True
+isListType (DefinitionList _) = True
+isListType _ = False
+
+registerAnchorId :: String -> Pres ()
+registerAnchorId anchor = do
+ anchorMap <- gets stAnchorMap
+ sldId <- asks envCurSlideId
+ unless (null anchor) $
+ modify $ \st -> st {stAnchorMap = M.insert anchor sldId anchorMap}
+
+-- Currently hardcoded, until I figure out how to make it dynamic.
+blockQuoteSize :: Pixels
+blockQuoteSize = 20
+
+noteSize :: Pixels
+noteSize = 18
+
+blockToParagraphs :: Block -> Pres [Paragraph]
+blockToParagraphs (Plain ils) = do
+ parElems <- inlinesToParElems ils
+ pProps <- asks envParaProps
+ return [Paragraph pProps parElems]
+blockToParagraphs (Para ils) = do
+ parElems <- inlinesToParElems ils
+ pProps <- asks envParaProps
+ return [Paragraph pProps parElems]
+blockToParagraphs (LineBlock ilsList) = do
+ parElems <- inlinesToParElems $ intercalate [LineBreak] ilsList
+ pProps <- asks envParaProps
+ return [Paragraph pProps parElems]
+-- TODO: work out the attributes
+blockToParagraphs (CodeBlock attr str) =
+ local (\r -> r{ envParaProps = def{pPropMarginLeft = Just 100}
+ , envRunProps = (envRunProps r){rPropCode = True}}) $ do
+ mbSty <- writerHighlightStyle <$> asks envOpts
+ synMap <- writerSyntaxMap <$> asks envOpts
+ case mbSty of
+ Just sty ->
+ case highlight synMap (formatSourceLines sty) attr str of
+ Right pElems -> do pProps <- asks envParaProps
+ return [Paragraph pProps pElems]
+ Left _ -> blockToParagraphs $ Para [Str str]
+ Nothing -> blockToParagraphs $ Para [Str str]
+-- We can't yet do incremental lists, but we should render a
+-- (BlockQuote List) as a list to maintain compatibility with other
+-- formats.
+blockToParagraphs (BlockQuote (blk : blks)) | isListType blk = do
+ ps <- blockToParagraphs blk
+ ps' <- blockToParagraphs $ BlockQuote blks
+ return $ ps ++ ps'
+blockToParagraphs (BlockQuote blks) =
+ local (\r -> r{ envParaProps = (envParaProps r){pPropMarginLeft = Just 100}
+ , envRunProps = (envRunProps r){rPropForceSize = Just blockQuoteSize}})$
+ concatMapM blockToParagraphs blks
+-- TODO: work out the format
+blockToParagraphs (RawBlock _ _) = return []
+blockToParagraphs (Header _ (ident, _, _) ils) = do
+ -- Note that this function only deals with content blocks, so it
+ -- will only touch headers that are above the current slide level --
+ -- slides at or below the slidelevel will be taken care of by
+ -- `blocksToSlide'`. We have the register anchors in both of them.
+ registerAnchorId ident
+ -- we set the subeader to bold
+ parElems <- local (\e->e{envRunProps = (envRunProps e){rPropBold=True}}) $
+ inlinesToParElems ils
+ -- and give it a bit of space before it.
+ return [Paragraph def{pPropSpaceBefore = Just 30} parElems]
+blockToParagraphs (BulletList blksLst) = do
+ pProps <- asks envParaProps
+ let lvl = pPropLevel pProps
+ local (\env -> env{ envInList = True
+ , envParaProps = pProps{ pPropLevel = lvl + 1
+ , pPropBullet = Just Bullet
+ , pPropMarginLeft = Nothing
+ }}) $
+ concatMapM multiParBullet blksLst
+blockToParagraphs (OrderedList listAttr blksLst) = do
+ pProps <- asks envParaProps
+ let lvl = pPropLevel pProps
+ local (\env -> env{ envInList = True
+ , envParaProps = pProps{ pPropLevel = lvl + 1
+ , pPropBullet = Just (AutoNumbering listAttr)
+ , pPropMarginLeft = Nothing
+ }}) $
+ concatMapM multiParBullet blksLst
+blockToParagraphs (DefinitionList entries) = do
+ let go :: ([Inline], [[Block]]) -> Pres [Paragraph]
+ go (ils, blksLst) = do
+ term <-blockToParagraphs $ Para [Strong ils]
+ -- For now, we'll treat each definition term as a
+ -- blockquote. We can extend this further later.
+ definition <- concatMapM (blockToParagraphs . BlockQuote) blksLst
+ return $ term ++ definition
+ concatMapM go entries
+blockToParagraphs (Div (_, "notes" : [], _) blks) =
+ local (\env -> env{envInSpeakerNotes=True}) $ do
+ sldId <- asks envCurSlideId
+ spkNotesMap <- gets stSpeakerNotesMap
+ paras <- concatMapM blockToParagraphs blks
+ let spkNotesMap' = case M.lookup sldId spkNotesMap of
+ Just lst -> M.insert sldId (paras : lst) spkNotesMap
+ Nothing -> M.insert sldId [paras] spkNotesMap
+ modify $ \st -> st{stSpeakerNotesMap = spkNotesMap'}
+ return []
+blockToParagraphs (Div _ blks) = concatMapM blockToParagraphs blks
+blockToParagraphs blk = do
+ addLogMessage $ BlockNotRendered blk
+ return []
+
+-- Make sure the bullet env gets turned off after the first para.
+multiParBullet :: [Block] -> Pres [Paragraph]
+multiParBullet [] = return []
+multiParBullet (b:bs) = do
+ pProps <- asks envParaProps
+ p <- blockToParagraphs b
+ ps <- local (\env -> env{envParaProps = pProps{pPropBullet = Nothing}}) $
+ concatMapM blockToParagraphs bs
+ return $ p ++ ps
+
+cellToParagraphs :: Alignment -> TableCell -> Pres [Paragraph]
+cellToParagraphs algn tblCell = do
+ paras <- mapM blockToParagraphs tblCell
+ let alignment = case algn of
+ AlignLeft -> Just AlgnLeft
+ AlignRight -> Just AlgnRight
+ AlignCenter -> Just AlgnCenter
+ AlignDefault -> Nothing
+ paras' = map (map (\p -> p{paraProps = (paraProps p){pPropAlign = alignment}})) paras
+ return $ concat paras'
+
+rowToParagraphs :: [Alignment] -> [TableCell] -> Pres [[Paragraph]]
+rowToParagraphs algns tblCells = do
+ -- We have to make sure we have the right number of alignments
+ let pairs = zip (algns ++ repeat AlignDefault) tblCells
+ mapM (uncurry cellToParagraphs) pairs
+
+withAttr :: Attr -> Shape -> Shape
+withAttr attr (Pic picPr url caption) =
+ let picPr' = picPr { picWidth = dimension Width attr
+ , picHeight = dimension Height attr
+ }
+ in
+ Pic picPr' url caption
+withAttr _ sp = sp
+
+blockToShape :: Block -> Pres Shape
+blockToShape (Plain (il:_)) | Image attr ils (url, _) <- il =
+ (withAttr attr . Pic def url) <$> inlinesToParElems ils
+blockToShape (Para (il:_)) | Image attr ils (url, _) <- il =
+ (withAttr attr . Pic def url) <$> inlinesToParElems ils
+blockToShape (Plain (il:_)) | Link _ (il':_) target <- il
+ , Image attr ils (url, _) <- il' =
+ (withAttr attr . Pic def {picPropLink = Just $ ExternalTarget target} url) <$>
+ inlinesToParElems ils
+blockToShape (Para (il:_)) | Link _ (il':_) target <- il
+ , Image attr ils (url, _) <- il' =
+ (withAttr attr . Pic def{picPropLink = Just $ ExternalTarget target} url) <$>
+ inlinesToParElems ils
+blockToShape (Table caption algn _ hdrCells rows) = do
+ caption' <- inlinesToParElems caption
+ hdrCells' <- rowToParagraphs algn hdrCells
+ rows' <- mapM (rowToParagraphs algn) rows
+ let tblPr = if null hdrCells
+ then TableProps { tblPrFirstRow = False
+ , tblPrBandRow = True
+ }
+ else TableProps { tblPrFirstRow = True
+ , tblPrBandRow = True
+ }
+
+ return $ GraphicFrame [Tbl tblPr hdrCells' rows'] caption'
+blockToShape blk = do paras <- blockToParagraphs blk
+ let paras' = map (\par -> par{paraElems = combineParaElems $ paraElems par}) paras
+ return $ TextBox paras'
+
+combineShapes :: [Shape] -> [Shape]
+combineShapes [] = []
+combineShapes[s] = [s]
+combineShapes (pic@(Pic{}) : ss) = pic : combineShapes ss
+combineShapes (TextBox [] : ss) = combineShapes ss
+combineShapes (s : TextBox [] : ss) = combineShapes (s : ss)
+combineShapes (TextBox (p:ps) : TextBox (p':ps') : ss) =
+ combineShapes $ TextBox ((p:ps) ++ (p':ps')) : ss
+combineShapes (s:ss) = s : combineShapes ss
+
+blocksToShapes :: [Block] -> Pres [Shape]
+blocksToShapes blks = combineShapes <$> mapM blockToShape blks
+
+isImage :: Inline -> Bool
+isImage (Image{}) = True
+isImage (Link _ (Image _ _ _ : _) _) = True
+isImage _ = False
+
+splitBlocks' :: [Block] -> [[Block]] -> [Block] -> Pres [[Block]]
+splitBlocks' cur acc [] = return $ acc ++ (if null cur then [] else [cur])
+splitBlocks' cur acc (HorizontalRule : blks) =
+ splitBlocks' [] (acc ++ (if null cur then [] else [cur])) blks
+splitBlocks' cur acc (h@(Header n _ _) : blks) = do
+ slideLevel <- asks envSlideLevel
+ case compare n slideLevel of
+ LT -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[h]]) blks
+ EQ -> splitBlocks' [h] (acc ++ (if null cur then [] else [cur])) blks
+ GT -> splitBlocks' (cur ++ [h]) acc blks
+-- `blockToParagraphs` treats Plain and Para the same, so we can save
+-- some code duplication by treating them the same here.
+splitBlocks' cur acc (Plain ils : blks) = splitBlocks' cur acc (Para ils : blks)
+splitBlocks' cur acc (Para (il:ils) : blks) | isImage il = do
+ slideLevel <- asks envSlideLevel
+ case cur of
+ [(Header n _ _)] | n == slideLevel ->
+ splitBlocks' []
+ (acc ++ [cur ++ [Para [il]]])
+ (if null ils then blks else Para ils : blks)
+ _ -> splitBlocks' []
+ (acc ++ (if null cur then [] else [cur]) ++ [[Para [il]]])
+ (if null ils then blks else Para ils : blks)
+splitBlocks' cur acc (tbl@(Table{}) : blks) = do
+ slideLevel <- asks envSlideLevel
+ case cur of
+ [(Header n _ _)] | n == slideLevel ->
+ splitBlocks' [] (acc ++ [cur ++ [tbl]]) blks
+ _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[tbl]]) blks
+splitBlocks' cur acc (d@(Div (_, classes, _) _): blks) | "columns" `elem` classes = do
+ slideLevel <- asks envSlideLevel
+ case cur of
+ [(Header n _ _)] | n == slideLevel ->
+ splitBlocks' [] (acc ++ [cur ++ [d]]) blks
+ _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[d]]) blks
+splitBlocks' cur acc (blk : blks) = splitBlocks' (cur ++ [blk]) acc blks
+
+splitBlocks :: [Block] -> Pres [[Block]]
+splitBlocks = splitBlocks' [] []
+
+getSpeakerNotes :: Pres (Maybe SpeakerNotes)
+getSpeakerNotes = do
+ sldId <- asks envCurSlideId
+ spkNtsMap <- gets stSpeakerNotesMap
+ return $ (SpeakerNotes . concat . reverse) <$> (M.lookup sldId spkNtsMap)
+
+blocksToSlide' :: Int -> [Block] -> Pres Slide
+blocksToSlide' lvl (Header n (ident, _, _) ils : blks)
+ | n < lvl = do
+ registerAnchorId ident
+ sldId <- asks envCurSlideId
+ hdr <- inlinesToParElems ils
+ return $ Slide sldId TitleSlide {titleSlideHeader = hdr} Nothing
+ | n == lvl = do
+ registerAnchorId ident
+ hdr <- inlinesToParElems ils
+ -- Now get the slide without the header, and then add the header
+ -- in.
+ slide <- blocksToSlide' lvl blks
+ let layout = case slideLayout slide of
+ ContentSlide _ cont -> ContentSlide hdr cont
+ TwoColumnSlide _ contL contR -> TwoColumnSlide hdr contL contR
+ layout' -> layout'
+ return $ slide{slideLayout = layout}
+blocksToSlide' _ (blk : blks)
+ | Div (_, classes, _) divBlks <- blk
+ , "columns" `elem` classes
+ , Div (_, clsL, _) blksL : Div (_, clsR, _) blksR : remaining <- divBlks
+ , "column" `elem` clsL, "column" `elem` clsR = do
+ unless (null blks)
+ (mapM (addLogMessage . BlockNotRendered) blks >> return ())
+ unless (null remaining)
+ (mapM (addLogMessage . BlockNotRendered) remaining >> return ())
+ mbSplitBlksL <- splitBlocks blksL
+ mbSplitBlksR <- splitBlocks blksR
+ let blksL' = case mbSplitBlksL of
+ bs : _ -> bs
+ [] -> []
+ let blksR' = case mbSplitBlksR of
+ bs : _ -> bs
+ [] -> []
+ shapesL <- blocksToShapes blksL'
+ shapesR <- blocksToShapes blksR'
+ sldId <- asks envCurSlideId
+ return $ Slide
+ sldId
+ TwoColumnSlide { twoColumnSlideHeader = []
+ , twoColumnSlideLeft = shapesL
+ , twoColumnSlideRight = shapesR
+ }
+ Nothing
+blocksToSlide' _ (blk : blks) = do
+ inNoteSlide <- asks envInNoteSlide
+ shapes <- if inNoteSlide
+ then forceFontSize noteSize $ blocksToShapes (blk : blks)
+ else blocksToShapes (blk : blks)
+ sldId <- asks envCurSlideId
+ return $
+ Slide
+ sldId
+ ContentSlide { contentSlideHeader = []
+ , contentSlideContent = shapes
+ }
+ Nothing
+blocksToSlide' _ [] = do
+ sldId <- asks envCurSlideId
+ return $
+ Slide
+ sldId
+ ContentSlide { contentSlideHeader = []
+ , contentSlideContent = []
+ }
+ Nothing
+
+blocksToSlide :: [Block] -> Pres Slide
+blocksToSlide blks = do
+ slideLevel <- asks envSlideLevel
+ sld <- blocksToSlide' slideLevel blks
+ spkNotes <- getSpeakerNotes
+ return $ sld{slideSpeakerNotes = spkNotes}
+
+makeNoteEntry :: Int -> [Block] -> [Block]
+makeNoteEntry n blks =
+ let enum = Str (show n ++ ".")
+ in
+ case blks of
+ (Para ils : blks') -> (Para $ enum : Space : ils) : blks'
+ _ -> Para [enum] : blks
+
+forceFontSize :: Pixels -> Pres a -> Pres a
+forceFontSize px x = do
+ rpr <- asks envRunProps
+ local (\r -> r {envRunProps = rpr{rPropForceSize = Just px}}) x
+
+-- We leave these as blocks because we will want to include them in
+-- the TOC.
+makeEndNotesSlideBlocks :: Pres [Block]
+makeEndNotesSlideBlocks = do
+ noteIds <- gets stNoteIds
+ slideLevel <- asks envSlideLevel
+ meta <- asks envMetadata
+ -- Get identifiers so we can give the notes section a unique ident.
+ anchorSet <- M.keysSet <$> gets stAnchorMap
+ if M.null noteIds
+ then return []
+ else do let title = case lookupMeta "notes-title" meta of
+ Just val -> metaValueToInlines val
+ Nothing -> [Str "Notes"]
+ ident = Shared.uniqueIdent title anchorSet
+ hdr = Header slideLevel (ident, [], []) title
+ blks <- return $
+ concatMap (\(n, bs) -> makeNoteEntry n bs) $
+ M.toList noteIds
+ return $ hdr : blks
+
+getMetaSlide :: Pres (Maybe Slide)
+getMetaSlide = do
+ meta <- asks envMetadata
+ title <- inlinesToParElems $ docTitle meta
+ subtitle <- inlinesToParElems $
+ case lookupMeta "subtitle" meta of
+ Just (MetaString s) -> [Str s]
+ Just (MetaInlines ils) -> ils
+ Just (MetaBlocks [Plain ils]) -> ils
+ Just (MetaBlocks [Para ils]) -> ils
+ _ -> []
+ authors <- mapM inlinesToParElems $ docAuthors meta
+ date <- inlinesToParElems $ docDate meta
+ if null title && null subtitle && null authors && null date
+ then return Nothing
+ else return $
+ Just $
+ Slide
+ metadataSlideId
+ MetadataSlide { metadataSlideTitle = title
+ , metadataSlideSubtitle = subtitle
+ , metadataSlideAuthors = authors
+ , metadataSlideDate = date
+ }
+ Nothing
+
+-- adapted from the markdown writer
+elementToListItem :: Shared.Element -> Pres [Block]
+elementToListItem (Shared.Sec lev _nums (ident,_,_) headerText subsecs) = do
+ opts <- asks envOpts
+ let headerLink = if null ident
+ then walk Shared.deNote headerText
+ else [Link nullAttr (walk Shared.deNote headerText)
+ ('#':ident, "")]
+ listContents <- if null subsecs || lev >= writerTOCDepth opts
+ then return []
+ else mapM elementToListItem subsecs
+ return [Plain headerLink, BulletList listContents]
+elementToListItem (Shared.Blk _) = return []
+
+makeTOCSlide :: [Block] -> Pres Slide
+makeTOCSlide blks = local (\env -> env{envCurSlideId = tocSlideId}) $ do
+ contents <- BulletList <$> mapM elementToListItem (Shared.hierarchicalize blks)
+ meta <- asks envMetadata
+ slideLevel <- asks envSlideLevel
+ let tocTitle = case lookupMeta "toc-title" meta of
+ Just val -> metaValueToInlines val
+ Nothing -> [Str "Table of Contents"]
+ hdr = Header slideLevel nullAttr tocTitle
+ sld <- blocksToSlide [hdr, contents]
+ return sld
+
+combineParaElems' :: Maybe ParaElem -> [ParaElem] -> [ParaElem]
+combineParaElems' mbPElem [] = maybeToList mbPElem
+combineParaElems' Nothing (pElem : pElems) =
+ combineParaElems' (Just pElem) pElems
+combineParaElems' (Just pElem') (pElem : pElems)
+ | Run rPr' s' <- pElem'
+ , Run rPr s <- pElem
+ , rPr == rPr' =
+ combineParaElems' (Just $ Run rPr' $ s' ++ s) pElems
+ | otherwise =
+ pElem' : combineParaElems' (Just pElem) pElems
+
+combineParaElems :: [ParaElem] -> [ParaElem]
+combineParaElems = combineParaElems' Nothing
+
+applyToParagraph :: Monad m => (ParaElem -> m ParaElem) -> Paragraph -> m Paragraph
+applyToParagraph f para = do
+ paraElems' <- mapM f $ paraElems para
+ return $ para {paraElems = paraElems'}
+
+applyToShape :: Monad m => (ParaElem -> m ParaElem) -> Shape -> m Shape
+applyToShape f (Pic pPr fp pes) = do
+ pes' <- mapM f pes
+ return $ Pic pPr fp pes'
+applyToShape f (GraphicFrame gfx pes) = do
+ pes' <- mapM f pes
+ return $ GraphicFrame gfx pes'
+applyToShape f (TextBox paras) = do
+ paras' <- mapM (applyToParagraph f) paras
+ return $ TextBox paras'
+
+applyToLayout :: Monad m => (ParaElem -> m ParaElem) -> Layout -> m Layout
+applyToLayout f (MetadataSlide title subtitle authors date) = do
+ title' <- mapM f title
+ subtitle' <- mapM f subtitle
+ authors' <- mapM (mapM f) authors
+ date' <- mapM f date
+ return $ MetadataSlide title' subtitle' authors' date'
+applyToLayout f (TitleSlide title) = do
+ title' <- mapM f title
+ return $ TitleSlide title'
+applyToLayout f (ContentSlide hdr content) = do
+ hdr' <- mapM f hdr
+ content' <- mapM (applyToShape f) content
+ return $ ContentSlide hdr' content'
+applyToLayout f (TwoColumnSlide hdr contentL contentR) = do
+ hdr' <- mapM f hdr
+ contentL' <- mapM (applyToShape f) contentL
+ contentR' <- mapM (applyToShape f) contentR
+ return $ TwoColumnSlide hdr' contentL' contentR'
+
+applyToSlide :: Monad m => (ParaElem -> m ParaElem) -> Slide -> m Slide
+applyToSlide f slide = do
+ layout' <- applyToLayout f $ slideLayout slide
+ mbNotes' <- case slideSpeakerNotes slide of
+ Just (SpeakerNotes notes) -> (Just . SpeakerNotes) <$>
+ mapM (applyToParagraph f) notes
+ Nothing -> return Nothing
+ return slide{slideLayout = layout', slideSpeakerNotes = mbNotes'}
+
+replaceAnchor :: ParaElem -> Pres ParaElem
+replaceAnchor (Run rProps s)
+ | Just (ExternalTarget ('#':anchor, _)) <- rLink rProps = do
+ anchorMap <- gets stAnchorMap
+ -- If the anchor is not in the anchormap, we just remove the
+ -- link.
+ let rProps' = case M.lookup anchor anchorMap of
+ Just n -> rProps{rLink = Just $ InternalTarget n}
+ Nothing -> rProps{rLink = Nothing}
+ return $ Run rProps' s
+replaceAnchor pe = return pe
+
+emptyParaElem :: ParaElem -> Bool
+emptyParaElem (Run _ s) =
+ null $ Shared.trim s
+emptyParaElem (MathElem _ ts) =
+ null $ Shared.trim $ unTeXString ts
+emptyParaElem _ = False
+
+emptyParagraph :: Paragraph -> Bool
+emptyParagraph para = all emptyParaElem $ paraElems para
+
+
+emptyShape :: Shape -> Bool
+emptyShape (TextBox paras) = all emptyParagraph $ paras
+emptyShape _ = False
+
+emptyLayout :: Layout -> Bool
+emptyLayout layout = case layout of
+ MetadataSlide title subtitle authors date ->
+ all emptyParaElem title &&
+ all emptyParaElem subtitle &&
+ all (all emptyParaElem) authors &&
+ all emptyParaElem date
+ TitleSlide hdr -> all emptyParaElem hdr
+ ContentSlide hdr shapes ->
+ all emptyParaElem hdr &&
+ all emptyShape shapes
+ TwoColumnSlide hdr shapes1 shapes2 ->
+ all emptyParaElem hdr &&
+ all emptyShape shapes1 &&
+ all emptyShape shapes2
+
+emptySlide :: Slide -> Bool
+emptySlide (Slide _ layout Nothing) = emptyLayout layout
+emptySlide _ = False
+
+blocksToPresentationSlides :: [Block] -> Pres [Slide]
+blocksToPresentationSlides blks = do
+ opts <- asks envOpts
+ metadataslides <- maybeToList <$> getMetaSlide
+ -- As far as I can tell, if we want to have a variable-length toc in
+ -- the future, we'll have to make it twice. Once to get the length,
+ -- and a second time to include the notes slide. We can't make the
+ -- notes slide before the body slides because we need to know if
+ -- there are notes, and we can't make either before the toc slide,
+ -- because we need to know its length to get slide numbers right.
+ --
+ -- For now, though, since the TOC slide is only length 1, if it
+ -- exists, we'll just get the length, and then come back to make the
+ -- slide later
+ blksLst <- splitBlocks blks
+ bodySlideIds <- mapM
+ (\n -> runUniqueSlideId $ "BodySlide" ++ show n)
+ (take (length blksLst) [1..] :: [Integer])
+ bodyslides <- mapM
+ (\(bs, ident) ->
+ local (\st -> st{envCurSlideId = ident}) (blocksToSlide bs))
+ (zip blksLst bodySlideIds)
+ endNotesSlideBlocks <- makeEndNotesSlideBlocks
+ -- now we come back and make the real toc...
+ tocSlides <- if writerTableOfContents opts
+ then do toc <- makeTOCSlide $ blks ++ endNotesSlideBlocks
+ return [toc]
+ else return []
+ -- ... and the notes slide. We test to see if the blocks are empty,
+ -- because we don't want to make an empty slide.
+ endNotesSlides <- if null endNotesSlideBlocks
+ then return []
+ else do endNotesSlide <- local
+ (\env -> env { envCurSlideId = endNotesSlideId
+ , envInNoteSlide = True
+ })
+ (blocksToSlide endNotesSlideBlocks)
+ return [endNotesSlide]
+
+ let slides = metadataslides ++ tocSlides ++ bodyslides ++ endNotesSlides
+ slides' = filter (not . emptySlide) slides
+ mapM (applyToSlide replaceAnchor) slides'
+
+metaToDocProps :: Meta -> DocProps
+metaToDocProps meta =
+ let keywords = case lookupMeta "keywords" meta of
+ Just (MetaList xs) -> Just $ map Shared.stringify xs
+ _ -> Nothing
+
+ authors = case map Shared.stringify $ docAuthors meta of
+ [] -> Nothing
+ ss -> Just $ intercalate ";" ss
+ in
+ DocProps{ dcTitle = Shared.stringify <$> lookupMeta "title" meta
+ , dcSubject = Shared.stringify <$> lookupMeta "subject" meta
+ , dcCreator = authors
+ , dcKeywords = keywords
+ , dcCreated = Nothing
+ }
+
+documentToPresentation :: WriterOptions
+ -> Pandoc
+ -> (Presentation, [LogMessage])
+documentToPresentation opts (Pandoc meta blks) =
+ let env = def { envOpts = opts
+ , envMetadata = meta
+ , envSlideLevel = fromMaybe (getSlideLevel blks) (writerSlideLevel opts)
+ }
+ (presSlides, msgs) = runPres env def $ blocksToPresentationSlides blks
+ docProps = metaToDocProps meta
+ in
+ (Presentation docProps presSlides, msgs)
+
+-- --------------------------------------------------------------
+
+applyTokStyToRunProps :: TokenStyle -> RunProps -> RunProps
+applyTokStyToRunProps tokSty rProps =
+ rProps{ rSolidFill = tokenColor tokSty <|> rSolidFill rProps
+ , rPropBold = tokenBold tokSty || rPropBold rProps
+ , rPropItalics = tokenItalic tokSty || rPropItalics rProps
+ , rPropUnderline = tokenUnderline tokSty || rPropUnderline rProps
+ }
+
+formatToken :: Style -> Token -> ParaElem
+formatToken sty (tokType, txt) =
+ let rProps = def{rPropCode = True, rSolidFill = defaultColor sty}
+ rProps' = case M.lookup tokType (tokenStyles sty) of
+ Just tokSty -> applyTokStyToRunProps tokSty rProps
+ Nothing -> rProps
+ in
+ Run rProps' $ T.unpack txt
+
+formatSourceLine :: Style -> FormatOptions -> SourceLine -> [ParaElem]
+formatSourceLine sty _ srcLn = map (formatToken sty) srcLn
+
+formatSourceLines :: Style -> FormatOptions -> [SourceLine] -> [ParaElem]
+formatSourceLines sty opts srcLns = intercalate [Break] $
+ map (formatSourceLine sty opts) srcLns
diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs
index 064434483..95cb46643 100644
--- a/src/Text/Pandoc/Writers/RST.hs
+++ b/src/Text/Pandoc/Writers/RST.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.RST
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,19 +31,21 @@ Conversion of 'Pandoc' documents to reStructuredText.
reStructuredText: <http://docutils.sourceforge.net/rst.html>
-}
module Text.Pandoc.Writers.RST ( writeRST ) where
+import Control.Monad.State.Strict
+import Data.Char (isSpace, toLower)
+import Data.List (isPrefixOf, stripPrefix)
+import Data.Maybe (fromMaybe)
+import Data.Text (Text, stripEnd)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
+import Text.Pandoc.Pretty
import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
-import Text.Pandoc.ImageSize
import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.Builder (deleteMeta)
-import Data.Maybe (fromMaybe)
-import Data.List ( isPrefixOf, stripPrefix, intersperse, transpose )
-import Network.URI (isURI)
-import Text.Pandoc.Pretty
-import Control.Monad.State
-import Data.Char (isSpace, toLower)
+import Text.Pandoc.Writers.Shared
type Refs = [([Inline], Target)]
@@ -57,95 +59,99 @@ data WriterState =
, stTopLevel :: Bool
}
+type RST = StateT WriterState
+
-- | Convert Pandoc to RST.
-writeRST :: WriterOptions -> Pandoc -> String
-writeRST opts document =
+writeRST :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeRST opts document = do
let st = WriterState { stNotes = [], stLinks = [],
stImages = [], stHasMath = False,
stHasRawTeX = False, stOptions = opts,
- stTopLevel = True}
- in evalState (pandocToRST document) st
+ stTopLevel = True }
+ evalStateT (pandocToRST document) st
-- | Return RST representation of document.
-pandocToRST :: Pandoc -> State WriterState String
+pandocToRST :: PandocMonad m => Pandoc -> RST m Text
pandocToRST (Pandoc meta blocks) = do
- opts <- liftM stOptions get
+ opts <- gets stOptions
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
let subtit = case lookupMeta "subtitle" meta of
Just (MetaBlocks [Plain xs]) -> xs
- _ -> []
+ _ -> []
title <- titleToRST (docTitle meta) subtit
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToRST)
- (fmap (trimr . render colwidth) . inlineListToRST)
- $ deleteMeta "title" $ deleteMeta "subtitle" meta
+ (fmap render' . blockListToRST)
+ (fmap (stripEnd . render') . inlineListToRST)
+ $ B.deleteMeta "title" $ B.deleteMeta "subtitle" meta
body <- blockListToRST' True $ case writerTemplate opts of
Just _ -> normalizeHeadings 1 blocks
Nothing -> blocks
- notes <- liftM (reverse . stNotes) get >>= notesToRST
+ notes <- gets (reverse . stNotes) >>= notesToRST
-- note that the notes may contain refs, so we do them first
- refs <- liftM (reverse . stLinks) get >>= refsToRST
- pics <- liftM (reverse . stImages) get >>= pictRefsToRST
- hasMath <- liftM stHasMath get
- rawTeX <- liftM stHasRawTeX get
- let main = render colwidth $ foldl ($+$) empty $ [body, notes, refs, pics]
+ refs <- gets (reverse . stLinks) >>= refsToRST
+ pics <- gets (reverse . stImages) >>= pictRefsToRST
+ hasMath <- gets stHasMath
+ rawTeX <- gets stHasRawTeX
+ let main = render' $ foldl ($+$) empty [body, notes, refs, pics]
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts)
$ defField "toc-depth" (show $ writerTOCDepth opts)
$ defField "math" hasMath
$ defField "title" (render Nothing title :: String)
$ defField "math" hasMath
- $ defField "rawtex" rawTeX
- $ metadata
+ $ defField "rawtex" rawTeX metadata
case writerTemplate opts of
Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
where
normalizeHeadings lev (Header l a i:bs) =
Header lev a i:normalizeHeadings (lev+1) cont ++ normalizeHeadings lev bs'
where (cont,bs') = break (headerLtEq l) bs
headerLtEq level (Header l' _ _) = l' <= level
- headerLtEq _ _ = False
+ headerLtEq _ _ = False
normalizeHeadings lev (b:bs) = b:normalizeHeadings lev bs
normalizeHeadings _ [] = []
-- | Return RST representation of reference key table.
-refsToRST :: Refs -> State WriterState Doc
+refsToRST :: PandocMonad m => Refs -> RST m Doc
refsToRST refs = mapM keyToRST refs >>= return . vcat
-- | Return RST representation of a reference key.
-keyToRST :: ([Inline], (String, String))
- -> State WriterState Doc
+keyToRST :: PandocMonad m => ([Inline], (String, String)) -> RST m Doc
keyToRST (label, (src, _)) = do
label' <- inlineListToRST label
- let label'' = if ':' `elem` ((render Nothing label') :: String)
+ let label'' = if ':' `elem` (render Nothing label' :: String)
then char '`' <> label' <> char '`'
else label'
return $ nowrap $ ".. _" <> label'' <> ": " <> text src
-- | Return RST representation of notes.
-notesToRST :: [[Block]] -> State WriterState Doc
+notesToRST :: PandocMonad m => [[Block]] -> RST m Doc
notesToRST notes =
- mapM (\(num, note) -> noteToRST num note) (zip [1..] notes) >>=
+ zipWithM noteToRST [1..] notes >>=
return . vsep
-- | Return RST representation of a note.
-noteToRST :: Int -> [Block] -> State WriterState Doc
+noteToRST :: PandocMonad m => Int -> [Block] -> RST m Doc
noteToRST num note = do
contents <- blockListToRST note
let marker = ".. [" <> text (show num) <> "]"
return $ nowrap $ marker $$ nest 3 contents
-- | Return RST representation of picture reference table.
-pictRefsToRST :: [([Inline], (Attr, String, String, Maybe String))]
- -> State WriterState Doc
+pictRefsToRST :: PandocMonad m
+ => [([Inline], (Attr, String, String, Maybe String))]
+ -> RST m Doc
pictRefsToRST refs = mapM pictToRST refs >>= return . vcat
-- | Return RST representation of a picture substitution reference.
-pictToRST :: ([Inline], (Attr, String, String, Maybe String))
- -> State WriterState Doc
+pictToRST :: PandocMonad m
+ => ([Inline], (Attr, String, String, Maybe String))
+ -> RST m Doc
pictToRST (label, (attr, src, _, mbtarget)) = do
label' <- inlineListToRST label
dims <- imageDimsToRST attr
@@ -160,10 +166,27 @@ pictToRST (label, (attr, src, _, mbtarget)) = do
Just t -> " :target: " <> text t
-- | Escape special characters for RST.
-escapeString :: String -> String
-escapeString = escapeStringUsing (backslashEscapes "`\\|*_")
+escapeString :: WriterOptions -> String -> String
+escapeString = escapeString' True
+ where
+ escapeString' _ _ [] = []
+ escapeString' firstChar opts (c:cs) =
+ case c of
+ _ | c `elem` ['\\','`','*','_','|'] &&
+ (firstChar || null cs) -> '\\':c:escapeString' False opts cs
+ '\'' | isEnabled Ext_smart opts -> '\\':'\'':escapeString' False opts cs
+ '"' | isEnabled Ext_smart opts -> '\\':'"':escapeString' False opts cs
+ '-' | isEnabled Ext_smart opts ->
+ case cs of
+ '-':_ -> '\\':'-':escapeString' False opts cs
+ _ -> '-':escapeString' False opts cs
+ '.' | isEnabled Ext_smart opts ->
+ case cs of
+ '.':'.':rest -> '\\':'.':'.':'.':escapeString' False opts rest
+ _ -> '.':escapeString' False opts cs
+ _ -> c : escapeString' False opts cs
-titleToRST :: [Inline] -> [Inline] -> State WriterState Doc
+titleToRST :: PandocMonad m => [Inline] -> [Inline] -> RST m Doc
titleToRST [] _ = return empty
titleToRST tit subtit = do
title <- inlineListToRST tit
@@ -179,8 +202,9 @@ bordered contents c =
border = text (replicate len c)
-- | Convert Pandoc block element to RST.
-blockToRST :: Block -- ^ Block element
- -> State WriterState Doc
+blockToRST :: PandocMonad m
+ => Block -- ^ Block element
+ -> RST m Doc
blockToRST Null = return empty
blockToRST (Div attr bs) = do
contents <- blockListToRST bs
@@ -200,7 +224,7 @@ blockToRST (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
else ":figclass: " <> text (unwords cls)
return $ hang 3 ".. " (fig $$ alt $$ classes $$ dims $+$ capt) $$ blankline
blockToRST (Para inlines)
- | LineBreak `elem` inlines = do -- use line block if LineBreaks
+ | LineBreak `elem` inlines =
linesToLineBlock $ splitBy (==LineBreak) inlines
| otherwise = do
contents <- inlineListToRST inlines
@@ -211,17 +235,22 @@ blockToRST (RawBlock f@(Format f') str)
| f == "rst" = return $ text str
| otherwise = return $ blankline <> ".. raw:: " <>
text (map toLower f') $+$
- (nest 3 $ text str) $$ blankline
+ nest 3 (text str) $$ blankline
blockToRST HorizontalRule =
return $ blankline $$ "--------------" $$ blankline
blockToRST (Header level (name,classes,_) inlines) = do
contents <- inlineListToRST inlines
+ -- we calculate the id that would be used by auto_identifiers
+ -- so we know whether to print an explicit identifier
+ let autoId = uniqueIdent inlines mempty
isTopLevel <- gets stTopLevel
if isTopLevel
then do
let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
let border = text $ replicate (offset contents) headerChar
- return $ nowrap $ contents $$ border $$ blankline
+ let anchor | null name || name == autoId = empty
+ | otherwise = ".. _" <> text name <> ":" $$ blankline
+ return $ nowrap $ anchor $$ contents $$ border $$ blankline
else do
let rub = "rubric:: " <> contents
let name' | null name = empty
@@ -230,7 +259,7 @@ blockToRST (Header level (name,classes,_) inlines) = do
| otherwise = ":class: " <> text (unwords classes)
return $ nowrap $ hang 3 ".. " (rub $$ name' $$ cls) $$ blankline
blockToRST (CodeBlock (_,classes,kvs) str) = do
- opts <- stOptions <$> get
+ opts <- gets stOptions
let tabstop = writerTabStop opts
let startnum = maybe "" (\x -> " " <> text x) $ lookup "startFrom" kvs
let numberlines = if "numberLines" `elem` classes
@@ -246,59 +275,38 @@ blockToRST (CodeBlock (_,classes,kvs) str) = do
(lang:_) -> (".. code:: " <> text lang) $$ numberlines)
$+$ nest tabstop (text str) $$ blankline
blockToRST (BlockQuote blocks) = do
- tabstop <- get >>= (return . writerTabStop . stOptions)
+ tabstop <- gets $ writerTabStop . stOptions
contents <- blockListToRST blocks
- return $ (nest tabstop contents) <> blankline
-blockToRST (Table caption _ widths headers rows) = do
+ return $ nest tabstop contents <> blankline
+blockToRST (Table caption aligns widths headers rows) = do
caption' <- inlineListToRST caption
- let caption'' = if null caption
- then empty
- else blankline <> text "Table: " <> caption'
- headers' <- mapM blockListToRST headers
- rawRows <- mapM (mapM blockListToRST) rows
- -- let isSimpleCell [Plain _] = True
- -- isSimpleCell [Para _] = True
- -- isSimpleCell [] = True
- -- isSimpleCell _ = False
- -- let isSimple = all (==0) widths && all (all isSimpleCell) rows
- let numChars = maximum . map offset
- opts <- get >>= return . stOptions
- let widthsInChars =
- if all (== 0) widths
- then map ((+2) . numChars) $ transpose (headers' : rawRows)
- else map (floor . (fromIntegral (writerColumns opts) *)) widths
- let hpipeBlocks blocks = hcat [beg, middle, end]
- where h = height (hcat blocks)
- sep' = lblock 3 $ vcat (map text $ replicate h " | ")
- beg = lblock 2 $ vcat (map text $ replicate h "| ")
- end = lblock 2 $ vcat (map text $ replicate h " |")
- middle = hcat $ intersperse sep' blocks
- let makeRow = hpipeBlocks . zipWith lblock widthsInChars
- let head' = makeRow headers'
- let rows' = map makeRow rawRows
- let border ch = char '+' <> char ch <>
- (hcat $ intersperse (char ch <> char '+' <> char ch) $
- map (\l -> text $ replicate l ch) widthsInChars) <>
- char ch <> char '+'
- let body = vcat $ intersperse (border '-') rows'
- let head'' = if all null headers
- then empty
- else head' $$ border '='
- return $ border '-' $$ head'' $$ body $$ border '-' $$ caption'' $$ blankline
+ let blocksToDoc opts bs = do
+ oldOpts <- gets stOptions
+ modify $ \st -> st{ stOptions = opts }
+ result <- blockListToRST bs
+ modify $ \st -> st{ stOptions = oldOpts }
+ return result
+ opts <- gets stOptions
+ tbl <- gridTable opts blocksToDoc (all null headers)
+ (map (const AlignDefault) aligns) widths
+ headers rows
+ return $ if null caption
+ then tbl $$ blankline
+ else (".. table:: " <> caption') $$ blankline $$ nest 3 tbl $$
+ blankline
blockToRST (BulletList items) = do
contents <- mapM bulletListItemToRST items
-- ensure that sublists have preceding blank line
return $ blankline $$ chomp (vcat contents) $$ blankline
blockToRST (OrderedList (start, style', delim) items) = do
let markers = if start == 1 && style' == DefaultStyle && delim == DefaultDelim
- then take (length items) $ repeat "#."
+ then replicate (length items) "#."
else take (length items) $ orderedListMarkers
(start, style', delim)
let maxMarkerLength = maximum $ map length markers
let markers' = map (\m -> let s = maxMarkerLength - length m
in m ++ replicate s ' ') markers
- contents <- mapM (\(item, num) -> orderedListItemToRST item num) $
- zip markers' items
+ contents <- zipWithM orderedListItemToRST markers' items
-- ensure that sublists have preceding blank line
return $ blankline $$ chomp (vcat contents) $$ blankline
blockToRST (DefinitionList items) = do
@@ -307,51 +315,69 @@ blockToRST (DefinitionList items) = do
return $ blankline $$ chomp (vcat contents) $$ blankline
-- | Convert bullet list item (list of blocks) to RST.
-bulletListItemToRST :: [Block] -> State WriterState Doc
+bulletListItemToRST :: PandocMonad m => [Block] -> RST m Doc
bulletListItemToRST items = do
contents <- blockListToRST items
return $ hang 3 "- " $ contents <> cr
-- | Convert ordered list item (a list of blocks) to RST.
-orderedListItemToRST :: String -- ^ marker for list item
+orderedListItemToRST :: PandocMonad m
+ => String -- ^ marker for list item
-> [Block] -- ^ list item (list of blocks)
- -> State WriterState Doc
+ -> RST m Doc
orderedListItemToRST marker items = do
contents <- blockListToRST items
let marker' = marker ++ " "
return $ hang (length marker') (text marker') $ contents <> cr
-- | Convert defintion list item (label, list of blocks) to RST.
-definitionListItemToRST :: ([Inline], [[Block]]) -> State WriterState Doc
+definitionListItemToRST :: PandocMonad m => ([Inline], [[Block]]) -> RST m Doc
definitionListItemToRST (label, defs) = do
label' <- inlineListToRST label
contents <- liftM vcat $ mapM blockListToRST defs
- tabstop <- get >>= (return . writerTabStop . stOptions)
- return $ label' $$ nest tabstop (nestle contents <> cr)
+ tabstop <- gets $ writerTabStop . stOptions
+ return $ nowrap label' $$ nest tabstop (nestle contents <> cr)
-- | Format a list of lines as line block.
-linesToLineBlock :: [[Inline]] -> State WriterState Doc
+linesToLineBlock :: PandocMonad m => [[Inline]] -> RST m Doc
linesToLineBlock inlineLines = do
lns <- mapM inlineListToRST inlineLines
- return $ (vcat $ map (hang 2 (text "| ")) lns) <> blankline
+ return $
+ vcat (map (hang 2 (text "| ")) lns) <> blankline
-- | Convert list of Pandoc block elements to RST.
-blockListToRST' :: Bool
+blockListToRST' :: PandocMonad m
+ => Bool
-> [Block] -- ^ List of block elements
- -> State WriterState Doc
+ -> RST m Doc
blockListToRST' topLevel blocks = do
+ -- insert comment between list and quoted blocks, see #4248 and #3675
+ let fixBlocks (b1:b2@(BlockQuote _):bs)
+ | toClose b1 = b1 : commentSep : b2 : fixBlocks bs
+ where
+ toClose Plain{} = False
+ toClose Header{} = False
+ toClose LineBlock{} = False
+ toClose HorizontalRule = False
+ toClose (Para [Image _ _ (_,'f':'i':'g':':':_)]) = True
+ toClose Para{} = False
+ toClose _ = True
+ commentSep = RawBlock "rst" "..\n\n"
+ fixBlocks (b:bs) = b : fixBlocks bs
+ fixBlocks [] = []
tl <- gets stTopLevel
modify (\s->s{stTopLevel=topLevel})
- res <- vcat `fmap` mapM blockToRST blocks
+ res <- vcat `fmap` mapM blockToRST (fixBlocks blocks)
modify (\s->s{stTopLevel=tl})
return res
-blockListToRST :: [Block] -- ^ List of block elements
- -> State WriterState Doc
+blockListToRST :: PandocMonad m
+ => [Block] -- ^ List of block elements
+ -> RST m Doc
blockListToRST = blockListToRST' False
-- | Convert list of Pandoc inline elements to RST.
-inlineListToRST :: [Inline] -> State WriterState Doc
+inlineListToRST :: PandocMonad m => [Inline] -> RST m Doc
inlineListToRST lst =
mapM inlineToRST (removeSpaceAfterDisplayMath $ insertBS lst) >>=
return . hcat
@@ -362,7 +388,7 @@ inlineListToRST lst =
removeSpaceAfterDisplayMath [] = []
insertBS :: [Inline] -> [Inline] -- insert '\ ' where needed
insertBS (x:y:z:zs)
- | isComplex y && (surroundComplex x z) =
+ | isComplex y && surroundComplex x z =
x : y : insertBS (z : zs)
insertBS (x:y:zs)
| isComplex x && not (okAfterComplex y) =
@@ -396,23 +422,28 @@ inlineListToRST lst =
okBeforeComplex (Str (c:_)) = isSpace c || c `elem` ("-:/'\"<([{–—" :: String)
okBeforeComplex _ = False
isComplex :: Inline -> Bool
- isComplex (Emph _) = True
- isComplex (Strong _) = True
- isComplex (SmallCaps _) = True
- isComplex (Strikeout _) = True
+ isComplex (Emph _) = True
+ isComplex (Strong _) = True
+ isComplex (SmallCaps _) = True
+ isComplex (Strikeout _) = True
isComplex (Superscript _) = True
- isComplex (Subscript _) = True
- isComplex (Link _ _ _) = True
- isComplex (Image _ _ _) = True
- isComplex (Code _ _) = True
- isComplex (Math _ _) = True
- isComplex (Cite _ (x:_)) = isComplex x
- isComplex (Span _ (x:_)) = isComplex x
- isComplex _ = False
+ isComplex (Subscript _) = True
+ isComplex Link{} = True
+ isComplex Image{} = True
+ isComplex (Code _ _) = True
+ isComplex (Math _ _) = True
+ isComplex (Cite _ (x:_)) = isComplex x
+ isComplex (Span _ (x:_)) = isComplex x
+ isComplex _ = False
-- | Convert Pandoc inline element to RST.
-inlineToRST :: Inline -> State WriterState Doc
-inlineToRST (Span _ ils) = inlineListToRST ils
+inlineToRST :: PandocMonad m => Inline -> RST m Doc
+inlineToRST (Span (_,_,kvs) ils) = do
+ contents <- inlineListToRST ils
+ return $
+ case lookup "role" kvs of
+ Just role -> ":" <> text role <> ":`" <> contents <> "`"
+ Nothing -> contents
inlineToRST (Emph lst) = do
contents <- inlineListToRST lst
return $ "*" <> contents <> "*"
@@ -431,14 +462,33 @@ inlineToRST (Subscript lst) = do
inlineToRST (SmallCaps lst) = inlineListToRST lst
inlineToRST (Quoted SingleQuote lst) = do
contents <- inlineListToRST lst
- return $ "‘" <> contents <> "’"
+ opts <- gets stOptions
+ if isEnabled Ext_smart opts
+ then return $ "'" <> contents <> "'"
+ else return $ "‘" <> contents <> "’"
inlineToRST (Quoted DoubleQuote lst) = do
contents <- inlineListToRST lst
- return $ "“" <> contents <> "”"
+ opts <- gets stOptions
+ if isEnabled Ext_smart opts
+ then return $ "\"" <> contents <> "\""
+ else return $ "“" <> contents <> "”"
inlineToRST (Cite _ lst) =
inlineListToRST lst
-inlineToRST (Code _ str) = return $ "``" <> text str <> "``"
-inlineToRST (Str str) = return $ text $ escapeString str
+inlineToRST (Code _ str) = do
+ opts <- gets stOptions
+ -- we trim the string because the delimiters must adjoin a
+ -- non-space character; see #3496
+ -- we use :literal: when the code contains backticks, since
+ -- :literal: allows backslash-escapes; see #3974
+ return $ if '`' `elem` str
+ then ":literal:`" <> text (escapeString opts (trim str)) <> "`"
+ else "``" <> text (trim str) <> "``"
+inlineToRST (Str str) = do
+ opts <- gets stOptions
+ return $ text $
+ (if isEnabled Ext_smart opts
+ then unsmartify opts
+ else id) $ escapeString opts str
inlineToRST (Math t str) = do
modify $ \st -> st{ stHasMath = True }
return $ if t == InlineMath
@@ -447,20 +497,20 @@ inlineToRST (Math t str) = do
then blankline $$ ".. math::" $$
blankline $$ nest 3 (text str) $$ blankline
else blankline $$ (".. math:: " <> text str) $$ blankline
-inlineToRST (RawInline f x)
+inlineToRST il@(RawInline f x)
| f == "rst" = return $ text x
| f == "latex" || f == "tex" = do
modify $ \st -> st{ stHasRawTeX = True }
return $ ":raw-latex:`" <> text x <> "`"
- | otherwise = return empty
-inlineToRST (LineBreak) = return cr -- there's no line break in RST (see Para)
+ | otherwise = empty <$ report (InlineNotRendered il)
+inlineToRST LineBreak = return cr -- there's no line break in RST (see Para)
inlineToRST Space = return space
inlineToRST SoftBreak = do
- wrapText <- gets (writerWrapText . stOptions)
+ wrapText <- gets $ writerWrapText . stOptions
case wrapText of
- WrapPreserve -> return cr
- WrapAuto -> return space
- WrapNone -> return space
+ WrapPreserve -> return cr
+ WrapAuto -> return space
+ WrapNone -> return space
-- autolink
inlineToRST (Link _ [Str str] (src, _))
| isURI src &&
@@ -473,15 +523,15 @@ inlineToRST (Link _ [Image attr alt (imgsrc,imgtit)] (src, _tit)) = do
label <- registerImage attr alt (imgsrc,imgtit) (Just src)
return $ "|" <> label <> "|"
inlineToRST (Link _ txt (src, tit)) = do
- useReferenceLinks <- get >>= return . writerReferenceLinks . stOptions
- linktext <- inlineListToRST $ normalizeSpaces txt
+ useReferenceLinks <- gets $ writerReferenceLinks . stOptions
+ linktext <- inlineListToRST $ B.toList . B.trimInlines . B.fromList $ txt
if useReferenceLinks
- then do refs <- get >>= return . stLinks
+ then do refs <- gets stLinks
case lookup txt refs of
Just (src',tit') ->
if src == src' && tit == tit'
then return $ "`" <> linktext <> "`_"
- else do -- duplicate label, use non-reference link
+ else
return $ "`" <> linktext <> " <" <> text src <> ">`__"
Nothing -> do
modify $ \st -> st { stLinks = (txt,(src,tit)):refs }
@@ -494,12 +544,12 @@ inlineToRST (Note contents) = do
-- add to notes in state
notes <- gets stNotes
modify $ \st -> st { stNotes = contents:notes }
- let ref = show $ (length notes) + 1
+ let ref = show $ length notes + 1
return $ " [" <> text ref <> "]_"
-registerImage :: Attr -> [Inline] -> Target -> Maybe String -> State WriterState Doc
+registerImage :: PandocMonad m => Attr -> [Inline] -> Target -> Maybe String -> RST m Doc
registerImage attr alt (src,tit) mbtarget = do
- pics <- get >>= return . stImages
+ pics <- gets stImages
txt <- case lookup alt pics of
Just (a,s,t,mbt) | (a,s,t,mbt) == (attr,src,tit,mbtarget)
-> return alt
@@ -512,14 +562,14 @@ registerImage attr alt (src,tit) mbtarget = do
return alt'
inlineListToRST txt
-imageDimsToRST :: Attr -> State WriterState Doc
+imageDimsToRST :: PandocMonad m => Attr -> RST m Doc
imageDimsToRST attr = do
let (ident, _, _) = attr
name = if null ident
then empty
else ":name: " <> text ident
showDim dir = let cols d = ":" <> text (show dir) <> ": " <> text (show d)
- in case (dimension dir attr) of
+ in case dimension dir attr of
Just (Percent a) ->
case dir of
Height -> empty
diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs
index 8f942b4d0..7006b58d1 100644
--- a/src/Text/Pandoc/Writers/RTF.hs
+++ b/src/Text/Pandoc/Writers/RTF.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.RTF
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -27,103 +28,125 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to RTF (rich text format).
-}
-module Text.Pandoc.Writers.RTF ( writeRTF, writeRTFWithEmbeddedImages ) where
+module Text.Pandoc.Writers.RTF ( writeRTF
+ ) where
+import Control.Monad.Except (catchError, throwError)
+import Control.Monad
+import qualified Data.ByteString as B
+import Data.Char (chr, isDigit, ord)
+import Data.List (intercalate, isSuffixOf)
+import qualified Data.Map as M
+import Data.Text (Text)
+import qualified Data.Text as T
+import Text.Pandoc.Class (PandocMonad, report)
+import qualified Text.Pandoc.Class as P
import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
-import Text.Pandoc.Readers.TeXMath
import Text.Pandoc.Templates (renderTemplate')
import Text.Pandoc.Walk
-import Data.List ( isSuffixOf, intercalate )
-import Data.Char ( ord, chr, isDigit )
-import qualified Data.ByteString as B
-import qualified Data.Map as M
-import Text.Printf ( printf )
-import Text.Pandoc.ImageSize
+import Text.Pandoc.Writers.Math
+import Text.Pandoc.Writers.Shared
+import Text.Printf (printf)
-- | Convert Image inlines into a raw RTF embedded image, read from a file,
-- or a MediaBag, or the internet.
-- If file not found or filetype not jpeg or png, leave the inline unchanged.
-rtfEmbedImage :: WriterOptions -> Inline -> IO Inline
-rtfEmbedImage opts x@(Image attr _ (src,_)) = do
- result <- fetchItem' (writerMediaBag opts) (writerSourceURL opts) src
- case result of
- Right (imgdata, Just mime)
- | mime == "image/jpeg" || mime == "image/png" -> do
- let bytes = map (printf "%02x") $ B.unpack imgdata
- let filetype = case mime of
- "image/jpeg" -> "\\jpegblip"
- "image/png" -> "\\pngblip"
- _ -> error "Unknown file type"
- sizeSpec <- case imageSize imgdata of
- Left msg -> do
- warn $ "Could not determine image size in `" ++
- src ++ "': " ++ msg
- return ""
- Right sz -> return $ "\\picw" ++ show xpx ++
- "\\pich" ++ show ypx ++
- "\\picwgoal" ++ show (floor (xpt * 20) :: Integer)
- ++ "\\pichgoal" ++ show (floor (ypt * 20) :: Integer)
- -- twip = 1/1440in = 1/20pt
- where (xpx, ypx) = sizeInPixels sz
- (xpt, ypt) = desiredSizeInPoints opts attr sz
- let raw = "{\\pict" ++ filetype ++ sizeSpec ++ "\\bin " ++
- concat bytes ++ "}"
- return $ if B.null imgdata
- then x
- else RawInline (Format "rtf") raw
- _ -> return x
+rtfEmbedImage :: PandocMonad m => WriterOptions -> Inline -> m Inline
+rtfEmbedImage opts x@(Image attr _ (src,_)) = catchError
+ (do result <- P.fetchItem src
+ case result of
+ (imgdata, Just mime)
+ | mime == "image/jpeg" || mime == "image/png" -> do
+ let bytes = map (printf "%02x") $ B.unpack imgdata
+ filetype <-
+ case mime of
+ "image/jpeg" -> return "\\jpegblip"
+ "image/png" -> return "\\pngblip"
+ _ -> throwError $
+ PandocShouldNeverHappenError $
+ "Unknown file type " ++ mime
+ sizeSpec <-
+ case imageSize opts imgdata of
+ Left msg -> do
+ report $ CouldNotDetermineImageSize src msg
+ return ""
+ Right sz -> return $ "\\picw" ++ show xpx ++
+ "\\pich" ++ show ypx ++
+ "\\picwgoal" ++ show (floor (xpt * 20) :: Integer)
+ ++ "\\pichgoal" ++ show (floor (ypt * 20) :: Integer)
+ -- twip = 1/1440in = 1/20pt
+ where (xpx, ypx) = sizeInPixels sz
+ (xpt, ypt) = desiredSizeInPoints opts attr sz
+ let raw = "{\\pict" ++ filetype ++ sizeSpec ++ "\\bin " ++
+ concat bytes ++ "}"
+ if B.null imgdata
+ then do
+ report $ CouldNotFetchResource src "image contained no data"
+ return x
+ else return $ RawInline (Format "rtf") raw
+ | otherwise -> do
+ report $ CouldNotFetchResource src "image is not a jpeg or png"
+ return x
+ (_, Nothing) -> do
+ report $ CouldNotDetermineMimeType src
+ return x)
+ (\e -> do
+ report $ CouldNotFetchResource src (show e)
+ return x)
rtfEmbedImage _ x = return x
--- | Convert Pandoc to a string in rich text format, with
--- images embedded as encoded binary data.
-writeRTFWithEmbeddedImages :: WriterOptions -> Pandoc -> IO String
-writeRTFWithEmbeddedImages options doc =
- writeRTF options `fmap` walkM (rtfEmbedImage options) doc
-
-- | Convert Pandoc to a string in rich text format.
-writeRTF :: WriterOptions -> Pandoc -> String
-writeRTF options (Pandoc meta@(Meta metamap) blocks) =
+writeRTF :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeRTF options doc = do
+ -- handle images
+ Pandoc meta@(Meta metamap) blocks <- walkM (rtfEmbedImage options) doc
let spacer = not $ all null $ docTitle meta : docDate meta : docAuthors meta
- toPlain (MetaBlocks [Para ils]) = MetaInlines ils
- toPlain x = x
- -- adjust title, author, date so we don't get para inside para
- meta' = Meta $ M.adjust toPlain "title"
+ let toPlain (MetaBlocks [Para ils]) = MetaInlines ils
+ toPlain x = x
+ -- adjust title, author, date so we don't get para inside para
+ let meta' = Meta $ M.adjust toPlain "title"
. M.adjust toPlain "author"
. M.adjust toPlain "date"
$ metamap
- Just metadata = metaToJSON options
- (Just . concatMap (blockToRTF 0 AlignDefault))
- (Just . inlineListToRTF)
+ metadata <- metaToJSON options
+ (fmap concat . mapM (blockToRTF 0 AlignDefault))
+ inlinesToRTF
meta'
- body = concatMap (blockToRTF 0 AlignDefault) blocks
- isTOCHeader (Header lev _ _) = lev <= writerTOCDepth options
- isTOCHeader _ = False
- context = defField "body" body
+ body <- blocksToRTF 0 AlignDefault blocks
+ let isTOCHeader (Header lev _ _) = lev <= writerTOCDepth options
+ isTOCHeader _ = False
+ toc <- tableOfContents $ filter isTOCHeader blocks
+ let context = defField "body" body
$ defField "spacer" spacer
- $ (if writerTableOfContents options
- then defField "toc"
- (tableOfContents $ filter isTOCHeader blocks)
- else id)
- $ metadata
- in case writerTemplate options of
+ $(if writerTableOfContents options
+ then defField "table-of-contents" toc
+ -- for backwards compatibility,
+ -- we populate toc with the contents
+ -- of the toc rather than a boolean:
+ . defField "toc" toc
+ else id) metadata
+ T.pack <$>
+ case writerTemplate options of
Just tpl -> renderTemplate' tpl context
- Nothing -> case reverse body of
+ Nothing -> return $
+ case reverse body of
('\n':_) -> body
_ -> body ++ "\n"
-- | Construct table of contents from list of header blocks.
-tableOfContents :: [Block] -> String
-tableOfContents headers =
- let contentsTree = hierarchicalize headers
- in concatMap (blockToRTF 0 AlignDefault) $
- [Header 1 nullAttr [Str "Contents"],
- BulletList (map elementToListItem contentsTree)]
+tableOfContents :: PandocMonad m => [Block] -> m String
+tableOfContents headers = do
+ let contents = map elementToListItem $ hierarchicalize headers
+ blocksToRTF 0 AlignDefault
+ [Header 1 nullAttr [Str "Contents"], BulletList contents]
elementToListItem :: Element -> [Block]
elementToListItem (Blk _) = []
-elementToListItem (Sec _ _ _ sectext subsecs) = [Plain sectext] ++
+elementToListItem (Sec _ _ _ sectext subsecs) = Plain sectext :
if null subsecs
then []
else [BulletList (map elementToListItem subsecs)]
@@ -140,11 +163,11 @@ handleUnicode (c:cs) =
lower = r + 0xDC00
in enc (chr upper) ++ enc (chr lower) ++ handleUnicode cs
else enc c ++ handleUnicode cs
- else c:(handleUnicode cs)
+ else c:handleUnicode cs
where
surrogate x = not ( (0x0000 <= ord x && ord x <= 0xd7ff)
|| (0xe000 <= ord x && ord x <= 0xffff) )
- enc x = '\\':'u':(show (ord x)) ++ "?"
+ enc x = '\\':'u':show (ord x) ++ "?"
-- | Escape special characters.
escapeSpecial :: String -> String
@@ -175,13 +198,13 @@ rtfParSpaced :: Int -- ^ space after (in twips)
-> String
rtfParSpaced spaceAfter indent firstLineIndent alignment content =
let alignString = case alignment of
- AlignLeft -> "\\ql "
- AlignRight -> "\\qr "
- AlignCenter -> "\\qc "
+ AlignLeft -> "\\ql "
+ AlignRight -> "\\qr "
+ AlignCenter -> "\\qc "
AlignDefault -> "\\ql "
in "{\\pard " ++ alignString ++
- "\\f0 \\sa" ++ (show spaceAfter) ++ " \\li" ++ (show indent) ++
- " \\fi" ++ (show firstLineIndent) ++ " " ++ content ++ "\\par}\n"
+ "\\f0 \\sa" ++ show spaceAfter ++ " \\li" ++ show indent ++
+ " \\fi" ++ show firstLineIndent ++ " " ++ content ++ "\\par}\n"
-- | Default paragraph.
rtfPar :: Int -- ^ block indent (in twips)
@@ -221,143 +244,180 @@ orderedMarkers indent (start, style, delim) =
_ -> orderedListMarkers (start, LowerAlpha, Period)
else orderedListMarkers (start, style, delim)
+blocksToRTF :: PandocMonad m
+ => Int
+ -> Alignment
+ -> [Block]
+ -> m String
+blocksToRTF indent align = fmap concat . mapM (blockToRTF indent align)
+
-- | Convert Pandoc block element to RTF.
-blockToRTF :: Int -- ^ indent level
+blockToRTF :: PandocMonad m
+ => Int -- ^ indent level
-> Alignment -- ^ alignment
-> Block -- ^ block to convert
- -> String
-blockToRTF _ _ Null = ""
+ -> m String
+blockToRTF _ _ Null = return ""
blockToRTF indent alignment (Div _ bs) =
- concatMap (blockToRTF indent alignment) bs
+ blocksToRTF indent alignment bs
blockToRTF indent alignment (Plain lst) =
- rtfCompact indent 0 alignment $ inlineListToRTF lst
+ rtfCompact indent 0 alignment <$> inlinesToRTF lst
blockToRTF indent alignment (Para lst) =
- rtfPar indent 0 alignment $ inlineListToRTF lst
+ rtfPar indent 0 alignment <$> inlinesToRTF lst
blockToRTF indent alignment (LineBlock lns) =
blockToRTF indent alignment $ linesToPara lns
blockToRTF indent alignment (BlockQuote lst) =
- concatMap (blockToRTF (indent + indentIncrement) alignment) lst
+ blocksToRTF (indent + indentIncrement) alignment lst
blockToRTF indent _ (CodeBlock _ str) =
- rtfPar indent 0 AlignLeft ("\\f1 " ++ (codeStringToRTF str))
-blockToRTF _ _ (RawBlock f str)
- | f == Format "rtf" = str
- | otherwise = ""
-blockToRTF indent alignment (BulletList lst) = spaceAtEnd $
- concatMap (listItemToRTF alignment indent (bulletMarker indent)) lst
-blockToRTF indent alignment (OrderedList attribs lst) = spaceAtEnd $ concat $
- zipWith (listItemToRTF alignment indent) (orderedMarkers indent attribs) lst
-blockToRTF indent alignment (DefinitionList lst) = spaceAtEnd $
- concatMap (definitionListItemToRTF alignment indent) lst
-blockToRTF indent _ HorizontalRule =
+ return $ rtfPar indent 0 AlignLeft ("\\f1 " ++ codeStringToRTF str)
+blockToRTF _ _ b@(RawBlock f str)
+ | f == Format "rtf" = return str
+ | otherwise = do
+ report $ BlockNotRendered b
+ return ""
+blockToRTF indent alignment (BulletList lst) = (spaceAtEnd . concat) <$>
+ mapM (listItemToRTF alignment indent (bulletMarker indent)) lst
+blockToRTF indent alignment (OrderedList attribs lst) =
+ (spaceAtEnd . concat) <$>
+ zipWithM (listItemToRTF alignment indent) (orderedMarkers indent attribs) lst
+blockToRTF indent alignment (DefinitionList lst) = (spaceAtEnd . concat) <$>
+ mapM (definitionListItemToRTF alignment indent) lst
+blockToRTF indent _ HorizontalRule = return $
rtfPar indent 0 AlignCenter "\\emdash\\emdash\\emdash\\emdash\\emdash"
-blockToRTF indent alignment (Header level _ lst) = rtfPar indent 0 alignment $
- "\\b \\fs" ++ (show (40 - (level * 4))) ++ " " ++ inlineListToRTF lst
-blockToRTF indent alignment (Table caption aligns sizes headers rows) =
- (if all null headers
- then ""
- else tableRowToRTF True indent aligns sizes headers) ++
- concatMap (tableRowToRTF False indent aligns sizes) rows ++
- rtfPar indent 0 alignment (inlineListToRTF caption)
+blockToRTF indent alignment (Header level _ lst) = do
+ contents <- inlinesToRTF lst
+ return $ rtfPar indent 0 alignment $
+ "\\b \\fs" ++ show (40 - (level * 4)) ++ " " ++ contents
+blockToRTF indent alignment (Table caption aligns sizes headers rows) = do
+ caption' <- inlinesToRTF caption
+ header' <- if all null headers
+ then return ""
+ else tableRowToRTF True indent aligns sizes headers
+ rows' <- concat <$> mapM (tableRowToRTF False indent aligns sizes) rows
+ return $ header' ++ rows' ++ rtfPar indent 0 alignment caption'
-tableRowToRTF :: Bool -> Int -> [Alignment] -> [Double] -> [[Block]] -> String
-tableRowToRTF header indent aligns sizes' cols =
+tableRowToRTF :: PandocMonad m
+ => Bool -> Int -> [Alignment] -> [Double] -> [[Block]] -> m String
+tableRowToRTF header indent aligns sizes' cols = do
let totalTwips = 6 * 1440 -- 6 inches
- sizes = if all (== 0) sizes'
- then take (length cols) $ repeat (1.0 / fromIntegral (length cols))
+ let sizes = if all (== 0) sizes'
+ then replicate (length cols) (1.0 / fromIntegral (length cols))
else sizes'
- columns = concat $ zipWith (tableItemToRTF indent) aligns cols
- rightEdges = tail $ scanl (\sofar new -> sofar + floor (new * totalTwips))
+ columns <- concat <$>
+ zipWithM (tableItemToRTF indent) aligns cols
+ let rightEdges = tail $ scanl (\sofar new -> sofar + floor (new * totalTwips))
(0 :: Integer) sizes
- cellDefs = map (\edge -> (if header
+ let cellDefs = map (\edge -> (if header
then "\\clbrdrb\\brdrs"
else "") ++ "\\cellx" ++ show edge)
rightEdges
- start = "{\n\\trowd \\trgaph120\n" ++ concat cellDefs ++ "\n" ++
+ let start = "{\n\\trowd \\trgaph120\n" ++ concat cellDefs ++ "\n" ++
"\\trkeep\\intbl\n{\n"
- end = "}\n\\intbl\\row}\n"
- in start ++ columns ++ end
+ let end = "}\n\\intbl\\row}\n"
+ return $ start ++ columns ++ end
-tableItemToRTF :: Int -> Alignment -> [Block] -> String
-tableItemToRTF indent alignment item =
- let contents = concatMap (blockToRTF indent alignment) item
- in "{" ++ substitute "\\pard" "\\pard\\intbl" contents ++ "\\cell}\n"
+tableItemToRTF :: PandocMonad m => Int -> Alignment -> [Block] -> m String
+tableItemToRTF indent alignment item = do
+ contents <- blocksToRTF indent alignment item
+ return $ "{" ++ substitute "\\pard" "\\pard\\intbl" contents ++ "\\cell}\n"
-- | Ensure that there's the same amount of space after compact
-- lists as after regular lists.
spaceAtEnd :: String -> String
spaceAtEnd str =
- if isSuffixOf "\\par}\n" str
- then (take ((length str) - 6) str) ++ "\\sa180\\par}\n"
+ if "\\par}\n" `isSuffixOf` str
+ then take (length str - 6) str ++ "\\sa180\\par}\n"
else str
-- | Convert list item (list of blocks) to RTF.
-listItemToRTF :: Alignment -- ^ alignment
+listItemToRTF :: PandocMonad m
+ => Alignment -- ^ alignment
-> Int -- ^ indent level
-> String -- ^ list start marker
-> [Block] -- ^ list item (list of blocks)
- -> [Char]
-listItemToRTF alignment indent marker [] =
- rtfCompact (indent + listIncrement) (0 - listIncrement) alignment
- (marker ++ "\\tx" ++ (show listIncrement) ++ "\\tab ")
-listItemToRTF alignment indent marker list =
- let (first:rest) = map (blockToRTF (indent + listIncrement) alignment) list
- listMarker = "\\fi" ++ show (0 - listIncrement) ++ " " ++ marker ++ "\\tx" ++
- show listIncrement ++ "\\tab"
- insertListMarker ('\\':'f':'i':'-':d:xs) | isDigit d =
+ -> m String
+listItemToRTF alignment indent marker [] = return $
+ rtfCompact (indent + listIncrement) (negate listIncrement) alignment
+ (marker ++ "\\tx" ++ show listIncrement ++ "\\tab ")
+listItemToRTF alignment indent marker list = do
+ (first:rest) <- mapM (blockToRTF (indent + listIncrement) alignment) list
+ let listMarker = "\\fi" ++ show (negate listIncrement) ++ " " ++ marker ++
+ "\\tx" ++ show listIncrement ++ "\\tab"
+ let insertListMarker ('\\':'f':'i':'-':d:xs) | isDigit d =
listMarker ++ dropWhile isDigit xs
insertListMarker ('\\':'f':'i':d:xs) | isDigit d =
listMarker ++ dropWhile isDigit xs
insertListMarker (x:xs) =
x : insertListMarker xs
insertListMarker [] = []
- -- insert the list marker into the (processed) first block
- in insertListMarker first ++ concat rest
+ -- insert the list marker into the (processed) first block
+ return $ insertListMarker first ++ concat rest
-- | Convert definition list item (label, list of blocks) to RTF.
-definitionListItemToRTF :: Alignment -- ^ alignment
+definitionListItemToRTF :: PandocMonad m
+ => Alignment -- ^ alignment
-> Int -- ^ indent level
-> ([Inline],[[Block]]) -- ^ list item (list of blocks)
- -> [Char]
-definitionListItemToRTF alignment indent (label, defs) =
- let labelText = blockToRTF indent alignment (Plain label)
- itemsText = concatMap (blockToRTF (indent + listIncrement) alignment) $
- concat defs
- in labelText ++ itemsText
+ -> m String
+definitionListItemToRTF alignment indent (label, defs) = do
+ labelText <- blockToRTF indent alignment (Plain label)
+ itemsText <- blocksToRTF (indent + listIncrement) alignment (concat defs)
+ return $ labelText ++ itemsText
-- | Convert list of inline items to RTF.
-inlineListToRTF :: [Inline] -- ^ list of inlines to convert
- -> String
-inlineListToRTF lst = concatMap inlineToRTF lst
+inlinesToRTF :: PandocMonad m
+ => [Inline] -- ^ list of inlines to convert
+ -> m String
+inlinesToRTF lst = concat <$> mapM inlineToRTF lst
-- | Convert inline item to RTF.
-inlineToRTF :: Inline -- ^ inline to convert
- -> String
-inlineToRTF (Span _ lst) = inlineListToRTF lst
-inlineToRTF (Emph lst) = "{\\i " ++ (inlineListToRTF lst) ++ "}"
-inlineToRTF (Strong lst) = "{\\b " ++ (inlineListToRTF lst) ++ "}"
-inlineToRTF (Strikeout lst) = "{\\strike " ++ (inlineListToRTF lst) ++ "}"
-inlineToRTF (Superscript lst) = "{\\super " ++ (inlineListToRTF lst) ++ "}"
-inlineToRTF (Subscript lst) = "{\\sub " ++ (inlineListToRTF lst) ++ "}"
-inlineToRTF (SmallCaps lst) = "{\\scaps " ++ (inlineListToRTF lst) ++ "}"
-inlineToRTF (Quoted SingleQuote lst) =
- "\\u8216'" ++ (inlineListToRTF lst) ++ "\\u8217'"
-inlineToRTF (Quoted DoubleQuote lst) =
- "\\u8220\"" ++ (inlineListToRTF lst) ++ "\\u8221\""
-inlineToRTF (Code _ str) = "{\\f1 " ++ (codeStringToRTF str) ++ "}"
-inlineToRTF (Str str) = stringToRTF str
-inlineToRTF (Math t str) = inlineListToRTF $ texMathToInlines t str
-inlineToRTF (Cite _ lst) = inlineListToRTF lst
-inlineToRTF (RawInline f str)
- | f == Format "rtf" = str
- | otherwise = ""
-inlineToRTF (LineBreak) = "\\line "
-inlineToRTF SoftBreak = " "
-inlineToRTF Space = " "
-inlineToRTF (Link _ text (src, _)) =
- "{\\field{\\*\\fldinst{HYPERLINK \"" ++ (codeStringToRTF src) ++
- "\"}}{\\fldrslt{\\ul\n" ++ (inlineListToRTF text) ++ "\n}}}\n"
+inlineToRTF :: PandocMonad m
+ => Inline -- ^ inline to convert
+ -> m String
+inlineToRTF (Span _ lst) = inlinesToRTF lst
+inlineToRTF (Emph lst) = do
+ contents <- inlinesToRTF lst
+ return $ "{\\i " ++ contents ++ "}"
+inlineToRTF (Strong lst) = do
+ contents <- inlinesToRTF lst
+ return $ "{\\b " ++ contents ++ "}"
+inlineToRTF (Strikeout lst) = do
+ contents <- inlinesToRTF lst
+ return $ "{\\strike " ++ contents ++ "}"
+inlineToRTF (Superscript lst) = do
+ contents <- inlinesToRTF lst
+ return $ "{\\super " ++ contents ++ "}"
+inlineToRTF (Subscript lst) = do
+ contents <- inlinesToRTF lst
+ return $ "{\\sub " ++ contents ++ "}"
+inlineToRTF (SmallCaps lst) = do
+ contents <- inlinesToRTF lst
+ return $ "{\\scaps " ++ contents ++ "}"
+inlineToRTF (Quoted SingleQuote lst) = do
+ contents <- inlinesToRTF lst
+ return $ "\\u8216'" ++ contents ++ "\\u8217'"
+inlineToRTF (Quoted DoubleQuote lst) = do
+ contents <- inlinesToRTF lst
+ return $ "\\u8220\"" ++ contents ++ "\\u8221\""
+inlineToRTF (Code _ str) = return $ "{\\f1 " ++ codeStringToRTF str ++ "}"
+inlineToRTF (Str str) = return $ stringToRTF str
+inlineToRTF (Math t str) = texMathToInlines t str >>= inlinesToRTF
+inlineToRTF (Cite _ lst) = inlinesToRTF lst
+inlineToRTF il@(RawInline f str)
+ | f == Format "rtf" = return str
+ | otherwise = do
+ return $ InlineNotRendered il
+ return ""
+inlineToRTF LineBreak = return "\\line "
+inlineToRTF SoftBreak = return " "
+inlineToRTF Space = return " "
+inlineToRTF (Link _ text (src, _)) = do
+ contents <- inlinesToRTF text
+ return $ "{\\field{\\*\\fldinst{HYPERLINK \"" ++ codeStringToRTF src ++
+ "\"}}{\\fldrslt{\\ul\n" ++ contents ++ "\n}}}\n"
inlineToRTF (Image _ _ (source, _)) =
- "{\\cf1 [image: " ++ source ++ "]\\cf0}"
-inlineToRTF (Note contents) =
- "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " ++
- (concatMap (blockToRTF 0 AlignDefault) contents) ++ "}"
+ return $ "{\\cf1 [image: " ++ source ++ "]\\cf0}"
+inlineToRTF (Note contents) = do
+ body <- concat <$> mapM (blockToRTF 0 AlignDefault) contents
+ return $ "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " ++
+ body ++ "}"
diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs
index 845d22077..ae4cc5cc5 100644
--- a/src/Text/Pandoc/Writers/Shared.hs
+++ b/src/Text/Pandoc/Writers/Shared.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Shared
- Copyright : Copyright (C) 2013-2015 John MacFarlane
+ Copyright : Copyright (C) 2013-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,62 +30,91 @@ Shared utility functions for pandoc writers.
-}
module Text.Pandoc.Writers.Shared (
metaToJSON
+ , metaToJSON'
+ , addVariablesToJSON
, getField
, setField
+ , resetField
, defField
, tagWithAttrs
, fixDisplayMath
+ , unsmartify
+ , gridTable
+ , metaValueToInlines
)
where
-import Text.Pandoc.Definition
-import Text.Pandoc.Pretty
-import Text.Pandoc.XML (escapeStringForXML)
-import Control.Monad (liftM)
-import Text.Pandoc.Options (WriterOptions(..))
+import Control.Monad (zipWithM)
+import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (Object),
+ encode, fromJSON)
import qualified Data.HashMap.Strict as H
+import Data.List (groupBy, intersperse, transpose)
import qualified Data.Map as M
+import Data.Maybe (isJust)
import qualified Data.Text as T
-import Data.Aeson (FromJSON(..), fromJSON, ToJSON (..), Value(Object), Result(..), encode)
-import Text.Pandoc.UTF8 (toStringLazy)
import qualified Data.Traversable as Traversable
-import Data.List ( groupBy )
-import Data.Maybe ( isJust )
+import qualified Text.Pandoc.Builder as Builder
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import Text.Pandoc.Pretty
+import Text.Pandoc.Walk (query)
+import Text.Pandoc.UTF8 (toStringLazy)
+import Text.Pandoc.XML (escapeStringForXML)
-- | Create JSON value for template from a 'Meta' and an association list
-- of variables, specified at the command line or in the writer.
-- Variables overwrite metadata fields with the same names.
-- If multiple variables are set with the same name, a list is
--- assigned.
-metaToJSON :: Monad m
+-- assigned. Does nothing if 'writerTemplate' is Nothing.
+metaToJSON :: (Functor m, Monad m, ToJSON a)
=> WriterOptions
- -> ([Block] -> m String)
- -> ([Inline] -> m String)
+ -> ([Block] -> m a)
+ -> ([Inline] -> m a)
-> Meta
-> m Value
-metaToJSON opts blockWriter inlineWriter (Meta metamap)
- | isJust (writerTemplate opts) = do
- let baseContext = foldl (\acc (x,y) -> setField x y acc) (Object H.empty)
- $ writerVariables opts
- renderedMap <- Traversable.mapM
- (metaValueToJSON blockWriter inlineWriter)
- metamap
- let metadata = M.foldWithKey defField baseContext renderedMap
- return $ defField "meta-json" (toStringLazy $ encode metadata) metadata
+metaToJSON opts blockWriter inlineWriter meta
+ | isJust (writerTemplate opts) =
+ addVariablesToJSON opts <$> metaToJSON' blockWriter inlineWriter meta
| otherwise = return (Object H.empty)
-metaValueToJSON :: Monad m
- => ([Block] -> m String)
- -> ([Inline] -> m String)
+-- | Like 'metaToJSON', but does not include variables and is
+-- not sensitive to 'writerTemplate'.
+metaToJSON' :: (Functor m, Monad m, ToJSON a)
+ => ([Block] -> m a)
+ -> ([Inline] -> m a)
+ -> Meta
+ -> m Value
+metaToJSON' blockWriter inlineWriter (Meta metamap) = do
+ renderedMap <- Traversable.mapM
+ (metaValueToJSON blockWriter inlineWriter)
+ metamap
+ return $ M.foldrWithKey defField (Object H.empty) renderedMap
+
+-- | Add variables to JSON object, replacing any existing values.
+-- Also include @meta-json@, a field containing a string representation
+-- of the original JSON object itself, prior to addition of variables.
+addVariablesToJSON :: WriterOptions -> Value -> Value
+addVariablesToJSON opts metadata =
+ foldl (\acc (x,y) -> setField x y acc)
+ (defField "meta-json" (toStringLazy $ encode metadata) (Object mempty))
+ (writerVariables opts)
+ `combineMetadata` metadata
+ where combineMetadata (Object o1) (Object o2) = Object $ H.union o1 o2
+ combineMetadata x _ = x
+
+metaValueToJSON :: (Functor m, Monad m, ToJSON a)
+ => ([Block] -> m a)
+ -> ([Inline] -> m a)
-> MetaValue
-> m Value
-metaValueToJSON blockWriter inlineWriter (MetaMap metamap) = liftM toJSON $
+metaValueToJSON blockWriter inlineWriter (MetaMap metamap) = toJSON <$>
Traversable.mapM (metaValueToJSON blockWriter inlineWriter) metamap
-metaValueToJSON blockWriter inlineWriter (MetaList xs) = liftM toJSON $
+metaValueToJSON blockWriter inlineWriter (MetaList xs) = toJSON <$>
Traversable.mapM (metaValueToJSON blockWriter inlineWriter) xs
metaValueToJSON _ _ (MetaBool b) = return $ toJSON b
-metaValueToJSON _ _ (MetaString s) = return $ toJSON s
-metaValueToJSON blockWriter _ (MetaBlocks bs) = liftM toJSON $ blockWriter bs
-metaValueToJSON _ inlineWriter (MetaInlines bs) = liftM toJSON $ inlineWriter bs
+metaValueToJSON _ inlineWriter (MetaString s) = toJSON <$>
+ inlineWriter (Builder.toList (Builder.text s))
+metaValueToJSON blockWriter _ (MetaBlocks bs) = toJSON <$> blockWriter bs
+metaValueToJSON _ inlineWriter (MetaInlines is) = toJSON <$> inlineWriter is
-- | Retrieve a field value from a JSON object.
getField :: FromJSON a
@@ -111,10 +140,22 @@ setField field val (Object hashmap) =
Object $ H.insertWith combine (T.pack field) (toJSON val) hashmap
where combine newval oldval =
case fromJSON oldval of
- Success xs -> toJSON $ xs ++ [newval]
- _ -> toJSON [oldval, newval]
+ Success xs -> toJSON $ xs ++ [newval]
+ _ -> toJSON [oldval, newval]
setField _ _ x = x
+resetField :: ToJSON a
+ => String
+ -> a
+ -> Value
+ -> Value
+-- | Reset a field of a JSON object. If the field already has a value,
+-- the new value replaces it.
+-- This is a utility function to be used in preparing template contexts.
+resetField field val (Object hashmap) =
+ Object $ H.insert (T.pack field) (toJSON val) hashmap
+resetField _ _ x = x
+
defField :: ToJSON a
=> String
-> a
@@ -148,22 +189,131 @@ isDisplayMath _ = False
stripLeadingTrailingSpace :: [Inline] -> [Inline]
stripLeadingTrailingSpace = go . reverse . go . reverse
- where go (Space:xs) = xs
+ where go (Space:xs) = xs
go (SoftBreak:xs) = xs
- go xs = xs
+ go xs = xs
-- Put display math in its own block (for ODT/DOCX).
fixDisplayMath :: Block -> Block
fixDisplayMath (Plain lst)
| any isDisplayMath lst && not (all isDisplayMath lst) =
-- chop into several paragraphs so each displaymath is its own
- Div ("",["math"],[]) $ map (Plain . stripLeadingTrailingSpace) $
+ Div ("",["math"],[]) $
+ map Plain $
+ filter (not . null) $
+ map stripLeadingTrailingSpace $
groupBy (\x y -> (isDisplayMath x && isDisplayMath y) ||
not (isDisplayMath x || isDisplayMath y)) lst
fixDisplayMath (Para lst)
| any isDisplayMath lst && not (all isDisplayMath lst) =
-- chop into several paragraphs so each displaymath is its own
- Div ("",["math"],[]) $ map (Para . stripLeadingTrailingSpace) $
+ Div ("",["math"],[]) $
+ map Para $
+ filter (not . null) $
+ map stripLeadingTrailingSpace $
groupBy (\x y -> (isDisplayMath x && isDisplayMath y) ||
not (isDisplayMath x || isDisplayMath y)) lst
fixDisplayMath x = x
+
+unsmartify :: WriterOptions -> String -> String
+unsmartify opts ('\8217':xs) = '\'' : unsmartify opts xs
+unsmartify opts ('\8230':xs) = "..." ++ unsmartify opts xs
+unsmartify opts ('\8211':xs)
+ | isEnabled Ext_old_dashes opts = '-' : unsmartify opts xs
+ | otherwise = "--" ++ unsmartify opts xs
+unsmartify opts ('\8212':xs)
+ | isEnabled Ext_old_dashes opts = "--" ++ unsmartify opts xs
+ | otherwise = "---" ++ unsmartify opts xs
+unsmartify opts ('\8220':xs) = '"' : unsmartify opts xs
+unsmartify opts ('\8221':xs) = '"' : unsmartify opts xs
+unsmartify opts ('\8216':xs) = '\'' : unsmartify opts xs
+unsmartify opts (x:xs) = x : unsmartify opts xs
+unsmartify _ [] = []
+
+gridTable :: Monad m
+ => WriterOptions
+ -> (WriterOptions -> [Block] -> m Doc)
+ -> Bool -- ^ headless
+ -> [Alignment]
+ -> [Double]
+ -> [[Block]]
+ -> [[[Block]]]
+ -> m Doc
+gridTable opts blocksToDoc headless aligns widths headers rows = do
+ let numcols = maximum (length aligns : length widths :
+ map length (headers:rows))
+ let handleGivenWidths widths' = do
+ let widthsInChars' = map (
+ (\x -> if x < 1 then 1 else x) .
+ (\x -> x - 3) . floor .
+ (fromIntegral (writerColumns opts) *)
+ ) widths'
+ rawHeaders' <- zipWithM blocksToDoc
+ (map (\w -> opts{writerColumns =
+ min (w - 2) (writerColumns opts)}) widthsInChars')
+ headers
+ rawRows' <- mapM
+ (\cs -> zipWithM blocksToDoc
+ (map (\w -> opts{writerColumns =
+ min (w - 2) (writerColumns opts)}) widthsInChars')
+ cs)
+ rows
+ return (widthsInChars', rawHeaders', rawRows')
+ let handleZeroWidths = do
+ rawHeaders' <- mapM (blocksToDoc opts) headers
+ rawRows' <- mapM (mapM (blocksToDoc opts)) rows
+ let numChars [] = 0
+ numChars xs = maximum . map offset $ xs
+ let widthsInChars' =
+ map numChars $ transpose (rawHeaders' : rawRows')
+ if sum widthsInChars' > writerColumns opts
+ then -- use even widths
+ handleGivenWidths
+ (replicate numcols (1.0 / fromIntegral numcols) :: [Double])
+ else return (widthsInChars', rawHeaders', rawRows')
+ (widthsInChars, rawHeaders, rawRows) <- if all (== 0) widths
+ then handleZeroWidths
+ else handleGivenWidths widths
+ let hpipeBlocks blocks = hcat [beg, middle, end]
+ where h = maximum (1 : map height blocks)
+ sep' = lblock 3 $ vcat (replicate h (text " | "))
+ beg = lblock 2 $ vcat (replicate h (text "| "))
+ end = lblock 2 $ vcat (replicate h (text " |"))
+ middle = chomp $ hcat $ intersperse sep' blocks
+ let makeRow = hpipeBlocks . zipWith lblock widthsInChars
+ let head' = makeRow rawHeaders
+ let rows' = map (makeRow . map chomp) rawRows
+ let borderpart ch align widthInChars =
+ (if align == AlignLeft || align == AlignCenter
+ then char ':'
+ else char ch) <>
+ text (replicate widthInChars ch) <>
+ (if align == AlignRight || align == AlignCenter
+ then char ':'
+ else char ch)
+ let border ch aligns' widthsInChars' =
+ char '+' <>
+ hcat (intersperse (char '+') (zipWith (borderpart ch)
+ aligns' widthsInChars')) <> char '+'
+ let body = vcat $ intersperse (border '-' (repeat AlignDefault) widthsInChars)
+ rows'
+ let head'' = if headless
+ then empty
+ else head' $$ border '=' aligns widthsInChars
+ if headless
+ then return $
+ border '-' aligns widthsInChars $$
+ body $$
+ border '-' (repeat AlignDefault) widthsInChars
+ else return $
+ border '-' (repeat AlignDefault) widthsInChars $$
+ head'' $$
+ body $$
+ border '-' (repeat AlignDefault) widthsInChars
+
+metaValueToInlines :: MetaValue -> [Inline]
+metaValueToInlines (MetaString s) = [Str s]
+metaValueToInlines (MetaInlines ils) = ils
+metaValueToInlines (MetaBlocks bs) = query return bs
+metaValueToInlines (MetaBool b) = [Str $ show b]
+metaValueToInlines _ = []
diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs
index 9bd23ac3b..4936c743e 100644
--- a/src/Text/Pandoc/Writers/TEI.hs
+++ b/src/Text/Pandoc/Writers/TEI.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE OverloadedStrings, PatternGuards #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Docbook
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,63 +30,67 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to Docbook XML.
-}
module Text.Pandoc.Writers.TEI (writeTEI) where
+import Data.Char (toLower)
+import Data.List (isPrefixOf, stripPrefix)
+import Data.Text (Text)
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
-import Text.Pandoc.XML
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
+import Text.Pandoc.Highlighting (languages, languagesByExtension)
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Templates (renderTemplate')
-import Data.List ( stripPrefix, isPrefixOf )
-import Data.Char ( toLower )
-import Text.Pandoc.Highlighting ( languages, languagesByExtension )
import Text.Pandoc.Pretty
-import Text.Pandoc.ImageSize
-import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Shared
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Shared
+import Text.Pandoc.XML
-- | Convert list of authors to a docbook <author> section
-authorToTEI :: WriterOptions -> [Inline] -> B.Inlines
-authorToTEI opts name' =
- let name = render Nothing $ inlinesToTEI opts name'
- colwidth = if writerWrapText opts == WrapAuto
+authorToTEI :: PandocMonad m => WriterOptions -> [Inline] -> m B.Inlines
+authorToTEI opts name' = do
+ name <- render Nothing <$> inlinesToTEI opts name'
+ let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- in B.rawInline "tei" $ render colwidth $
+ return $ B.rawInline "tei" $ render colwidth $
inTagsSimple "author" (text $ escapeStringForXML name)
-- | Convert Pandoc document to string in Docbook format.
-writeTEI :: WriterOptions -> Pandoc -> String
-writeTEI opts (Pandoc meta blocks) =
+writeTEI :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeTEI opts (Pandoc meta blocks) = do
let elements = hierarchicalize blocks
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ render' :: Doc -> Text
render' = render colwidth
startLvl = case writerTopLevelDivision opts of
TopLevelPart -> -1
TopLevelChapter -> 0
TopLevelSection -> 1
TopLevelDefault -> 1
- auths' = map (authorToTEI opts) $ docAuthors meta
- meta' = B.setMeta "author" auths' meta
- Just metadata = metaToJSON opts
- (Just . render colwidth . (vcat .
- (map (elementToTEI opts startLvl)) . hierarchicalize))
- (Just . render colwidth . inlinesToTEI opts)
+ auths' <- mapM (authorToTEI opts) $ docAuthors meta
+ let meta' = B.setMeta "author" auths' meta
+ metadata <- metaToJSON opts
+ (fmap (render' . vcat) .
+ mapM (elementToTEI opts startLvl) . hierarchicalize)
+ (fmap render' . inlinesToTEI opts)
meta'
- main = render' $ vcat (map (elementToTEI opts startLvl) elements)
- context = defField "body" main
- $ defField "mathml" (case writerHTMLMathMethod opts of
- MathML _ -> True
- _ -> False)
- $ metadata
- in case writerTemplate opts of
- Nothing -> main
- Just tpl -> renderTemplate' tpl context
+ main <- (render' . vcat) <$> mapM (elementToTEI opts startLvl) elements
+ let context = defField "body" main
+ $
+ defField "mathml" (case writerHTMLMathMethod opts of
+ MathML -> True
+ _ -> False) metadata
+ case writerTemplate opts of
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
-- | Convert an Element to TEI.
-elementToTEI :: WriterOptions -> Int -> Element -> Doc
+elementToTEI :: PandocMonad m => WriterOptions -> Int -> Element -> m Doc
elementToTEI opts _ (Blk block) = blockToTEI opts block
-elementToTEI opts lvl (Sec _ _num (id',_,_) title elements) =
+elementToTEI opts lvl (Sec _ _num attr title elements) = do
-- TEI doesn't allow sections with no content, so insert some if needed
let elements' = if null elements
then [Blk (Para [])]
@@ -96,14 +101,14 @@ elementToTEI opts lvl (Sec _ _num (id',_,_) title elements) =
| n == 0 -> "chapter"
| n >= 1 && n <= 5 -> "level" ++ show n
| otherwise -> "section"
- in inTags True "div" [("type", divType) | not (null id')] $
--- ("id", writerIdentifierPrefix opts ++ id') | not (null id')] $
- inTagsSimple "head" (inlinesToTEI opts title) $$
- vcat (map (elementToTEI opts (lvl + 1)) elements')
+ contents <- vcat <$> mapM (elementToTEI opts (lvl + 1)) elements'
+ titleContents <- inlinesToTEI opts title
+ return $ inTags True "div" (("type", divType) : idFromAttr opts attr) $
+ inTagsSimple "head" titleContents $$ contents
-- | Convert a list of Pandoc blocks to TEI.
-blocksToTEI :: WriterOptions -> [Block] -> Doc
-blocksToTEI opts = vcat . map (blockToTEI opts)
+blocksToTEI :: PandocMonad m => WriterOptions -> [Block] -> m Doc
+blocksToTEI opts bs = vcat <$> mapM (blockToTEI opts) bs
-- | Auxiliary function to convert Plain block to Para.
plainToPara :: Block -> Block
@@ -112,48 +117,54 @@ plainToPara x = x
-- | Convert a list of pairs of terms and definitions into a TEI
-- list with labels and items.
-deflistItemsToTEI :: WriterOptions -> [([Inline],[[Block]])] -> Doc
+deflistItemsToTEI :: PandocMonad m
+ => WriterOptions -> [([Inline],[[Block]])] -> m Doc
deflistItemsToTEI opts items =
- vcat $ map (\(term, defs) -> deflistItemToTEI opts term defs) items
+ vcat <$> mapM (uncurry (deflistItemToTEI opts)) items
-- | Convert a term and a list of blocks into a TEI varlistentry.
-deflistItemToTEI :: WriterOptions -> [Inline] -> [[Block]] -> Doc
-deflistItemToTEI opts term defs =
- let def' = concatMap (map plainToPara) defs
- in inTagsIndented "label" (inlinesToTEI opts term) $$
- inTagsIndented "item" (blocksToTEI opts def')
+deflistItemToTEI :: PandocMonad m
+ => WriterOptions -> [Inline] -> [[Block]] -> m Doc
+deflistItemToTEI opts term defs = do
+ term' <- inlinesToTEI opts term
+ defs' <- blocksToTEI opts $ concatMap (map plainToPara) defs
+ return $ inTagsIndented "label" term' $$
+ inTagsIndented "item" defs'
-- | Convert a list of lists of blocks to a list of TEI list items.
-listItemsToTEI :: WriterOptions -> [[Block]] -> Doc
-listItemsToTEI opts items = vcat $ map (listItemToTEI opts) items
+listItemsToTEI :: PandocMonad m => WriterOptions -> [[Block]] -> m Doc
+listItemsToTEI opts items = vcat <$> mapM (listItemToTEI opts) items
-- | Convert a list of blocks into a TEI list item.
-listItemToTEI :: WriterOptions -> [Block] -> Doc
+listItemToTEI :: PandocMonad m => WriterOptions -> [Block] -> m Doc
listItemToTEI opts item =
- inTagsIndented "item" $ blocksToTEI opts $ map plainToPara item
+ inTagsIndented "item" <$> blocksToTEI opts (map plainToPara item)
-imageToTEI :: WriterOptions -> Attr -> String -> Doc
-imageToTEI _ attr src = selfClosingTag "graphic" $
- ("url", src) : idAndRole attr ++ dims
+imageToTEI :: PandocMonad m => WriterOptions -> Attr -> String -> m Doc
+imageToTEI opts attr src = return $ selfClosingTag "graphic" $
+ ("url", src) : idFromAttr opts attr ++ dims
where
- dims = go Width "width" ++ go Height "depth"
- go dir dstr = case (dimension dir attr) of
+ dims = go Width "width" ++ go Height "height"
+ go dir dstr = case dimension dir attr of
Just a -> [(dstr, show a)]
Nothing -> []
-- | Convert a Pandoc block element to TEI.
-blockToTEI :: WriterOptions -> Block -> Doc
-blockToTEI _ Null = empty
+blockToTEI :: PandocMonad m => WriterOptions -> Block -> m Doc
+blockToTEI _ Null = return empty
-- Add ids to paragraphs in divs with ids - this is needed for
-- pandoc-citeproc to get link anchors in bibliographies:
-blockToTEI opts (Div (ident,_,_) [Para lst]) =
- let attribs = [("id", ident) | not (null ident)] in
- inTags False "p" attribs $ inlinesToTEI opts lst
+blockToTEI opts (Div attr [Para lst]) = do
+ let attribs = idFromAttr opts attr
+ inTags False "p" attribs <$> inlinesToTEI opts lst
blockToTEI opts (Div _ bs) = blocksToTEI opts $ map plainToPara bs
-blockToTEI _ (Header _ _ _) = empty -- should not occur after hierarchicalize
+blockToTEI _ h@Header{} = do
+ -- should not occur after hierarchicalize, except inside lists/blockquotes
+ report $ BlockNotRendered h
+ return empty
-- For TEI simple, text must be within containing block element, so
--- we use plainToPara to ensure that Plain text ends up contained by
--- something.
+-- we use treat as Para to ensure that Plain text ends up contained by
+-- something:
blockToTEI opts (Plain lst) = blockToTEI opts $ Para lst
-- title beginning with fig: indicates that the image is a figure
--blockToTEI opts (Para [Image attr txt (src,'f':'i':'g':':':_)]) =
@@ -168,13 +179,13 @@ blockToTEI opts (Plain lst) = blockToTEI opts $ Para lst
-- (imageToTEI opts attr src)) $$
-- inTagsSimple "textobject" (inTagsSimple "phrase" alt))
blockToTEI opts (Para lst) =
- inTags False "p" [] $ inlinesToTEI opts lst
+ inTags False "p" [] <$> inlinesToTEI opts lst
blockToTEI opts (LineBlock lns) =
blockToTEI opts $ linesToPara lns
blockToTEI opts (BlockQuote blocks) =
- inTagsIndented "quote" $ blocksToTEI opts blocks
+ inTagsIndented "quote" <$> blocksToTEI opts blocks
blockToTEI _ (CodeBlock (_,classes,_) str) =
- text ("<ab type='codeblock " ++ lang ++ "'>") <> cr <>
+ return $ text ("<ab type='codeblock " ++ lang ++ "'>") <> cr <>
flush (text (escapeStringForXML str) <> cr <> text "</ab>")
where lang = if null langs
then ""
@@ -184,11 +195,11 @@ blockToTEI _ (CodeBlock (_,classes,_) str) =
then [s]
else languagesByExtension . map toLower $ s
langs = concatMap langsFrom classes
-blockToTEI opts (BulletList lst) =
+blockToTEI opts (BulletList lst) = do
let attribs = [("type", "unordered")]
- in inTags True "list" attribs $ listItemsToTEI opts lst
-blockToTEI _ (OrderedList _ []) = empty
-blockToTEI opts (OrderedList (start, numstyle, _) (first:rest)) =
+ inTags True "list" attribs <$> listItemsToTEI opts lst
+blockToTEI _ (OrderedList _ []) = return empty
+blockToTEI opts (OrderedList (start, numstyle, _) (first:rest)) = do
let attribs = case numstyle of
DefaultStyle -> []
Decimal -> [("type", "ordered:arabic")]
@@ -197,127 +208,138 @@ blockToTEI opts (OrderedList (start, numstyle, _) (first:rest)) =
LowerAlpha -> [("type", "ordered:loweralpha")]
UpperRoman -> [("type", "ordered:upperroman")]
LowerRoman -> [("type", "ordered:lowerroman")]
- items = if start == 1
- then listItemsToTEI opts (first:rest)
- else (inTags True "item" [("n",show start)]
- (blocksToTEI opts $ map plainToPara first)) $$
- listItemsToTEI opts rest
- in inTags True "list" attribs items
-blockToTEI opts (DefinitionList lst) =
+ items <- if start == 1
+ then listItemsToTEI opts (first:rest)
+ else do
+ fi <- blocksToTEI opts $ map plainToPara first
+ re <- listItemsToTEI opts rest
+ return $ inTags True "item" [("n",show start)] fi $$ re
+ return $ inTags True "list" attribs items
+blockToTEI opts (DefinitionList lst) = do
let attribs = [("type", "definition")]
- in inTags True "list" attribs $ deflistItemsToTEI opts lst
-blockToTEI _ (RawBlock f str)
- | f == "tei" = text str -- raw TEI block (should such a thing exist).
--- | f == "html" = text str -- allow html for backwards compatibility
- | otherwise = empty
-blockToTEI _ HorizontalRule =
- selfClosingTag "milestone" [("unit","undefined"), ("type","separator"),("rendition","line")]
+ inTags True "list" attribs <$> deflistItemsToTEI opts lst
+blockToTEI _ b@(RawBlock f str)
+ | f == "tei" = return $ text str
+ -- raw TEI block (should such a thing exist).
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
+blockToTEI _ HorizontalRule = return $
+ selfClosingTag "milestone" [("unit","undefined")
+ ,("type","separator")
+ ,("rendition","line")]
-- | TEI Tables
-- TEI Simple's tables are composed of cells and rows; other
-- table info in the AST is here lossily discard.
-blockToTEI opts (Table _ _ _ headers rows) =
- let
- headers' = tableHeadersToTEI opts headers
--- headers' = if all null headers
--- then return empty
--- else tableRowToTEI opts headers
- in
- inTags True "table" [] $
- vcat $ [headers'] <> map (tableRowToTEI opts) rows
+blockToTEI opts (Table _ _ _ headers rows) = do
+ headers' <- tableHeadersToTEI opts headers
+ rows' <- mapM (tableRowToTEI opts) rows
+ return $ inTags True "table" [] $ headers' $$ vcat rows'
-tableRowToTEI :: WriterOptions
- -> [[Block]]
- -> Doc
+tableRowToTEI :: PandocMonad m
+ => WriterOptions
+ -> [[Block]]
+ -> m Doc
tableRowToTEI opts cols =
- inTagsIndented "row" $ vcat $ map (tableItemToTEI opts) cols
+ (inTagsIndented "row" . vcat) <$> mapM (tableItemToTEI opts) cols
-tableHeadersToTEI :: WriterOptions
+tableHeadersToTEI :: PandocMonad m
+ => WriterOptions
-> [[Block]]
- -> Doc
+ -> m Doc
tableHeadersToTEI opts cols =
- inTags True "row" [("role","label")] $ vcat $ map (tableItemToTEI opts) cols
+ (inTags True "row" [("role","label")] . vcat) <$>
+ mapM (tableItemToTEI opts) cols
-tableItemToTEI :: WriterOptions
- -> [Block]
- -> Doc
+tableItemToTEI :: PandocMonad m
+ => WriterOptions
+ -> [Block]
+ -> m Doc
tableItemToTEI opts item =
- inTags False "cell" [] $ vcat $ map (blockToTEI opts) item
+ (inTags False "cell" [] . vcat) <$> mapM (blockToTEI opts) item
-- | Convert a list of inline elements to TEI.
-inlinesToTEI :: WriterOptions -> [Inline] -> Doc
-inlinesToTEI opts lst = hcat $ map (inlineToTEI opts) lst
+inlinesToTEI :: PandocMonad m => WriterOptions -> [Inline] -> m Doc
+inlinesToTEI opts lst = hcat <$> mapM (inlineToTEI opts) lst
-- | Convert an inline element to TEI.
-inlineToTEI :: WriterOptions -> Inline -> Doc
-inlineToTEI _ (Str str) = text $ escapeStringForXML str
+inlineToTEI :: PandocMonad m => WriterOptions -> Inline -> m Doc
+inlineToTEI _ (Str str) = return $ text $ escapeStringForXML str
inlineToTEI opts (Emph lst) =
- inTags False "hi" [("rendition","simple:italic")] $ inlinesToTEI opts lst
+ inTags False "hi" [("rendition","simple:italic")] <$> inlinesToTEI opts lst
inlineToTEI opts (Strong lst) =
- inTags False "hi" [("rendition", "simple:bold")] $ inlinesToTEI opts lst
+ inTags False "hi" [("rendition", "simple:bold")] <$> inlinesToTEI opts lst
inlineToTEI opts (Strikeout lst) =
- inTags False "hi" [("rendition", "simple:strikethrough")] $
+ inTags False "hi" [("rendition", "simple:strikethrough")] <$>
inlinesToTEI opts lst
inlineToTEI opts (Superscript lst) =
- inTags False "hi" [("rendition", "simple:superscript")] $ inlinesToTEI opts lst
+ inTags False "hi" [("rendition", "simple:superscript")] <$>
+ inlinesToTEI opts lst
inlineToTEI opts (Subscript lst) =
- inTags False "hi" [("rendition", "simple:subscript")] $ inlinesToTEI opts lst
+ inTags False "hi" [("rendition", "simple:subscript")] <$>
+ inlinesToTEI opts lst
inlineToTEI opts (SmallCaps lst) =
- inTags False "hi" [("rendition", "simple:smallcaps")] $
- inlinesToTEI opts lst
+ inTags False "hi" [("rendition", "simple:smallcaps")] <$>
+ inlinesToTEI opts lst
inlineToTEI opts (Quoted _ lst) =
- inTagsSimple "quote" $ inlinesToTEI opts lst
+ inTagsSimple "quote" <$> inlinesToTEI opts lst
inlineToTEI opts (Cite _ lst) =
inlinesToTEI opts lst
inlineToTEI opts (Span _ ils) =
inlinesToTEI opts ils
-inlineToTEI _ (Code _ str) =
+inlineToTEI _ (Code _ str) = return $
inTags False "seg" [("type","code")] $ text (escapeStringForXML str)
-- Distinguish display from inline math by wrapping the former in a "figure."
-inlineToTEI _ (Math t str) =
+inlineToTEI _ (Math t str) = return $
case t of
InlineMath -> inTags False "formula" [("notation","TeX")] $
- text (str)
+ text str
DisplayMath -> inTags True "figure" [("type","math")] $
- inTags False "formula" [("notation","TeX")] $ text (str)
+ inTags False "formula" [("notation","TeX")] $ text str
-inlineToTEI _ (RawInline f x) | f == "tei" = text x
- | otherwise = empty
-inlineToTEI _ LineBreak = selfClosingTag "lb" []
-inlineToTEI _ Space = space
+inlineToTEI _ il@(RawInline f x) | f == "tei" = return $ text x
+ | otherwise = empty <$
+ report (InlineNotRendered il)
+inlineToTEI _ LineBreak = return $ selfClosingTag "lb" []
+inlineToTEI _ Space =
+ return space
-- because we use \n for LineBreak, we can't do soft breaks:
-inlineToTEI _ SoftBreak = space
+inlineToTEI _ SoftBreak =
+ return space
inlineToTEI opts (Link attr txt (src, _))
- | Just email <- stripPrefix "mailto:" src =
+ | Just email <- stripPrefix "mailto:" src = do
let emailLink = text $
- escapeStringForXML $ email
- in case txt of
- [Str s] | escapeURI s == email -> emailLink
- _ -> inlinesToTEI opts txt <+>
- char '(' <> emailLink <> char ')'
+ escapeStringForXML email
+ case txt of
+ [Str s] | escapeURI s == email ->
+ return emailLink
+ _ -> do
+ linktext <- inlinesToTEI opts txt
+ return $ linktext <+> char '(' <> emailLink <> char ')'
| otherwise =
- (if isPrefixOf "#" src
- then inTags False "ref" $ ("target", drop 1 src) : idAndRole attr
- else inTags False "ref" $ ("target", src) : idAndRole attr ) $
+ (if "#" `isPrefixOf` src
+ then inTags False "ref" $ ("target", drop 1 src)
+ : idFromAttr opts attr
+ else inTags False "ref" $ ("target", src)
+ : idFromAttr opts attr ) <$>
inlinesToTEI opts txt
-inlineToTEI opts (Image attr description (src, tit)) =
+inlineToTEI opts (Image attr description (src, tit)) = do
let titleDoc = if null tit
then empty
- else inTags False "figDesc" [] (text $ escapeStringForXML tit)
- imageDesc = if null description
- then empty
- else inTags False "head" [] (inlinesToTEI opts description)
- in inTagsIndented "figure" $ imageDesc $$
- imageToTEI opts attr src $$ titleDoc
+ else inTags False "figDesc" []
+ (text $ escapeStringForXML tit)
+ imageDesc <- if null description
+ then return empty
+ else inTags False "head" []
+ <$> inlinesToTEI opts description
+ img <- imageToTEI opts attr src
+ return $ inTagsIndented "figure" $ imageDesc $$ img $$ titleDoc
inlineToTEI opts (Note contents) =
- inTagsIndented "note" $ blocksToTEI opts contents
+ inTagsIndented "note" <$> blocksToTEI opts contents
-idAndRole :: Attr -> [(String, String)]
-idAndRole (id',cls,_) = ident ++ role
- where
- ident = if null id'
- then []
- else [("id", id')]
- role = if null cls
- then []
- else [("role", unwords cls)]
+idFromAttr :: WriterOptions -> Attr -> [(String, String)]
+idFromAttr opts (id',_,_) =
+ if null id'
+ then []
+ else [("xml:id", writerIdentifierPrefix opts ++ id')]
diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs
index f2b9aa15f..bf434642e 100644
--- a/src/Text/Pandoc/Writers/Texinfo.hs
+++ b/src/Text/Pandoc/Writers/Texinfo.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2008-2015 John MacFarlane and Peter Wang
+Copyright (C) 2008-2018 John MacFarlane
+ 2012 Peter Wang
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Texinfo
- Copyright : Copyright (C) 2008-2015 John MacFarlane and Peter Wang
+ Copyright : Copyright (C) 2008-2018 John MacFarlane
+ 2012 Peter Wang
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,21 +31,26 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' format into Texinfo.
-}
module Text.Pandoc.Writers.Texinfo ( writeTexinfo ) where
+import Control.Monad.Except (throwError)
+import Control.Monad.State.Strict
+import Data.Char (chr, ord)
+import Data.List (maximumBy, transpose)
+import Data.Ord (comparing)
+import qualified Data.Set as Set
+import Data.Text (Text)
+import Network.URI (unEscapeString)
+import System.FilePath
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
+import Text.Pandoc.Pretty
import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
import Text.Pandoc.Templates (renderTemplate')
-import Text.Printf ( printf )
-import Data.List ( transpose, maximumBy )
-import Data.Ord ( comparing )
-import Data.Char ( chr, ord )
-import Control.Monad.State
-import Text.Pandoc.Pretty
-import Text.Pandoc.ImageSize
-import Network.URI ( isURI, unEscapeString )
-import System.FilePath
-import qualified Data.Set as Set
+import Text.Pandoc.Writers.Shared
+import Text.Printf (printf)
data WriterState =
WriterState { stStrikeout :: Bool -- document contains strikeout
@@ -59,10 +66,12 @@ data WriterState =
- generated .texi files don't work when run through texi2dvi
-}
+type TI m = StateT WriterState m
+
-- | Convert Pandoc to Texinfo.
-writeTexinfo :: WriterOptions -> Pandoc -> String
+writeTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeTexinfo options document =
- evalState (pandocToTexinfo options $ wrapTop document) $
+ evalStateT (pandocToTexinfo options $ wrapTop document)
WriterState { stStrikeout = False, stSuperscript = False,
stEscapeComma = False, stSubscript = False,
stIdentifiers = Set.empty, stOptions = options}
@@ -72,16 +81,18 @@ wrapTop :: Pandoc -> Pandoc
wrapTop (Pandoc meta blocks) =
Pandoc meta (Header 0 nullAttr (docTitle meta) : blocks)
-pandocToTexinfo :: WriterOptions -> Pandoc -> State WriterState String
+pandocToTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> TI m Text
pandocToTexinfo options (Pandoc meta blocks) = do
let titlePage = not $ all null
$ docTitle meta : docDate meta : docAuthors meta
let colwidth = if writerWrapText options == WrapAuto
then Just $ writerColumns options
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON options
- (fmap (render colwidth) . blockListToTexinfo)
- (fmap (render colwidth) . inlineListToTexinfo)
+ (fmap render' . blockListToTexinfo)
+ (fmap render' . inlineListToTexinfo)
meta
main <- blockListToTexinfo blocks
st <- get
@@ -91,11 +102,11 @@ pandocToTexinfo options (Pandoc meta blocks) = do
$ defField "titlepage" titlePage
$ defField "subscript" (stSubscript st)
$ defField "superscript" (stSuperscript st)
- $ defField "strikeout" (stStrikeout st)
- $ metadata
+ $
+ defField "strikeout" (stStrikeout st) metadata
case writerTemplate options of
Nothing -> return body
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
-- | Escape things as needed for Texinfo.
stringToTexinfo :: String -> String
@@ -110,7 +121,7 @@ stringToTexinfo = escapeStringUsing texinfoEscapes
, ('\x2019', "'")
]
-escapeCommas :: State WriterState Doc -> State WriterState Doc
+escapeCommas :: PandocMonad m => TI m Doc -> TI m Doc
escapeCommas parser = do
oldEscapeComma <- gets stEscapeComma
modify $ \st -> st{ stEscapeComma = True }
@@ -123,8 +134,9 @@ inCmd :: String -> Doc -> Doc
inCmd cmd contents = char '@' <> text cmd <> braces contents
-- | Convert Pandoc block element to Texinfo.
-blockToTexinfo :: Block -- ^ Block to convert
- -> State WriterState Doc
+blockToTexinfo :: PandocMonad m
+ => Block -- ^ Block to convert
+ -> TI m Doc
blockToTexinfo Null = return empty
@@ -154,17 +166,19 @@ blockToTexinfo (BlockQuote lst) = do
contents $$
text "@end quotation"
-blockToTexinfo (CodeBlock _ str) = do
+blockToTexinfo (CodeBlock _ str) =
return $ blankline $$
- text "@verbatim" $$
- flush (text str) $$
- text "@end verbatim" <> blankline
+ text "@verbatim" $$
+ flush (text str) $$
+ text "@end verbatim" <> blankline
-blockToTexinfo (RawBlock f str)
+blockToTexinfo b@(RawBlock f str)
| f == "texinfo" = return $ text str
| f == "latex" || f == "tex" =
return $ text "@tex" $$ text str $$ text "@end tex"
- | otherwise = return empty
+ | otherwise = do
+ report $ BlockNotRendered b
+ return empty
blockToTexinfo (BulletList lst) = do
items <- mapM listItemToTexinfo lst
@@ -204,7 +218,7 @@ blockToTexinfo HorizontalRule =
text "@bigskip@hrule@bigskip" $$
text "@end iftex" $$
text "@ifnottex" $$
- text (take 72 $ repeat '-') $$
+ text (replicate 72 '-') $$
text "@end ifnottex"
blockToTexinfo (Header 0 _ lst) = do
@@ -214,23 +228,27 @@ blockToTexinfo (Header 0 _ lst) = do
return $ text "@node Top" $$
text "@top " <> txt <> blankline
-blockToTexinfo (Header level _ lst) = do
- node <- inlineListForNode lst
- txt <- inlineListToTexinfo lst
- idsUsed <- gets stIdentifiers
- let id' = uniqueIdent lst idsUsed
- modify $ \st -> st{ stIdentifiers = Set.insert id' idsUsed }
- return $ if (level > 0) && (level <= 4)
- then blankline <> text "@node " <> node $$
- text (seccmd level) <> txt $$
- text "@anchor" <> braces (text $ '#':id')
- else txt
- where
- seccmd 1 = "@chapter "
- seccmd 2 = "@section "
- seccmd 3 = "@subsection "
- seccmd 4 = "@subsubsection "
- seccmd _ = error "illegal seccmd level"
+blockToTexinfo (Header level _ lst)
+ | level < 1 || level > 4 = blockToTexinfo (Para lst)
+ | otherwise = do
+ node <- inlineListForNode lst
+ txt <- inlineListToTexinfo lst
+ idsUsed <- gets stIdentifiers
+ let id' = uniqueIdent lst idsUsed
+ modify $ \st -> st{ stIdentifiers = Set.insert id' idsUsed }
+ sec <- seccmd level
+ return $ if (level > 0) && (level <= 4)
+ then blankline <> text "@node " <> node $$
+ text sec <> txt $$
+ text "@anchor" <> braces (text $ '#':id')
+ else txt
+ where
+ seccmd :: PandocMonad m => Int -> TI m String
+ seccmd 1 = return "@chapter "
+ seccmd 2 = return "@section "
+ seccmd 3 = return "@subsection "
+ seccmd 4 = return "@subsubsection "
+ seccmd _ = throwError $ PandocSomeError "illegal seccmd level"
blockToTexinfo (Table caption aligns widths heads rows) = do
headers <- if all null heads
@@ -256,28 +274,32 @@ blockToTexinfo (Table caption aligns widths heads rows) = do
inCmd "caption" captionText $$
text "@end float"
-tableHeadToTexinfo :: [Alignment]
+tableHeadToTexinfo :: PandocMonad m
+ => [Alignment]
-> [[Block]]
- -> State WriterState Doc
+ -> TI m Doc
tableHeadToTexinfo = tableAnyRowToTexinfo "@headitem "
-tableRowToTexinfo :: [Alignment]
+tableRowToTexinfo :: PandocMonad m
+ => [Alignment]
-> [[Block]]
- -> State WriterState Doc
+ -> TI m Doc
tableRowToTexinfo = tableAnyRowToTexinfo "@item "
-tableAnyRowToTexinfo :: String
+tableAnyRowToTexinfo :: PandocMonad m
+ => String
-> [Alignment]
-> [[Block]]
- -> State WriterState Doc
+ -> TI m Doc
tableAnyRowToTexinfo itemtype aligns cols =
zipWithM alignedBlock aligns cols >>=
return . (text itemtype $$) . foldl (\row item -> row $$
(if isEmpty row then empty else text " @tab ") <> item) empty
-alignedBlock :: Alignment
+alignedBlock :: PandocMonad m
+ => Alignment
-> [Block]
- -> State WriterState Doc
+ -> TI m Doc
-- XXX @flushleft and @flushright text won't get word wrapped. Since word
-- wrapping is more important than alignment, we ignore the alignment.
alignedBlock _ = blockListToTexinfo
@@ -292,8 +314,9 @@ alignedBlock _ col = blockListToTexinfo col
-}
-- | Convert Pandoc block elements to Texinfo.
-blockListToTexinfo :: [Block]
- -> State WriterState Doc
+blockListToTexinfo :: PandocMonad m
+ => [Block]
+ -> TI m Doc
blockListToTexinfo [] = return empty
blockListToTexinfo (x:xs) = do
x' <- blockToTexinfo x
@@ -316,8 +339,8 @@ blockListToTexinfo (x:xs) = do
Para _ -> do
xs' <- blockListToTexinfo xs
case xs of
- ((CodeBlock _ _):_) -> return $ x' $$ xs'
- _ -> return $ x' $+$ xs'
+ (CodeBlock _ _:_) -> return $ x' $$ xs'
+ _ -> return $ x' $+$ xs'
_ -> do
xs' <- blockListToTexinfo xs
return $ x' $$ xs'
@@ -335,15 +358,17 @@ collectNodes level (x:xs) =
_ ->
collectNodes level xs
-makeMenuLine :: Block
- -> State WriterState Doc
+makeMenuLine :: PandocMonad m
+ => Block
+ -> TI m Doc
makeMenuLine (Header _ _ lst) = do
txt <- inlineListForNode lst
return $ text "* " <> txt <> text "::"
-makeMenuLine _ = error "makeMenuLine called with non-Header block"
+makeMenuLine _ = throwError $ PandocSomeError "makeMenuLine called with non-Header block"
-listItemToTexinfo :: [Block]
- -> State WriterState Doc
+listItemToTexinfo :: PandocMonad m
+ => [Block]
+ -> TI m Doc
listItemToTexinfo lst = do
contents <- blockListToTexinfo lst
let spacer = case reverse lst of
@@ -351,8 +376,9 @@ listItemToTexinfo lst = do
_ -> empty
return $ text "@item" $$ contents <> spacer
-defListItemToTexinfo :: ([Inline], [[Block]])
- -> State WriterState Doc
+defListItemToTexinfo :: PandocMonad m
+ => ([Inline], [[Block]])
+ -> TI m Doc
defListItemToTexinfo (term, defs) = do
term' <- inlineListToTexinfo term
let defToTexinfo bs = do d <- blockListToTexinfo bs
@@ -363,13 +389,15 @@ defListItemToTexinfo (term, defs) = do
return $ text "@item " <> term' $+$ vcat defs'
-- | Convert list of inline elements to Texinfo.
-inlineListToTexinfo :: [Inline] -- ^ Inlines to convert
- -> State WriterState Doc
+inlineListToTexinfo :: PandocMonad m
+ => [Inline] -- ^ Inlines to convert
+ -> TI m Doc
inlineListToTexinfo lst = mapM inlineToTexinfo lst >>= return . hcat
-- | Convert list of inline elements to Texinfo acceptable for a node name.
-inlineListForNode :: [Inline] -- ^ Inlines to convert
- -> State WriterState Doc
+inlineListForNode :: PandocMonad m
+ => [Inline] -- ^ Inlines to convert
+ -> TI m Doc
inlineListForNode = return . text . stringToTexinfo .
filter (not . disallowedInNode) . stringify
@@ -378,8 +406,9 @@ disallowedInNode :: Char -> Bool
disallowedInNode c = c `elem` (".,:()" :: String)
-- | Convert inline element to Texinfo
-inlineToTexinfo :: Inline -- ^ Inline to convert
- -> State WriterState Doc
+inlineToTexinfo :: PandocMonad m
+ => Inline -- ^ Inline to convert
+ -> TI m Doc
inlineToTexinfo (Span _ lst) =
inlineListToTexinfo lst
@@ -408,7 +437,7 @@ inlineToTexinfo (Subscript lst) = do
inlineToTexinfo (SmallCaps lst) =
inlineListToTexinfo lst >>= return . inCmd "sc"
-inlineToTexinfo (Code _ str) = do
+inlineToTexinfo (Code _ str) =
return $ text $ "@code{" ++ stringToTexinfo str ++ "}"
inlineToTexinfo (Quoted SingleQuote lst) = do
@@ -423,12 +452,14 @@ inlineToTexinfo (Cite _ lst) =
inlineListToTexinfo lst
inlineToTexinfo (Str str) = return $ text (stringToTexinfo str)
inlineToTexinfo (Math _ str) = return $ inCmd "math" $ text str
-inlineToTexinfo (RawInline f str)
+inlineToTexinfo il@(RawInline f str)
| f == "latex" || f == "tex" =
return $ text "@tex" $$ text str $$ text "@end tex"
| f == "texinfo" = return $ text str
- | otherwise = return empty
-inlineToTexinfo (LineBreak) = return $ text "@*" <> cr
+ | otherwise = do
+ report $ InlineNotRendered il
+ return empty
+inlineToTexinfo LineBreak = return $ text "@*" <> cr
inlineToTexinfo SoftBreak = do
wrapText <- gets (writerWrapText . stOptions)
case wrapText of
@@ -441,10 +472,10 @@ inlineToTexinfo (Link _ txt (src@('#':_), _)) = do
contents <- escapeCommas $ inlineListToTexinfo txt
return $ text "@ref" <>
braces (text (stringToTexinfo src) <> text "," <> contents)
-inlineToTexinfo (Link _ txt (src, _)) = do
+inlineToTexinfo (Link _ txt (src, _)) =
case txt of
[Str x] | escapeURI x == src -> -- autolink
- do return $ text $ "@url{" ++ x ++ "}"
+ return $ text $ "@url{" ++ x ++ "}"
_ -> do contents <- escapeCommas $ inlineListToTexinfo txt
let src1 = stringToTexinfo src
return $ text ("@uref{" ++ src1 ++ ",") <> contents <>
@@ -453,7 +484,7 @@ inlineToTexinfo (Link _ txt (src, _)) = do
inlineToTexinfo (Image attr alternate (source, _)) = do
content <- escapeCommas $ inlineListToTexinfo alternate
opts <- gets stOptions
- let showDim dim = case (dimension dim attr) of
+ let showDim dim = case dimension dim attr of
(Just (Pixel a)) -> showInInch opts (Pixel a) ++ "in"
(Just (Percent _)) -> ""
(Just d) -> show d
diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs
index f73876fd2..f46eb43bc 100644
--- a/src/Text/Pandoc/Writers/Textile.hs
+++ b/src/Text/Pandoc/Writers/Textile.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Textile
- Copyright : Copyright (C) 2010-2015 John MacFarlane
+ Copyright : Copyright (C) 2010-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,17 +30,20 @@ Conversion of 'Pandoc' documents to Textile markup.
Textile: <http://thresholdstate.com/articles/4312/the-textile-reference-manual>
-}
module Text.Pandoc.Writers.Textile ( writeTextile ) where
+import Control.Monad.State.Strict
+import Data.Char (isSpace)
+import Data.List (intercalate)
+import Data.Text (Text, pack)
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
+import Text.Pandoc.ImageSize
+import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Shared
import Text.Pandoc.Pretty (render)
-import Text.Pandoc.ImageSize
-import Text.Pandoc.Writers.Shared
+import Text.Pandoc.Shared
import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.XML ( escapeStringForXML )
-import Data.List ( intercalate )
-import Control.Monad.State
-import Data.Char ( isSpace )
+import Text.Pandoc.Writers.Shared
+import Text.Pandoc.XML (escapeStringForXML)
data WriterState = WriterState {
stNotes :: [String] -- Footnotes
@@ -49,29 +52,34 @@ data WriterState = WriterState {
, stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
}
+type TW = StateT WriterState
+
-- | Convert Pandoc to Textile.
-writeTextile :: WriterOptions -> Pandoc -> String
+writeTextile :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeTextile opts document =
- evalState (pandocToTextile opts document)
- WriterState { stNotes = [], stListLevel = [], stStartNum = Nothing,
+ evalStateT (pandocToTextile opts document)
+ WriterState { stNotes = [],
+ stListLevel = [],
+ stStartNum = Nothing,
stUseTags = False }
-- | Return Textile representation of document.
-pandocToTextile :: WriterOptions -> Pandoc -> State WriterState String
+pandocToTextile :: PandocMonad m
+ => WriterOptions -> Pandoc -> TW m Text
pandocToTextile opts (Pandoc meta blocks) = do
metadata <- metaToJSON opts (blockListToTextile opts)
(inlineListToTextile opts) meta
body <- blockListToTextile opts blocks
- notes <- liftM (unlines . reverse . stNotes) get
- let main = body ++ if null notes then "" else ("\n\n" ++ notes)
+ notes <- gets $ unlines . reverse . stNotes
+ let main = pack $ body ++ if null notes then "" else ("\n\n" ++ notes)
let context = defField "body" main metadata
case writerTemplate opts of
- Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Nothing -> return main
+ Just tpl -> renderTemplate' tpl context
-withUseTags :: State WriterState a -> State WriterState a
+withUseTags :: PandocMonad m => TW m a -> TW m a
withUseTags action = do
- oldUseTags <- liftM stUseTags get
+ oldUseTags <- gets stUseTags
modify $ \s -> s { stUseTags = True }
result <- action
modify $ \s -> s { stUseTags = oldUseTags }
@@ -101,9 +109,10 @@ escapeStringForTextile :: String -> String
escapeStringForTextile = concatMap escapeCharForTextile
-- | Convert Pandoc block element to Textile.
-blockToTextile :: WriterOptions -- ^ Options
- -> Block -- ^ Block element
- -> State WriterState String
+blockToTextile :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> Block -- ^ Block element
+ -> TW m String
blockToTextile _ Null = return ""
@@ -123,8 +132,8 @@ blockToTextile opts (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
return $ im ++ "\n" ++ capt
blockToTextile opts (Para inlines) = do
- useTags <- liftM stUseTags get
- listLevel <- liftM stListLevel get
+ useTags <- gets stUseTags
+ listLevel <- gets stListLevel
contents <- inlineListToTextile opts inlines
return $ if useTags
then "<p>" ++ contents ++ "</p>"
@@ -133,9 +142,11 @@ blockToTextile opts (Para inlines) = do
blockToTextile opts (LineBlock lns) =
blockToTextile opts $ linesToPara lns
-blockToTextile _ (RawBlock f str)
+blockToTextile _ b@(RawBlock f str)
| f == Format "html" || f == Format "textile" = return str
- | otherwise = return ""
+ | otherwise = do
+ report $ BlockNotRendered b
+ return ""
blockToTextile _ HorizontalRule = return "<hr />\n"
@@ -211,7 +222,7 @@ blockToTextile opts (Table capt aligns widths headers rows') = do
"<tbody>\n" ++ unlines body' ++ "</tbody>\n</table>\n"
blockToTextile opts x@(BulletList items) = do
- oldUseTags <- liftM stUseTags get
+ oldUseTags <- gets stUseTags
let useTags = oldUseTags || not (isSimpleList x)
if useTags
then do
@@ -219,13 +230,13 @@ blockToTextile opts x@(BulletList items) = do
return $ "<ul>\n" ++ vcat contents ++ "\n</ul>\n"
else do
modify $ \s -> s { stListLevel = stListLevel s ++ "*" }
- level <- get >>= return . length . stListLevel
+ level <- gets $ length . stListLevel
contents <- mapM (listItemToTextile opts) items
modify $ \s -> s { stListLevel = init (stListLevel s) }
return $ vcat contents ++ (if level > 1 then "" else "\n")
blockToTextile opts x@(OrderedList attribs@(start, _, _) items) = do
- oldUseTags <- liftM stUseTags get
+ oldUseTags <- gets stUseTags
let useTags = oldUseTags || not (isSimpleList x)
if useTags
then do
@@ -237,7 +248,7 @@ blockToTextile opts x@(OrderedList attribs@(start, _, _) items) = do
, stStartNum = if start > 1
then Just start
else Nothing }
- level <- get >>= return . length . stListLevel
+ level <- gets $ length . stListLevel
contents <- mapM (listItemToTextile opts) items
modify $ \s -> s { stListLevel = init (stListLevel s),
stStartNum = Nothing }
@@ -261,10 +272,11 @@ listAttribsToString (startnum, numstyle, _) =
else "")
-- | Convert bullet or ordered list item (list of blocks) to Textile.
-listItemToTextile :: WriterOptions -> [Block] -> State WriterState String
+listItemToTextile :: PandocMonad m
+ => WriterOptions -> [Block] -> TW m String
listItemToTextile opts items = do
contents <- blockListToTextile opts items
- useTags <- get >>= return . stUseTags
+ useTags <- gets stUseTags
if useTags
then return $ "<li>" ++ contents ++ "</li>"
else do
@@ -277,14 +289,15 @@ listItemToTextile opts items = do
Nothing -> return $ marker ++ " " ++ contents
-- | Convert definition list item (label, list of blocks) to Textile.
-definitionListItemToTextile :: WriterOptions
+definitionListItemToTextile :: PandocMonad m
+ => WriterOptions
-> ([Inline],[[Block]])
- -> State WriterState String
+ -> TW m String
definitionListItemToTextile opts (label, items) = do
labelText <- inlineListToTextile opts label
contents <- mapM (blockListToTextile opts) items
return $ "<dt>" ++ labelText ++ "</dt>\n" ++
- (intercalate "\n" $ map (\d -> "<dd>" ++ d ++ "</dd>") contents)
+ intercalate "\n" (map (\d -> "<dd>" ++ d ++ "</dd>") contents)
-- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.
isSimpleList :: Block -> Bool
@@ -301,16 +314,16 @@ isSimpleListItem :: [Block] -> Bool
isSimpleListItem [] = True
isSimpleListItem [x] =
case x of
- Plain _ -> True
- Para _ -> True
- BulletList _ -> isSimpleList x
- OrderedList _ _ -> isSimpleList x
- _ -> False
+ Plain _ -> True
+ Para _ -> True
+ BulletList _ -> isSimpleList x
+ OrderedList _ _ -> isSimpleList x
+ _ -> False
isSimpleListItem [x, y] | isPlainOrPara x =
case y of
- BulletList _ -> isSimpleList y
- OrderedList _ _ -> isSimpleList y
- _ -> False
+ BulletList _ -> isSimpleList y
+ OrderedList _ _ -> isSimpleList y
+ _ -> False
isSimpleListItem _ = False
isPlainOrPara :: Block -> Bool
@@ -325,18 +338,19 @@ vcat = intercalate "\n"
-- Auxiliary functions for tables. (TODO: these are common to HTML, MediaWiki,
-- and Textile writers, and should be abstracted out.)
-tableRowToTextile :: WriterOptions
- -> [String]
- -> Int
- -> [[Block]]
- -> State WriterState String
+tableRowToTextile :: PandocMonad m
+ => WriterOptions
+ -> [String]
+ -> Int
+ -> [[Block]]
+ -> TW m String
tableRowToTextile opts alignStrings rownum cols' = do
let celltype = if rownum == 0 then "th" else "td"
let rowclass = case rownum of
- 0 -> "header"
+ 0 -> "header"
x | x `rem` 2 == 1 -> "odd"
- _ -> "even"
- cols'' <- sequence $ zipWith
+ _ -> "even"
+ cols'' <- zipWithM
(\alignment item -> tableItemToTextile opts celltype alignment item)
alignStrings cols'
return $ "<tr class=\"" ++ rowclass ++ "\">\n" ++ unlines cols'' ++ "</tr>"
@@ -348,11 +362,12 @@ alignmentToString alignment = case alignment of
AlignCenter -> "center"
AlignDefault -> "left"
-tableItemToTextile :: WriterOptions
- -> String
- -> String
- -> [Block]
- -> State WriterState String
+tableItemToTextile :: PandocMonad m
+ => WriterOptions
+ -> String
+ -> String
+ -> [Block]
+ -> TW m String
tableItemToTextile opts celltype align' item = do
let mkcell x = "<" ++ celltype ++ " align=\"" ++ align' ++ "\">" ++
x ++ "</" ++ celltype ++ ">"
@@ -360,19 +375,21 @@ tableItemToTextile opts celltype align' item = do
return $ mkcell contents
-- | Convert list of Pandoc block elements to Textile.
-blockListToTextile :: WriterOptions -- ^ Options
- -> [Block] -- ^ List of block elements
- -> State WriterState String
+blockListToTextile :: PandocMonad m
+ => WriterOptions -- ^ Options
+ -> [Block] -- ^ List of block elements
+ -> TW m String
blockListToTextile opts blocks =
mapM (blockToTextile opts) blocks >>= return . vcat
-- | Convert list of Pandoc inline elements to Textile.
-inlineListToTextile :: WriterOptions -> [Inline] -> State WriterState String
+inlineListToTextile :: PandocMonad m
+ => WriterOptions -> [Inline] -> TW m String
inlineListToTextile opts lst =
mapM (inlineToTextile opts) lst >>= return . concat
-- | Convert Pandoc inline element to Textile.
-inlineToTextile :: WriterOptions -> Inline -> State WriterState String
+inlineToTextile :: PandocMonad m => WriterOptions -> Inline -> TW m String
inlineToTextile opts (Span _ lst) =
inlineListToTextile opts lst
@@ -429,13 +446,15 @@ inlineToTextile _ (Str str) = return $ escapeStringForTextile str
inlineToTextile _ (Math _ str) =
return $ "<span class=\"math\">" ++ escapeStringForXML str ++ "</math>"
-inlineToTextile opts (RawInline f str)
+inlineToTextile opts il@(RawInline f str)
| f == Format "html" || f == Format "textile" = return str
| (f == Format "latex" || f == Format "tex") &&
isEnabled Ext_raw_tex opts = return str
- | otherwise = return ""
+ | otherwise = do
+ report $ InlineNotRendered il
+ return ""
-inlineToTextile _ (LineBreak) = return "\n"
+inlineToTextile _ LineBreak = return "\n"
inlineToTextile _ SoftBreak = return " "
@@ -464,7 +483,7 @@ inlineToTextile opts (Image attr@(_, cls, _) alt (source, tit)) = do
then ""
else "(" ++ unwords cls ++ ")"
showDim dir = let toCss str = Just $ show dir ++ ":" ++ str ++ ";"
- in case (dimension dir attr) of
+ in case dimension dir attr of
Just (Percent a) -> toCss $ show (Percent a)
Just dim -> toCss $ showInPixel opts dim ++ "px"
Nothing -> Nothing
@@ -476,7 +495,7 @@ inlineToTextile opts (Image attr@(_, cls, _) alt (source, tit)) = do
return $ "!" ++ classes ++ styles ++ source ++ txt ++ "!"
inlineToTextile opts (Note contents) = do
- curNotes <- liftM stNotes get
+ curNotes <- gets stNotes
let newnum = length curNotes + 1
contents' <- blockListToTextile opts contents
let thisnote = "fn" ++ show newnum ++ ". " ++ contents' ++ "\n"
diff --git a/src/Text/Pandoc/Writers/ZimWiki.hs b/src/Text/Pandoc/Writers/ZimWiki.hs
index 423928c8a..dec1f9d4a 100644
--- a/src/Text/Pandoc/Writers/ZimWiki.hs
+++ b/src/Text/Pandoc/Writers/ZimWiki.hs
@@ -1,5 +1,6 @@
{-
-Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
+ 2017-2018 Alex Ivkin
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,11 +19,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.ZimWiki
- Copyright : Copyright (C) 2008-2015 John MacFarlane, 2016 Alex Ivkin
+ Copyright : Copyright (C) 2008-2018 John MacFarlane, 2017-2018 Alex Ivkin
License : GNU GPL, version 2 or above
Maintainer : Alex Ivkin <alex@ivkin.net>
- Stability : alpha
+ Stability : beta
Portability : portable
Conversion of 'Pandoc' documents to ZimWiki markup.
@@ -31,48 +32,53 @@ http://zim-wiki.org/manual/Help/Wiki_Syntax.html
-}
module Text.Pandoc.Writers.ZimWiki ( writeZimWiki ) where
+import Control.Monad (zipWithM)
+import Control.Monad.State.Strict (StateT, evalStateT, gets, modify)
+import Data.Default (Default (..))
+import Data.List (intercalate, isInfixOf, isPrefixOf, transpose)
+import qualified Data.Map as Map
+import Data.Maybe (fromMaybe)
+import Data.Text (Text, breakOnAll, pack)
+import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
-import Text.Pandoc.Options ( WriterOptions(writerTableOfContents, writerTemplate, writerWrapText), WrapOption(..) )
-import Text.Pandoc.Shared ( escapeURI, linesToPara, removeFormatting, trimr
- , substitute )
-import Text.Pandoc.Writers.Shared ( defField, metaToJSON )
import Text.Pandoc.ImageSize
-import Text.Pandoc.Templates ( renderTemplate' )
-import Data.List ( intercalate, isPrefixOf, transpose, isInfixOf )
-import Data.Text ( breakOnAll, pack )
-import Data.Default (Default(..))
-import Network.URI ( isURI )
-import Control.Monad ( zipWithM )
-import Control.Monad.State ( modify, State, get, evalState )
---import Control.Monad.Reader ( ReaderT, runReaderT, ask, local )
+import Text.Pandoc.Logging
+import Text.Pandoc.Options (WrapOption (..), WriterOptions (writerTableOfContents, writerTemplate, writerWrapText))
+import Text.Pandoc.Shared (escapeURI, isURI, linesToPara, removeFormatting,
+ substitute, trimr)
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Shared (defField, metaToJSON)
data WriterState = WriterState {
- stItemNum :: Int,
- stIndent :: String -- Indent after the marker at the beginning of list items
+ stItemNum :: Int,
+ stIndent :: String, -- Indent after the marker at the beginning of list items
+ stInTable :: Bool, -- Inside a table
+ stInLink :: Bool -- Inside a link description
}
instance Default WriterState where
- def = WriterState { stItemNum = 1, stIndent = "" }
+ def = WriterState { stItemNum = 1, stIndent = "", stInTable = False, stInLink = False }
+
+type ZW = StateT WriterState
-- | Convert Pandoc to ZimWiki.
-writeZimWiki :: WriterOptions -> Pandoc -> String
-writeZimWiki opts document = evalState (pandocToZimWiki opts document) (WriterState 1 "")
+writeZimWiki :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeZimWiki opts document = evalStateT (pandocToZimWiki opts document) def
-- | Return ZimWiki representation of document.
-pandocToZimWiki :: WriterOptions -> Pandoc -> State WriterState String
+pandocToZimWiki :: PandocMonad m => WriterOptions -> Pandoc -> ZW m Text
pandocToZimWiki opts (Pandoc meta blocks) = do
metadata <- metaToJSON opts
(fmap trimr . blockListToZimWiki opts)
(inlineListToZimWiki opts)
meta
- body <- blockListToZimWiki opts blocks
+ body <- pack <$> blockListToZimWiki opts blocks
--let header = "Content-Type: text/x-zim-wiki\nWiki-Format: zim 0.4\n"
let main = body
let context = defField "body" main
- $ defField "toc" (writerTableOfContents opts)
- $ metadata
+ $ defField "toc" (writerTableOfContents opts) metadata
case writerTemplate opts of
- Just tpl -> return $ renderTemplate' tpl context
+ Just tpl -> renderTemplate' tpl context
Nothing -> return main
-- | Escape special characters for ZimWiki.
@@ -83,7 +89,7 @@ escapeString = substitute "__" "''__''" .
substitute "//" "''//''"
-- | Convert Pandoc block element to ZimWiki.
-blockToZimWiki :: WriterOptions -> Block -> State WriterState String
+blockToZimWiki :: PandocMonad m => WriterOptions -> Block -> ZW m String
blockToZimWiki _ Null = return ""
@@ -107,18 +113,20 @@ blockToZimWiki opts (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
return $ "{{" ++ prefix ++ src ++ imageDims opts attr ++ opt ++ "}}\n"
blockToZimWiki opts (Para inlines) = do
- indent <- stIndent <$> get
- -- useTags <- stUseTags <$> get
+ indent <- gets stIndent
+ -- useTags <- gets stUseTags
contents <- inlineListToZimWiki opts inlines
return $ contents ++ if null indent then "\n" else ""
-blockToZimWiki opts (LineBlock lns) = do
+blockToZimWiki opts (LineBlock lns) =
blockToZimWiki opts $ linesToPara lns
-blockToZimWiki opts (RawBlock f str)
+blockToZimWiki opts b@(RawBlock f str)
| f == Format "zimwiki" = return str
- | f == Format "html" = do cont <- indentFromHTML opts str; return cont
- | otherwise = return ""
+ | f == Format "html" = indentFromHTML opts str
+ | otherwise = do
+ report $ BlockNotRendered b
+ return ""
blockToZimWiki _ HorizontalRule = return "\n----\n"
@@ -128,9 +136,13 @@ blockToZimWiki opts (Header level _ inlines) = do
return $ eqs ++ " " ++ contents ++ " " ++ eqs ++ "\n"
blockToZimWiki _ (CodeBlock (_,classes,_) str) = do
+ -- Remap languages into the gtksourceview2 convention that ZimWiki source code plugin is using
+ let langal = [("javascript", "js"), ("bash", "sh"), ("winbatch", "dosbatch")]
+ let langmap = Map.fromList langal
return $ case classes of
- [] -> "'''\n" ++ cleanupCode str ++ "\n'''\n" -- no lang block is a quote block
- (x:_) -> "{{{code: lang=\"" ++ x ++ "\" linenumbers=\"True\"\n" ++ str ++ "\n}}}\n" -- for zim's code plugin, go verbatim on the lang spec
+ [] -> "'''\n" ++ cleanupCode str ++ "\n'''\n" -- turn no lang block into a quote block
+ (x:_) -> "{{{code: lang=\"" ++
+ fromMaybe x (Map.lookup x langmap) ++ "\" linenumbers=\"True\"\n" ++ str ++ "\n}}}\n" -- for zim's code plugin, go verbatim on the lang spec
blockToZimWiki opts (BlockQuote blocks) = do
contents <- blockListToZimWiki opts blocks
@@ -143,12 +155,12 @@ blockToZimWiki opts (Table capt aligns _ headers rows) = do
c <- inlineListToZimWiki opts capt
return $ "" ++ c ++ "\n"
headers' <- if all null headers
- then zipWithM (tableItemToZimWiki opts) aligns (rows !! 0)
- else zipWithM (tableItemToZimWiki opts) aligns headers
+ then zipWithM (tableItemToZimWiki opts) aligns (head rows)
+ else mapM (inlineListToZimWiki opts . removeFormatting)headers -- emphasis, links etc. are not allowed in table headers
rows' <- mapM (zipWithM (tableItemToZimWiki opts) aligns) rows
let widths = map (maximum . map length) $ transpose (headers':rows')
let padTo (width, al) s =
- case (width - length s) of
+ case width - length s of
x | x > 0 ->
if al == AlignLeft || al == AlignDefault
then s ++ replicate x ' '
@@ -157,63 +169,63 @@ blockToZimWiki opts (Table capt aligns _ headers rows) = do
else replicate (x `div` 2) ' ' ++
s ++ replicate (x - x `div` 2) ' '
| otherwise -> s
- let borderCell (width, al) _ =
- if al == AlignLeft
- then ":"++ replicate (width-1) '-'
- else if al == AlignDefault
- then replicate width '-'
- else if al == AlignRight
- then replicate (width-1) '-' ++ ":"
- else ":" ++ replicate (width-2) '-' ++ ":"
+ let borderCell (width, al) _
+ | al == AlignLeft = ":"++ replicate (width-1) '-'
+ | al == AlignDefault = replicate width '-'
+ | al == AlignRight = replicate (width-1) '-' ++ ":"
+ | otherwise = ":" ++ replicate (width-2) '-' ++ ":"
let underheader = "|" ++ intercalate "|" (zipWith borderCell (zip widths aligns) headers') ++ "|"
- let renderRow sep cells = sep ++ intercalate sep (zipWith padTo (zip widths aligns) cells) ++ sep
+ let renderRow cells = "|" ++ intercalate "|" (zipWith padTo (zip widths aligns) cells) ++ "|"
return $ captionDoc ++
- (if null headers' then "" else renderRow "|" headers' ++ "\n") ++ underheader ++ "\n" ++
- unlines (map (renderRow "|") rows')
+ (if null headers' then "" else renderRow headers' ++ "\n") ++ underheader ++ "\n" ++
+ unlines (map renderRow rows')
blockToZimWiki opts (BulletList items) = do
- indent <- stIndent <$> get
+ indent <- gets stIndent
modify $ \s -> s { stIndent = stIndent s ++ "\t" }
- contents <- (mapM (listItemToZimWiki opts) items)
+ contents <- mapM (listItemToZimWiki opts) items
modify $ \s -> s{ stIndent = indent } -- drop 1 (stIndent s) }
return $ vcat contents ++ if null indent then "\n" else ""
blockToZimWiki opts (OrderedList _ items) = do
- indent <- stIndent <$> get
+ indent <- gets stIndent
modify $ \s -> s { stIndent = stIndent s ++ "\t", stItemNum = 1 }
- contents <- (mapM (orderedListItemToZimWiki opts) items)
+ contents <- mapM (orderedListItemToZimWiki opts) items
modify $ \s -> s{ stIndent = indent } -- drop 1 (stIndent s) }
return $ vcat contents ++ if null indent then "\n" else ""
blockToZimWiki opts (DefinitionList items) = do
- contents <- (mapM (definitionListItemToZimWiki opts) items)
+ contents <- mapM (definitionListItemToZimWiki opts) items
return $ vcat contents
-definitionListItemToZimWiki :: WriterOptions -> ([Inline],[[Block]]) -> State WriterState String
+definitionListItemToZimWiki :: PandocMonad m
+ => WriterOptions
+ -> ([Inline],[[Block]])
+ -> ZW m String
definitionListItemToZimWiki opts (label, items) = do
labelText <- inlineListToZimWiki opts label
contents <- mapM (blockListToZimWiki opts) items
- indent <- stIndent <$> get
+ indent <- gets stIndent
return $ indent ++ "* **" ++ labelText ++ "** " ++ concat contents
-- Auxiliary functions for lists:
-indentFromHTML :: WriterOptions -> String -> State WriterState String
+indentFromHTML :: PandocMonad m => WriterOptions -> String -> ZW m String
indentFromHTML _ str = do
- indent <- stIndent <$> get
- itemnum <- stItemNum <$> get
- if isInfixOf "<li>" str then return $ indent ++ show itemnum ++ "."
- else if isInfixOf "</li>" str then return "\n"
- else if isInfixOf "<li value=" str then do
+ indent <- gets stIndent
+ itemnum <- gets stItemNum
+ if "<li>" `isInfixOf` str then return $ indent ++ show itemnum ++ "."
+ else if "</li>" `isInfixOf` str then return "\n"
+ else if "<li value=" `isInfixOf` str then do
-- poor man's cut
let val = drop 10 $ reverse $ drop 1 $ reverse str
--let val = take ((length valls) - 2) valls
modify $ \s -> s { stItemNum = read val }
return ""
- else if isInfixOf "<ol>" str then do
+ else if "<ol>" `isInfixOf` str then do
let olcount=countSubStrs "<ol>" str
modify $ \s -> s { stIndent = stIndent s ++ replicate olcount '\t', stItemNum = 1 }
return ""
- else if isInfixOf "</ol>" str then do
+ else if "</ol>" `isInfixOf` str then do
let olcount=countSubStrs "/<ol>" str
modify $ \s -> s{ stIndent = drop olcount (stIndent s) }
return ""
@@ -230,23 +242,25 @@ vcat :: [String] -> String
vcat = intercalate "\n"
-- | Convert bullet list item (list of blocks) to ZimWiki.
-listItemToZimWiki :: WriterOptions -> [Block] -> State WriterState String
+listItemToZimWiki :: PandocMonad m => WriterOptions -> [Block] -> ZW m String
listItemToZimWiki opts items = do
contents <- blockListToZimWiki opts items
- indent <- stIndent <$> get
+ indent <- gets stIndent
return $ indent ++ "* " ++ contents
-- | Convert ordered list item (list of blocks) to ZimWiki.
-orderedListItemToZimWiki :: WriterOptions -> [Block] -> State WriterState String
+orderedListItemToZimWiki :: PandocMonad m
+ => WriterOptions -> [Block] -> ZW m String
orderedListItemToZimWiki opts items = do
contents <- blockListToZimWiki opts items
- indent <- stIndent <$> get
- itemnum <- stItemNum <$> get
+ indent <- gets stIndent
+ itemnum <- gets stItemNum
--modify $ \s -> s { stItemNum = itemnum + 1 } -- this is not strictly necessary for zim as zim does its own renumbering
return $ indent ++ show itemnum ++ ". " ++ contents
-- Auxiliary functions for tables:
-tableItemToZimWiki :: WriterOptions -> Alignment -> [Block] -> State WriterState String
+tableItemToZimWiki :: PandocMonad m
+ => WriterOptions -> Alignment -> [Block] -> ZW m String
tableItemToZimWiki opts align' item = do
let mkcell x = (if align' == AlignRight || align' == AlignCenter
then " "
@@ -254,19 +268,24 @@ tableItemToZimWiki opts align' item = do
(if align' == AlignLeft || align' == AlignCenter
then " "
else "")
- contents <- blockListToZimWiki opts item -- local (\s -> s { stBackSlashLB = True }) $
+ modify $ \s -> s { stInTable = True }
+ contents <- blockListToZimWiki opts item
+ modify $ \s -> s { stInTable = False }
return $ mkcell contents
-- | Convert list of Pandoc block elements to ZimWiki.
-blockListToZimWiki :: WriterOptions -> [Block] -> State WriterState String
+blockListToZimWiki :: PandocMonad m
+ => WriterOptions -> [Block] -> ZW m String
blockListToZimWiki opts blocks = vcat <$> mapM (blockToZimWiki opts) blocks
-- | Convert list of Pandoc inline elements to ZimWiki.
-inlineListToZimWiki :: WriterOptions -> [Inline] -> State WriterState String
-inlineListToZimWiki opts lst = concat <$> (mapM (inlineToZimWiki opts) lst)
+inlineListToZimWiki :: PandocMonad m
+ => WriterOptions -> [Inline] -> ZW m String
+inlineListToZimWiki opts lst = concat <$> mapM (inlineToZimWiki opts) lst
-- | Convert Pandoc inline element to ZimWiki.
-inlineToZimWiki :: WriterOptions -> Inline -> State WriterState String
+inlineToZimWiki :: PandocMonad m
+ => WriterOptions -> Inline -> ZW m String
inlineToZimWiki opts (Emph lst) = do
contents <- inlineListToZimWiki opts lst
@@ -304,7 +323,15 @@ inlineToZimWiki opts (Cite _ lst) = inlineListToZimWiki opts lst
inlineToZimWiki _ (Code _ str) = return $ "''" ++ str ++ "''"
-inlineToZimWiki _ (Str str) = return $ escapeString str
+inlineToZimWiki _ (Str str) = do
+ inTable <- gets stInTable
+ inLink <- gets stInLink
+ if inTable
+ then return $ substitute "|" "\\|" . escapeString $ str
+ else
+ if inLink
+ then return str
+ else return $ escapeString str
inlineToZimWiki _ (Math mathType str) = return $ delim ++ str ++ delim -- note: str should NOT be escaped
where delim = case mathType of
@@ -312,12 +339,18 @@ inlineToZimWiki _ (Math mathType str) = return $ delim ++ str ++ delim -- note
InlineMath -> "$"
-- | f == Format "html" = return $ "<html>" ++ str ++ "</html>"
-inlineToZimWiki opts (RawInline f str)
+inlineToZimWiki opts il@(RawInline f str)
| f == Format "zimwiki" = return str
- | f == Format "html" = do cont <- indentFromHTML opts str; return cont
- | otherwise = return ""
+ | f == Format "html" = indentFromHTML opts str
+ | otherwise = do
+ report $ InlineNotRendered il
+ return ""
-inlineToZimWiki _ (LineBreak) = return "\n" -- was \\\\
+inlineToZimWiki _ LineBreak = do
+ inTable <- gets stInTable
+ if inTable
+ then return "\\n"
+ else return "\n"
inlineToZimWiki opts SoftBreak =
case writerWrapText opts of
@@ -328,37 +361,45 @@ inlineToZimWiki opts SoftBreak =
inlineToZimWiki _ Space = return " "
inlineToZimWiki opts (Link _ txt (src, _)) = do
- label <- inlineListToZimWiki opts txt
+ inTable <- gets stInTable
+ modify $ \s -> s { stInLink = True }
+ label <- inlineListToZimWiki opts $ removeFormatting txt -- zim does not allow formatting in link text, it takes the text verbatim, no need to escape it
+ modify $ \s -> s { stInLink = False }
+ let label'= if inTable
+ then "" -- no label is allowed in a table
+ else "|"++label
case txt of
[Str s] | "mailto:" `isPrefixOf` src -> return $ "<" ++ s ++ ">"
| escapeURI s == src -> return src
_ -> if isURI src
- then return $ "[[" ++ src ++ "|" ++ label ++ "]]"
- else return $ "[[" ++ src' ++ "|" ++ label ++ "]]"
+ then return $ "[[" ++ src ++ label' ++ "]]"
+ else return $ "[[" ++ src' ++ label' ++ "]]"
where src' = case src of
'/':xs -> xs -- with leading / it's a
_ -> src -- link to a help page
inlineToZimWiki opts (Image attr alt (source, tit)) = do
alt' <- inlineListToZimWiki opts alt
- let txt = case (tit, alt) of
- ("", []) -> ""
- ("", _ ) -> "|" ++ alt'
- (_ , _ ) -> "|" ++ tit
+ inTable <- gets stInTable
+ let txt = case (tit, alt, inTable) of
+ ("",[], _) -> ""
+ ("", _, False ) -> "|" ++ alt'
+ (_ , _, False ) -> "|" ++ tit
+ (_ , _, True ) -> ""
-- Relative links fail isURI and receive a colon
prefix = if isURI source then "" else ":"
return $ "{{" ++ prefix ++ source ++ imageDims opts attr ++ txt ++ "}}"
inlineToZimWiki opts (Note contents) = do
+ -- no concept of notes in zim wiki, use a text block
contents' <- blockListToZimWiki opts contents
- return $ "((" ++ contents' ++ "))"
- -- note - may not work for notes with multiple blocks
+ return $ " **{Note:** " ++ trimr contents' ++ "**}**"
imageDims :: WriterOptions -> Attr -> String
imageDims opts attr = go (toPx $ dimension Width attr) (toPx $ dimension Height attr)
where
toPx = fmap (showInPixel opts) . checkPct
checkPct (Just (Percent _)) = Nothing
- checkPct maybeDim = maybeDim
+ checkPct maybeDim = maybeDim
go (Just w) Nothing = "?" ++ w
go (Just w) (Just h) = "?" ++ w ++ "x" ++ h
go Nothing (Just h) = "?0x" ++ h
diff --git a/src/Text/Pandoc/XML.hs b/src/Text/Pandoc/XML.hs
index e105aee91..62874f0b9 100644
--- a/src/Text/Pandoc/XML.hs
+++ b/src/Text/Pandoc/XML.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.XML
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -36,18 +36,20 @@ module Text.Pandoc.XML ( escapeCharForXML,
toEntities,
fromEntities ) where
-import Text.Pandoc.Pretty
-import Data.Char (ord, isAscii, isSpace)
+import Data.Char (isAscii, isSpace, ord)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.HTML.TagSoup.Entity (lookupEntity)
+import Text.Pandoc.Pretty
-- | Escape one character as needed for XML.
escapeCharForXML :: Char -> String
escapeCharForXML x = case x of
- '&' -> "&amp;"
- '<' -> "&lt;"
- '>' -> "&gt;"
- '"' -> "&quot;"
- c -> [c]
+ '&' -> "&amp;"
+ '<' -> "&lt;"
+ '>' -> "&gt;"
+ '"' -> "&quot;"
+ c -> [c]
-- | Escape string as needed for XML. Entity references are not preserved.
escapeStringForXML :: String -> String
@@ -91,11 +93,10 @@ inTagsIndented :: String -> Doc -> Doc
inTagsIndented tagType = inTags True tagType []
-- | Escape all non-ascii characters using numerical entities.
-toEntities :: String -> String
-toEntities [] = ""
-toEntities (c:cs)
- | isAscii c = c : toEntities cs
- | otherwise = "&#" ++ show (ord c) ++ ";" ++ toEntities cs
+toEntities :: Text -> Text
+toEntities = T.concatMap go
+ where go c | isAscii c = T.singleton c
+ | otherwise = T.pack ("&#" ++ show (ord c) ++ ";")
-- Unescapes XML entities
fromEntities :: String -> String
@@ -108,8 +109,8 @@ fromEntities ('&':xs) =
(zs, ys) -> (zs,ys)
ent' = case ent of
'#':'X':ys -> '#':'x':ys -- workaround tagsoup bug
- '#':_ -> ent
- _ -> ent ++ ";"
+ '#':_ -> ent
+ _ -> ent ++ ";"
fromEntities (x:xs) = x : fromEntities xs
fromEntities [] = []
diff --git a/stack.yaml b/stack.yaml
index 7d5fc84b9..16d12088a 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,14 +1,25 @@
flags:
pandoc:
trypandoc: false
- https: true
- embed_data_files: false
+ embed_data_files: true
old-locale: false
network-uri: true
+ pandoc-citeproc:
+ bibutils: true
+ embed_data_files: true
+ unicode_collation: false
+ test_citeproc: false
+ debug: false
packages:
- '.'
extra-deps:
-- pandoc-types-1.17.0.5
-- skylighting-0.1.1.5
-- texmath-0.9
-resolver: lts-9.2
+- pandoc-citeproc-0.14.1.5
+- hslua-0.9.5
+- skylighting-0.6
+- ansi-terminal-0.7.1.1
+- tasty-1.0.0.1
+- texmath-0.10.1.1
+- tagsoup-0.14.6
+ghc-options:
+ "$locals": -fhide-source-paths
+resolver: lts-10.3
diff --git a/test/Tests/Command.hs b/test/Tests/Command.hs
new file mode 100644
index 000000000..de83d0639
--- /dev/null
+++ b/test/Tests/Command.hs
@@ -0,0 +1,95 @@
+module Tests.Command (findPandoc, runTest, tests)
+where
+
+import Data.Algorithm.Diff
+import qualified Data.ByteString as BS
+import Data.List (isSuffixOf)
+import Prelude hiding (readFile)
+import System.Directory
+import System.Exit
+import System.FilePath (joinPath, splitDirectories, takeDirectory, (</>))
+import System.IO (hPutStr, stderr)
+import System.IO.Unsafe (unsafePerformIO)
+import System.Process
+import Test.Tasty
+import Test.Tasty.HUnit
+import Tests.Helpers
+import Text.Pandoc
+import qualified Text.Pandoc.UTF8 as UTF8
+
+-- | Run a test with normalize function, return True if test passed.
+runTest :: String -- ^ Title of test
+ -> FilePath -- ^ Path to pandoc
+ -> String -- ^ Shell command
+ -> String -- ^ Input text
+ -> String -- ^ Expected output
+ -> TestTree
+runTest testname pandocpath cmd inp norm = testCase testname $ do
+ let findDynlibDir [] = Nothing
+ findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build"
+ findDynlibDir (_:xs) = findDynlibDir xs
+ let mbDynlibDir = findDynlibDir (reverse $ splitDirectories $
+ takeDirectory $ takeWhile (/=' ') cmd)
+ let dynlibEnv = case mbDynlibDir of
+ Nothing -> []
+ Just d -> [("DYLD_LIBRARY_PATH", d),
+ ("LD_LIBRARY_PATH", d)]
+ let env' = dynlibEnv ++ [("PATH",takeDirectory pandocpath),("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./"),("pandoc_datadir", "..")]
+ let pr = (shell cmd){ env = Just env' }
+ (ec, out', err') <- readCreateProcessWithExitCode pr inp
+ -- filter \r so the tests will work on Windows machines
+ let out = filter (/= '\r') $ err' ++ out'
+ result <- if ec == ExitSuccess
+ then
+ if out == norm
+ then return TestPassed
+ else return
+ $ TestFailed cmd "expected"
+ $ getDiff (lines out) (lines norm)
+ else do
+ hPutStr stderr err'
+ return $ TestError ec
+ assertBool (show result) (result == TestPassed)
+
+tests :: TestTree
+{-# NOINLINE tests #-}
+tests = unsafePerformIO $ do
+ pandocpath <- findPandoc
+ files <- filter (".md" `isSuffixOf`) <$>
+ getDirectoryContents "command"
+ let cmds = map (extractCommandTest pandocpath) files
+ return $ testGroup "Command:" cmds
+
+isCodeBlock :: Block -> Bool
+isCodeBlock (CodeBlock _ _) = True
+isCodeBlock _ = False
+
+extractCode :: Block -> String
+extractCode (CodeBlock _ code) = code
+extractCode _ = ""
+
+dropPercent :: String -> String
+dropPercent ('%':xs) = dropWhile (== ' ') xs
+dropPercent xs = xs
+
+runCommandTest :: FilePath -> (Int, String) -> TestTree
+runCommandTest pandocpath (num, code) =
+ let codelines = lines code
+ (continuations, r1) = span ("\\" `isSuffixOf`) codelines
+ (cmd, r2) = (dropPercent (unwords (map init continuations ++ take 1 r1)),
+ drop 1 r1)
+ (inplines, r3) = break (=="^D") r2
+ normlines = takeWhile (/=".") (drop 1 r3)
+ input = unlines inplines
+ norm = unlines normlines
+ shcmd = cmd -- trimr $ takeDirectory pandocpath </> cmd
+ in runTest ("#" ++ show num) pandocpath shcmd input norm
+
+extractCommandTest :: FilePath -> FilePath -> TestTree
+extractCommandTest pandocpath fp = unsafePerformIO $ do
+ contents <- UTF8.toText <$> BS.readFile ("command" </> fp)
+ Pandoc _ blocks <- runIOorExplode (readMarkdown
+ def{ readerExtensions = pandocExtensions } contents)
+ let codeblocks = map extractCode $ filter isCodeBlock blocks
+ let cases = map (runCommandTest pandocpath) $ zip [1..] codeblocks
+ return $ testGroup fp cases
diff --git a/test/Tests/Helpers.hs b/test/Tests/Helpers.hs
new file mode 100644
index 000000000..2a6543ea0
--- /dev/null
+++ b/test/Tests/Helpers.hs
@@ -0,0 +1,138 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+-- Utility functions for the test suite.
+
+module Tests.Helpers ( test
+ , TestResult(..)
+ , showDiff
+ , findPandoc
+ , (=?>)
+ , purely
+ , ToString(..)
+ , ToPandoc(..)
+ )
+ where
+
+import Data.Algorithm.Diff
+import qualified Data.Map as M
+import Data.Text (Text, unpack)
+import System.Directory
+import System.Environment.Executable (getExecutablePath)
+import System.Exit
+import System.FilePath
+import Test.Tasty
+import Test.Tasty.HUnit
+import Text.Pandoc.Builder (Blocks, Inlines, doc, plain)
+import Text.Pandoc.Class
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import Text.Pandoc.Shared (trimr)
+import Text.Pandoc.Writers.Native (writeNative)
+import Text.Printf
+
+test :: (ToString a, ToString b, ToString c)
+ => (a -> b) -- ^ function to test
+ -> String -- ^ name of test case
+ -> (a, c) -- ^ (input, expected value)
+ -> TestTree
+test fn name (input, expected) =
+ testCase name' $ assertBool msg (actual' == expected')
+ where msg = nl ++ dashes "input" ++ nl ++ input' ++ nl ++
+ dashes "result" ++ nl ++
+ unlines (map vividize diff) ++
+ dashes ""
+ nl = "\n"
+ name' = if length name > 54
+ then take 52 name ++ "..." -- avoid wide output
+ else name
+ input' = toString input
+ actual' = lines $ toString $ fn input
+ expected' = lines $ toString expected
+ diff = getDiff expected' actual'
+ dashes "" = replicate 72 '-'
+ dashes x = replicate (72 - length x - 5) '-' ++ " " ++ x ++ " ---"
+
+data TestResult = TestPassed
+ | TestError ExitCode
+ | TestFailed String FilePath [Diff String]
+ deriving (Eq)
+
+instance Show TestResult where
+ show TestPassed = "PASSED"
+ show (TestError ec) = "ERROR " ++ show ec
+ show (TestFailed cmd file d) = '\n' : dash ++
+ "\n--- " ++ file ++
+ "\n+++ " ++ cmd ++ "\n" ++ showDiff (1,1) d ++
+ dash
+ where dash = replicate 72 '-'
+
+showDiff :: (Int,Int) -> [Diff String] -> String
+showDiff _ [] = ""
+showDiff (l,r) (First ln : ds) =
+ printf "+%4d " l ++ ln ++ "\n" ++ showDiff (l+1,r) ds
+showDiff (l,r) (Second ln : ds) =
+ printf "-%4d " r ++ ln ++ "\n" ++ showDiff (l,r+1) ds
+showDiff (l,r) (Both _ _ : ds) =
+ showDiff (l+1,r+1) ds
+
+-- | Find pandoc executable relative to test-pandoc
+-- First, try in same directory (e.g. if both in ~/.cabal/bin)
+-- Second, try ../pandoc (e.g. if in dist/XXX/build/test-pandoc)
+findPandoc :: IO FilePath
+findPandoc = do
+ testExePath <- getExecutablePath
+ let testExeDir = takeDirectory testExePath
+ found <- doesFileExist (testExeDir </> "pandoc")
+ return $ if found
+ then testExeDir </> "pandoc"
+ else case splitDirectories testExeDir of
+ [] -> error "test-pandoc: empty testExeDir"
+ xs -> joinPath (init xs) </> "pandoc" </> "pandoc"
+
+
+vividize :: Diff String -> String
+vividize (Both s _) = " " ++ s
+vividize (First s) = "- " ++ s
+vividize (Second s) = "+ " ++ s
+
+purely :: (b -> PandocPure a) -> b -> a
+purely f = either (error . show) id . runPure . f
+
+infix 5 =?>
+(=?>) :: a -> b -> (a,b)
+x =?> y = (x, y)
+
+class ToString a where
+ toString :: a -> String
+
+instance ToString Pandoc where
+ toString d = unpack $
+ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
+ where s = case d of
+ (Pandoc (Meta m) _)
+ | M.null m -> Nothing
+ | otherwise -> Just "" -- need this to get meta output
+
+instance ToString Blocks where
+ toString = unpack . purely (writeNative def) . toPandoc
+
+instance ToString Inlines where
+ toString = trimr . unpack . purely (writeNative def) . toPandoc
+
+instance ToString String where
+ toString = id
+
+instance ToString Text where
+ toString = unpack
+
+class ToPandoc a where
+ toPandoc :: a -> Pandoc
+
+instance ToPandoc Pandoc where
+ toPandoc = id
+
+instance ToPandoc Blocks where
+ toPandoc = doc
+
+instance ToPandoc Inlines where
+ toPandoc = doc . plain
diff --git a/test/Tests/Lua.hs b/test/Tests/Lua.hs
new file mode 100644
index 000000000..4599e544d
--- /dev/null
+++ b/test/Tests/Lua.hs
@@ -0,0 +1,196 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Lua ( tests ) where
+
+import Control.Monad (when)
+import Data.Version (Version (versionBranch))
+import System.FilePath ((</>))
+import Test.Tasty (TestTree, localOption)
+import Test.Tasty.HUnit (Assertion, assertEqual, testCase)
+import Test.Tasty.QuickCheck (QuickCheckTests (..), ioProperty, testProperty)
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder (bulletList, divWith, doc, doubleQuoted, emph,
+ header, linebreak, para, plain, rawBlock,
+ singleQuoted, space, str, strong, (<>))
+import Text.Pandoc.Class (runIOorExplode, setUserDataDir)
+import Text.Pandoc.Definition (Block (BlockQuote, Div, Para), Inline (Emph, Str),
+ Attr, Meta, Pandoc, pandocTypesVersion)
+import Text.Pandoc.Lua (runLuaFilter, runPandocLua)
+import Text.Pandoc.Options (def)
+import Text.Pandoc.Shared (pandocVersion)
+
+import qualified Foreign.Lua as Lua
+
+tests :: [TestTree]
+tests = map (localOption (QuickCheckTests 20))
+ [ testProperty "inline elements can be round-tripped through the lua stack" $
+ \x -> ioProperty (roundtripEqual (x::Inline))
+
+ , testProperty "block elements can be round-tripped through the lua stack" $
+ \x -> ioProperty (roundtripEqual (x::Block))
+
+ , testProperty "meta blocks can be round-tripped through the lua stack" $
+ \x -> ioProperty (roundtripEqual (x::Meta))
+
+ , testProperty "documents can be round-tripped through the lua stack" $
+ \x -> ioProperty (roundtripEqual (x::Pandoc))
+
+ , testCase "macro expansion via filter" $
+ assertFilterConversion "a '{{helloworld}}' string is expanded"
+ "strmacro.lua"
+ (doc . para $ str "{{helloworld}}")
+ (doc . para . emph $ str "Hello, World")
+
+ , testCase "convert all plains to paras" $
+ assertFilterConversion "plains become para"
+ "plain-to-para.lua"
+ (doc $ bulletList [plain (str "alfa"), plain (str "bravo")])
+ (doc $ bulletList [para (str "alfa"), para (str "bravo")])
+
+ , testCase "make hello world document" $
+ assertFilterConversion "Document contains 'Hello, World!'"
+ "hello-world-doc.lua"
+ (doc . para $ str "Hey!" <> linebreak <> str "What's up?")
+ (doc . para $ str "Hello," <> space <> str "World!")
+
+ , testCase "implicit doc filter" $
+ assertFilterConversion "Document contains 'Hello, World!'"
+ "implicit-doc-filter.lua"
+ (doc . plain $ linebreak)
+ (doc . para $ str "Hello," <> space <> str "World!")
+
+ , testCase "parse raw markdown blocks" $
+ assertFilterConversion "raw markdown block is converted"
+ "markdown-reader.lua"
+ (doc $ rawBlock "markdown" "*charly* **delta**")
+ (doc . para $ emph "charly" <> space <> strong "delta")
+
+ , testCase "allow shorthand functions for quote types" $
+ assertFilterConversion "single quoted becomes double quoted string"
+ "single-to-double-quoted.lua"
+ (doc . para . singleQuoted $ str "simple")
+ (doc . para . doubleQuoted $ str "simple")
+
+ , testCase "Count inlines via metatable catch-all" $
+ assertFilterConversion "filtering with metatable catch-all failed"
+ "metatable-catch-all.lua"
+ (doc . para $ "four words, three spaces")
+ (doc . para $ str "7")
+
+ , testCase "Count blocks via Block-specific catch-all" $
+ assertFilterConversion "filtering with Block catch-all failed"
+ "block-count.lua"
+ (doc $ para "one" <> para "two")
+ (doc $ para "2")
+
+ , testCase "Convert header upper case" $
+ assertFilterConversion "converting header to upper case failed"
+ "uppercase-header.lua"
+ (doc $ header 1 "les états-unis" <> para "text")
+ (doc $ header 1 "LES ÉTATS-UNIS" <> para "text")
+
+ , testCase "Attribute lists are convenient to use" $
+ let kv_before = [("one", "1"), ("two", "2"), ("three", "3")]
+ kv_after = [("one", "eins"), ("three", "3"), ("five", "5")]
+ in assertFilterConversion "Attr doesn't behave as expected"
+ "attr-test.lua"
+ (doc $ divWith ("", [], kv_before) (para "nil"))
+ (doc $ divWith ("", [], kv_after) (para "nil"))
+
+ , testCase "Test module pandoc.utils" $
+ assertFilterConversion "pandoc.utils doesn't work as expected."
+ "test-pandoc-utils.lua"
+ (doc $ para "doesn't matter")
+ (doc $ mconcat [ plain (str "hierarchicalize: OK")
+ , plain (str "normalize_date: OK")
+ , plain (str "pipe: OK")
+ , plain (str "failing pipe: OK")
+ , plain (str "read: OK")
+ , plain (str "failing read: OK")
+ , plain (str "sha1: OK")
+ , plain (str "stringify: OK")
+ , plain (str "to_roman_numeral: OK")
+ ])
+
+ , testCase "Script filename is set" $
+ assertFilterConversion "unexpected script name"
+ "script-name.lua"
+ (doc $ para "ignored")
+ (doc $ para (str $ "lua" </> "script-name.lua"))
+
+ , testCase "Pandoc version is set" . runPandocLua' $ do
+ Lua.getglobal' "table.concat"
+ Lua.getglobal "PANDOC_VERSION"
+ Lua.push ("." :: String) -- seperator
+ Lua.call 2 1
+ Lua.liftIO . assertEqual "pandoc version is wrong" pandocVersion
+ =<< Lua.peek Lua.stackTop
+
+ , testCase "Pandoc types version is set" . runPandocLua' $ do
+ let versionNums = versionBranch pandocTypesVersion
+ Lua.getglobal "PANDOC_API_VERSION"
+ Lua.liftIO . assertEqual "pandoc-types version is wrong" versionNums
+ =<< Lua.peek Lua.stackTop
+
+ , testCase "Allow singleton inline in constructors" . runPandocLua' $ do
+ Lua.liftIO . assertEqual "Not the exptected Emph" (Emph [Str "test"])
+ =<< Lua.callFunc "pandoc.Emph" (Str "test")
+ Lua.liftIO . assertEqual "Unexpected element" (Para [Str "test"])
+ =<< Lua.callFunc "pandoc.Para" ("test" :: String)
+ Lua.liftIO . assertEqual "Unexptected element"
+ (BlockQuote [Para [Str "foo"]]) =<< (
+ do
+ Lua.getglobal' "pandoc.BlockQuote"
+ Lua.push (Para [Str "foo"])
+ _ <- Lua.call 1 1
+ Lua.peek Lua.stackTop
+ )
+
+ , testCase "Elements with Attr have `attr` accessor" . runPandocLua' $ do
+ Lua.push (Div ("hi", ["moin"], [])
+ [Para [Str "ignored"]])
+ Lua.getfield Lua.stackTop "attr"
+ Lua.liftIO . assertEqual "no accessor" (("hi", ["moin"], []) :: Attr)
+ =<< Lua.peek Lua.stackTop
+
+ , testCase "informative error messages" . runPandocLua' $ do
+ Lua.pushboolean True
+ err <- Lua.peekEither Lua.stackTop :: Lua.Lua (Either String Pandoc)
+ case err of
+ Left msg -> do
+ let expectedMsg = "Could not get Pandoc value: "
+ ++ "expected table but got boolean."
+ Lua.liftIO $ assertEqual "unexpected error message" expectedMsg msg
+ Right _ -> error "Getting a Pandoc element from a bool should fail."
+ ]
+
+assertFilterConversion :: String -> FilePath -> Pandoc -> Pandoc -> Assertion
+assertFilterConversion msg filterPath docIn docExpected = do
+ docEither <- runIOorExplode $ do
+ setUserDataDir (Just "../data")
+ runLuaFilter def ("lua" </> filterPath) [] docIn
+ case docEither of
+ Left _ -> fail "lua filter failed"
+ Right docRes -> assertEqual msg docExpected docRes
+
+roundtripEqual :: (Eq a, Lua.FromLuaStack a, Lua.ToLuaStack a) => a -> IO Bool
+roundtripEqual x = (x ==) <$> roundtripped
+ where
+ roundtripped :: (Lua.FromLuaStack a, Lua.ToLuaStack a) => IO a
+ roundtripped = runPandocLua' $ do
+ oldSize <- Lua.gettop
+ Lua.push x
+ size <- Lua.gettop
+ when (size - oldSize /= 1) $
+ error ("not exactly one additional element on the stack: " ++ show size)
+ res <- Lua.peekEither (-1)
+ case res of
+ Left e -> error (show e)
+ Right y -> return y
+
+runPandocLua' :: Lua.Lua a -> IO a
+runPandocLua' op = runIOorExplode $ do
+ setUserDataDir (Just "../data")
+ res <- runPandocLua op
+ case res of
+ Left e -> error (show e)
+ Right x -> return x
diff --git a/test/Tests/Old.hs b/test/Tests/Old.hs
new file mode 100644
index 000000000..b82251a56
--- /dev/null
+++ b/test/Tests/Old.hs
@@ -0,0 +1,289 @@
+module Tests.Old (tests) where
+
+import Data.Algorithm.Diff
+import Prelude hiding (readFile)
+import System.Exit
+import System.FilePath (joinPath, splitDirectories, (<.>), (</>))
+import System.IO.Temp (withTempFile)
+import System.Process (runProcess, waitForProcess)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.Golden.Advanced (goldenTest)
+import Tests.Helpers hiding (test)
+import qualified Text.Pandoc.UTF8 as UTF8
+
+tests :: [TestTree]
+tests = [ testGroup "markdown"
+ [ testGroup "writer"
+ $ writerTests "markdown" ++ lhsWriterTests "markdown"
+ , testGroup "reader"
+ [ test "basic" ["-r", "markdown", "-w", "native", "-s"]
+ "testsuite.txt" "testsuite.native"
+ , test "tables" ["-r", "markdown", "-w", "native", "--columns=80"]
+ "tables.txt" "tables.native"
+ , test "pipe tables" ["-r", "markdown", "-w", "native", "--columns=80"]
+ "pipe-tables.txt" "pipe-tables.native"
+ , test "more" ["-r", "markdown", "-w", "native", "-s"]
+ "markdown-reader-more.txt" "markdown-reader-more.native"
+ , lhsReaderTest "markdown+lhs"
+ ]
+ , testGroup "citations"
+ [ test "citations" ["-r", "markdown", "-w", "native"]
+ "markdown-citations.txt" "markdown-citations.native"
+ ]
+ ]
+ , testGroup "rst"
+ [ testGroup "writer" (writerTests "rst" ++ lhsWriterTests "rst")
+ , testGroup "reader"
+ [ test "basic" ["-r", "rst+smart", "-w", "native",
+ "-s", "--columns=80"] "rst-reader.rst" "rst-reader.native"
+ , test "tables" ["-r", "rst", "-w", "native", "--columns=80"]
+ "tables.rst" "tables-rstsubset.native"
+ , lhsReaderTest "rst+lhs"
+ ]
+ ]
+ , testGroup "latex"
+ [ testGroup "writer" (writerTests "latex" ++ lhsWriterTests "latex")
+ , testGroup "reader"
+ [ test "basic" ["-r", "latex+raw_tex", "-w", "native", "-s"]
+ "latex-reader.latex" "latex-reader.native"
+ , lhsReaderTest "latex+lhs"
+ ]
+ ]
+ , testGroup "html"
+ [ testGroup "writer" (writerTests "html4" ++ writerTests "html5" ++
+ lhsWriterTests "html")
+ , test "reader" ["-r", "html", "-w", "native", "-s"]
+ "html-reader.html" "html-reader.native"
+ ]
+ , testGroup "s5"
+ [ s5WriterTest "basic" ["-s"] "s5"
+ , s5WriterTest "fancy" ["-s","-m","-i"] "s5"
+ , s5WriterTest "fragment" [] "html4"
+ , s5WriterTest "inserts" ["-s", "-H", "insert",
+ "-B", "insert", "-A", "insert", "-c", "main.css"] "html4"
+ ]
+ , testGroup "textile"
+ [ testGroup "writer" $ writerTests "textile"
+ , test "reader" ["-r", "textile", "-w", "native", "-s"]
+ "textile-reader.textile" "textile-reader.native"
+ ]
+ , testGroup "docbook"
+ [ testGroup "writer" $ writerTests "docbook4"
+ , test "reader" ["-r", "docbook", "-w", "native", "-s"]
+ "docbook-reader.docbook" "docbook-reader.native"
+ , test "reader" ["-r", "docbook", "-w", "native", "-s"]
+ "docbook-xref.docbook" "docbook-xref.native"
+ ]
+ , testGroup "docbook5"
+ [ testGroup "writer" $ writerTests "docbook5"
+ ]
+ , testGroup "jats"
+ [ testGroup "writer" $ writerTests "jats"
+ , test "reader" ["-r", "jats", "-w", "native", "-s"]
+ "jats-reader.xml" "jats-reader.native"
+ ]
+ , testGroup "native"
+ [ testGroup "writer" $ writerTests "native"
+ , test "reader" ["-r", "native", "-w", "native", "-s"]
+ "testsuite.native" "testsuite.native"
+ ]
+ , testGroup "fb2"
+ [ fb2WriterTest "basic" [] "fb2/basic.markdown" "fb2/basic.fb2"
+ , fb2WriterTest "titles" [] "fb2/titles.markdown" "fb2/titles.fb2"
+ , fb2WriterTest "images" [] "fb2/images.markdown" "fb2/images.fb2"
+ , fb2WriterTest "images-embedded" [] "fb2/images-embedded.html" "fb2/images-embedded.fb2"
+ , fb2WriterTest "math" [] "fb2/math.markdown" "fb2/math.fb2"
+ , fb2WriterTest "tables" [] "tables.native" "tables.fb2"
+ , fb2WriterTest "testsuite" [] "testsuite.native" "writer.fb2"
+ ]
+ , testGroup "mediawiki"
+ [ testGroup "writer" $ writerTests "mediawiki"
+ , test "reader" ["-r", "mediawiki", "-w", "native", "-s"]
+ "mediawiki-reader.wiki" "mediawiki-reader.native"
+ ]
+ , testGroup "vimwiki"
+ [ test "reader" ["-r", "vimwiki", "-w", "native", "-s"]
+ "vimwiki-reader.wiki" "vimwiki-reader.native"
+ ]
+ , testGroup "dokuwiki"
+ [ testGroup "writer" $ writerTests "dokuwiki"
+ , test "inline_formatting" ["-r", "native", "-w", "dokuwiki", "-s"]
+ "dokuwiki_inline_formatting.native" "dokuwiki_inline_formatting.dokuwiki"
+ , test "multiblock table" ["-r", "native", "-w", "dokuwiki", "-s"]
+ "dokuwiki_multiblock_table.native" "dokuwiki_multiblock_table.dokuwiki"
+ , test "external images" ["-r", "native", "-w", "dokuwiki", "-s"]
+ "dokuwiki_external_images.native" "dokuwiki_external_images.dokuwiki"
+ ]
+ , testGroup "opml"
+ [ test "basic" ["-r", "native", "-w", "opml", "--columns=78", "-s"]
+ "testsuite.native" "writer.opml"
+ , test "reader" ["-r", "opml", "-w", "native", "-s"]
+ "opml-reader.opml" "opml-reader.native"
+ ]
+ , testGroup "haddock"
+ [ testGroup "writer" $ writerTests "haddock"
+ , test "reader" ["-r", "haddock", "-w", "native", "-s"]
+ "haddock-reader.haddock" "haddock-reader.native"
+ ]
+ , testGroup "txt2tags"
+ [ test "reader" ["-r", "t2t", "-w", "native", "-s"]
+ "txt2tags.t2t" "txt2tags.native" ]
+ , testGroup "epub" [
+ test "features" ["-r", "epub", "-w", "native"]
+ "epub/features.epub" "epub/features.native"
+ , test "wasteland" ["-r", "epub", "-w", "native"]
+ "epub/wasteland.epub" "epub/wasteland.native"
+ , test "formatting" ["-r", "epub", "-w", "native"]
+ "epub/formatting.epub" "epub/formatting.native"
+ ]
+ , testGroup "twiki"
+ [ test "reader" ["-r", "twiki", "-w", "native", "-s"]
+ "twiki-reader.twiki" "twiki-reader.native" ]
+ , testGroup "tikiwiki"
+ [ test "reader" ["-r", "tikiwiki", "-w", "native", "-s"]
+ "tikiwiki-reader.tikiwiki" "tikiwiki-reader.native" ]
+ , testGroup "other writers" $ map (\f -> testGroup f $ writerTests f)
+ [ "opendocument" , "context" , "texinfo", "icml", "tei"
+ , "man" , "plain" , "rtf", "org", "asciidoc", "zimwiki"
+ ]
+ , testGroup "writers-lang-and-dir"
+ [ test "latex" ["-f", "native", "-t", "latex", "-s"]
+ "writers-lang-and-dir.native" "writers-lang-and-dir.latex"
+ , test "context" ["-f", "native", "-t", "context", "-s"]
+ "writers-lang-and-dir.native" "writers-lang-and-dir.context"
+ ]
+ , testGroup "muse"
+ [ testGroup "writer" $ writerTests "muse"
+ ]
+ , testGroup "ms"
+ [ testGroup "writer" $ writerTests "ms"
+ ]
+ , testGroup "creole"
+ [ test "reader" ["-r", "creole", "-w", "native", "-s"]
+ "creole-reader.txt" "creole-reader.native"
+ ]
+ , testGroup "custom writer"
+ [ test "basic" ["-f", "native", "-t", "../data/sample.lua"]
+ "testsuite.native" "writer.custom"
+ , test "tables" ["-f", "native", "-t", "../data/sample.lua"]
+ "tables.native" "tables.custom"
+ ]
+ ]
+
+-- makes sure file is fully closed after reading
+readFile' :: FilePath -> IO String
+readFile' f = do s <- UTF8.readFile f
+ return $! (length s `seq` s)
+
+lhsWriterTests :: String -> [TestTree]
+lhsWriterTests format
+ = [ t "lhs to normal" format
+ , t "lhs to lhs" (format ++ "+lhs")
+ ]
+ where
+ t n f = test n ["--wrap=preserve", "-r", "native", "-s", "-w", f]
+ "lhs-test.native" ("lhs-test" <.> f)
+
+lhsReaderTest :: String -> TestTree
+lhsReaderTest format =
+ test "lhs" ["-r", format, "-w", "native"]
+ ("lhs-test" <.> format) norm
+ where norm = if format == "markdown+lhs"
+ then "lhs-test-markdown.native"
+ else "lhs-test.native"
+
+writerTests :: String -> [TestTree]
+writerTests format
+ = [ test "basic" (opts ++ ["-s"]) "testsuite.native" ("writer" <.> format)
+ , test "tables" opts "tables.native" ("tables" <.> format)
+ ]
+ where
+ opts = ["-r", "native", "-w", format, "--columns=78",
+ "--variable", "pandoc-version="]
+
+s5WriterTest :: String -> [String] -> String -> TestTree
+s5WriterTest modifier opts format
+ = test (format ++ " writer (" ++ modifier ++ ")")
+ (["-r", "native", "-w", format] ++ opts)
+ "s5.native" ("s5-" ++ modifier <.> "html")
+
+fb2WriterTest :: String -> [String] -> String -> String -> TestTree
+fb2WriterTest title opts inputfile normfile =
+ testWithNormalize (ignoreBinary . formatXML)
+ title (["-t", "fb2"]++opts) inputfile normfile
+ where
+ formatXML xml = splitTags $ zip xml (drop 1 xml)
+ splitTags [] = []
+ splitTags [end] = fst end : snd end : []
+ splitTags (('>','<'):rest) = ">\n" ++ splitTags rest
+ splitTags ((c,_):rest) = c : splitTags rest
+ ignoreBinary = unlines . filter (not . startsWith "<binary ") . lines
+ startsWith tag str = all (uncurry (==)) $ zip tag str
+
+-- | Run a test without normalize function, return True if test passed.
+test :: String -- ^ Title of test
+ -> [String] -- ^ Options to pass to pandoc
+ -> String -- ^ Input filepath
+ -> FilePath -- ^ Norm (for test results) filepath
+ -> TestTree
+test = testWithNormalize id
+
+-- | Run a test with normalize function, return True if test passed.
+testWithNormalize :: (String -> String) -- ^ Normalize function for output
+ -> String -- ^ Title of test
+ -> [String] -- ^ Options to pass to pandoc
+ -> String -- ^ Input filepath
+ -> FilePath -- ^ Norm (for test results) filepath
+ -> TestTree
+testWithNormalize normalizer testname opts inp norm =
+ goldenTest testname getExpected getActual
+ (compareValues norm options) updateGolden
+ where getExpected = normalizer <$> readFile' norm
+ getActual =
+ withTempFile "." "pandoc-test" $ \outputPath hOut -> do
+ withTempFile "." "pandoc-test" $ \errorPath hErr -> do
+ pandocPath <- findPandoc
+ let mbDynlibDir = findDynlibDir (reverse $
+ splitDirectories pandocPath)
+ let dynlibEnv = case mbDynlibDir of
+ Nothing -> []
+ Just d -> [("DYLD_LIBRARY_PATH", d),
+ ("LD_LIBRARY_PATH", d)]
+ let env = dynlibEnv ++
+ [("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./"),
+ ("pandoc_datadir","..")]
+ ph <- runProcess pandocPath options Nothing
+ (Just env) Nothing (Just hOut) (Just hErr)
+ ec <- waitForProcess ph
+ if ec == ExitSuccess
+ then
+ -- filter \r so the tests will work on Windows machines
+ (filter (/='\r') . normalizer) <$> readFile' outputPath
+ else do
+ errcontents <- UTF8.readFile errorPath
+ fail $ "Pandoc failed with " ++ show ec ++
+ if null errcontents
+ then ""
+ else '\n':errcontents
+ updateGolden = UTF8.writeFile norm
+ options = ["--quiet"] ++ [inp] ++ opts
+
+compareValues :: FilePath -> [String] -> String -> String -> IO (Maybe String)
+compareValues norm options expected actual = do
+ pandocPath <- findPandoc
+ let cmd = pandocPath ++ " " ++ unwords options
+ let dash = replicate 72 '-'
+ let diff = getDiff (lines actual) (lines expected)
+ if expected == actual
+ then return Nothing
+ else return $ Just $
+ '\n' : dash ++
+ "\n--- " ++ norm ++
+ "\n+++ " ++ cmd ++ "\n" ++
+ showDiff (1,1) diff ++ dash
+
+findDynlibDir :: [FilePath] -> Maybe FilePath
+findDynlibDir [] = Nothing
+findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build"
+findDynlibDir (_:xs) = findDynlibDir xs
+
diff --git a/test/Tests/Readers/Creole.hs b/test/Tests/Readers/Creole.hs
new file mode 100644
index 000000000..3f60a523d
--- /dev/null
+++ b/test/Tests/Readers/Creole.hs
@@ -0,0 +1,286 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Creole (tests) where
+
+import Data.Text (Text)
+import qualified Data.Text as T
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+creole :: Text -> Pandoc
+creole = purely $ readCreole def{ readerStandalone = True }
+
+infix 4 =:
+(=:) :: ToString c
+ => String -> (Text, c) -> TestTree
+(=:) = test creole
+
+tests :: [TestTree]
+tests = [
+ testGroup "Basic Text Formatting" [
+ "bold, single line, fully delimited" =:
+ "only **bold** is bold"
+ =?> para ("only " <> strong "bold" <> " is bold")
+ , "italics, single line, fully delimited" =:
+ "only //this// is in italics"
+ =?> para ("only " <> emph "this" <> " is in italics")
+ , "bold in italics, fully delimited" =:
+ "//**this**// is in bold italics"
+ =?> para (emph (strong "this") <> " is in bold italics")
+ , "italics in bold, fully delimited" =:
+ "**//this//** is in bold italics"
+ =?> para (strong (emph "this") <> " is in bold italics")
+
+ , "escape bold marker" =:
+ "~**not bold" =?> para "**not bold"
+ , "escape italics marker" =:
+ "~//not in italics" =?> para "//not in italics"
+
+ , "inline nowiki, simple" =:
+ "this is {{{**not** ~interpreted}}} at all"
+ =?> para ("this is " <> code "**not** ~interpreted" <> " at all")
+ , "inline nowiki, curly braces inside" =:
+ "this is {{{{{{//including// some `}' chars}}}}}}"
+ =?> para ("this is " <> code "{{{//including// some `}' chars}}}")
+
+ , "placeholder" =:
+ "foo <<<place holder>>> bar"
+ =?> para "foo bar"
+ , "placeholder escaped" =:
+ "foo ~<<<no place holder>>> bar"
+ =?> para "foo <<<no place holder>>> bar"
+ ]
+ , testGroup "Headers" [
+ "header level 1, no space, no trailing =" =:
+ "= Top-Level Header"
+ =?> header 1 (str "Top-Level Header")
+ , "header level 1, leading space, trailing =" =:
+ " = Top-Level Header = "
+ =?> header 1 (str "Top-Level Header")
+ , "header level 2, no space, no trailing =" =:
+ "== Second Level"
+ =?> header 2 (str "Second Level")
+ , "header level 2, leading space, no trailing =" =:
+ " == Second Level"
+ =?> header 2 (str "Second Level")
+ , "header level 3, no space, no trailing =" =:
+ "=== Third"
+ =?> header 3 (str "Third")
+ , "header level 3, no space, > 3 trailing =" =:
+ "=== Third ======="
+ =?> header 3 (str "Third")
+ , "header level 4, no space, no trailing =" =:
+ "==== Fourth Level Heading"
+ =?> header 4 (str "Fourth Level Heading")
+ , "header level 4, no space, < 4 trailing =" =:
+ "==== Fourth Level Heading =="
+ =?> header 4 (str "Fourth Level Heading")
+ , "header level 5, no space, no trailing =" =:
+ "===== Fifth"
+ =?> header 5 (str "Fifth")
+ , "header level 6, no space, no trailing =" =:
+ "====== Sixth"
+ =?> header 6 (str "Sixth")
+ ]
+ , testGroup "Paragraphs" [
+ "paragraphs: multiple, one line" =:
+ "first line\n\nanother line\n"
+ =?> para "first line" <> para "another line"
+ ]
+ , testGroup "Lists" [
+ "unordered list, two entries, one separating space" =:
+ "* foo\n* bar"
+ =?> bulletList [ plain "foo", plain "bar" ]
+ , "unordered list, three entries, one separating space" =:
+ "* foo\n* bar\n* baz"
+ =?> bulletList [ plain "foo", plain "bar", plain "baz" ]
+ , "para followed by, unordered list, two entries, one separating space" =:
+ "blubber\n* foo\n* bar"
+ =?> para "blubber" <> bulletList [ plain "foo", plain "bar" ]
+ , "nested unordered list, one separating space" =:
+ "* foo\n** bar\n** baz\n* blubb"
+ =?> bulletList [ plain "foo"
+ <> bulletList [ plain "bar", plain "baz" ]
+ , plain "blubb" ]
+ , "nested many unordered lists, one separating space" =:
+ ("* foo\n** bar\n*** third\n*** third two\n** baz\n*** third again\n"
+ <> "**** fourth\n***** fith\n* blubb")
+ =?> bulletList [ plain "foo"
+ <> bulletList [ plain "bar"
+ <> bulletList [ plain "third"
+ , plain "third two"]
+ , plain "baz"
+ <> bulletList [ plain "third again"
+ <> bulletList [
+ plain "fourth"
+ <> bulletList [
+ plain "fith"
+ ]
+ ]
+ ]
+ ]
+ , plain "blubb" ]
+ , "nested unordered list, mixed separating space" =:
+ "*foo\n ** bar\n **baz\n * blubb"
+ =?> bulletList [ plain "foo"
+ <> bulletList [ plain "bar", plain "baz" ]
+ , plain "blubb" ]
+ , "nested unordered list, one separating space, trailing space" =:
+ "* foo \n** bar \n** baz \n* blubb "
+ =?> bulletList [ plain "foo"
+ <> bulletList [ plain "bar", plain "baz" ]
+ , plain "blubb" ]
+ , "ordered list, two entries, one separating space" =:
+ "# foo\n# bar"
+ =?> orderedList [ plain "foo", plain "bar" ]
+ , "ordered list, three entries, one separating space" =:
+ "# foo\n# bar\n# baz"
+ =?> orderedList [ plain "foo", plain "bar", plain "baz" ]
+ , "para followed by, ordered list, two entries, one separating space" =:
+ "blubber\n# foo\n# bar"
+ =?> para "blubber" <> orderedList [ plain "foo", plain "bar" ]
+ , "nested ordered list, one separating space" =:
+ "# foo\n## bar\n## baz\n# blubb"
+ =?> orderedList [ plain "foo"
+ <> orderedList [ plain "bar", plain "baz" ]
+ , plain "blubb" ]
+ , "nested ordered list, one separating space, trailing space" =:
+ "# foo \n## bar \n## baz \n# blubb "
+ =?> orderedList [ plain "foo"
+ <> orderedList [ plain "bar", plain "baz" ]
+ , plain "blubb" ]
+ , "nested many ordered lists, one separating space" =:
+ ("# foo\n## bar\n### third\n### third two\n## baz\n### third again\n"
+ <> "#### fourth\n##### fith\n# blubb")
+ =?> orderedList [ plain "foo"
+ <> orderedList [ plain "bar"
+ <> orderedList [ plain "third"
+ , plain "third two"]
+ , plain "baz"
+ <> orderedList [ plain "third again"
+ <> orderedList [
+ plain "fourth"
+ <> orderedList [
+ plain "fith"
+ ]
+ ]
+ ]
+ ]
+ , plain "blubb" ]
+ , "nested ordered list, mixed separating space" =:
+ "#foo\n ## bar\n ##baz\n # blubb"
+ =?> orderedList [ plain "foo"
+ <> orderedList [ plain "bar", plain "baz" ]
+ , plain "blubb" ]
+ , "mixed nested ordered and unordered lists, one separating space" =:
+ ("# foo\n** bar\n### third\n### third two\n** baz\n### third again\n"
+ <> "#### fourth\n***** fith\n# blubb")
+ =?> orderedList [ plain "foo"
+ <> bulletList [ plain "bar"
+ <> orderedList [ plain "third"
+ , plain "third two"]
+ , plain "baz"
+ <> orderedList [ plain "third again"
+ <> orderedList [
+ plain "fourth"
+ <> bulletList [
+ plain "fith"
+ ]
+ ]
+ ]
+ ]
+ , plain "blubb" ]
+ ]
+ , testGroup "NoWiki" [
+ "quoted block, simple" =:
+ "{{{\nfoo bar\n //baz//\n}}}"
+ =?> codeBlock "foo bar\n //baz//"
+ , "quoted block, curly bracket exception" =:
+ "{{{\nfoo bar\n }}}\nbaz\n }}}\n}}}"
+ =?> codeBlock "foo bar\n }}}\nbaz\n}}}"
+ , "forced line breaks" =:
+ "{{{no break!\\\\here}}} but a break\\\\here!"
+ =?> para (code "no break!\\\\here" <> " but a break"
+ <> linebreak <> "here!"),
+ "quoted block, after trailing white space" =:
+ "this is a paragraph \n{{{\nfoo bar\n //baz//\n}}}"
+ =?> para "this is a paragraph" <> codeBlock "foo bar\n //baz//"
+ ]
+ , testGroup "Images and Links" [
+ "image simple" =:
+ "{{foo.png}}" =?> para (image "foo.png" "" (str ""))
+ , "image with alt text" =:
+ "Image of a bar: {{/path/to/bar.png|A Bar}} look at it!"
+ =?> para ("Image of a bar: "
+ <> image "/path/to/bar.png" "" (str "A Bar") <> " look at it!")
+
+ , "auto link" =:
+ "foo http://foo.example.com/bar/baz.html bar"
+ =?> para ("foo "
+ <> link "http://foo.example.com/bar/baz.html" ""
+ (str "http://foo.example.com/bar/baz.html")
+ <> " bar")
+ , "escaped auto link" =:
+ "foo ~http://foo.example.com/bar/baz.html bar"
+ =?> para "foo http://foo.example.com/bar/baz.html bar"
+ , "wiki link simple" =:
+ "foo [[http://foo.example.com/foo.png]] bar"
+ =?> para ("foo "
+ <> link "http://foo.example.com/foo.png" ""
+ (str "http://foo.example.com/foo.png")
+ <> " bar")
+ , "wiki link with name" =:
+ "foo [[http://foo.example.com/foo.png|my link]] bar"
+ =?> para ("foo "
+ <> link "http://foo.example.com/foo.png" ""
+ (str "my link")
+ <> " bar")
+ , "image link" =:
+ "[[http://foo.example.com/|{{foo.png}}]]"
+ =?> para (link "http://foo.example.com/" "" (image "foo.png" "" (str "")))
+ ]
+ , testGroup "Table" [
+ "Table with Header" =:
+ T.unlines [ "|= Foo |= Bar |= Baz |"
+ , "| One | Two | Three |"
+ , "| 1 | 2 | 3 |"
+ , "| A | B | C |"
+ ]
+ =?> simpleTable
+ [plain "Foo", plain "Bar" , plain "Baz"]
+ [[plain "One", plain "Two" , plain "Three"]
+ ,[plain "1", plain "2" , plain "3"]
+ ,[plain "A", plain "B" , plain "C"]]
+ , "Table without Header" =:
+ T.unlines [ "| One | Two | Three |"
+ , "| 1 | 2 | 3 |"
+ , "| A | B | C |"
+ ]
+ =?> simpleTable [mempty]
+ [[plain "One", plain "Two" , plain "Three"]
+ ,[plain "1", plain "2" , plain "3"]
+ ,[plain "A", plain "B" , plain "C"]]
+ , "Table without Header, no markers at line ends" =:
+ T.unlines [ "| One | Two | Three"
+ , "| 1 | 2 | 3"
+ , "| A | B | C "
+ ]
+ =?> simpleTable [mempty]
+ [[plain "One", plain "Two" , plain "Three"]
+ ,[plain "1", plain "2" , plain "3"]
+ ,[plain "A", plain "B" , plain "C"]]
+ , "Table with Header, with formatting" =:
+ T.unlines [ "|= **Foo** |= **Bar** |= **Baz** |"
+ , "|//one// element |//second// elt|Three |"
+ , "| {{{1}}} | {{{{}}}} | [[link]] |"
+ ]
+ =?> simpleTable
+ [plain $ strong "Foo", plain $ strong "Bar" , plain $ strong "Baz"]
+ [[plain (emph "one" <> " element"), plain (emph "second" <> " elt")
+ ,plain "Three"]
+ ,[plain $ code "1", plain $ code "{}"
+ ,plain $ link "link" "" (str "link")]]
+ ]
+ ]
diff --git a/test/Tests/Readers/Docx.hs b/test/Tests/Readers/Docx.hs
new file mode 100644
index 000000000..0ba765c93
--- /dev/null
+++ b/test/Tests/Readers/Docx.hs
@@ -0,0 +1,401 @@
+module Tests.Readers.Docx (tests) where
+
+import Codec.Archive.Zip
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as B
+import qualified Data.Map as M
+import qualified Data.Text as T
+import Data.Maybe
+import System.IO.Unsafe
+import Test.Tasty
+import Test.Tasty.HUnit
+import Tests.Helpers
+import Text.Pandoc
+import qualified Text.Pandoc.Class as P
+import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
+import Text.Pandoc.UTF8 as UTF8
+
+-- We define a wrapper around pandoc that doesn't normalize in the
+-- tests. Since we do our own normalization, we want to make sure
+-- we're doing it right.
+
+data NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc}
+ deriving Show
+
+noNorm :: Pandoc -> NoNormPandoc
+noNorm = NoNormPandoc
+
+defopts :: ReaderOptions
+defopts = def{ readerExtensions = getDefaultExtensions "docx" }
+
+instance ToString NoNormPandoc where
+ toString d = T.unpack $ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
+ where s = case d of
+ NoNormPandoc (Pandoc (Meta m) _)
+ | M.null m -> Nothing
+ | otherwise -> Just "" -- need this to get meta output
+
+instance ToPandoc NoNormPandoc where
+ toPandoc = unNoNorm
+
+compareOutput :: ReaderOptions
+ -> FilePath
+ -> FilePath
+ -> IO (NoNormPandoc, NoNormPandoc)
+compareOutput opts docxFile nativeFile = do
+ df <- B.readFile docxFile
+ nf <- UTF8.toText <$> BS.readFile nativeFile
+ p <- runIOorExplode $ readDocx opts df
+ df' <- runIOorExplode $ readNative def nf
+ return (noNorm p, noNorm df')
+
+testCompareWithOptsIO :: ReaderOptions -> String -> FilePath -> FilePath -> IO TestTree
+testCompareWithOptsIO opts name docxFile nativeFile = do
+ (dp, np) <- compareOutput opts docxFile nativeFile
+ return $ test id name (dp, np)
+
+testCompareWithOpts :: ReaderOptions -> String -> FilePath -> FilePath -> TestTree
+testCompareWithOpts opts name docxFile nativeFile =
+ unsafePerformIO $ testCompareWithOptsIO opts name docxFile nativeFile
+
+testCompare :: String -> FilePath -> FilePath -> TestTree
+testCompare = testCompareWithOpts defopts
+
+testForWarningsWithOptsIO :: ReaderOptions -> String -> FilePath -> [String] -> IO TestTree
+testForWarningsWithOptsIO opts name docxFile expected = do
+ df <- B.readFile docxFile
+ logs <- runIOorExplode $ setVerbosity ERROR >> readDocx opts df >> P.getLog
+ let warns = [m | DocxParserWarning m <- logs]
+ return $ test id name (unlines warns, unlines expected)
+
+testForWarningsWithOpts :: ReaderOptions -> String -> FilePath -> [String] -> TestTree
+testForWarningsWithOpts opts name docxFile expected =
+ unsafePerformIO $ testForWarningsWithOptsIO opts name docxFile expected
+
+-- testForWarnings :: String -> FilePath -> [String] -> TestTree
+-- testForWarnings = testForWarningsWithOpts defopts
+
+getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString)
+getMedia archivePath mediaPath = do
+ zf <- B.readFile archivePath >>= return . toArchive
+ return $ findEntryByPath ("word/" ++ mediaPath) zf >>= (Just . fromEntry)
+
+compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool
+compareMediaPathIO mediaPath mediaBag docxPath = do
+ docxMedia <- getMedia docxPath mediaPath
+ let mbBS = case lookupMedia mediaPath mediaBag of
+ Just (_, bs) -> bs
+ Nothing -> error ("couldn't find " ++
+ mediaPath ++
+ " in media bag")
+ docxBS = fromMaybe (error ("couldn't find " ++
+ mediaPath ++
+ " in media bag")) docxMedia
+ return $ mbBS == docxBS
+
+compareMediaBagIO :: FilePath -> IO Bool
+compareMediaBagIO docxFile = do
+ df <- B.readFile docxFile
+ mb <- runIOorExplode $ readDocx defopts df >> P.getMediaBag
+ bools <- mapM
+ (\(fp, _, _) -> compareMediaPathIO fp mb docxFile)
+ (mediaDirectory mb)
+ return $ and bools
+
+testMediaBagIO :: String -> FilePath -> IO TestTree
+testMediaBagIO name docxFile = do
+ outcome <- compareMediaBagIO docxFile
+ return $ testCase name (assertBool
+ ("Media didn't match media bag in file " ++ docxFile)
+ outcome)
+
+testMediaBag :: String -> FilePath -> TestTree
+testMediaBag name docxFile = unsafePerformIO $ testMediaBagIO name docxFile
+
+tests :: [TestTree]
+tests = [ testGroup "inlines"
+ [ testCompare
+ "font formatting"
+ "docx/inline_formatting.docx"
+ "docx/inline_formatting.native"
+ , testCompare
+ "font formatting with character styles"
+ "docx/char_styles.docx"
+ "docx/char_styles.native"
+ , testCompare
+ "hyperlinks"
+ "docx/links.docx"
+ "docx/links.native"
+ , testCompare
+ "hyperlinks in <w:instrText> tag"
+ "docx/instrText_hyperlink.docx"
+ "docx/instrText_hyperlink.native"
+ , testCompare
+ "inline image"
+ "docx/image.docx"
+ "docx/image_no_embed.native"
+ , testCompare
+ "VML image"
+ "docx/image_vml.docx"
+ "docx/image_vml.native"
+ , testCompare
+ "inline image in links"
+ "docx/inline_images.docx"
+ "docx/inline_images.native"
+ , testCompare
+ "handling unicode input"
+ "docx/unicode.docx"
+ "docx/unicode.native"
+ , testCompare
+ "literal tabs"
+ "docx/tabs.docx"
+ "docx/tabs.native"
+ , testCompare
+ "special punctuation"
+ "docx/special_punctuation.docx"
+ "docx/special_punctuation.native"
+ , testCompare
+ "normalizing inlines"
+ "docx/normalize.docx"
+ "docx/normalize.native"
+ , testCompare
+ "normalizing inlines deep inside blocks"
+ "docx/deep_normalize.docx"
+ "docx/deep_normalize.native"
+ , testCompare
+ "move trailing spaces outside of formatting"
+ "docx/trailing_spaces_in_formatting.docx"
+ "docx/trailing_spaces_in_formatting.native"
+ , testCompare
+ "inline code (with VerbatimChar style)"
+ "docx/inline_code.docx"
+ "docx/inline_code.native"
+ , testCompare
+ "inline code in subscript and superscript"
+ "docx/verbatim_subsuper.docx"
+ "docx/verbatim_subsuper.native"
+ , testCompare
+ "inlines inside of Structured Document Tags"
+ "docx/sdt_elements.docx"
+ "docx/sdt_elements.native"
+ , testCompare
+ "nested Structured Document Tags"
+ "docx/nested_sdt.docx"
+ "docx/nested_sdt.native"
+ , testCompare
+ "remove anchor spans with nothing pointing to them"
+ "docx/unused_anchors.docx"
+ "docx/unused_anchors.native"
+ , testCompare
+ "collapse overlapping targets (anchor spans)"
+ "docx/overlapping_targets.docx"
+ "docx/overlapping_targets.native"
+ ]
+ , testGroup "blocks"
+ [ testCompare
+ "headers"
+ "docx/headers.docx"
+ "docx/headers.native"
+ , testCompare
+ "headers already having auto identifiers"
+ "docx/already_auto_ident.docx"
+ "docx/already_auto_ident.native"
+ , testCompare
+ "avoid zero-level headers"
+ "docx/0_level_headers.docx"
+ "docx/0_level_headers.native"
+ , testCompare
+ "nested anchor spans in header"
+ "docx/nested_anchors_in_header.docx"
+ "docx/nested_anchors_in_header.native"
+ , testCompare
+ "single numbered item not made into list"
+ "docx/numbered_header.docx"
+ "docx/numbered_header.native"
+ , testCompare
+ "enumerated headers not made into numbered list"
+ "docx/enumerated_headings.docx"
+ "docx/enumerated_headings.native"
+ , testCompare
+ "i18n blocks (headers and blockquotes)"
+ "docx/i18n_blocks.docx"
+ "docx/i18n_blocks.native"
+ , testCompare
+ "lists"
+ "docx/lists.docx"
+ "docx/lists.native"
+ , testCompare
+ "lists continuing after interruption"
+ "docx/lists_continuing.docx"
+ "docx/lists_continuing.native"
+ , testCompare
+ "lists restarting after interruption"
+ "docx/lists_restarting.docx"
+ "docx/lists_restarting.native"
+ , testCompare
+ "definition lists"
+ "docx/definition_list.docx"
+ "docx/definition_list.native"
+ , testCompare
+ "custom defined lists in styles"
+ "docx/german_styled_lists.docx"
+ "docx/german_styled_lists.native"
+ , testCompare
+ "user deletes bullet after list item (=> part of item par)"
+ "docx/dummy_item_after_list_item.docx"
+ "docx/dummy_item_after_list_item.native"
+ , testCompare
+ "user deletes bullet after par (=> new par)"
+ "docx/dummy_item_after_paragraph.docx"
+ "docx/dummy_item_after_paragraph.native"
+ , testCompare
+ "footnotes and endnotes"
+ "docx/notes.docx"
+ "docx/notes.native"
+ , testCompare
+ "links in footnotes and endnotes"
+ "docx/link_in_notes.docx"
+ "docx/link_in_notes.native"
+ , testCompare
+ "blockquotes (parsing indent as blockquote)"
+ "docx/block_quotes.docx"
+ "docx/block_quotes_parse_indent.native"
+ , testCompare
+ "hanging indents"
+ "docx/hanging_indent.docx"
+ "docx/hanging_indent.native"
+ , testCompare
+ "tables"
+ "docx/tables.docx"
+ "docx/tables.native"
+ , testCompare
+ "tables with lists in cells"
+ "docx/table_with_list_cell.docx"
+ "docx/table_with_list_cell.native"
+ , testCompare
+ "tables with one row"
+ "docx/table_one_row.docx"
+ "docx/table_one_row.native"
+ , testCompare
+ "tables with variable width"
+ "docx/table_variable_width.docx"
+ "docx/table_variable_width.native"
+ , testCompare
+ "code block"
+ "docx/codeblock.docx"
+ "docx/codeblock.native"
+ , testCompare
+ "dropcap paragraphs"
+ "docx/drop_cap.docx"
+ "docx/drop_cap.native"
+ ]
+ , testGroup "track changes"
+ [ testCompare
+ "insertion (default)"
+ "docx/track_changes_insertion.docx"
+ "docx/track_changes_insertion_accept.native"
+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
+ "insert insertion (accept)"
+ "docx/track_changes_insertion.docx"
+ "docx/track_changes_insertion_accept.native"
+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
+ "remove insertion (reject)"
+ "docx/track_changes_insertion.docx"
+ "docx/track_changes_insertion_reject.native"
+ , testCompare
+ "deletion (default)"
+ "docx/track_changes_deletion.docx"
+ "docx/track_changes_deletion_accept.native"
+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
+ "remove deletion (accept)"
+ "docx/track_changes_deletion.docx"
+ "docx/track_changes_deletion_accept.native"
+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
+ "insert deletion (reject)"
+ "docx/track_changes_deletion.docx"
+ "docx/track_changes_deletion_reject.native"
+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
+ "keep insertion (all)"
+ "docx/track_changes_deletion.docx"
+ "docx/track_changes_deletion_all.native"
+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
+ "keep deletion (all)"
+ "docx/track_changes_deletion.docx"
+ "docx/track_changes_deletion_all.native"
+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
+ "move text (accept)"
+ "docx/track_changes_move.docx"
+ "docx/track_changes_move_accept.native"
+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
+ "move text (reject)"
+ "docx/track_changes_move.docx"
+ "docx/track_changes_move_reject.native"
+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
+ "move text (all)"
+ "docx/track_changes_move.docx"
+ "docx/track_changes_move_all.native"
+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
+ "comments (accept -- no comments)"
+ "docx/comments.docx"
+ "docx/comments_no_comments.native"
+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
+ "comments (reject -- comments)"
+ "docx/comments.docx"
+ "docx/comments_no_comments.native"
+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
+ "comments (all comments)"
+ "docx/comments.docx"
+ "docx/comments.native"
+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
+ "paragraph insertion/deletion (accept)"
+ "docx/paragraph_insertion_deletion.docx"
+ "docx/paragraph_insertion_deletion_accept.native"
+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
+ "paragraph insertion/deletion (reject)"
+ "docx/paragraph_insertion_deletion.docx"
+ "docx/paragraph_insertion_deletion_reject.native"
+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
+ "paragraph insertion/deletion (all)"
+ "docx/paragraph_insertion_deletion.docx"
+ "docx/paragraph_insertion_deletion_all.native"
+ , testForWarningsWithOpts def{readerTrackChanges=AcceptChanges}
+ "comment warnings (accept -- no warnings)"
+ "docx/comments_warning.docx"
+ []
+ , testForWarningsWithOpts def{readerTrackChanges=RejectChanges}
+ "comment warnings (reject -- no warnings)"
+ "docx/comments_warning.docx"
+ []
+ , testForWarningsWithOpts def{readerTrackChanges=AllChanges}
+ "comment warnings (all)"
+ "docx/comments_warning.docx"
+ ["Docx comment 1 will not retain formatting"]
+ ]
+ , testGroup "media"
+ [ testMediaBag
+ "image extraction"
+ "docx/image.docx"
+ ]
+ , testGroup "custom styles"
+ [ testCompare
+ "custom styles (`+styles`) not enabled (default)"
+ "docx/custom-style-reference.docx"
+ "docx/custom-style-no-styles.native"
+ , testCompareWithOpts
+ def{readerExtensions=extensionsFromList [Ext_styles]}
+ "custom styles (`+styles`) enabled"
+ "docx/custom-style-reference.docx"
+ "docx/custom-style-with-styles.native"
+ ]
+ , testGroup "metadata"
+ [ testCompareWithOpts def{readerStandalone=True}
+ "metadata fields"
+ "docx/metadata.docx"
+ "docx/metadata.native"
+ , testCompareWithOpts def{readerStandalone=True}
+ "stop recording metadata with normal text"
+ "docx/metadata_after_normal.docx"
+ "docx/metadata_after_normal.native"
+ ]
+
+ ]
diff --git a/test/Tests/Readers/EPUB.hs b/test/Tests/Readers/EPUB.hs
new file mode 100644
index 000000000..1337a9c11
--- /dev/null
+++ b/test/Tests/Readers/EPUB.hs
@@ -0,0 +1,40 @@
+module Tests.Readers.EPUB (tests) where
+
+import qualified Data.ByteString.Lazy as BL
+import Test.Tasty
+import Test.Tasty.HUnit
+import qualified Text.Pandoc.Class as P
+import Text.Pandoc.MediaBag (MediaBag, mediaDirectory)
+import Text.Pandoc.Options
+import Text.Pandoc.Readers.EPUB
+
+getMediaBag :: FilePath -> IO MediaBag
+getMediaBag fp = do
+ bs <- BL.readFile fp
+ P.runIOorExplode $ do
+ readEPUB def bs
+ P.getMediaBag
+
+testMediaBag :: FilePath -> [(String, String, Int)] -> IO ()
+testMediaBag fp bag = do
+ actBag <- mediaDirectory <$> getMediaBag fp
+ assertBool (show "MediaBag did not match:\nExpected: "
+ ++ show bag
+ ++ "\nActual: "
+ ++ show actBag)
+ (actBag == bag)
+
+featuresBag :: [(String, String, Int)]
+featuresBag = [("img/check.gif","image/gif",1340)
+ ,("img/check.jpg","image/jpeg",2661)
+ ,("img/check.png","image/png",2815)
+ ,("img/multiscripts_and_greek_alphabet.png","image/png",10060)
+ ]
+
+tests :: [TestTree]
+tests =
+ [ testGroup "EPUB Mediabag"
+ [ testCase "features bag"
+ (testMediaBag "epub/img.epub" featuresBag)
+ ]
+ ]
diff --git a/test/Tests/Readers/HTML.hs b/test/Tests/Readers/HTML.hs
new file mode 100644
index 000000000..70f33d2b2
--- /dev/null
+++ b/test/Tests/Readers/HTML.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.HTML (tests) where
+
+import Data.Text (Text)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+html :: Text -> Pandoc
+html = purely $ readHtml def
+
+htmlNativeDivs :: Text -> Pandoc
+htmlNativeDivs = purely $ readHtml def { readerExtensions = enableExtension Ext_native_divs $ readerExtensions def }
+
+tests :: [TestTree]
+tests = [ testGroup "base tag"
+ [ test html "simple" $
+ "<head><base href=\"http://www.w3schools.com/images/foo\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
+ plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
+ , test html "slash at end of base" $
+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
+ plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
+ , test html "slash at beginning of href" $
+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"/stickman.gif\" alt=\"Stickman\"></head>" =?>
+ plain (image "http://www.w3schools.com/stickman.gif" "" (text "Stickman"))
+ , test html "absolute URL" $
+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"http://example.com/stickman.gif\" alt=\"Stickman\"></head>" =?>
+ plain (image "http://example.com/stickman.gif" "" (text "Stickman"))
+ ]
+ , testGroup "anchors"
+ [ test html "anchor without href" $ "<a name=\"anchor\"/>" =?>
+ plain (spanWith ("anchor",[],[]) mempty)
+ ]
+ , testGroup "lang"
+ [ test html "lang on <html>" $ "<html lang=\"es\">hola" =?>
+ setMeta "lang" (text "es") (doc (plain (text "hola")))
+ , test html "xml:lang on <html>" $ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"es\"><head></head><body>hola</body></html>" =?>
+ setMeta "lang" (text "es") (doc (plain (text "hola")))
+ ]
+ , testGroup "main"
+ [ test htmlNativeDivs "<main> becomes <div role=main>" $ "<main>hello</main>" =?>
+ doc (divWith ("", [], [("role", "main")]) (plain (text "hello")))
+ , test htmlNativeDivs "<main role=X> becomes <div role=X>" $ "<main role=foobar>hello</main>" =?>
+ doc (divWith ("", [], [("role", "foobar")]) (plain (text "hello")))
+ , test htmlNativeDivs "<main> has attributes preserved" $ "<main id=foo class=bar data-baz=qux>hello</main>" =?>
+ doc (divWith ("foo", ["bar"], [("role", "main"), ("data-baz", "qux")]) (plain (text "hello")))
+ , test htmlNativeDivs "<main> closes <p>" $ "<p>hello<main>main content</main>" =?>
+ doc (para (text "hello") <> divWith ("", [], [("role", "main")]) (plain (text "main content")))
+ , test htmlNativeDivs "<main> followed by text" $ "<main>main content</main>non-main content" =?>
+ doc (divWith ("", [], [("role", "main")]) (plain (text "main content")) <> plain (text "non-main content"))
+ ]
+ ]
diff --git a/test/Tests/Readers/JATS.hs b/test/Tests/Readers/JATS.hs
new file mode 100644
index 000000000..5c7dfa77c
--- /dev/null
+++ b/test/Tests/Readers/JATS.hs
@@ -0,0 +1,116 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.JATS (tests) where
+
+import Data.Text (Text)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+jats :: Text -> Pandoc
+jats = purely $ readJATS def
+
+tests :: [TestTree]
+tests = [ testGroup "inline code"
+ [ test jats "basic" $ "<p>\n <monospace>@&amp;</monospace>\n</p>" =?> para (code "@&")
+ , test jats "lang" $ "<p>\n <code language=\"c\">@&amp;</code>\n</p>" =?> para (codeWith ("", ["c"], []) "@&")
+ ]
+ , testGroup "block code"
+ [ test jats "basic" $ "<preformat>@&amp;</preformat>" =?> codeBlock "@&"
+ , test jats "lang" $ "<code language=\"c\">@&amp;</code>" =?> codeBlockWith ("", ["c"], []) "@&"
+ ]
+ , testGroup "images"
+ [ test jats "basic" $ "<graphic mimetype=\"image\" mime-subtype=\"\" xlink:href=\"/url\" xlink:title=\"title\" />"
+ =?> para (image "/url" "title" mempty)
+ ]
+ , test jats "bullet list" $
+ "<list list-type=\"bullet\">\n\
+ \ <list-item>\n\
+ \ <p>\n\
+ \ first\n\
+ \ </p>\n\
+ \ </list-item>\n\
+ \ <list-item>\n\
+ \ <p>\n\
+ \ second\n\
+ \ </p>\n\
+ \ </list-item>\n\
+ \ <list-item>\n\
+ \ <p>\n\
+ \ third\n\
+ \ </p>\n\
+ \ </list-item>\n\
+ \</list>"
+ =?> bulletList [ para $ text "first"
+ , para $ text "second"
+ , para $ text "third"
+ ]
+ , testGroup "definition lists"
+ [ test jats "with internal link" $
+ "<def-list>\n\
+ \ <def-item>\n\
+ \ <term>\n\
+ \ <xref alt=\"testing\" rid=\"go\">testing</xref>\n\
+ \ </term>\n\
+ \ <def>\n\
+ \ <p>\n\
+ \ hi there\n\
+ \ </p>\n\
+ \ </def>\n\
+ \ </def-item>\n\
+ \</def-list>"
+ =?> definitionList [(link "#go" "" (str "testing"),
+ [para (text "hi there")])]
+ ]
+ , testGroup "math"
+ [ test jats "escape |" $
+ "<p>\n\
+ \ <inline-formula><alternatives>\n\
+ \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
+ \ <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\
+ \</p>"
+ =?> para (math "\\sigma|_{\\{x\\}}")
+ , test jats "tex-math only" $
+ "<p>\n\
+ \ <inline-formula><alternatives>\n\
+ \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
+ \</p>"
+ =?> para (math "\\sigma|_{\\{x\\}}")
+ , test jats "math ml only" $
+ "<p>\n\
+ \ <inline-formula><alternatives>\n\
+ \ <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\
+ \</p>"
+ =?> para (math "\\sigma|_{\\{ x\\}}")
+ ]
+ , testGroup "headers"
+-- TODO fix footnotes in headers
+-- [ test jats "unnumbered header" $
+-- "<sec>\n\
+-- \ <title>Header 1<fn>\n\
+-- \ <p>\n\
+-- \ note\n\
+-- \ </p>\n\
+-- \ </fn></title>\n\
+-- \</sec>"
+-- =?> header 1
+-- (text "Header 1" <> note (plain $ text "note"))
+ [ test jats "unnumbered sub header" $
+ "<sec id=\"foo\">\n\
+ \ <title>Header</title>\n\
+ \ <sec id=\"foo2\">\n\
+ \ <title>Sub-Header</title>\n\
+ \ </sec>\n\
+ \</sec>"
+ =?> headerWith ("foo", [], []) 1
+ (text "Header")
+ <> headerWith ("foo2", [], []) 2
+ (text "Sub-Header")
+ , test jats "containing image" $
+ "<sec>\n\
+ \ <title><inline-graphic mimetype=\"image\" mime-subtype=\"jpeg\" xlink:href=\"imgs/foo.jpg\" /></title>\n\
+ \</sec>"
+ =?> header 1 (image "imgs/foo.jpg" "" mempty)
+ ]
+ ]
diff --git a/test/Tests/Readers/LaTeX.hs b/test/Tests/Readers/LaTeX.hs
new file mode 100644
index 000000000..4396d550f
--- /dev/null
+++ b/test/Tests/Readers/LaTeX.hs
@@ -0,0 +1,341 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.LaTeX (tests) where
+
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Text.Pandoc.UTF8 as UTF8
+import Text.Pandoc.Readers.LaTeX (tokenize, untokenize)
+import Test.Tasty
+import Test.Tasty.HUnit
+import Test.Tasty.QuickCheck
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+latex :: Text -> Pandoc
+latex = purely $ readLaTeX def{
+ readerExtensions = getDefaultExtensions "latex" }
+
+infix 4 =:
+(=:) :: ToString c
+ => String -> (Text, c) -> TestTree
+(=:) = test latex
+
+simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks
+simpleTable' aligns = table "" (zip aligns (repeat 0.0))
+ (map (const mempty) aligns)
+
+tokUntokRt :: String -> Bool
+tokUntokRt s = untokenize (tokenize "random" t) == t
+ where t = T.pack s
+
+tests :: [TestTree]
+tests = [ testGroup "tokenization"
+ [ testCase "tokenizer round trip on test case" $ do
+ orig <- T.pack <$> UTF8.readFile "../test/latex-reader.latex"
+ let new = untokenize $ tokenize "../test/latex-reader.latex"
+ orig
+ assertEqual "untokenize . tokenize is identity" orig new
+ , testProperty "untokenize . tokenize is identity" tokUntokRt
+ ]
+
+ , testGroup "basic"
+ [ "simple" =:
+ "word" =?> para "word"
+ , "space" =:
+ "some text" =?> para "some text"
+ , "emphasized" =:
+ "\\emph{emphasized}" =?> para (emph "emphasized")
+ ]
+
+ , testGroup "headers"
+ [ "level 1" =:
+ "\\section{header}" =?> headerWith ("header",[],[]) 1 "header"
+ , "level 2" =:
+ "\\subsection{header}" =?> headerWith ("header",[],[]) 2 "header"
+ , "level 3" =:
+ "\\subsubsection{header}" =?> headerWith ("header",[],[]) 3 "header"
+ , "emph" =:
+ "\\section{text \\emph{emph}}" =?>
+ headerWith ("text-emph",[],[]) 1 ("text" <> space <> emph "emph")
+ , "link" =:
+ "\\section{text \\href{/url}{link}}" =?>
+ headerWith ("text-link",[],[]) 1 ("text" <> space <> link "/url" "" "link")
+ ]
+
+ , testGroup "math"
+ [ "escaped $" =:
+ "$x=\\$4$" =?> para (math "x=\\$4")
+ ]
+
+ , testGroup "space and comments"
+ [ "blank lines + space at beginning" =:
+ "\n \n hi" =?> para "hi"
+ , "blank lines + space + comments" =:
+ "% my comment\n\n \n % another\n\nhi" =?> para "hi"
+ , "comment in paragraph" =:
+ "hi % this is a comment\nthere\n" =?>
+ para ("hi" <> softbreak <> "there")
+ ]
+
+ , testGroup "code blocks"
+ [ "identifier" =:
+ "\\begin{lstlisting}[label=test]\\end{lstlisting}" =?> codeBlockWith ("test", [], [("label","test")]) ""
+ , "no identifier" =:
+ "\\begin{lstlisting}\\end{lstlisting}" =?> codeBlock ""
+ ]
+
+ , testGroup "tables"
+ [ "Single cell table" =:
+ "\\begin{tabular}{|l|}Test\\\\\\end{tabular}" =?>
+ simpleTable' [AlignLeft] [[plain "Test"]]
+ , "Multi cell table" =:
+ "\\begin{tabular}{|rl|}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Multi line table" =:
+ T.unlines [ "\\begin{tabular}{|c|}"
+ , "One\\\\"
+ , "Two\\\\"
+ , "Three\\\\"
+ , "\\end{tabular}" ] =?>
+ simpleTable' [AlignCenter]
+ [[plain "One"], [plain "Two"], [plain "Three"]]
+ , "Empty table" =:
+ "\\begin{tabular}{}\\end{tabular}" =?>
+ simpleTable' [] []
+ , "Table with fixed column width" =:
+ "\\begin{tabular}{|p{5cm}r|}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignLeft,AlignRight] [[plain "One", plain "Two"]]
+ , "Table with empty column separators" =:
+ "\\begin{tabular}{@{}r@{}l}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Table with custom column separators" =:
+ T.unlines [ "\\begin{tabular}{@{($\\to$)}r@{\\hspace{2cm}}l}"
+ , "One&Two\\\\"
+ , "\\end{tabular}" ] =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Table with vertical alignment argument" =:
+ "\\begin{tabular}[t]{r|r}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignRight] [[plain "One", plain "Two"]]
+ ]
+
+ , testGroup "citations"
+ [ natbibCitations
+ , biblatexCitations
+ ]
+
+ , testGroup "images"
+ [ "Basic image" =:
+ "\\includegraphics{foo.png}" =?>
+ para (image "foo.png" "" (text "image"))
+ , "Basic image with blank options" =:
+ "\\includegraphics[]{foo.png}" =?>
+ para (image "foo.png" "" (text "image"))
+ , "Image with both width and height" =:
+ "\\includegraphics[width=17cm,height=5cm]{foo.png}" =?>
+ para (imageWith ("", [], [("width", "17cm"), ("height", "5cm")]) "foo.png" "" "image")
+ , "Image with width and height and a bunch of other options" =:
+ "\\includegraphics[width=17cm,height=5cm,clip,keepaspectratio]{foo.png}" =?>
+ para (imageWith ("", [], [("width", "17cm"), ("height", "5cm")]) "foo.png" "" "image")
+ , "Image with just width" =:
+ "\\includegraphics[width=17cm]{foo.png}" =?>
+ para (imageWith ("", [], [("width", "17cm")]) "foo.png" "" "image")
+ , "Image with just height" =:
+ "\\includegraphics[height=17cm]{foo.png}" =?>
+ para (imageWith ("", [], [("height", "17cm")]) "foo.png" "" "image")
+ , "Image width relative to textsize" =:
+ "\\includegraphics[width=0.6\\textwidth]{foo.png}" =?>
+ para (imageWith ("", [], [("width", "60%")]) "foo.png" "" "image")
+ , "Image with options with spaces" =:
+ "\\includegraphics[width=12cm, height = 5cm]{foo.png}" =?>
+ para (imageWith ("", [], [("width", "12cm"), ("height", "5cm")]) "foo.png" "" "image")
+ ]
+
+ , let hex = ['0'..'9']++['a'..'f'] in
+ testGroup "Character Escapes"
+ [ "Two-character escapes" =:
+ mconcat ["^^" <> T.pack [i,j] | i <- hex, j <- hex] =?>
+ para (str ['\0'..'\255'])
+ , "One-character escapes" =:
+ mconcat ["^^" <> T.pack [i] | i <- hex] =?>
+ para (str $ ['p'..'y']++['!'..'&'])
+ ]
+ , testGroup "memoir scene breaks"
+ [ "plainbreak" =:
+ "hello\\plainbreak{2}goodbye" =?>
+ para (str "hello") <> horizontalRule <> para (str "goodbye")
+ , "plainbreak*" =:
+ "hello\\plainbreak*{2}goodbye" =?>
+ para (str "hello") <> horizontalRule <> para (str "goodbye")
+ , "fancybreak" =:
+ "hello\\fancybreak{b r e a k}goodbye" =?>
+ para (str "hello") <> horizontalRule <> para (str "goodbye")
+ , "fancybreak*" =:
+ "hello\\fancybreak*{b r e a k}goodbye" =?>
+ para (str "hello") <> horizontalRule <> para (str "goodbye")
+ , "plainfancybreak" =:
+ "hello\\plainfancybreak{4}{2}{b r e a k}goodbye" =?>
+ para (str "hello") <> horizontalRule <> para (str "goodbye")
+ , "plainfancybreak*" =:
+ "hello\\plainfancybreak*{4}{2}{b r e a k}goodbye" =?>
+ para (str "hello") <> horizontalRule <> para (str "goodbye")
+ , "pfbreak" =:
+ "hello\\pfbreak{}goodbye" =?>
+ para (str "hello") <> horizontalRule <> para (str "goodbye")
+ , "pfbreak*" =:
+ "hello\\pfbreak*{}goodbye" =?>
+ para (str "hello") <> horizontalRule <> para (str "goodbye")
+ ]
+ , testGroup "biblatex roman numerals"
+ [ "upper" =:
+ "number \\RN{12}" =?>
+ para (str "number" <> space <> str "XII")
+ , "lower" =:
+ "number \\Rn{29}" =?>
+ para (str "number" <> space <> str "xxix")
+ , "leading zero" =:
+ "\\Rn{014}" =?>
+ para (str "xiv")
+ , "surrounding spaces" =:
+ "number \\Rn{ 41 }" =?>
+ para (str "number" <> space <> str "xli")
+ , "zero" =:
+ "\\RN{0}" =?>
+ para (str "")
+ , "space then unbraced argument" =:
+ "\\RN 7 ok" =?>
+ para (str "VII" <> space <> str "ok")
+ , "space before braced argument" =:
+ "\\Rn {13}ok" =?>
+ para (str "xiiiok")
+ ]
+ , testGroup "polyglossia language spans"
+ [ "french" =:
+ "hello \\textfrench{bonjour}" =?>
+ para (str "hello" <> space <> spanWith ("", [], [("lang", "fr")]) (str "bonjour"))
+ , "nested" =:
+ "\\textfrench{quelle c'est \\textlatin{primus}?}" =?>
+ para (spanWith ("", [], [("lang", "fr")]) $
+ str "quelle" <> space <> str "c\8217est" <> space <>
+ spanWith ("", [], [("lang", "la")]) (str "primus") <> str "?")
+ , "with formatting" =:
+ "\\textgerman{wie \\emph{spaet} ist es?}" =?>
+ para (spanWith ("", [], [("lang", "de")]) $
+ str "wie" <> space <> emph (str "spaet") <> space <> str "ist" <> space <> str "es?")
+ , "language options" =:
+ "\\textgerman[variant=swiss]{hoechdeutsche}" =?>
+ para (spanWith ("", [], [("lang", "de-CH")]) $ str "hoechdeutsche")
+ , "unknown option fallback" =:
+ "\\textgerman[variant=moon]{ueberhoechdeutsche}" =?>
+ para (spanWith ("", [], [("lang", "de")]) $ str "ueberhoechdeutsche")
+ ]
+ ]
+
+baseCitation :: Citation
+baseCitation = Citation{ citationId = "item1"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+
+rt :: String -> Inlines
+rt = rawInline "latex"
+
+natbibCitations :: TestTree
+natbibCitations = testGroup "natbib"
+ [ "citet" =: "\\citet{item1}"
+ =?> para (cite [baseCitation] (rt "\\citet{item1}"))
+ , "suffix" =: "\\citet[p.~30]{item1}"
+ =?> para
+ (cite [baseCitation{ citationSuffix = toList $ text "p.\160\&30" }] (rt "\\citet[p.~30]{item1}"))
+ , "suffix long" =: "\\citet[p.~30, with suffix]{item1}"
+ =?> para (cite [baseCitation{ citationSuffix =
+ toList $ text "p.\160\&30, with suffix" }] (rt "\\citet[p.~30, with suffix]{item1}"))
+ , "multiple" =: "\\citeauthor{item1} \\citetext{\\citeyear{item1}; \\citeyear[p.~30]{item2}; \\citealp[see also][]{item3}}"
+ =?> para (cite [baseCitation{ citationMode = AuthorInText }
+ ,baseCitation{ citationMode = SuppressAuthor
+ , citationSuffix = [Str "p.\160\&30"]
+ , citationId = "item2" }
+ ,baseCitation{ citationId = "item3"
+ , citationPrefix = [Str "see",Space,Str "also"]
+ , citationMode = NormalCitation }
+ ] (rt "\\citetext{\\citeyear{item1}; \\citeyear[p.~30]{item2}; \\citealp[see also][]{item3}}"))
+ , "group" =: "\\citetext{\\citealp[see][p.~34--35]{item1}; \\citealp[also][chap. 3]{item3}}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation
+ , citationPrefix = [Str "see"]
+ , citationSuffix = [Str "p.\160\&34\8211\&35"] }
+ ,baseCitation{ citationMode = NormalCitation
+ , citationId = "item3"
+ , citationPrefix = [Str "also"]
+ , citationSuffix = [Str "chap.",Space,Str "3"] }
+ ] (rt "\\citetext{\\citealp[see][p.~34--35]{item1}; \\citealp[also][chap. 3]{item3}}"))
+ , "suffix and locator" =: "\\citep[pp.~33, 35--37, and nowhere else]{item1}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation
+ , 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}"))
+ , "suffix only" =: "\\citep[and nowhere else]{item1}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation
+ , citationSuffix = toList $ text "and nowhere else" }] (rt "\\citep[and nowhere else]{item1}"))
+ , "no author" =: "\\citeyearpar{item1}, and now Doe with a locator \\citeyearpar[p.~44]{item2}"
+ =?> para (cite [baseCitation{ citationMode = SuppressAuthor }] (rt "\\citeyearpar{item1}") <>
+ text ", and now Doe with a locator " <>
+ cite [baseCitation{ citationMode = SuppressAuthor
+ , citationSuffix = [Str "p.\160\&44"]
+ , citationId = "item2" }] (rt "\\citeyearpar[p.~44]{item2}"))
+ , "markup" =: "\\citep[\\emph{see}][p. \\textbf{32}]{item1}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation
+ , citationPrefix = [Emph [Str "see"]]
+ , citationSuffix = [Str "p.",Space,
+ Strong [Str "32"]] }] (rt "\\citep[\\emph{see}][p. \\textbf{32}]{item1}"))
+ ]
+
+biblatexCitations :: TestTree
+biblatexCitations = testGroup "biblatex"
+ [ "textcite" =: "\\textcite{item1}"
+ =?> para (cite [baseCitation] (rt "\\textcite{item1}"))
+ , "suffix" =: "\\textcite[p.~30]{item1}"
+ =?> para
+ (cite [baseCitation{ citationSuffix = toList $ text "p.\160\&30" }] (rt "\\textcite[p.~30]{item1}"))
+ , "suffix long" =: "\\textcite[p.~30, with suffix]{item1}"
+ =?> para (cite [baseCitation{ citationSuffix =
+ toList $ text "p.\160\&30, with suffix" }] (rt "\\textcite[p.~30, with suffix]{item1}"))
+ , "multiple" =: "\\textcites{item1}[p.~30]{item2}[see also][]{item3}"
+ =?> para (cite [baseCitation{ citationMode = AuthorInText }
+ ,baseCitation{ citationMode = NormalCitation
+ , citationSuffix = [Str "p.\160\&30"]
+ , citationId = "item2" }
+ ,baseCitation{ citationId = "item3"
+ , citationPrefix = [Str "see",Space,Str "also"]
+ , citationMode = NormalCitation }
+ ] (rt "\\textcites{item1}[p.~30]{item2}[see also][]{item3}"))
+ , "group" =: "\\autocites[see][p.~34--35]{item1}[also][chap. 3]{item3}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation
+ , citationPrefix = [Str "see"]
+ , citationSuffix = [Str "p.\160\&34\8211\&35"] }
+ ,baseCitation{ citationMode = NormalCitation
+ , citationId = "item3"
+ , citationPrefix = [Str "also"]
+ , citationSuffix = [Str "chap.",Space,Str "3"] }
+ ] (rt "\\autocites[see][p.~34--35]{item1}[also][chap. 3]{item3}"))
+ , "suffix and locator" =: "\\autocite[pp.~33, 35--37, and nowhere else]{item1}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation
+ , 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}"))
+ , "suffix only" =: "\\autocite[and nowhere else]{item1}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation
+ , citationSuffix = toList $ text "and nowhere else" }] (rt "\\autocite[and nowhere else]{item1}"))
+ , "no author" =: "\\autocite*{item1}, and now Doe with a locator \\autocite*[p.~44]{item2}"
+ =?> para (cite [baseCitation{ citationMode = SuppressAuthor }] (rt "\\autocite*{item1}") <>
+ text ", and now Doe with a locator " <>
+ cite [baseCitation{ citationMode = SuppressAuthor
+ , citationSuffix = [Str "p.\160\&44"]
+ , citationId = "item2" }] (rt "\\autocite*[p.~44]{item2}"))
+ , "markup" =: "\\autocite[\\emph{see}][p. \\textbf{32}]{item1}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation
+ , citationPrefix = [Emph [Str "see"]]
+ , citationSuffix = [Str "p.",Space,
+ Strong [Str "32"]] }] (rt "\\autocite[\\emph{see}][p. \\textbf{32}]{item1}"))
+ , "parencite" =: "\\parencite{item1}"
+ =?> para (cite [baseCitation{ citationMode = NormalCitation }] (rt "\\parencite{item1}"))
+ ]
diff --git a/test/Tests/Readers/Markdown.hs b/test/Tests/Readers/Markdown.hs
new file mode 100644
index 000000000..1cd32b87d
--- /dev/null
+++ b/test/Tests/Readers/Markdown.hs
@@ -0,0 +1,462 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Markdown (tests) where
+
+import Data.Text (Text, unpack)
+import qualified Data.Text as T
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+markdown :: Text -> Pandoc
+markdown = purely $ readMarkdown def { readerExtensions =
+ disableExtension Ext_smart pandocExtensions }
+
+markdownSmart :: Text -> Pandoc
+markdownSmart = purely $ readMarkdown def { readerExtensions =
+ enableExtension Ext_smart pandocExtensions }
+
+markdownCDL :: Text -> Pandoc
+markdownCDL = purely $ readMarkdown def { readerExtensions = enableExtension
+ Ext_compact_definition_lists pandocExtensions }
+
+markdownGH :: Text -> Pandoc
+markdownGH = purely $ readMarkdown def {
+ readerExtensions = githubMarkdownExtensions }
+
+infix 4 =:
+(=:) :: ToString c
+ => String -> (Text, c) -> TestTree
+(=:) = test markdown
+
+testBareLink :: (Text, Inlines) -> TestTree
+testBareLink (inp, ils) =
+ test (purely $ readMarkdown def{ readerExtensions =
+ extensionsFromList [Ext_autolink_bare_uris, Ext_raw_html] })
+ (unpack inp) (inp, doc $ para ils)
+
+autolink :: String -> Inlines
+autolink = autolinkWith nullAttr
+
+autolinkWith :: Attr -> String -> Inlines
+autolinkWith attr s = linkWith attr s "" (str s)
+
+bareLinkTests :: [(Text, Inlines)]
+bareLinkTests =
+ [ ("http://google.com is a search engine.",
+ autolink "http://google.com" <> " is a search engine.")
+ , ("<a href=\"http://foo.bar.baz\">http://foo.bar.baz</a>",
+ rawInline "html" "<a href=\"http://foo.bar.baz\">" <>
+ "http://foo.bar.baz" <> rawInline "html" "</a>")
+ , ("Try this query: http://google.com?search=fish&time=hour.",
+ "Try this query: " <> autolink "http://google.com?search=fish&time=hour" <> ".")
+ , ("HTTPS://GOOGLE.COM,",
+ autolink "HTTPS://GOOGLE.COM" <> ",")
+ , ("http://el.wikipedia.org/wiki/Τεχνολογία,",
+ autolink "http://el.wikipedia.org/wiki/Τεχνολογία" <> ",")
+ , ("doi:10.1000/182,",
+ autolink "doi:10.1000/182" <> ",")
+ , ("git://github.com/foo/bar.git,",
+ autolink "git://github.com/foo/bar.git" <> ",")
+ , ("file:///Users/joe/joe.txt, and",
+ autolink "file:///Users/joe/joe.txt" <> ", and")
+ , ("mailto:someone@somedomain.com.",
+ autolink "mailto:someone@somedomain.com" <> ".")
+ , ("Use http: this is not a link!",
+ "Use http: this is not a link!")
+ , ("(http://google.com).",
+ "(" <> autolink "http://google.com" <> ").")
+ , ("http://en.wikipedia.org/wiki/Sprite_(computer_graphics)",
+ autolink "http://en.wikipedia.org/wiki/Sprite_(computer_graphics)")
+ , ("http://en.wikipedia.org/wiki/Sprite_[computer_graphics]",
+ link "http://en.wikipedia.org/wiki/Sprite_%5Bcomputer_graphics%5D" ""
+ (str "http://en.wikipedia.org/wiki/Sprite_[computer_graphics]"))
+ , ("http://en.wikipedia.org/wiki/Sprite_{computer_graphics}",
+ link "http://en.wikipedia.org/wiki/Sprite_%7Bcomputer_graphics%7D" ""
+ (str "http://en.wikipedia.org/wiki/Sprite_{computer_graphics}"))
+ , ("http://example.com/Notification_Center-GitHub-20101108-140050.jpg",
+ autolink "http://example.com/Notification_Center-GitHub-20101108-140050.jpg")
+ , ("https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20",
+ autolink "https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20")
+ , ("http://www.rubyonrails.com",
+ autolink "http://www.rubyonrails.com")
+ , ("http://www.rubyonrails.com:80",
+ autolink "http://www.rubyonrails.com:80")
+ , ("http://www.rubyonrails.com/~minam",
+ autolink "http://www.rubyonrails.com/~minam")
+ , ("https://www.rubyonrails.com/~minam",
+ autolink "https://www.rubyonrails.com/~minam")
+ , ("http://www.rubyonrails.com/~minam/url%20with%20spaces",
+ autolink "http://www.rubyonrails.com/~minam/url%20with%20spaces")
+ , ("http://www.rubyonrails.com/foo.cgi?something=here",
+ autolink "http://www.rubyonrails.com/foo.cgi?something=here")
+ , ("http://www.rubyonrails.com/foo.cgi?something=here&and=here",
+ autolink "http://www.rubyonrails.com/foo.cgi?something=here&and=here")
+ , ("http://www.rubyonrails.com/contact;new",
+ autolink "http://www.rubyonrails.com/contact;new")
+ , ("http://www.rubyonrails.com/contact;new%20with%20spaces",
+ autolink "http://www.rubyonrails.com/contact;new%20with%20spaces")
+ , ("http://www.rubyonrails.com/contact;new?with=query&string=params",
+ autolink "http://www.rubyonrails.com/contact;new?with=query&string=params")
+ , ("http://www.rubyonrails.com/~minam/contact;new?with=query&string=params",
+ autolink "http://www.rubyonrails.com/~minam/contact;new?with=query&string=params")
+ , ("http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007",
+ autolink "http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007")
+ , ("http://www.mail-archive.com/rails@lists.rubyonrails.org/",
+ autolink "http://www.mail-archive.com/rails@lists.rubyonrails.org/")
+ , ("http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1",
+ autolink "http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1")
+ , ("http://en.wikipedia.org/wiki/Texas_hold%27em",
+ autolink "http://en.wikipedia.org/wiki/Texas_hold%27em")
+ , ("https://www.google.com/doku.php?id=gps:resource:scs:start",
+ autolink "https://www.google.com/doku.php?id=gps:resource:scs:start")
+ , ("http://www.rubyonrails.com",
+ autolink "http://www.rubyonrails.com")
+ , ("http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281",
+ autolink "http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281")
+ , ("http://foo.example.com/controller/action?parm=value&p2=v2#anchor123",
+ autolink "http://foo.example.com/controller/action?parm=value&p2=v2#anchor123")
+ , ("http://foo.example.com:3000/controller/action",
+ autolink "http://foo.example.com:3000/controller/action")
+ , ("http://foo.example.com:3000/controller/action+pack",
+ autolink "http://foo.example.com:3000/controller/action+pack")
+ , ("http://business.timesonline.co.uk/article/0,,9065-2473189,00.html",
+ autolink "http://business.timesonline.co.uk/article/0,,9065-2473189,00.html")
+ , ("http://www.mail-archive.com/ruby-talk@ruby-lang.org/",
+ autolink "http://www.mail-archive.com/ruby-talk@ruby-lang.org/")
+ , ("https://example.org/?anchor=lala-",
+ autolink "https://example.org/?anchor=lala-")
+ , ("https://example.org/?anchor=-lala",
+ autolink "https://example.org/?anchor=-lala")
+ ]
+
+{-
+p_markdown_round_trip :: Block -> Bool
+p_markdown_round_trip b = matches d' d''
+ where d' = normalize $ Pandoc (Meta [] [] []) [b]
+ d'' = normalize
+ $ readMarkdown def { readerSmart = True }
+ $ writeMarkdown def d'
+ matches (Pandoc _ [Plain []]) (Pandoc _ []) = True
+ matches (Pandoc _ [Para []]) (Pandoc _ []) = True
+ matches (Pandoc _ [Plain xs]) (Pandoc _ [Para xs']) = xs == xs'
+ matches x y = x == y
+-}
+
+tests :: [TestTree]
+tests = [ testGroup "inline code"
+ [ "with attribute" =:
+ "`document.write(\"Hello\");`{.javascript}"
+ =?> para
+ (codeWith ("",["javascript"],[]) "document.write(\"Hello\");")
+ , "with attribute space" =:
+ "`*` {.haskell .special x=\"7\"}"
+ =?> para (code "*" <> space <> str "{.haskell" <> space <>
+ str ".special" <> space <> str "x=\"7\"}")
+ ]
+ , testGroup "emph and strong"
+ [ "two strongs in emph" =:
+ "***a**b **c**d*" =?> para (emph (strong (str "a") <> str "b" <> space
+ <> strong (str "c") <> str "d"))
+ , "emph and strong emph alternating" =:
+ "*xxx* ***xxx*** xxx\n*xxx* ***xxx*** xxx"
+ =?> para (emph "xxx" <> space <> strong (emph "xxx") <>
+ space <> "xxx" <> softbreak <>
+ emph "xxx" <> space <> strong (emph "xxx") <>
+ space <> "xxx")
+ , "emph with spaced strong" =:
+ "*x **xx** x*"
+ =?> para (emph ("x" <> space <> strong "xx" <> space <> "x"))
+ , "intraword underscore with opening underscore (#1121)" =:
+ "_foot_ball_" =?> para (emph (text "foot_ball"))
+ ]
+ , testGroup "raw LaTeX"
+ [ "in URL" =:
+ "\\begin\n" =?> para (text "\\begin")
+ ]
+ , testGroup "raw HTML"
+ [ "nesting (issue #1330)" =:
+ "<del>test</del>" =?>
+ rawBlock "html" "<del>" <> plain (str "test") <>
+ rawBlock "html" "</del>"
+ , "invalid tag (issue #1820" =:
+ "</ div></.div>" =?>
+ para (text "</ div></.div>")
+ , "technically invalid comment" =:
+ "<!-- pandoc --help -->" =?>
+ rawBlock "html" "<!-- pandoc --help -->"
+ , test markdownGH "issue 2469" $
+ "<\n\na>" =?>
+ para (text "<") <> para (text "a>")
+ ]
+ , testGroup "raw email addresses"
+ [ test markdownGH "issue 2940" $
+ "**@user**" =?>
+ para (strong (text "@user"))
+ ]
+ , testGroup "emoji"
+ [ test markdownGH "emoji symbols" $
+ ":smile: and :+1:" =?> para (text "😄 and 👍")
+ ]
+ , "unbalanced brackets" =:
+ "[[[[[[[[[[[[hi" =?> para (text "[[[[[[[[[[[[hi")
+ , testGroup "backslash escapes"
+ [ "in URL" =:
+ "[hi](/there\\))"
+ =?> para (link "/there)" "" "hi")
+ , "in title" =:
+ "[hi](/there \"a\\\"a\")"
+ =?> para (link "/there" "a\"a" "hi")
+ , "in reference link title" =:
+ "[hi]\n\n[hi]: /there (a\\)a)"
+ =?> para (link "/there" "a)a" "hi")
+ , "in reference link URL" =:
+ "[hi]\n\n[hi]: /there\\.0"
+ =?> para (link "/there.0" "" "hi")
+ ]
+ , testGroup "bare URIs"
+ (map testBareLink bareLinkTests)
+ , testGroup "autolinks"
+ [ "with unicode dash following" =:
+ "<http://foo.bar>\8212" =?> para (autolink "http://foo.bar" <>
+ str "\8212")
+ , "a partial URL (#2277)" =:
+ "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>" =?>
+ para (text "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>")
+ , "with some attributes" =:
+ "<http://foo.bar>{#i .j .z k=v}" =?>
+ para (autolinkWith ("i", ["j", "z"], [("k", "v")]) "http://foo.bar")
+ , "with some attributes and spaces" =:
+ "<http://foo.bar> {#i .j .z k=v}" =?>
+ para (autolink "http://foo.bar" <> space <> text "{#i .j .z k=v}")
+ ]
+ , testGroup "links"
+ [ "no autolink inside link" =:
+ "[<https://example.org>](url)" =?>
+ para (link "url" "" (text "<https://example.org>"))
+ , "no inline link inside link" =:
+ "[[a](url2)](url)" =?>
+ para (link "url" "" (text "[a](url2)"))
+ , "no bare URI inside link" =:
+ "[https://example.org(](url)" =?>
+ para (link "url" "" (text "https://example.org("))
+ ]
+ , testGroup "Headers"
+ [ "blank line before header" =:
+ "\n# Header\n"
+ =?> headerWith ("header",[],[]) 1 "Header"
+ , "bracketed text (#2062)" =:
+ "# [hi]\n"
+ =?> headerWith ("hi",[],[]) 1 "[hi]"
+ , "ATX header without trailing #s" =:
+ "# Foo bar\n\n" =?>
+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
+ , "ATX header without trailing #s" =:
+ "# Foo bar with # #" =?>
+ headerWith ("foo-bar-with",[],[]) 1 "Foo bar with #"
+ , "setext header" =:
+ "Foo bar\n=\n\n Foo bar 2 \n=" =?>
+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
+ <> headerWith ("foo-bar-2",[],[]) 1 "Foo bar 2"
+ ]
+ , testGroup "Implicit header references"
+ [ "ATX header without trailing #s" =:
+ "# Header\n[header]\n\n[header ]\n\n[ header]" =?>
+ headerWith ("header",[],[]) 1 "Header"
+ <> para (link "#header" "" (text "header"))
+ <> para (link "#header" "" (text "header"))
+ <> para (link "#header" "" (text "header"))
+ , "ATX header with trailing #s" =:
+ "# Foo bar #\n[foo bar]\n\n[foo bar ]\n\n[ foo bar]" =?>
+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
+ <> para (link "#foo-bar" "" (text "foo bar"))
+ <> para (link "#foo-bar" "" (text "foo bar"))
+ <> para (link "#foo-bar" "" (text "foo bar"))
+ , "setext header" =:
+ " Header \n=\n\n[header]\n\n[header ]\n\n[ header]" =?>
+ headerWith ("header",[],[]) 1 "Header"
+ <> para (link "#header" "" (text "header"))
+ <> para (link "#header" "" (text "header"))
+ <> para (link "#header" "" (text "header"))
+ ]
+ , testGroup "smart punctuation"
+ [ test markdownSmart "quote before ellipses"
+ ("'...hi'"
+ =?> para (singleQuoted "…hi"))
+ , test markdownSmart "apostrophe before emph"
+ ("D'oh! A l'*aide*!"
+ =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
+ , test markdownSmart "apostrophe in French"
+ ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
+ =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
+ , test markdownSmart "apostrophe after math" $ -- issue #1909
+ "The value of the $x$'s and the systems' condition." =?>
+ para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.")
+ ]
+ , testGroup "footnotes"
+ [ "indent followed by newline and flush-left text" =:
+ "[^1]\n\n[^1]: my note\n\n \nnot in note\n"
+ =?> para (note (para "my note")) <> para "not in note"
+ , "indent followed by newline and indented text" =:
+ "[^1]\n\n[^1]: my note\n \n in note\n"
+ =?> para (note (para "my note" <> para "in note"))
+ , "recursive note" =:
+ "[^1]\n\n[^1]: See [^1]\n"
+ =?> para (note (para "See [^1]"))
+ ]
+ , testGroup "lhs"
+ [ test (purely $ readMarkdown def{ readerExtensions = enableExtension
+ Ext_literate_haskell pandocExtensions })
+ "inverse bird tracks and html" $
+ "> a\n\n< b\n\n<div>\n"
+ =?> codeBlockWith ("",["sourceCode","literate","haskell"],[]) "a"
+ <>
+ codeBlockWith ("",["sourceCode","haskell"],[]) "b"
+ <>
+ rawBlock "html" "<div>\n\n"
+ ]
+-- the round-trip properties frequently fail
+-- , testGroup "round trip"
+-- [ property "p_markdown_round_trip" p_markdown_round_trip
+-- ]
+ , testGroup "definition lists"
+ [ "no blank space" =:
+ "foo1\n : bar\n\nfoo2\n : bar2\n : bar3\n" =?>
+ definitionList [ (text "foo1", [plain (text "bar")])
+ , (text "foo2", [plain (text "bar2"),
+ plain (text "bar3")])
+ ]
+ , "blank space before first def" =:
+ "foo1\n\n : bar\n\nfoo2\n\n : bar2\n : bar3\n" =?>
+ definitionList [ (text "foo1", [para (text "bar")])
+ , (text "foo2", [para (text "bar2"),
+ plain (text "bar3")])
+ ]
+ , "blank space before second def" =:
+ "foo1\n : bar\n\nfoo2\n : bar2\n\n : bar3\n" =?>
+ definitionList [ (text "foo1", [plain (text "bar")])
+ , (text "foo2", [plain (text "bar2"),
+ para (text "bar3")])
+ ]
+ , "laziness" =:
+ "foo1\n : bar\nbaz\n : bar2\n" =?>
+ definitionList [ (text "foo1", [plain (text "bar" <>
+ softbreak <> text "baz"),
+ plain (text "bar2")])
+ ]
+ , "no blank space before first of two paragraphs" =:
+ "foo1\n : bar\n\n baz\n" =?>
+ definitionList [ (text "foo1", [para (text "bar") <>
+ para (text "baz")])
+ ]
+ , "first line not indented" =:
+ "foo\n: bar\n" =?>
+ definitionList [ (text "foo", [plain (text "bar")]) ]
+ , "list in definition" =:
+ "foo\n: - bar\n" =?>
+ definitionList [ (text "foo", [bulletList [plain (text "bar")]]) ]
+ , "in div" =:
+ "<div>foo\n: - bar\n</div>" =?>
+ divWith nullAttr (definitionList
+ [ (text "foo", [bulletList [plain (text "bar")]]) ])
+ ]
+ , testGroup "+compact_definition_lists"
+ [ test markdownCDL "basic compact list" $
+ "foo1\n: bar\n baz\nfoo2\n: bar2\n" =?>
+ definitionList [ (text "foo1", [plain (text "bar" <> softbreak <>
+ text "baz")])
+ , (text "foo2", [plain (text "bar2")])
+ ]
+ ]
+ , testGroup "lists"
+ [ "issue #1154" =:
+ " - <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"
+ =?> bulletList [divWith nullAttr (para $ text "first div breaks") <>
+ rawBlock "html" "<button>" <>
+ plain (text "if this button exists") <>
+ rawBlock "html" "</button>" <>
+ divWith nullAttr (para $ text "with this div too.")]
+ , test markdownGH "issue #1636" $
+ T.unlines [ "* a"
+ , "* b"
+ , "* c"
+ , " * d" ]
+ =?>
+ bulletList [ plain "a"
+ , plain "b"
+ , plain "c" <> bulletList [plain "d"] ]
+ ]
+ , testGroup "entities"
+ [ "character references" =:
+ "&lang; &ouml;" =?> para (text "\10216 ö")
+ , "numeric" =:
+ "&#44;&#x44;&#X44;" =?> para (text ",DD")
+ , "in link title" =:
+ "[link](/url \"title &lang; &ouml; &#44;\")" =?>
+ para (link "/url" "title \10216 ö ," (text "link"))
+ ]
+ , testGroup "citations"
+ [ "simple" =:
+ "@item1" =?> para (cite [
+ Citation{ citationId = "item1"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ ] "@item1")
+ , "key starts with digit" =:
+ "@1657:huyghens" =?> para (cite [
+ Citation{ citationId = "1657:huyghens"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ ] "@1657:huyghens")
+ ]
+ , let citation = cite [Citation "cita" [] [] AuthorInText 0 0] (str "@cita")
+ in testGroup "footnote/link following citation" -- issue #2083
+ [ "footnote" =:
+ T.unlines [ "@cita[^note]"
+ , ""
+ , "[^note]: note" ] =?>
+ para (
+ citation <> note (para $ str "note")
+ )
+ , "normal link" =:
+ "@cita [link](http://www.com)" =?>
+ para (
+ citation <> space <> link "http://www.com" "" (str "link")
+ )
+ , "reference link" =:
+ T.unlines [ "@cita [link][link]"
+ , ""
+ , "[link]: http://www.com" ] =?>
+ para (
+ citation <> space <> link "http://www.com" "" (str "link")
+ )
+ , "short reference link" =:
+ T.unlines [ "@cita [link]"
+ , ""
+ , "[link]: http://www.com" ] =?>
+ para (
+ citation <> space <> link "http://www.com" "" (str "link")
+ )
+ , "implicit header link" =:
+ T.unlines [ "# Header"
+ , "@cita [Header]" ] =?>
+ headerWith ("header",[],[]) 1 (str "Header") <> para (
+ citation <> space <> link "#header" "" (str "Header")
+ )
+ , "regular citation" =:
+ "@cita [foo]" =?>
+ para (
+ cite [Citation "cita" [] [Str "foo"] AuthorInText 0 0]
+ (str "@cita" <> space <> str "[foo]")
+ )
+ ]
+ ]
diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs
new file mode 100644
index 000000000..508d79e18
--- /dev/null
+++ b/test/Tests/Readers/Muse.hs
@@ -0,0 +1,1224 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Muse (tests) where
+
+import Data.List (intersperse)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Test.Tasty
+import Test.Tasty.QuickCheck
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+import Text.Pandoc.Shared (underlineSpan)
+import Text.Pandoc.Walk (walk)
+
+amuse :: Text -> Pandoc
+amuse = purely $ readMuse def { readerExtensions = extensionsFromList [Ext_amuse]}
+
+emacsMuse :: Text -> Pandoc
+emacsMuse = purely $ readMuse def { readerExtensions = emptyExtensions }
+
+infix 4 =:
+(=:) :: ToString c
+ => String -> (Text, c) -> TestTree
+(=:) = test amuse
+
+spcSep :: [Inlines] -> Inlines
+spcSep = mconcat . intersperse space
+
+-- Tables don't round-trip yet
+--
+makeRoundTrip :: Block -> Block
+makeRoundTrip Table{} = Para [Str "table was here"]
+makeRoundTrip (OrderedList (start, LowerAlpha, _) items) = OrderedList (start, Decimal, Period) items
+makeRoundTrip (OrderedList (start, UpperAlpha, _) items) = OrderedList (start, Decimal, Period) items
+makeRoundTrip x = x
+
+-- Demand that any AST produced by Muse reader and written by Muse writer can be read back exactly the same way.
+-- Currently we remove tables and compare third rewrite to the second.
+-- First and second rewrites are not equal yet.
+roundTrip :: Block -> Bool
+roundTrip b = d'' == d'''
+ where d = walk makeRoundTrip $ Pandoc nullMeta [b]
+ d' = rewrite d
+ d'' = rewrite d'
+ d''' = rewrite d''
+ rewrite = amuse . T.pack . (++ "\n") . T.unpack .
+ purely (writeMuse def { writerExtensions = extensionsFromList [Ext_amuse]
+ , writerWrapText = WrapPreserve
+ })
+
+tests :: [TestTree]
+tests =
+ [ testGroup "Inlines"
+ [ "Plain String" =:
+ "Hello, World" =?>
+ para "Hello, World"
+
+ , "Muse is not XML" =: "&lt;" =?> para "&lt;"
+
+ , "Emphasis" =:
+ "*Foo bar*" =?>
+ para (emph . spcSep $ ["Foo", "bar"])
+
+ , "Comma after closing *" =:
+ "Foo *bar*, baz" =?>
+ para ("Foo " <> emph "bar" <> ", baz")
+
+ , "Letter after closing *" =:
+ "Foo *bar*x baz" =?>
+ para "Foo *bar*x baz"
+
+ , "Letter before opening *" =:
+ "Foo x*bar* baz" =?>
+ para "Foo x*bar* baz"
+
+ , "Emphasis tag" =:
+ "<em>Foo bar</em>" =?>
+ para (emph . spcSep $ ["Foo", "bar"])
+
+ , "Strong" =:
+ "**Cider**" =?>
+ para (strong "Cider")
+
+ , "Strong tag" =: "<strong>Strong</strong>" =?> para (strong "Strong")
+
+ , "Strong Emphasis" =:
+ "***strength***" =?>
+ para (strong . emph $ "strength")
+
+ , test emacsMuse "Underline"
+ ("_Underline_" =?> para (underlineSpan "Underline"))
+
+ , "Superscript tag" =: "<sup>Superscript</sup>" =?> para (superscript "Superscript")
+
+ , "Subscript tag" =: "<sub>Subscript</sub>" =?> para (subscript "Subscript")
+
+ , "Strikeout tag" =: "<del>Strikeout</del>" =?> para (strikeout "Strikeout")
+
+ , "Opening inline tags" =: "foo <em> bar <strong>baz" =?> para "foo <em> bar <strong>baz"
+
+ , "Closing inline tags" =: "foo </em> bar </strong>baz" =?> para "foo </em> bar </strong>baz"
+
+ , "Tag soup" =: "foo <em> bar </strong>baz" =?> para "foo <em> bar </strong>baz"
+
+ -- Both inline tags must be within the same paragraph
+ , "No multiparagraph inline tags" =:
+ T.unlines [ "First line"
+ , "<em>Second line"
+ , ""
+ , "Fourth line</em>"
+ ] =?>
+ para "First line\n<em>Second line" <>
+ para "Fourth line</em>"
+
+ , "Linebreak" =: "Line <br> break" =?> para ("Line" <> linebreak <> "break")
+
+ , "Trailing whitespace inside paragraph" =:
+ T.unlines [ "First line " -- trailing whitespace here
+ , "second line"
+ ]
+ =?> para "First line\nsecond line"
+
+ , "Non-breaking space" =: "Foo~~bar" =?> para "Foo\160bar"
+ , "Single ~" =: "Foo~bar" =?> para "Foo~bar"
+
+ , testGroup "Code markup"
+ [ "Code" =: "=foo(bar)=" =?> para (code "foo(bar)")
+
+ , "Not code" =: "a=b= =c=d" =?> para (text "a=b= =c=d")
+
+ -- Emacs Muse 3.20 parses this as code, we follow Amusewiki
+ , "Not code if closing = is detached" =: "=this is not a code =" =?> para "=this is not a code ="
+
+ , "Not code if opening = is detached" =: "= this is not a code=" =?> para "= this is not a code="
+
+ , "Code if followed by comma" =:
+ "Foo =bar=, baz" =?>
+ para (text "Foo " <> code "bar" <> text ", baz")
+
+ , "One character code" =: "=c=" =?> para (code "c")
+
+ , "Three = characters is not a code" =: "===" =?> para "==="
+
+ , "Multiline code markup" =:
+ "foo =bar\nbaz= end of code" =?>
+ para (text "foo " <> code "bar\nbaz" <> text " end of code")
+
+{- Emacs Muse 3.20 has a bug: it publishes
+ - <p>foo <code>bar
+ -
+ - baz</code> foo</p>
+ - which is displayed as one paragraph by browsers.
+ - We follow Amusewiki here and avoid joining paragraphs.
+ -}
+ , "No multiparagraph code" =:
+ T.unlines [ "foo =bar"
+ , ""
+ , "baz= foo"
+ ] =?>
+ para "foo =bar" <>
+ para "baz= foo"
+
+ , "Code at the beginning of paragraph but not first column" =:
+ " - =foo=" =?> bulletList [ para $ code "foo" ]
+ ]
+
+ , "Code tag" =: "<code>foo(bar)</code>" =?> para (code "foo(bar)")
+
+ , "Verbatim tag" =: "*<verbatim>*</verbatim>*" =?> para (emph "*")
+
+ , "Verbatim inside code" =: "<code><verbatim>foo</verbatim></code>" =?> para (code "<verbatim>foo</verbatim>")
+
+ , "Verbatim tag after text" =: "Foo <verbatim>bar</verbatim>" =?> para "Foo bar"
+
+ -- <em> tag should match with the last </em> tag, not verbatim one
+ , "Nested \"</em>\" inside em tag" =: "<em>foo<verbatim></em></verbatim>bar</em>" =?> para (emph ("foo</em>bar"))
+
+ , testGroup "Links"
+ [ "Link without description" =:
+ "[[https://amusewiki.org/]]" =?>
+ para (link "https://amusewiki.org/" "" (str "https://amusewiki.org/"))
+ , "Link with description" =:
+ "[[https://amusewiki.org/][A Muse Wiki]]" =?>
+ para (link "https://amusewiki.org/" "" (text "A Muse Wiki"))
+ , "Image" =:
+ "[[image.jpg]]" =?>
+ para (image "image.jpg" "" mempty)
+ , "Image with description" =:
+ "[[image.jpg][Image]]" =?>
+ para (image "image.jpg" "" (text "Image"))
+ , "Image link" =:
+ "[[URL:image.jpg]]" =?>
+ para (link "image.jpg" "" (str "image.jpg"))
+ , "Image link with description" =:
+ "[[URL:image.jpg][Image]]" =?>
+ para (link "image.jpg" "" (text "Image"))
+ -- Implicit links are supported in Emacs Muse, but not in Amusewiki:
+ -- https://github.com/melmothx/text-amuse/issues/18
+ --
+ -- This test also makes sure '=' without whitespace is not treated as code markup
+ , "No implicit links" =: "http://example.org/index.php?action=view&id=1"
+ =?> para "http://example.org/index.php?action=view&id=1"
+ ]
+
+ , testGroup "Literal"
+ [ test emacsMuse "Inline literal"
+ ("Foo<literal style=\"html\">lit</literal>bar" =?>
+ para (text "Foo" <> rawInline "html" "lit" <> text "bar"))
+ ]
+ ]
+
+ , testGroup "Blocks"
+ [ testProperty "Round trip" roundTrip,
+ "Block elements end paragraphs" =:
+ T.unlines [ "First paragraph"
+ , "----"
+ , "Second paragraph"
+ ] =?> para (text "First paragraph") <> horizontalRule <> para (text "Second paragraph")
+ , testGroup "Horizontal rule"
+ [ "Less than 4 dashes is not a horizontal rule" =: "---" =?> para (text "---")
+ , "4 dashes is a horizontal rule" =: "----" =?> horizontalRule
+ , "5 dashes is a horizontal rule" =: "-----" =?> horizontalRule
+ , "4 dashes with spaces is a horizontal rule" =: "---- " =?> horizontalRule
+ ]
+ , testGroup "Paragraphs"
+ [ "Simple paragraph" =:
+ T.unlines [ "First line"
+ , "second line."
+ ] =?>
+ para "First line\nsecond line."
+ , "Indented paragraph" =:
+ T.unlines [ " First line"
+ , "second line."
+ ] =?>
+ para "First line\nsecond line."
+ -- Emacs Muse starts a blockquote on the second line.
+ -- We copy Amusewiki behavior and require a blank line to start a blockquote.
+ , "Indentation in the middle of paragraph" =:
+ T.unlines [ "First line"
+ , " second line"
+ , "third line"
+ ] =?>
+ para "First line\nsecond line\nthird line"
+ , "Quote" =:
+ " This is a quotation\n" =?>
+ blockQuote (para "This is a quotation")
+ , "Indentation does not indicate quote inside quote tag" =:
+ T.unlines [ "<quote>"
+ , " Not a nested quote"
+ , "</quote>"
+ ] =?>
+ blockQuote (para "Not a nested quote")
+ , "Multiline quote" =:
+ T.unlines [ " This is a quotation"
+ , " with a continuation"
+ ] =?>
+ blockQuote (para "This is a quotation\nwith a continuation")
+ , testGroup "Div"
+ [ "Div without id" =:
+ T.unlines [ "<div>"
+ , "Foo bar"
+ , "</div>"
+ ] =?>
+ divWith nullAttr (para "Foo bar")
+ , "Div with id" =:
+ T.unlines [ "<div id=\"foo\">"
+ , "Foo bar"
+ , "</div>"
+ ] =?>
+ divWith ("foo", [], []) (para "Foo bar")
+ ]
+ , "Verse" =:
+ T.unlines [ "> This is"
+ , "> First stanza"
+ , ">" -- Emacs produces verbatim ">" here, we follow Amusewiki
+ , "> And this is"
+ , "> Second stanza"
+ , ">"
+ , ""
+ , ">"
+ , ""
+ , "> Another verse"
+ , "> is here"
+ ] =?>
+ lineBlock [ "This is"
+ , "First stanza"
+ , ""
+ , "And this is"
+ , "\160\160Second stanza"
+ , ""
+ ] <>
+ lineBlock [ "" ] <>
+ lineBlock [ "Another verse"
+ , "\160\160\160is here"
+ ]
+ ]
+ , "Verse in list" =: " - > foo" =?> bulletList [ lineBlock [ "foo" ] ]
+ , "Multiline verse in list" =:
+ T.unlines [ " - > foo"
+ , " > bar"
+ ] =?>
+ bulletList [ lineBlock [ "foo", "bar" ] ]
+ , "Paragraph after verse in list" =:
+ T.unlines [ " - > foo"
+ , " bar"
+ ] =?>
+ bulletList [ lineBlock [ "foo" ] <> para "bar" ]
+ , "Empty quote tag" =:
+ T.unlines [ "<quote>"
+ , "</quote>"
+ ]
+ =?> blockQuote mempty
+ , "Quote tag" =:
+ T.unlines [ "<quote>"
+ , "Hello, world"
+ , "</quote>"
+ ]
+ =?> blockQuote (para $ text "Hello, world")
+ , "Nested quote tag" =:
+ T.unlines [ "<quote>"
+ , "foo"
+ , "<quote>"
+ , "bar"
+ , "</quote>"
+ , "baz"
+ , "</quote>"
+ ] =?>
+ blockQuote (para "foo" <> blockQuote (para "bar") <> para "baz")
+ , "Indented quote inside list" =:
+ T.unlines [ " - <quote>"
+ , " foo"
+ , " </quote>"
+ ] =?>
+ bulletList [ blockQuote (para "foo") ]
+ , "Verse tag" =:
+ T.unlines [ "<verse>"
+ , ""
+ , "Foo bar baz"
+ , " One two three"
+ , ""
+ , "</verse>"
+ ] =?>
+ lineBlock [ ""
+ , text "Foo bar baz"
+ , text "\160\160One two three"
+ , ""
+ ]
+ , "Verse tag with empty line inside" =:
+ T.unlines [ "<verse>"
+ , ""
+ , "</verse>"
+ ] =?>
+ lineBlock [ "" ]
+ , testGroup "Example"
+ [ "Braces on separate lines" =:
+ T.unlines [ "{{{"
+ , "Example line"
+ , "}}}"
+ ] =?>
+ codeBlock "Example line"
+ , "Spaces after opening braces" =:
+ T.unlines [ "{{{ "
+ , "Example line"
+ , "}}}"
+ ] =?>
+ codeBlock "Example line"
+ , "One blank line in the beginning" =:
+ T.unlines [ "{{{"
+ , ""
+ , "Example line"
+ , "}}}"
+ ] =?>
+ codeBlock "\nExample line"
+ , "One blank line in the end" =:
+ T.unlines [ "{{{"
+ , "Example line"
+ , ""
+ , "}}}"
+ ] =?>
+ codeBlock "Example line\n"
+ -- Amusewiki requires braces to be on separate line,
+ -- this is an extension.
+ , "One line" =:
+ "{{{Example line}}}" =?>
+ codeBlock "Example line"
+ ]
+ , testGroup "Example tag"
+ [ "Tags on separate lines" =:
+ T.unlines [ "<example>"
+ , "Example line"
+ , "</example>"
+ ] =?>
+ codeBlock "Example line"
+ , "One line" =:
+ "<example>Example line</example>" =?>
+ codeBlock "Example line"
+ , "One blank line in the beginning" =:
+ T.unlines [ "<example>"
+ , ""
+ , "Example line"
+ , "</example>"
+ ] =?>
+ codeBlock "\nExample line"
+ , "One blank line in the end" =:
+ T.unlines [ "<example>"
+ , "Example line"
+ , ""
+ , "</example>"
+ ] =?>
+ codeBlock "Example line\n"
+ , "Example inside list" =:
+ T.unlines [ " - <example>"
+ , " foo"
+ , " </example>"
+ ] =?>
+ bulletList [ codeBlock "foo" ]
+ , "Empty example inside list" =:
+ T.unlines [ " - <example>"
+ , " </example>"
+ ] =?>
+ bulletList [ codeBlock "" ]
+ , "Example inside list with empty lines" =:
+ T.unlines [ " - <example>"
+ , " foo"
+ , " </example>"
+ , ""
+ , " bar"
+ , ""
+ , " <example>"
+ , " baz"
+ , " </example>"
+ ] =?>
+ bulletList [ codeBlock "foo" <> para "bar" <> codeBlock "baz" ]
+ , "Indented example inside list" =:
+ T.unlines [ " - <example>"
+ , " foo"
+ , " </example>"
+ ] =?>
+ bulletList [ codeBlock "foo" ]
+ , "Example inside definition list" =:
+ T.unlines [ " foo :: <example>"
+ , " bar"
+ , " </example>"
+ ] =?>
+ definitionList [ ("foo", [codeBlock "bar"]) ]
+ , "Example inside list definition with empty lines" =:
+ T.unlines [ " term :: <example>"
+ , " foo"
+ , " </example>"
+ , ""
+ , " bar"
+ , ""
+ , " <example>"
+ , " baz"
+ , " </example>"
+ ] =?>
+ definitionList [ ("term", [codeBlock "foo" <> para "bar" <> codeBlock "baz"]) ]
+ , "Example inside note" =:
+ T.unlines [ "Foo[1]"
+ , ""
+ , "[1] <example>"
+ , " bar"
+ , " </example>"
+ ] =?>
+ para ("Foo" <> note (codeBlock "bar"))
+ ]
+ , testGroup "Literal blocks"
+ [ test emacsMuse "Literal block"
+ (T.unlines [ "<literal style=\"latex\">"
+ , "\\newpage"
+ , "</literal>"
+ ] =?>
+ rawBlock "latex" "\\newpage")
+ ]
+ , "Center" =:
+ T.unlines [ "<center>"
+ , "Hello, world"
+ , "</center>"
+ ] =?>
+ para (text "Hello, world")
+ , "Right" =:
+ T.unlines [ "<right>"
+ , "Hello, world"
+ , "</right>"
+ ] =?>
+ para (text "Hello, world")
+ , testGroup "Comments"
+ [ "Comment tag" =: "<comment>\nThis is a comment\n</comment>" =?> (mempty::Blocks)
+ , "Line comment" =: "; Comment" =?> (mempty::Blocks)
+ , "Empty comment" =: ";" =?> (mempty::Blocks)
+ , "Text after empty comment" =: ";\nfoo" =?> para "foo" -- Make sure we don't consume newline while looking for whitespace
+ , "Not a comment (does not start with a semicolon)" =: " ; Not a comment" =?> para (text "; Not a comment")
+ , "Not a comment (has no space after semicolon)" =: ";Not a comment" =?> para (text ";Not a comment")
+ ]
+ , testGroup "Headers"
+ [ "Part" =:
+ "* First level" =?>
+ header 1 "First level"
+ , "Chapter" =:
+ "** Second level" =?>
+ header 2 "Second level"
+ , "Section" =:
+ "*** Third level" =?>
+ header 3 "Third level"
+ , "Subsection" =:
+ "**** Fourth level" =?>
+ header 4 "Fourth level"
+ , "Subsubsection" =:
+ "***** Fifth level" =?>
+ header 5 "Fifth level"
+ , "Whitespace is required after *" =: "**Not a header" =?> para "**Not a header"
+ , "No headers in footnotes" =:
+ T.unlines [ "Foo[1]"
+ , "[1] * Bar"
+ ] =?>
+ para (text "Foo" <>
+ note (para "* Bar"))
+ , "No headers in quotes" =:
+ T.unlines [ "<quote>"
+ , "* Hi"
+ , "</quote>"
+ ] =?>
+ blockQuote (para "* Hi")
+ , "Headers consume anchors" =:
+ T.unlines [ "** Foo"
+ , "#bar"
+ ] =?>
+ headerWith ("bar",[],[]) 2 "Foo"
+ , "Headers don't consume anchors separated with a blankline" =:
+ T.unlines [ "** Foo"
+ , ""
+ , "#bar"
+ ] =?>
+ header 2 "Foo" <>
+ para (spanWith ("bar", [], []) mempty)
+ , "Headers terminate lists" =:
+ T.unlines [ " - foo"
+ , "* bar"
+ ] =?>
+ bulletList [ para "foo" ] <>
+ header 1 "bar"
+ ]
+ , testGroup "Directives"
+ [ "Title" =:
+ "#title Document title" =?>
+ let titleInline = toList "Document title"
+ meta = setMeta "title" (MetaInlines titleInline) nullMeta
+ in Pandoc meta mempty
+ -- Emacs Muse documentation says that "You can use any combination
+ -- of uppercase and lowercase letters for directives",
+ -- but also allows '-', which is not documented, but used for disable-tables.
+ , test emacsMuse "Disable tables"
+ ("#disable-tables t" =?>
+ Pandoc (setMeta "disable-tables" (MetaInlines $ toList "t") nullMeta) mempty)
+ , "Multiple directives" =:
+ T.unlines [ "#title Document title"
+ , "#subtitle Document subtitle"
+ ] =?>
+ Pandoc (setMeta "title" (MetaInlines $ toList "Document title") $
+ setMeta "subtitle" (MetaInlines $ toList "Document subtitle") nullMeta) mempty
+ , "Multiline directive" =:
+ T.unlines [ "#title Document title"
+ , "#notes First line"
+ , "and second line"
+ , "#author Name"
+ ] =?>
+ Pandoc (setMeta "title" (MetaInlines $ toList "Document title") $
+ setMeta "notes" (MetaInlines $ toList "First line\nand second line") $
+ setMeta "author" (MetaInlines $ toList "Name") nullMeta) mempty
+ ]
+ , testGroup "Anchors"
+ [ "Anchor" =:
+ T.unlines [ "; A comment to make sure anchor is not parsed as a directive"
+ , "#anchor Target"
+ ] =?>
+ para (spanWith ("anchor", [], []) mempty <> "Target")
+ , "Anchor cannot start with a number" =:
+ T.unlines [ "; A comment to make sure anchor is not parsed as a directive"
+ , "#0notanchor Target"
+ ] =?>
+ para "#0notanchor Target"
+ , "Not anchor if starts with a space" =:
+ " #notanchor Target" =?>
+ para "#notanchor Target"
+ , "Anchor inside a paragraph" =:
+ T.unlines [ "Paragraph starts here"
+ , "#anchor and ends here."
+ ] =?>
+ para ("Paragraph starts here\n" <> spanWith ("anchor", [], []) mempty <> "and ends here.")
+ ]
+ , testGroup "Footnotes"
+ [ "Simple footnote" =:
+ T.unlines [ "Here is a footnote[1]."
+ , ""
+ , "[1] Footnote contents"
+ ] =?>
+ para (text "Here is a footnote" <>
+ note (para "Footnote contents") <>
+ str ".")
+ , "Recursive footnote" =:
+ T.unlines [ "Start recursion here[1]"
+ , ""
+ , "[1] Recursion continues here[1]"
+ ] =?>
+ para (text "Start recursion here" <>
+ note (para "Recursion continues here[1]"))
+ , "No zero footnotes" =:
+ T.unlines [ "Here is a footnote[0]."
+ , ""
+ , "[0] Footnote contents"
+ ] =?>
+ para "Here is a footnote[0]." <>
+ para "[0] Footnote contents"
+ , "Footnotes can't start with zero" =:
+ T.unlines [ "Here is a footnote[01]."
+ , ""
+ , "[01] Footnote contents"
+ ] =?>
+ para "Here is a footnote[01]." <>
+ para "[01] Footnote contents"
+ , testGroup "Multiparagraph footnotes"
+ [ "Amusewiki multiparagraph footnotes" =:
+ T.unlines [ "Multiparagraph[1] footnotes[2]"
+ , ""
+ , "[1] First footnote paragraph"
+ , ""
+ , " Second footnote paragraph"
+ , "with continuation"
+ , ""
+ , "Not a note"
+ , "[2] Second footnote"
+ ] =?>
+ para (text "Multiparagraph" <>
+ note (para "First footnote paragraph" <>
+ para "Second footnote paragraph\nwith continuation") <>
+ text " footnotes" <>
+ note (para "Second footnote")) <>
+ para (text "Not a note")
+
+ -- Verse requires precise indentation, so it is good to test indentation requirements
+ , "Note continuation with verse" =:
+ T.unlines [ "Foo[1]"
+ , ""
+ , "[1] Bar"
+ , ""
+ , " > Baz"
+ ] =?>
+ para ("Foo" <> note (para "Bar" <> lineBlock ["Baz"]))
+ , test emacsMuse "Emacs multiparagraph footnotes"
+ (T.unlines
+ [ "First footnote reference[1] and second footnote reference[2]."
+ , ""
+ , "[1] First footnote paragraph"
+ , ""
+ , "Second footnote"
+ , "paragraph"
+ , ""
+ , "[2] Third footnote paragraph"
+ , ""
+ , "Fourth footnote paragraph"
+ ] =?>
+ para (text "First footnote reference" <>
+ note (para "First footnote paragraph" <>
+ para "Second footnote\nparagraph") <>
+ text " and second footnote reference" <>
+ note (para "Third footnote paragraph" <>
+ para "Fourth footnote paragraph") <>
+ text "."))
+ ]
+ ]
+ ]
+ , testGroup "Tables"
+ [ "Two cell table" =:
+ "One | Two" =?>
+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
+ []
+ [[plain "One", plain "Two"]]
+ , "Table with multiple words" =:
+ "One two | three four" =?>
+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
+ []
+ [[plain "One two", plain "three four"]]
+ , "Not a table" =:
+ "One| Two" =?>
+ para (text "One| Two")
+ , "Not a table again" =:
+ "One |Two" =?>
+ para (text "One |Two")
+ , "Two line table" =:
+ T.unlines
+ [ "One | Two"
+ , "Three | Four"
+ ] =?>
+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
+ []
+ [[plain "One", plain "Two"],
+ [plain "Three", plain "Four"]]
+ , "Table with one header" =:
+ T.unlines
+ [ "First || Second"
+ , "Third | Fourth"
+ ] =?>
+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
+ [plain "First", plain "Second"]
+ [[plain "Third", plain "Fourth"]]
+ , "Table with two headers" =:
+ T.unlines
+ [ "First || header"
+ , "Second || header"
+ , "Foo | bar"
+ ] =?>
+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
+ [plain "First", plain "header"]
+ [[plain "Second", plain "header"],
+ [plain "Foo", plain "bar"]]
+ , "Header and footer reordering" =:
+ T.unlines
+ [ "Foo ||| bar"
+ , "Baz || foo"
+ , "Bar | baz"
+ ] =?>
+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
+ [plain "Baz", plain "foo"]
+ [[plain "Bar", plain "baz"],
+ [plain "Foo", plain "bar"]]
+ , "Table with caption" =:
+ T.unlines
+ [ "Foo || bar || baz"
+ , "First | row | here"
+ , "Second | row | there"
+ , "|+ Table caption +|"
+ ] =?>
+ table (text "Table caption") (replicate 3 (AlignDefault, 0.0))
+ [plain "Foo", plain "bar", plain "baz"]
+ [[plain "First", plain "row", plain "here"],
+ [plain "Second", plain "row", plain "there"]]
+ , "Caption without table" =:
+ "|+ Foo bar baz +|" =?>
+ table (text "Foo bar baz") [] [] []
+ , "Table indented with space" =:
+ T.unlines
+ [ " Foo | bar"
+ , " Baz | foo"
+ , " Bar | baz"
+ ] =?>
+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
+ []
+ [[plain "Foo", plain "bar"],
+ [plain "Baz", plain "foo"],
+ [plain "Bar", plain "baz"]]
+ , "Empty cells" =:
+ T.unlines
+ [ " | Foo"
+ , " |"
+ , " bar |"
+ , " || baz"
+ ] =?>
+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
+ [plain "", plain "baz"]
+ [[plain "", plain "Foo"],
+ [plain "", plain ""],
+ [plain "bar", plain ""]]
+ ]
+ , testGroup "Lists"
+ [ "Bullet list" =:
+ T.unlines
+ [ " - Item1"
+ , ""
+ , " - Item2"
+ ] =?>
+ bulletList [ para "Item1"
+ , para "Item2"
+ ]
+ , "Ordered list" =:
+ T.unlines
+ [ " 1. Item1"
+ , ""
+ , " 2. Item2"
+ ] =?>
+ orderedListWith (1, Decimal, Period) [ para "Item1"
+ , para "Item2"
+ ]
+ , "Ordered list with implicit numbers" =:
+ T.unlines
+ [ " 1. Item1"
+ , ""
+ , " 1. Item2"
+ , ""
+ , " 1. Item3"
+ ] =?>
+ orderedListWith (1, Decimal, Period) [ para "Item1"
+ , para "Item2"
+ , para "Item3"
+ ]
+ , "Ordered list with roman numerals" =:
+ T.unlines
+ [ " i. First"
+ , " ii. Second"
+ , " iii. Third"
+ , " iv. Fourth"
+ ] =?>
+ orderedListWith (1, LowerRoman, Period) [ para "First"
+ , para "Second"
+ , para "Third"
+ , para "Fourth"
+ ]
+ , "Bullet list with empty items" =:
+ T.unlines
+ [ " -"
+ , ""
+ , " - Item2"
+ ] =?>
+ bulletList [ mempty
+ , para "Item2"
+ ]
+ , "Ordered list with empty items" =:
+ T.unlines
+ [ " 1."
+ , ""
+ , " 2."
+ , ""
+ , " 3. Item3"
+ ] =?>
+ orderedListWith (1, Decimal, Period) [ mempty
+ , mempty
+ , para "Item3"
+ ]
+ , "Bullet list with last item empty" =:
+ T.unlines
+ [ " -"
+ , ""
+ , "foo"
+ ] =?>
+ bulletList [ mempty ] <>
+ para "foo"
+ , testGroup "Nested lists"
+ [ "Nested bullet list" =:
+ T.unlines [ " - Item1"
+ , " - Item2"
+ , " - Item3"
+ , " - Item4"
+ , " - Item5"
+ , " - Item6"
+ ] =?>
+ bulletList [ para "Item1" <>
+ bulletList [ para "Item2" <>
+ bulletList [ para "Item3" ]
+ , para "Item4" <>
+ bulletList [ para "Item5" ]
+ ]
+ , para "Item6"
+ ]
+ , "Nested ordered list" =:
+ T.unlines [ " 1. Item1"
+ , " 1. Item2"
+ , " 1. Item3"
+ , " 2. Item4"
+ , " 1. Item5"
+ , " 2. Item6"
+ ] =?>
+ orderedListWith (1, Decimal, Period) [ para "Item1" <>
+ orderedListWith (1, Decimal, Period) [ para "Item2" <>
+ orderedListWith (1, Decimal, Period) [ para "Item3" ]
+ , para "Item4" <>
+ orderedListWith (1, Decimal, Period) [ para "Item5" ]
+ ]
+ , para "Item6"
+ ]
+ , "Mixed nested list" =:
+ T.unlines
+ [ " - Item1"
+ , " - Item2"
+ , " - Item3"
+ , " - Item4"
+ , " 1. Nested"
+ , " 2. Ordered"
+ , " 3. List"
+ ] =?>
+ bulletList [ mconcat [ para "Item1"
+ , bulletList [ para "Item2"
+ , para "Item3"
+ ]
+ ]
+ , mconcat [ para "Item4"
+ , orderedListWith (1, Decimal, Period) [ para "Nested"
+ , para "Ordered"
+ , para "List"
+ ]
+ ]
+ ]
+ , "Text::Amuse includes only one space in list marker" =:
+ T.unlines
+ [ " - First item"
+ , " - Nested item"
+ ] =?>
+ bulletList [ para "First item" <> bulletList [ para "Nested item"]]
+ ]
+ , "List continuation" =:
+ T.unlines
+ [ " - a"
+ , ""
+ , " b"
+ , ""
+ , " c"
+ ] =?>
+ bulletList [ mconcat [ para "a"
+ , para "b"
+ , para "c"
+ ]
+ ]
+ , "List continuation afeter nested list" =:
+ T.unlines
+ [ " - - foo"
+ , ""
+ , " bar"
+ ] =?>
+ bulletList [ bulletList [ para "foo" ] <>
+ para "bar"
+ ]
+ -- Emacs Muse allows to separate lists with two or more blank lines.
+ -- Text::Amuse (Amusewiki engine) always creates a single list as of version 0.82.
+ -- pandoc follows Emacs Muse behavior
+ , testGroup "Blank lines"
+ [ "Blank lines between list items are not required" =:
+ T.unlines
+ [ " - Foo"
+ , " - Bar"
+ ] =?>
+ bulletList [ para "Foo"
+ , para "Bar"
+ ]
+ , "One blank line between list items is allowed" =:
+ T.unlines
+ [ " - Foo"
+ , ""
+ , " - Bar"
+ ] =?>
+ bulletList [ para "Foo"
+ , para "Bar"
+ ]
+ , "Two blank lines separate lists" =:
+ T.unlines
+ [ " - Foo"
+ , ""
+ , ""
+ , " - Bar"
+ ] =?>
+ bulletList [ para "Foo" ] <> bulletList [ para "Bar" ]
+ , "No blank line after multiline first item" =:
+ T.unlines
+ [ " - Foo"
+ , " bar"
+ , " - Baz"
+ ] =?>
+ bulletList [ para "Foo\nbar"
+ , para "Baz"
+ ]
+ , "One blank line after multiline first item" =:
+ T.unlines
+ [ " - Foo"
+ , " bar"
+ , ""
+ , " - Baz"
+ ] =?>
+ bulletList [ para "Foo\nbar"
+ , para "Baz"
+ ]
+ , "Two blank lines after multiline first item" =:
+ T.unlines
+ [ " - Foo"
+ , " bar"
+ , ""
+ , ""
+ , " - Baz"
+ ] =?>
+ bulletList [ para "Foo\nbar" ] <> bulletList [ para "Baz" ]
+ , "No blank line after list continuation" =:
+ T.unlines
+ [ " - Foo"
+ , ""
+ , " bar"
+ , " - Baz"
+ ] =?>
+ bulletList [ para "Foo" <> para "bar"
+ , para "Baz"
+ ]
+ , "One blank line after list continuation" =:
+ T.unlines
+ [ " - Foo"
+ , ""
+ , " bar"
+ , ""
+ , " - Baz"
+ ] =?>
+ bulletList [ para "Foo" <> para "bar"
+ , para "Baz"
+ ]
+ , "Two blank lines after list continuation" =:
+ T.unlines
+ [ " - Foo"
+ , ""
+ , " bar"
+ , ""
+ , ""
+ , " - Baz"
+ ] =?>
+ bulletList [ para "Foo" <> para "bar" ] <> bulletList [ para "Baz" ]
+ , "No blank line after blockquote" =:
+ T.unlines
+ [ " - <quote>"
+ , " foo"
+ , " </quote>"
+ , " - bar"
+ ] =?>
+ bulletList [ blockQuote $ para "foo", para "bar" ]
+ , "One blank line after blockquote" =:
+ T.unlines
+ [ " - <quote>"
+ , " foo"
+ , " </quote>"
+ , ""
+ , " - bar"
+ ] =?>
+ bulletList [ blockQuote $ para "foo", para "bar" ]
+ , "Two blank lines after blockquote" =:
+ T.unlines
+ [ " - <quote>"
+ , " foo"
+ , " </quote>"
+ , ""
+ , ""
+ , " - bar"
+ ] =?>
+ bulletList [ blockQuote $ para "foo" ] <> bulletList [ para "bar" ]
+ , "No blank line after verse" =:
+ T.unlines
+ [ " - > foo"
+ , " - bar"
+ ] =?>
+ bulletList [ lineBlock [ "foo" ], para "bar" ]
+ , "One blank line after verse" =:
+ T.unlines
+ [ " - > foo"
+ , ""
+ , " - bar"
+ ] =?>
+ bulletList [ lineBlock [ "foo" ], para "bar" ]
+ , "Two blank lines after verse" =:
+ T.unlines
+ [ " - > foo"
+ , ""
+ , ""
+ , " - bar"
+ ] =?>
+ bulletList [ lineBlock [ "foo" ] ] <> bulletList [ para "bar" ]
+ ]
+ -- Test that definition list requires a leading space.
+ -- Emacs Muse does not require a space, we follow Amusewiki here.
+ , "Not a definition list" =:
+ T.unlines
+ [ "First :: second"
+ , "Foo :: bar"
+ ] =?>
+ para "First :: second\nFoo :: bar"
+ , test emacsMuse "Emacs Muse definition list"
+ (T.unlines
+ [ "First :: second"
+ , "Foo :: bar"
+ ] =?>
+ definitionList [ ("First", [ para "second" ])
+ , ("Foo", [ para "bar" ])
+ ])
+ , "Definition list" =:
+ T.unlines
+ [ " First :: second"
+ , " Foo :: bar"
+ ] =?>
+ definitionList [ ("First", [ para "second" ])
+ , ("Foo", [ para "bar" ])
+ ]
+ , "Definition list term cannot include newline" =:
+ T.unlines
+ [ " Foo" -- "Foo" is not a part of the definition list term
+ , " Bar :: baz"
+ ] =?>
+ para "Foo" <>
+ definitionList [ ("Bar", [ para "baz" ]) ]
+ , "One-line definition list" =: " foo :: bar" =?>
+ definitionList [ ("foo", [ para "bar" ]) ]
+ , "Definition list term may include single colon" =:
+ " foo:bar :: baz" =?>
+ definitionList [ ("foo:bar", [ para "baz" ]) ]
+ , "Definition list term with emphasis" =: " *Foo* :: bar\n" =?>
+ definitionList [ (emph "Foo", [ para "bar" ]) ]
+ , "Definition list term with :: inside code" =: " foo <code> :: </code> :: bar <code> :: </code> baz\n" =?>
+ definitionList [ ("foo " <> code " :: ", [ para $ "bar " <> code " :: " <> " baz" ]) ]
+ , "Multi-line definition lists" =:
+ T.unlines
+ [ " First term :: Definition of first term"
+ , "and its continuation."
+ , " Second term :: Definition of second term."
+ ] =?>
+ definitionList [ ("First term", [ para "Definition of first term\nand its continuation." ])
+ , ("Second term", [ para "Definition of second term." ])
+ ]
+ , test emacsMuse "Multi-line definition lists from Emacs Muse manual"
+ (T.unlines
+ [ "Term1 ::"
+ , " This is a first definition"
+ , " And it has two lines;"
+ , "no, make that three."
+ , ""
+ , "Term2 :: This is a second definition"
+ ] =?>
+ definitionList [ ("Term1", [ para "This is a first definition\nAnd it has two lines;\nno, make that three."])
+ , ("Term2", [ para "This is a second definition"])
+ ])
+ -- Text::Amuse requires indentation with one space
+ , "Multi-line definition lists from Emacs Muse manual with initial space" =:
+ (T.unlines
+ [ " Term1 ::"
+ , " This is a first definition"
+ , " And it has two lines;"
+ , "no, make that three."
+ , ""
+ , " Term2 :: This is a second definition"
+ ] =?>
+ definitionList [ ("Term1", [ para "This is a first definition\nAnd it has two lines;\nno, make that three."])
+ , ("Term2", [ para "This is a second definition"])
+ ])
+ , "One-line nested definition list" =:
+ " Foo :: bar :: baz" =?>
+ definitionList [ ("Foo", [ definitionList [ ("bar", [ para "baz" ])]])]
+ , "Nested definition list" =:
+ T.unlines
+ [ " First :: Second :: Third"
+ , " Fourth :: Fifth :: Sixth"
+ , " Seventh :: Eighth"
+ ] =?>
+ definitionList [ ("First", [ definitionList [ ("Second", [ para "Third" ]),
+ ("Fourth", [ definitionList [ ("Fifth", [ para "Sixth"] ) ] ] ) ] ] )
+ , ("Seventh", [ para "Eighth" ])
+ ]
+ , testGroup "Definition lists with multiple descriptions"
+ [ "Correctly indented second description" =:
+ T.unlines
+ [ " First term :: first description"
+ , " :: second description"
+ ] =?>
+ definitionList [ ("First term", [ para "first description"
+ , para "second description"
+ ])
+ ]
+ , "Incorrectly indented second description" =:
+ T.unlines
+ [ " First term :: first description"
+ , " :: second description"
+ ] =?>
+ definitionList [ ("First term", [ para "first description" ])
+ , ("", [ para "second description" ])
+ ]
+ ]
+ , "Two blank lines separate definition lists" =:
+ T.unlines
+ [ " First :: list"
+ , ""
+ , ""
+ , " Second :: list"
+ ] =?>
+ definitionList [ ("First", [ para "list" ]) ] <>
+ definitionList [ ("Second", [ para "list" ]) ]
+ -- Headers in first column of list continuation are not allowed
+ , "No headers in list continuation" =:
+ T.unlines
+ [ " - Foo"
+ , ""
+ , " * Bar"
+ ] =?>
+ bulletList [ mconcat [ para "Foo"
+ , para "* Bar"
+ ]
+ ]
+ , "Bullet list inside a tag" =:
+ T.unlines
+ [ "<quote>"
+ , " - First"
+ , ""
+ , " - Second"
+ , ""
+ , " - Third"
+ , "</quote>"
+ ] =?>
+ blockQuote (bulletList [ para "First"
+ , para "Second"
+ , para "Third"
+ ])
+ , "Ordered list inside a tag" =:
+ T.unlines
+ [ "<quote>"
+ , " 1. First"
+ , ""
+ , " 2. Second"
+ , ""
+ , " 3. Third"
+ , "</quote>"
+ ] =?>
+ blockQuote (orderedListWith (1, Decimal, Period) [ para "First"
+ , para "Second"
+ , para "Third"
+ ])
+ -- Regression test for a bug caught by round-trip test
+ , "Do not consume whitespace while looking for end tag" =:
+ T.unlines
+ [ "<quote>"
+ , " - <quote>"
+ , " foo"
+ , " </quote>"
+ , " bar" -- Do not consume whitespace while looking for arbitraritly indented </quote>
+ , "</quote>"
+ ] =?>
+ blockQuote (bulletList [ blockQuote $ para "foo" ] <> para "bar")
+ ]
+ ]
diff --git a/test/Tests/Readers/Odt.hs b/test/Tests/Readers/Odt.hs
new file mode 100644
index 000000000..4b7058cf9
--- /dev/null
+++ b/test/Tests/Readers/Odt.hs
@@ -0,0 +1,170 @@
+module Tests.Readers.Odt (tests) where
+
+import Control.Monad (liftM)
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as B
+import qualified Data.Map as M
+import Data.Text (unpack)
+import System.IO.Unsafe (unsafePerformIO)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import qualified Text.Pandoc.UTF8 as UTF8
+
+defopts :: ReaderOptions
+defopts = def{ readerExtensions = getDefaultExtensions "odt" }
+
+tests :: [TestTree]
+tests = testsComparingToMarkdown ++ testsComparingToNative
+
+testsComparingToMarkdown :: [TestTree]
+testsComparingToMarkdown = map nameToTest namesOfTestsComparingToMarkdown
+ where nameToTest name = createTest
+ compareOdtToMarkdown
+ name
+ (toOdtPath name)
+ (toMarkdownPath name)
+ toOdtPath name = "odt/odt/" ++ name ++ ".odt"
+ toMarkdownPath name = "odt/markdown/" ++ name ++ ".md"
+
+testsComparingToNative :: [TestTree]
+testsComparingToNative = map nameToTest namesOfTestsComparingToNative
+ where nameToTest name = createTest
+ compareOdtToNative
+ name
+ (toOdtPath name)
+ (toNativePath name)
+ toOdtPath name = "odt/odt/" ++ name ++ ".odt"
+ toNativePath name = "odt/native/" ++ name ++ ".native"
+
+
+newtype NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc}
+ deriving ( Show )
+
+instance ToString NoNormPandoc where
+ toString d = unpack $
+ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
+ where s = case d of
+ NoNormPandoc (Pandoc (Meta m) _)
+ | M.null m -> Nothing
+ | otherwise -> Just "" -- need this for Meta output
+
+instance ToPandoc NoNormPandoc where
+ toPandoc = unNoNorm
+
+getNoNormVia :: (a -> Pandoc) -> String -> Either PandocError a -> NoNormPandoc
+getNoNormVia _ readerName (Left _) = error (readerName ++ " reader failed")
+getNoNormVia f _ (Right a) = NoNormPandoc (f a)
+
+type TestCreator = ReaderOptions
+ -> FilePath -> FilePath
+ -> IO (NoNormPandoc, NoNormPandoc)
+
+compareOdtToNative :: TestCreator
+compareOdtToNative opts odtPath nativePath = do
+ nativeFile <- UTF8.toText <$> BS.readFile nativePath
+ odtFile <- B.readFile odtPath
+ native <- getNoNormVia id "native" <$> runIO (readNative def nativeFile)
+ odt <- getNoNormVia id "odt" <$> runIO (readOdt opts odtFile)
+ return (odt,native)
+
+compareOdtToMarkdown :: TestCreator
+compareOdtToMarkdown opts odtPath markdownPath = do
+ markdownFile <- UTF8.toText <$> BS.readFile markdownPath
+ odtFile <- B.readFile odtPath
+ markdown <- getNoNormVia id "markdown" <$>
+ runIO (readMarkdown def{ readerExtensions = pandocExtensions }
+ markdownFile)
+ odt <- getNoNormVia id "odt" <$> runIO (readOdt opts odtFile)
+ return (odt,markdown)
+
+
+createTest :: TestCreator
+ -> TestName
+ -> FilePath -> FilePath
+ -> TestTree
+createTest creator name path1 path2 =
+ unsafePerformIO $ liftM (test id name) (creator defopts path1 path2)
+
+{-
+--
+
+getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString)
+getMedia archivePath mediaPath = do
+ zf <- B.readFile archivePath >>= return . toArchive
+ return $ findEntryByPath ("Pictures/" ++ mediaPath) zf >>= (Just . fromEntry)
+
+compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool
+compareMediaPathIO mediaPath mediaBag odtPath = do
+ odtMedia <- getMedia odtPath mediaPath
+ let mbBS = case lookupMedia mediaPath mediaBag of
+ Just (_, bs) -> bs
+ Nothing -> error ("couldn't find " ++
+ mediaPath ++
+ " in media bag")
+ odtBS = case odtMedia of
+ Just bs -> bs
+ Nothing -> error ("couldn't find " ++
+ mediaPath ++
+ " in media bag")
+ return $ mbBS == odtBS
+
+compareMediaBagIO :: FilePath -> IO Bool
+compareMediaBagIO odtFile = do
+ df <- B.readFile odtFile
+ let (_, mb) = readOdt def df
+ bools <- mapM
+ (\(fp, _, _) -> compareMediaPathIO fp mb odtFile)
+ (mediaDirectory mb)
+ return $ and bools
+
+testMediaBagIO :: String -> FilePath -> IO TestTree
+testMediaBagIO name odtFile = do
+ outcome <- compareMediaBagIO odtFile
+ return $ testCase name (assertBool
+ ("Media didn't match media bag in file " ++ odtFile)
+ outcome)
+
+testMediaBag :: String -> FilePath -> TestTree
+testMediaBag name odtFile = buildTest $ testMediaBagIO name odtFile
+-}
+--
+
+
+
+namesOfTestsComparingToMarkdown :: [ String ]
+namesOfTestsComparingToMarkdown = [ "bold"
+-- , "citation"
+ , "endnote"
+ , "externalLink"
+ , "footnote"
+ , "headers"
+-- , "horizontalRule"
+ , "italic"
+-- , "listBlocks"
+ , "paragraph"
+ , "strikeout"
+-- , "trackedChanges"
+ , "underlined"
+ ]
+
+namesOfTestsComparingToNative :: [ String ]
+namesOfTestsComparingToNative = [ "blockquote"
+ , "image"
+ , "imageIndex"
+ , "imageWithCaption"
+ , "inlinedCode"
+ , "orderedListMixed"
+ , "orderedListRoman"
+ , "orderedListSimple"
+ , "referenceToChapter"
+ , "referenceToListItem"
+ , "referenceToText"
+ , "simpleTable"
+ , "simpleTableWithCaption"
+-- , "table"
+ , "textMixedStyles"
+ , "tableWithContents"
+ , "unicode"
+ , "unorderedList"
+ ]
diff --git a/test/Tests/Readers/Org.hs b/test/Tests/Readers/Org.hs
new file mode 100644
index 000000000..de7f14e32
--- /dev/null
+++ b/test/Tests/Readers/Org.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org (tests) where
+
+import Test.Tasty (TestTree, testGroup)
+import qualified Tests.Readers.Org.Block as Block
+import qualified Tests.Readers.Org.Directive as Directive
+import qualified Tests.Readers.Org.Inline as Inline
+import qualified Tests.Readers.Org.Meta as Meta
+
+tests :: [TestTree]
+tests =
+ [ testGroup "Inlines" Inline.tests
+ , testGroup "Basic Blocks" Block.tests
+ , testGroup "Meta Information" Meta.tests
+ , testGroup "Directives" Directive.tests
+ ]
diff --git a/test/Tests/Readers/Org/Block.hs b/test/Tests/Readers/Org/Block.hs
new file mode 100644
index 000000000..15dc63554
--- /dev/null
+++ b/test/Tests/Readers/Org/Block.hs
@@ -0,0 +1,192 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block (tests) where
+
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+import qualified Tests.Readers.Org.Block.CodeBlock as CodeBlock
+import qualified Tests.Readers.Org.Block.Figure as Figure
+import qualified Tests.Readers.Org.Block.Header as Header
+import qualified Tests.Readers.Org.Block.List as List
+import qualified Tests.Readers.Org.Block.Table as Table
+
+tests :: [TestTree]
+tests =
+ [ "Paragraph" =:
+ "Paragraph\n" =?>
+ para "Paragraph"
+
+ , "Paragraph starting with an asterisk" =:
+ "*five" =?>
+ para "*five"
+
+ , "Paragraph containing asterisk at beginning of line" =:
+ T.unlines [ "lucky"
+ , "*star"
+ ] =?>
+ para ("lucky" <> softbreak <> "*star")
+
+ , "Example block" =:
+ T.unlines [ ": echo hello"
+ , ": echo dear tester"
+ ] =?>
+ codeBlockWith ("", ["example"], []) "echo hello\necho dear tester\n"
+
+ , "Example block surrounded by text" =:
+ T.unlines [ "Greetings"
+ , ": echo hello"
+ , ": echo dear tester"
+ , "Bye"
+ ] =?>
+ mconcat [ para "Greetings"
+ , codeBlockWith ("", ["example"], [])
+ "echo hello\necho dear tester\n"
+ , para "Bye"
+ ]
+
+ , "Horizontal Rule" =:
+ T.unlines [ "before"
+ , "-----"
+ , "after"
+ ] =?>
+ mconcat [ para "before"
+ , horizontalRule
+ , para "after"
+ ]
+
+ , "Not a Horizontal Rule" =:
+ "----- em and en dash" =?>
+ para "\8212\8211 em and en dash"
+
+ , "Comment Block" =:
+ T.unlines [ "#+BEGIN_COMMENT"
+ , "stuff"
+ , "bla"
+ , "#+END_COMMENT"] =?>
+ (mempty::Blocks)
+
+ , testGroup "Blocks and fragments"
+ [ "HTML block" =:
+ T.unlines [ "#+BEGIN_HTML"
+ , "<aside>HTML5 is pretty nice.</aside>"
+ , "#+END_HTML"
+ ] =?>
+ rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
+
+ , "Quote block" =:
+ T.unlines [ "#+BEGIN_QUOTE"
+ , "/Niemand/ hat die Absicht, eine Mauer zu errichten!"
+ , "#+END_QUOTE"
+ ] =?>
+ blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
+ , "eine", "Mauer", "zu", "errichten!"
+ ]))
+
+ , "Verse block" =:
+ T.unlines [ "The first lines of Goethe's /Faust/:"
+ , "#+begin_verse"
+ , "Habe nun, ach! Philosophie,"
+ , "Juristerei und Medizin,"
+ , "Und leider auch Theologie!"
+ , "Durchaus studiert, mit heißem Bemühn."
+ , "#+end_verse"
+ ] =?>
+ mconcat
+ [ para $ spcSep [ "The", "first", "lines", "of"
+ , "Goethe's", emph "Faust" <> ":"]
+ , lineBlock
+ [ "Habe nun, ach! Philosophie,"
+ , "Juristerei und Medizin,"
+ , "Und leider auch Theologie!"
+ , "Durchaus studiert, mit heißem Bemühn."
+ ]
+ ]
+
+ , "Verse block with blank lines" =:
+ T.unlines [ "#+BEGIN_VERSE"
+ , "foo"
+ , ""
+ , "bar"
+ , "#+END_VERSE"
+ ] =?>
+ lineBlock [ "foo", mempty, "bar" ]
+
+ , "Verse block with varying indentation" =:
+ T.unlines [ "#+BEGIN_VERSE"
+ , " hello darkness"
+ , "my old friend"
+ , "#+END_VERSE"
+ ] =?>
+ lineBlock [ "\160\160hello darkness", "my old friend" ]
+
+ , "Raw block LaTeX" =:
+ T.unlines [ "#+BEGIN_LaTeX"
+ , "The category $\\cat{Set}$ is adhesive."
+ , "#+END_LaTeX"
+ ] =?>
+ rawBlock "latex" "The category $\\cat{Set}$ is adhesive.\n"
+
+ , "Raw LaTeX line" =:
+ "#+LATEX: \\let\\foo\\bar" =?>
+ rawBlock "latex" "\\let\\foo\\bar"
+
+ , "Raw Beamer line" =:
+ "#+beamer: \\pause" =?>
+ rawBlock "beamer" "\\pause"
+
+ , "Raw HTML line" =:
+ "#+HTML: <aside>not important</aside>" =?>
+ rawBlock "html" "<aside>not important</aside>"
+
+ , "Export block HTML" =:
+ T.unlines [ "#+BEGIN_export html"
+ , "<samp>Hello, World!</samp>"
+ , "#+END_export"
+ ] =?>
+ rawBlock "html" "<samp>Hello, World!</samp>\n"
+
+ , "LaTeX fragment" =:
+ T.unlines [ "\\begin{equation}"
+ , "X_i = \\begin{cases}"
+ , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) = \\alpha(i)\\\\"
+ , " C_{\\alpha(i)} & \\text{otherwise}"
+ , " \\end{cases}"
+ , "\\end{equation}"
+ ] =?>
+ rawBlock "latex"
+ (unlines [ "\\begin{equation}"
+ , "X_i = \\begin{cases}"
+ , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" <>
+ " \\alpha(i)\\\\"
+ , " C_{\\alpha(i)} & \\text{otherwise}"
+ , " \\end{cases}"
+ , "\\end{equation}"
+ ])
+
+ , "Convert blank lines in blocks to single newlines" =:
+ T.unlines [ "#+begin_html"
+ , ""
+ , "<span>boring</span>"
+ , ""
+ , "#+end_html"
+ ] =?>
+ rawBlock "html" "\n<span>boring</span>\n\n"
+
+ , "Accept `ATTR_HTML` attributes for generic block" =:
+ T.unlines [ "#+ATTR_HTML: :title hello, world :id test :class fun code"
+ , "#+BEGIN_TEST"
+ , "nonsense"
+ , "#+END_TEST"
+ ] =?>
+ let attr = ("test", ["fun", "code", "TEST"], [("title", "hello, world")])
+ in divWith attr (para "nonsense")
+ ]
+
+ , testGroup "Headers" Header.tests
+ , testGroup "Figures" Figure.tests
+ , testGroup "Lists" List.tests
+ , testGroup "CodeBlocks" CodeBlock.tests
+ , testGroup "Tables" Table.tests
+ ]
diff --git a/test/Tests/Readers/Org/Block/CodeBlock.hs b/test/Tests/Readers/Org/Block/CodeBlock.hs
new file mode 100644
index 000000000..8fa822089
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/CodeBlock.hs
@@ -0,0 +1,194 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.CodeBlock (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Source block" =:
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"moin\""
+ , " #+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"moin\"\n"
+ in codeBlockWith attr' code'
+
+ , "Source block with indented code" =:
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"moin\""
+ , " #+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"moin\"\n"
+ in codeBlockWith attr' code'
+
+ , "Source block with tab-indented code" =:
+ T.unlines [ "\t#+BEGIN_SRC haskell"
+ , "\tmain = putStrLn greeting"
+ , "\t where greeting = \"moin\""
+ , "\t#+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"moin\"\n"
+ in codeBlockWith attr' code'
+
+ , "Empty source block" =:
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " #+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = ""
+ in codeBlockWith attr' code'
+
+ , "Source block between paragraphs" =:
+ T.unlines [ "Low German greeting"
+ , " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"Moin!\""
+ , " #+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"Moin!\"\n"
+ in mconcat [ para $ spcSep [ "Low", "German", "greeting" ]
+ , codeBlockWith attr' code'
+ ]
+ , "Source block with babel arguments" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC" ] =?>
+ let classes = [ "commonlisp" ] -- as kate doesn't know emacs-lisp syntax
+ params = [ ("org-language", "emacs-lisp")
+ , ("exports", "both")
+ ]
+ code' = unlines [ "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))" ]
+ in codeBlockWith ("", classes, params) code'
+
+ , "Source block with results and :exports both" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65"] =?>
+ let classes = [ "commonlisp" ]
+ params = [ ("org-language", "emacs-lisp")
+ , ("exports", "both")
+ ]
+ code' = unlines [ "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))" ]
+ results' = "65\n"
+ in codeBlockWith ("", classes, params) code'
+ <>
+ codeBlockWith ("", ["example"], []) results'
+
+ , "Source block with results and :exports code" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports code"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
+ let classes = [ "commonlisp" ]
+ params = [ ("org-language", "emacs-lisp")
+ , ("exports", "code")
+ ]
+ code' = unlines [ "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))" ]
+ in codeBlockWith ("", classes, params) code'
+
+ , "Source block with results and :exports results" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports results"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
+ let results' = "65\n"
+ in codeBlockWith ("", ["example"], []) results'
+
+ , "Source block with results and :exports none" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports none"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
+ (mempty :: Blocks)
+
+ , "Source block with toggling header arguments" =:
+ T.unlines [ "#+BEGIN_SRC sh :noeval"
+ , "echo $HOME"
+ , "#+END_SRC"
+ ] =?>
+ let classes = [ "bash" ]
+ params = [ ("org-language", "sh"), ("noeval", "yes") ]
+ in codeBlockWith ("", classes, params) "echo $HOME\n"
+
+ , "Source block with line number switch" =:
+ T.unlines [ "#+BEGIN_SRC sh -n 10"
+ , ":() { :|:& };:"
+ , "#+END_SRC"
+ ] =?>
+ let classes = [ "bash", "numberLines" ]
+ params = [ ("org-language", "sh"), ("startFrom", "10") ]
+ in codeBlockWith ("", classes, params) ":() { :|:& };:\n"
+
+ , "Source block with multi-word parameter values" =:
+ T.unlines [ "#+BEGIN_SRC dot :cmdline -Kdot -Tpng "
+ , "digraph { id [label=\"ID\"] }"
+ , "#+END_SRC"
+ ] =?>
+ let classes = [ "dot" ]
+ params = [ ("cmdline", "-Kdot -Tpng") ]
+ in codeBlockWith ("", classes, params) "digraph { id [label=\"ID\"] }\n"
+
+ , "Example block" =:
+ T.unlines [ "#+begin_example"
+ , "A chosen representation of"
+ , "a rule."
+ , "#+eND_exAMPle"
+ ] =?>
+ codeBlockWith ("", ["example"], [])
+ "A chosen representation of\na rule.\n"
+
+ , "Code block with caption" =:
+ T.unlines [ "#+CAPTION: Functor laws in Haskell"
+ , "#+NAME: functor-laws"
+ , "#+BEGIN_SRC haskell"
+ , "fmap id = id"
+ , "fmap (p . q) = (fmap p) . (fmap q)"
+ , "#+END_SRC"
+ ] =?>
+ divWith
+ nullAttr
+ (mappend
+ (plain $ spanWith ("", ["label"], [])
+ (spcSep [ "Functor", "laws", "in", "Haskell" ]))
+ (codeBlockWith ("functor-laws", ["haskell"], [])
+ (unlines [ "fmap id = id"
+ , "fmap (p . q) = (fmap p) . (fmap q)"
+ ])))
+
+ , "Non-letter chars in source block parameters" =:
+ T.unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich"
+ , "code body"
+ , "#+END_SRC"
+ ] =?>
+ let params = [ ("org-language", "C")
+ , ("tangle", "xxxx.c")
+ , ("city", "Zürich")
+ ]
+ in codeBlockWith ( "", ["c"], params) "code body\n"
+ ]
diff --git a/test/Tests/Readers/Org/Block/Figure.hs b/test/Tests/Readers/Org/Block/Figure.hs
new file mode 100644
index 000000000..cae6ef179
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/Figure.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.Figure (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:))
+import Text.Pandoc.Builder (image, imageWith, para)
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Figure" =:
+ T.unlines [ "#+caption: A very courageous man."
+ , "#+name: goodguy"
+ , "[[file:edward.jpg]]"
+ ] =?>
+ para (image "edward.jpg" "fig:goodguy" "A very courageous man.")
+
+ , "Figure with no name" =:
+ T.unlines [ "#+caption: I've been through the desert on this"
+ , "[[file:horse.png]]"
+ ] =?>
+ para (image "horse.png" "fig:" "I've been through the desert on this")
+
+ , "Figure with `fig:` prefix in name" =:
+ T.unlines [ "#+caption: Used as a metapher in evolutionary biology."
+ , "#+name: fig:redqueen"
+ , "[[./the-red-queen.jpg]]"
+ ] =?>
+ para (image "./the-red-queen.jpg" "fig:redqueen"
+ "Used as a metapher in evolutionary biology.")
+
+ , "Figure with HTML attributes" =:
+ T.unlines [ "#+CAPTION: mah brain just explodid"
+ , "#+NAME: lambdacat"
+ , "#+ATTR_HTML: :style color: blue :role button"
+ , "[[file:lambdacat.jpg]]"
+ ] =?>
+ let kv = [("style", "color: blue"), ("role", "button")]
+ name = "fig:lambdacat"
+ caption = "mah brain just explodid"
+ in para (imageWith (mempty, mempty, kv) "lambdacat.jpg" name caption)
+
+ , "Labelled figure" =:
+ T.unlines [ "#+CAPTION: My figure"
+ , "#+LABEL: fig:myfig"
+ , "[[file:blub.png]]"
+ ] =?>
+ let attr = ("fig:myfig", mempty, mempty)
+ in para (imageWith attr "blub.png" "fig:" "My figure")
+
+ , "Figure with empty caption" =:
+ T.unlines [ "#+CAPTION:"
+ , "[[file:guess.jpg]]"
+ ] =?>
+ para (image "guess.jpg" "fig:" "")
+ ]
diff --git a/test/Tests/Readers/Org/Block/Header.hs b/test/Tests/Readers/Org/Block/Header.hs
new file mode 100644
index 000000000..e8ad88558
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/Header.hs
@@ -0,0 +1,182 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.Header (tests) where
+
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep, tagSpan)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "First Level Header" =:
+ "* Headline\n" =?>
+ headerWith ("headline", [], []) 1 "Headline"
+
+ , "Third Level Header" =:
+ "*** Third Level Headline\n" =?>
+ headerWith ("third-level-headline", [], [])
+ 3
+ ("Third" <> space <> "Level" <> space <> "Headline")
+
+ , "Compact Headers with Paragraph" =:
+ T.unlines [ "* First Level"
+ , "** Second Level"
+ , " Text"
+ ] =?>
+ mconcat [ headerWith ("first-level", [], [])
+ 1
+ ("First" <> space <> "Level")
+ , headerWith ("second-level", [], [])
+ 2
+ ("Second" <> space <> "Level")
+ , para "Text"
+ ]
+
+ , "Separated Headers with Paragraph" =:
+ T.unlines [ "* First Level"
+ , ""
+ , "** Second Level"
+ , ""
+ , " Text"
+ ] =?>
+ mconcat [ headerWith ("first-level", [], [])
+ 1
+ ("First" <> space <> "Level")
+ , headerWith ("second-level", [], [])
+ 2
+ ("Second" <> space <> "Level")
+ , para "Text"
+ ]
+
+ , "Headers not preceded by a blank line" =:
+ T.unlines [ "** eat dinner"
+ , "Spaghetti and meatballs tonight."
+ , "** walk dog"
+ ] =?>
+ mconcat [ headerWith ("eat-dinner", [], [])
+ 2
+ ("eat" <> space <> "dinner")
+ , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
+ , headerWith ("walk-dog", [], [])
+ 2
+ ("walk" <> space <> "dog")
+ ]
+
+ , testGroup "Todo keywords"
+ [ "Header with known todo keyword" =:
+ "* TODO header" =?>
+ let todoSpan = spanWith ("", ["todo", "TODO"], []) "TODO"
+ in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
+
+ , "Header marked as done" =:
+ "* DONE header" =?>
+ let todoSpan = spanWith ("", ["done", "DONE"], []) "DONE"
+ in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
+
+ , "Header with unknown todo keyword" =:
+ "* WAITING header" =?>
+ headerWith ("waiting-header", [], []) 1 "WAITING header"
+
+ , "Custom todo keywords" =:
+ T.unlines [ "#+TODO: WAITING CANCELLED"
+ , "* WAITING compile"
+ , "* CANCELLED lunch"
+ ] =?>
+ let todoSpan = spanWith ("", ["todo", "WAITING"], []) "WAITING"
+ doneSpan = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
+ in headerWith ("compile", [], []) 1 (todoSpan <> space <> "compile")
+ <> headerWith ("lunch", [], []) 1 (doneSpan <> space <> "lunch")
+
+ , "Custom todo keywords with multiple done-states" =:
+ T.unlines [ "#+TODO: WAITING | DONE CANCELLED "
+ , "* WAITING compile"
+ , "* CANCELLED lunch"
+ , "* DONE todo-feature"
+ ] =?>
+ let waiting = spanWith ("", ["todo", "WAITING"], []) "WAITING"
+ cancelled = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
+ done = spanWith ("", ["done", "DONE"], []) "DONE"
+ in headerWith ("compile", [], []) 1 (waiting <> space <> "compile")
+ <> headerWith ("lunch", [], []) 1 (cancelled <> space <> "lunch")
+ <> headerWith ("todo-feature", [], []) 1 (done <> space <> "todo-feature")
+ ]
+
+ , "Tagged headers" =:
+ T.unlines [ "* Personal :PERSONAL:"
+ , "** Call Mom :@PHONE:"
+ , "** Call John :@PHONE:JOHN: "
+ ] =?>
+ mconcat [ headerWith ("personal", [], [])
+ 1
+ ("Personal " <> tagSpan "PERSONAL")
+ , headerWith ("call-mom", [], [])
+ 2
+ ("Call Mom " <> tagSpan "@PHONE")
+ , headerWith ("call-john", [], [])
+ 2
+ ("Call John " <> tagSpan "@PHONE" <> "\160" <> tagSpan "JOHN")
+ ]
+
+ , "Untagged header containing colons" =:
+ "* This: is not: tagged" =?>
+ headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged"
+
+ , "Header starting with strokeout text" =:
+ T.unlines [ "foo"
+ , ""
+ , "* +thing+ other thing"
+ ] =?>
+ mconcat [ para "foo"
+ , headerWith ("thing-other-thing", [], [])
+ 1
+ (strikeout "thing" <> " other thing")
+ ]
+
+ , "Comment Trees" =:
+ T.unlines [ "* COMMENT A comment tree"
+ , " Not much going on here"
+ , "** This will be dropped"
+ , "* Comment tree above"
+ ] =?>
+ headerWith ("comment-tree-above", [], []) 1 "Comment tree above"
+
+ , "Nothing but a COMMENT header" =:
+ "* COMMENT Test" =?>
+ (mempty::Blocks)
+
+ , "Tree with :noexport:" =:
+ T.unlines [ "* Should be ignored :archive:noexport:old:"
+ , "** Old stuff"
+ , " This is not going to be exported"
+ ] =?>
+ (mempty::Blocks)
+
+ , "Subtree with :noexport:" =:
+ T.unlines [ "* Exported"
+ , "** This isn't exported :noexport:"
+ , "*** This neither"
+ , "** But this is"
+ ] =?>
+ mconcat [ headerWith ("exported", [], []) 1 "Exported"
+ , headerWith ("but-this-is", [], []) 2 "But this is"
+ ]
+
+ , "Preferences are treated as header attributes" =:
+ T.unlines [ "* foo"
+ , " :PROPERTIES:"
+ , " :custom_id: fubar"
+ , " :bar: baz"
+ , " :END:"
+ ] =?>
+ headerWith ("fubar", [], [("bar", "baz")]) 1 "foo"
+
+
+ , "Headers marked with a unnumbered property get a class of the same name" =:
+ T.unlines [ "* Not numbered"
+ , " :PROPERTIES:"
+ , " :UNNUMBERED: t"
+ , " :END:"
+ ] =?>
+ headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
+ ]
diff --git a/test/Tests/Readers/Org/Block/List.hs b/test/Tests/Readers/Org/Block/List.hs
new file mode 100644
index 000000000..343682a80
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/List.hs
@@ -0,0 +1,244 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.List (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Simple Bullet Lists" =:
+ ("- Item1\n" <>
+ "- Item2\n") =?>
+ bulletList [ plain "Item1"
+ , plain "Item2"
+ ]
+
+ , "Indented Bullet Lists" =:
+ (" - Item1\n" <>
+ " - Item2\n") =?>
+ bulletList [ plain "Item1"
+ , plain "Item2"
+ ]
+
+ , "Unindented *" =:
+ ("- Item1\n" <>
+ "* Item2\n") =?>
+ bulletList [ plain "Item1"
+ ] <>
+ headerWith ("item2", [], []) 1 "Item2"
+
+ , "Multi-line Bullet Lists" =:
+ ("- *Fat\n" <>
+ " Tony*\n" <>
+ "- /Sideshow\n" <>
+ " Bob/") =?>
+ bulletList [ plain $ strong ("Fat" <> softbreak <> "Tony")
+ , plain $ emph ("Sideshow" <> softbreak <> "Bob")
+ ]
+
+ , "Nested Bullet Lists" =:
+ ("- Discovery\n" <>
+ " + One More Time\n" <>
+ " + Harder, Better, Faster, Stronger\n" <>
+ "- Homework\n" <>
+ " + Around the World\n"<>
+ "- Human After All\n" <>
+ " + Technologic\n" <>
+ " + Robot Rock\n") =?>
+ bulletList [ mconcat
+ [ plain "Discovery"
+ , bulletList [ plain ("One" <> space <>
+ "More" <> space <>
+ "Time")
+ , plain ("Harder," <> space <>
+ "Better," <> space <>
+ "Faster," <> space <>
+ "Stronger")
+ ]
+ ]
+ , mconcat
+ [ plain "Homework"
+ , bulletList [ plain ("Around" <> space <>
+ "the" <> space <>
+ "World")
+ ]
+ ]
+ , mconcat
+ [ plain ("Human" <> space <> "After" <> space <> "All")
+ , bulletList [ plain "Technologic"
+ , plain ("Robot" <> space <> "Rock")
+ ]
+ ]
+ ]
+
+ , "Bullet List with Decreasing Indent" =:
+ " - Discovery\n\
+ \ - Human After All\n" =?>
+ mconcat [ bulletList [ plain "Discovery" ]
+ , bulletList [ plain ("Human" <> space <> "After" <> space <> "All")]
+ ]
+
+ , "Header follows Bullet List" =:
+ " - Discovery\n\
+ \ - Human After All\n\
+ \* Homework" =?>
+ mconcat [ bulletList [ plain "Discovery"
+ , plain ("Human" <> space <> "After" <> space <> "All")
+ ]
+ , headerWith ("homework", [], []) 1 "Homework"
+ ]
+
+ , "Bullet List Unindented with trailing Header" =:
+ "- Discovery\n\
+ \- Homework\n\
+ \* NotValidListItem" =?>
+ mconcat [ bulletList [ plain "Discovery"
+ , plain "Homework"
+ ]
+ , headerWith ("notvalidlistitem", [], []) 1 "NotValidListItem"
+ ]
+
+ , "Empty bullet points" =:
+ T.unlines [ "-"
+ , "- "
+ ] =?>
+ bulletList [ plain "", plain "" ]
+
+ , "Simple Ordered List" =:
+ ("1. Item1\n" <>
+ "2. Item2\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ plain "Item1"
+ , plain "Item2"
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Simple Ordered List with Parens" =:
+ ("1) Item1\n" <>
+ "2) Item2\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ plain "Item1"
+ , plain "Item2"
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Indented Ordered List" =:
+ (" 1. Item1\n" <>
+ " 2. Item2\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ plain "Item1"
+ , plain "Item2"
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Empty ordered list item" =:
+ T.unlines [ "1."
+ , "3. "
+ ] =?>
+ orderedList [ plain "", plain "" ]
+
+ , "Nested Ordered Lists" =:
+ ("1. One\n" <>
+ " 1. One-One\n" <>
+ " 2. One-Two\n" <>
+ "2. Two\n" <>
+ " 1. Two-One\n"<>
+ " 2. Two-Two\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ mconcat
+ [ plain "One"
+ , orderedList [ plain "One-One"
+ , plain "One-Two"
+ ]
+ ]
+ , mconcat
+ [ plain "Two"
+ , orderedList [ plain "Two-One"
+ , plain "Two-Two"
+ ]
+ ]
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Ordered List in Bullet List" =:
+ ("- Emacs\n" <>
+ " 1. Org\n") =?>
+ bulletList [ plain "Emacs" <>
+ orderedList [ plain "Org"]
+ ]
+
+ , "Bullet List in Ordered List" =:
+ ("1. GNU\n" <>
+ " - Freedom\n") =?>
+ orderedList [ plain "GNU" <> bulletList [ plain "Freedom" ] ]
+
+ , "Definition List" =:
+ T.unlines [ "- PLL :: phase-locked loop"
+ , "- TTL ::"
+ , " transistor-transistor logic"
+ , "- PSK :: phase-shift keying"
+ , ""
+ , " a digital modulation scheme"
+ ] =?>
+ definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
+ , ("TTL", [ plain $ "transistor-transistor" <> space <>
+ "logic" ])
+ , ("PSK", [ mconcat
+ [ para $ "phase-shift" <> space <> "keying"
+ , para $ spcSep [ "a", "digital"
+ , "modulation", "scheme" ]
+ ]
+ ])
+ ]
+ , "Definition list with multi-word term" =:
+ " - Elijah Wood :: He plays Frodo" =?>
+ definitionList [ ("Elijah" <> space <> "Wood", [plain $ "He" <> space <> "plays" <> space <> "Frodo"])]
+ , "Compact definition list" =:
+ T.unlines [ "- ATP :: adenosine 5' triphosphate"
+ , "- DNA :: deoxyribonucleic acid"
+ , "- PCR :: polymerase chain reaction"
+ , ""
+ ] =?>
+ definitionList
+ [ ("ATP", [ plain $ spcSep [ "adenosine", "5'", "triphosphate" ] ])
+ , ("DNA", [ plain $ spcSep [ "deoxyribonucleic", "acid" ] ])
+ , ("PCR", [ plain $ spcSep [ "polymerase", "chain", "reaction" ] ])
+ ]
+
+ , "Definition List With Trailing Header" =:
+ "- definition :: list\n\
+ \- cool :: defs\n\
+ \* header" =?>
+ mconcat [ definitionList [ ("definition", [plain "list"])
+ , ("cool", [plain "defs"])
+ ]
+ , headerWith ("header", [], []) 1 "header"
+ ]
+
+ , "Definition lists double-colon markers must be surrounded by whitespace" =:
+ "- std::cout" =?>
+ bulletList [ plain "std::cout" ]
+
+ , "Loose bullet list" =:
+ T.unlines [ "- apple"
+ , ""
+ , "- orange"
+ , ""
+ , "- peach"
+ ] =?>
+ bulletList [ para "apple"
+ , para "orange"
+ , para "peach"
+ ]
+
+ , "Recognize preceding paragraphs in non-list contexts" =:
+ T.unlines [ "CLOSED: [2015-10-19 Mon 15:03]"
+ , "- Note taken on [2015-10-19 Mon 13:24]"
+ ] =?>
+ mconcat [ para "CLOSED: [2015-10-19 Mon 15:03]"
+ , bulletList [ plain "Note taken on [2015-10-19 Mon 13:24]" ]
+ ]
+ ]
diff --git a/test/Tests/Readers/Org/Block/Table.hs b/test/Tests/Readers/Org/Block/Table.hs
new file mode 100644
index 000000000..db6e756f8
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/Table.hs
@@ -0,0 +1,150 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.Table (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+simpleTable' :: Int
+ -> [Blocks]
+ -> [[Blocks]]
+ -> Blocks
+simpleTable' n = table "" (replicate n (AlignDefault, 0.0))
+
+tests :: [TestTree]
+tests =
+ [ "Single cell table" =:
+ "|Test|" =?>
+ simpleTable' 1 mempty [[plain "Test"]]
+
+ , "Multi cell table" =:
+ "| One | Two |" =?>
+ simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
+
+ , "Multi line table" =:
+ T.unlines [ "| One |"
+ , "| Two |"
+ , "| Three |"
+ ] =?>
+ simpleTable' 1 mempty
+ [ [ plain "One" ]
+ , [ plain "Two" ]
+ , [ plain "Three" ]
+ ]
+
+ , "Empty table" =:
+ "||" =?>
+ simpleTable' 1 mempty [[mempty]]
+
+ , "Glider Table" =:
+ T.unlines [ "| 1 | 0 | 0 |"
+ , "| 0 | 1 | 1 |"
+ , "| 1 | 1 | 0 |"
+ ] =?>
+ simpleTable' 3 mempty
+ [ [ plain "1", plain "0", plain "0" ]
+ , [ plain "0", plain "1", plain "1" ]
+ , [ plain "1", plain "1", plain "0" ]
+ ]
+
+ , "Table between Paragraphs" =:
+ T.unlines [ "Before"
+ , "| One | Two |"
+ , "After"
+ ] =?>
+ mconcat [ para "Before"
+ , simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
+ , para "After"
+ ]
+
+ , "Table with Header" =:
+ T.unlines [ "| Species | Status |"
+ , "|--------------+--------------|"
+ , "| cervisiae | domesticated |"
+ , "| paradoxus | wild |"
+ ] =?>
+ simpleTable [ plain "Species", plain "Status" ]
+ [ [ plain "cervisiae", plain "domesticated" ]
+ , [ plain "paradoxus", plain "wild" ]
+ ]
+
+ , "Table with final hline" =:
+ T.unlines [ "| cervisiae | domesticated |"
+ , "| paradoxus | wild |"
+ , "|--------------+--------------|"
+ ] =?>
+ simpleTable' 2 mempty
+ [ [ plain "cervisiae", plain "domesticated" ]
+ , [ plain "paradoxus", plain "wild" ]
+ ]
+
+ , "Table in a box" =:
+ T.unlines [ "|---------|---------|"
+ , "| static | Haskell |"
+ , "| dynamic | Lisp |"
+ , "|---------+---------|"
+ ] =?>
+ simpleTable' 2 mempty
+ [ [ plain "static", plain "Haskell" ]
+ , [ plain "dynamic", plain "Lisp" ]
+ ]
+
+ , "Table with empty cells" =:
+ "|||c|" =?>
+ simpleTable' 3 mempty [[mempty, mempty, plain "c"]]
+
+ , "Table with empty rows" =:
+ T.unlines [ "| first |"
+ , "| |"
+ , "| third |"
+ ] =?>
+ simpleTable' 1 mempty [[plain "first"], [mempty], [plain "third"]]
+
+ , "Table with alignment row" =:
+ T.unlines [ "| Numbers | Text | More |"
+ , "| <c> | <r> | |"
+ , "| 1 | One | foo |"
+ , "| 2 | Two | bar |"
+ ] =?>
+ table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
+ []
+ [ [ plain "Numbers", plain "Text", plain "More" ]
+ , [ plain "1" , plain "One" , plain "foo" ]
+ , [ plain "2" , plain "Two" , plain "bar" ]
+ ]
+
+ , "Pipe within text doesn't start a table" =:
+ "Ceci n'est pas une | pipe " =?>
+ para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ])
+
+ , "Missing pipe at end of row" =:
+ "|incomplete-but-valid" =?>
+ simpleTable' 1 mempty [ [ plain "incomplete-but-valid" ] ]
+
+ , "Table with differing row lengths" =:
+ T.unlines [ "| Numbers | Text "
+ , "|-"
+ , "| <c> | <r> |"
+ , "| 1 | One | foo |"
+ , "| 2"
+ ] =?>
+ table "" (zip [AlignCenter, AlignRight] [0, 0])
+ [ plain "Numbers", plain "Text" ]
+ [ [ plain "1" , plain "One" , plain "foo" ]
+ , [ plain "2" ]
+ ]
+
+ , "Table with caption" =:
+ T.unlines [ "#+CAPTION: Hitchhiker's Multiplication Table"
+ , "| x | 6 |"
+ , "| 9 | 42 |"
+ ] =?>
+ table "Hitchhiker's Multiplication Table"
+ [(AlignDefault, 0), (AlignDefault, 0)]
+ []
+ [ [ plain "x", plain "6" ]
+ , [ plain "9", plain "42" ]
+ ]
+ ]
diff --git a/test/Tests/Readers/Org/Directive.hs b/test/Tests/Readers/Org/Directive.hs
new file mode 100644
index 000000000..7e2c0fb8d
--- /dev/null
+++ b/test/Tests/Readers/Org/Directive.hs
@@ -0,0 +1,199 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Directive (tests) where
+
+import Data.Time (UTCTime (UTCTime), secondsToDiffTime)
+import Data.Time.Calendar (Day (ModifiedJulianDay))
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>), ToString, purely, test)
+import Tests.Readers.Org.Shared ((=:), tagSpan)
+import Text.Pandoc
+import Text.Pandoc.Builder
+import qualified Data.ByteString as BS
+import qualified Data.Text as T
+
+testWithFiles :: (ToString c)
+ => [(FilePath, BS.ByteString)]
+ -> String -- ^ name of test case
+ -> (T.Text, c) -- ^ (input, expected value)
+ -> TestTree
+testWithFiles fileDefs = test (orgWithFiles fileDefs)
+ where
+orgWithFiles :: [(FilePath, BS.ByteString)] -> T.Text -> Pandoc
+orgWithFiles fileDefs input =
+ let readOrg' = readOrg def{ readerExtensions = getDefaultExtensions "org" }
+ in flip purely input $ \inp -> do
+ modifyPureState (\st -> st { stFiles = files fileDefs })
+ readOrg' inp
+
+
+files :: [(FilePath, BS.ByteString)] -> FileTree
+files fileDefs =
+ let dummyTime = UTCTime (ModifiedJulianDay 125) (secondsToDiffTime 0)
+ in foldr (\(fp, bs) -> insertInFileTree fp (FileInfo dummyTime bs))
+ mempty fileDefs
+
+tests :: [TestTree]
+tests =
+ [ testGroup "export options"
+ [ "disable simple sub/superscript syntax" =:
+ T.unlines [ "#+OPTIONS: ^:nil"
+ , "a^b"
+ ] =?>
+ para "a^b"
+
+ , "directly select drawers to be exported" =:
+ T.unlines [ "#+OPTIONS: d:(\"IMPORTANT\")"
+ , ":IMPORTANT:"
+ , "23"
+ , ":END:"
+ , ":BORING:"
+ , "very boring"
+ , ":END:"
+ ] =?>
+ divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "23")
+
+ , "exclude drawers from being exported" =:
+ T.unlines [ "#+OPTIONS: d:(not \"BORING\")"
+ , ":IMPORTANT:"
+ , "5"
+ , ":END:"
+ , ":BORING:"
+ , "very boring"
+ , ":END:"
+ ] =?>
+ divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "5")
+
+ , "don't include archive trees" =:
+ T.unlines [ "#+OPTIONS: arch:nil"
+ , "* old :ARCHIVE:"
+ ] =?>
+ (mempty ::Blocks)
+
+ , "include complete archive trees" =:
+ T.unlines [ "#+OPTIONS: arch:t"
+ , "* old :ARCHIVE:"
+ , " boring"
+ ] =?>
+ mconcat [ headerWith ("old", [], mempty) 1
+ ("old" <> space <> tagSpan "ARCHIVE")
+ , para "boring"
+ ]
+
+ , "include archive tree header only" =:
+ T.unlines [ "#+OPTIONS: arch:headline"
+ , "* old :ARCHIVE:"
+ , " boring"
+ ] =?>
+ headerWith ("old", [], mempty) 1 ("old" <> space <> tagSpan "ARCHIVE")
+
+ , "limit headline depth" =:
+ T.unlines [ "#+OPTIONS: H:2"
+ , "* top-level section"
+ , "** subsection"
+ , "*** list item 1"
+ , "*** list item 2"
+ ] =?>
+ mconcat [ headerWith ("top-level-section", [], []) 1 "top-level section"
+ , headerWith ("subsection", [], []) 2 "subsection"
+ , orderedList [ para "list item 1", para "list item 2" ]
+ ]
+
+ , "turn all headlines into lists" =:
+ T.unlines [ "#+OPTIONS: H:0"
+ , "first block"
+ , "* top-level section 1"
+ , "** subsection"
+ , "* top-level section 2"
+ ] =?>
+ mconcat [ para "first block"
+ , orderedList
+ [ para "top-level section 1" <>
+ orderedList [ para "subsection" ]
+ , para "top-level section 2" ]
+ ]
+
+ , "preserve linebreaks as hard breaks" =:
+ T.unlines [ "#+OPTIONS: \\n:t"
+ , "first"
+ , "second"
+ ] =?>
+ para ("first" <> linebreak <> "second")
+
+ , "disable author export" =:
+ T.unlines [ "#+OPTIONS: author:nil"
+ , "#+AUTHOR: ShyGuy"
+ ] =?>
+ Pandoc nullMeta mempty
+
+ , "disable creator export" =:
+ T.unlines [ "#+OPTIONS: creator:nil"
+ , "#+creator: The Architect"
+ ] =?>
+ Pandoc nullMeta mempty
+
+ , "disable email export" =:
+ T.unlines [ "#+OPTIONS: email:nil"
+ , "#+email: no-mail-please@example.com"
+ ] =?>
+ Pandoc nullMeta mempty
+
+ , "disable inclusion of todo keywords" =:
+ T.unlines [ "#+OPTIONS: todo:nil"
+ , "** DONE todo export"
+ ] =?>
+ headerWith ("todo-export", [], []) 2 "todo export"
+
+ , "remove tags from headlines" =:
+ T.unlines [ "#+OPTIONS: tags:nil"
+ , "* Headline :hello:world:"
+ ] =?>
+ headerWith ("headline", [], mempty) 1 "Headline"
+ ]
+
+ , testGroup "Include"
+ [ testWithFiles [("./other.org", "content of other file\n")]
+ "file inclusion"
+ (T.unlines [ "#+include: \"other.org\"" ] =?>
+ plain "content of other file")
+
+ , testWithFiles [("./world.org", "World\n\n")]
+ "Included file belongs to item"
+ (T.unlines [ "- Hello,\n #+include: \"world.org\"" ] =?>
+ bulletList [para "Hello," <> para "World"])
+
+ , testWithFiles [("./level3.org", "*** Level3\n\n")]
+ "Default include preserves level"
+ (T.unlines [ "#+include: \"level3.org\"" ] =?>
+ headerWith ("level3", [], []) 3 "Level3")
+
+ , testWithFiles [("./level3.org", "*** Level3\n\n")]
+ "Minlevel shifts level"
+ (T.unlines [ "#+include: \"level3.org\" :minlevel 1" ] =?>
+ headerWith ("level3", [], []) 1 "Level3")
+
+ , testWithFiles [("./src.hs", "putStrLn outString\n")]
+ "Include file as source code snippet"
+ (T.unlines [ "#+include: \"src.hs\" src haskell" ] =?>
+ codeBlockWith ("", ["haskell"], []) "putStrLn outString\n")
+
+ , testWithFiles [("./export-latex.org", "\\emph{Hello}\n")]
+ "Include file as export snippet"
+ (T.unlines [ "#+include: \"export-latex.org\" export latex" ] =?>
+ rawBlock "latex" "\\emph{Hello}\n")
+
+ , testWithFiles [("./subdir/foo-bar.latex", "foo\n"),
+ ("./hello.lisp", "(print \"Hello!\")\n")
+ ]
+ "include directive is limited to one line"
+ (T.unlines [ "#+INCLUDE: \"hello.lisp\" src lisp"
+ , "#+include: \"subdir/foo-bar.latex\" export latex"
+ , "bar"
+ ] =?>
+ mconcat
+ [ codeBlockWith ("", ["lisp"], []) "(print \"Hello!\")\n"
+ , rawBlock "latex" "foo\n"
+ , para "bar"
+ ]
+ )
+ ]
+ ]
diff --git a/test/Tests/Readers/Org/Inline.hs b/test/Tests/Readers/Org/Inline.hs
new file mode 100644
index 000000000..9bf5556d2
--- /dev/null
+++ b/test/Tests/Readers/Org/Inline.hs
@@ -0,0 +1,352 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Inline (tests) where
+
+import Data.List (intersperse)
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import Text.Pandoc.Shared (underlineSpan)
+import qualified Data.Text as T
+import qualified Tests.Readers.Org.Inline.Citation as Citation
+import qualified Tests.Readers.Org.Inline.Note as Note
+import qualified Tests.Readers.Org.Inline.Smart as Smart
+
+tests :: [TestTree]
+tests =
+ [ "Plain String" =:
+ "Hello, World" =?>
+ para (spcSep [ "Hello,", "World" ])
+
+ , "Emphasis" =:
+ "/Planet Punk/" =?>
+ para (emph . spcSep $ ["Planet", "Punk"])
+
+ , "Strong" =:
+ "*Cider*" =?>
+ para (strong "Cider")
+
+ , "Strong Emphasis" =:
+ "/*strength*/" =?>
+ para (emph . strong $ "strength")
+
+ , "Emphasized Strong preceded by space" =:
+ " */super/*" =?>
+ para (strong . emph $ "super")
+
+ , "Underline" =:
+ "_underline_" =?>
+ para (underlineSpan "underline")
+
+ , "Strikeout" =:
+ "+Kill Bill+" =?>
+ para (strikeout . spcSep $ [ "Kill", "Bill" ])
+
+ , "Verbatim" =:
+ "=Robot.rock()=" =?>
+ para (code "Robot.rock()")
+
+ , "Code" =:
+ "~word for word~" =?>
+ para (code "word for word")
+
+ , "Math $..$" =:
+ "$E=mc^2$" =?>
+ para (math "E=mc^2")
+
+ , "Math $$..$$" =:
+ "$$E=mc^2$$" =?>
+ para (displayMath "E=mc^2")
+
+ , "Math \\[..\\]" =:
+ "\\[E=ℎν\\]" =?>
+ para (displayMath "E=ℎν")
+
+ , "Math \\(..\\)" =:
+ "\\(σ_x σ_p ≥ \\frac{ℏ}{2}\\)" =?>
+ para (math "σ_x σ_p ≥ \\frac{ℏ}{2}")
+
+ , "Symbol" =:
+ "A * symbol" =?>
+ para (str "A" <> space <> str "*" <> space <> "symbol")
+
+ , "Superscript simple expression" =:
+ "2^-λ" =?>
+ para (str "2" <> superscript "-λ")
+
+ , "Superscript multi char" =:
+ "2^{n-1}" =?>
+ para (str "2" <> superscript "n-1")
+
+ , "Subscript simple expression" =:
+ "a_n" =?>
+ para (str "a" <> subscript "n")
+
+ , "Subscript multi char" =:
+ "a_{n+1}" =?>
+ para (str "a" <> subscript "n+1")
+
+ , "Linebreak" =:
+ "line \\\\ \nbreak" =?>
+ para ("line" <> linebreak <> "break")
+
+ , "Inline note" =:
+ "[fn::Schreib mir eine E-Mail]" =?>
+ para (note $ para "Schreib mir eine E-Mail")
+
+ , "Markup-chars not occuring on word break are symbols" =:
+ T.unlines [ "this+that+ +so+on"
+ , "seven*eight* nine*"
+ , "+not+funny+"
+ ] =?>
+ para ("this+that+ +so+on" <> softbreak <>
+ "seven*eight* nine*" <> softbreak <>
+ strikeout "not+funny")
+
+ , "No empty markup" =:
+ "// ** __ <> == ~~ $$" =?>
+ para (spcSep [ "//", "**", "__", "<>", "==", "~~", "$$" ])
+
+ , "Adherence to Org's rules for markup borders" =:
+ "/t/& a/ / ./r/ (*l*) /e/! /b/." =?>
+ para (spcSep [ emph $ "t/&" <> space <> "a"
+ , "/"
+ , "./r/"
+ , "(" <> strong "l" <> ")"
+ , emph "e" <> "!"
+ , emph "b" <> "."
+ ])
+
+ , "Quotes are allowed border chars" =:
+ "/'yep/ *sure\"*" =?>
+ para (emph "'yep" <> space <> strong "sure\"")
+
+ , "Spaces are forbidden border chars" =:
+ "/nada /" =?>
+ para "/nada /"
+
+ , "Markup should work properly after a blank line" =:
+ T.unlines ["foo", "", "/bar/"] =?>
+ para (text "foo") <>
+ para (emph $ text "bar")
+
+ , "Inline math must stay within three lines" =:
+ T.unlines [ "$a", "b", "c$", "$d", "e", "f", "g$" ] =?>
+ para (math "a\nb\nc" <> softbreak <>
+ "$d" <> softbreak <> "e" <> softbreak <>
+ "f" <> softbreak <> "g$")
+
+ , "Single-character math" =:
+ "$a$ $b$! $c$?" =?>
+ para (spcSep [ math "a"
+ , "$b$!"
+ , math "c" <> "?"
+ ])
+
+ , "Markup may not span more than two lines" =:
+ "/this *is +totally\nnice+ not*\nemph/" =?>
+ para ("/this" <> space <>
+ strong ("is" <> space <>
+ strikeout ("totally" <>
+ softbreak <> "nice") <>
+ space <> "not") <>
+ softbreak <> "emph/")
+
+ , "Sub- and superscript expressions" =:
+ T.unlines [ "a_(a(b)(c)d)"
+ , "e^(f(g)h)"
+ , "i_(jk)l)"
+ , "m^()n"
+ , "o_{p{q{}r}}"
+ , "s^{t{u}v}"
+ , "w_{xy}z}"
+ , "1^{}2"
+ , "3_{{}}"
+ , "4^(a(*b(c*)d))"
+ ] =?>
+ para (mconcat $ intersperse softbreak
+ [ "a" <> subscript "(a(b)(c)d)"
+ , "e" <> superscript "(f(g)h)"
+ , "i" <> subscript "(jk)" <> "l)"
+ , "m" <> superscript "()" <> "n"
+ , "o" <> subscript "p{q{}r}"
+ , "s" <> superscript "t{u}v"
+ , "w" <> subscript "xy" <> "z}"
+ , "1" <> superscript "" <> "2"
+ , "3" <> subscript "{}"
+ , "4" <> superscript ("(a(" <> strong "b(c" <> ")d))")
+ ])
+ , "Verbatim text can contain equal signes (=)" =:
+ "=is_subst = True=" =?>
+ para (code "is_subst = True")
+
+ , testGroup "Images"
+ [ "Image" =:
+ "[[./sunset.jpg]]" =?>
+ para (image "./sunset.jpg" "" "")
+
+ , "Image with explicit file: prefix" =:
+ "[[file:sunrise.jpg]]" =?>
+ para (image "sunrise.jpg" "" "")
+
+ , "Multiple images within a paragraph" =:
+ T.unlines [ "[[file:sunrise.jpg]]"
+ , "[[file:sunset.jpg]]"
+ ] =?>
+ para ((image "sunrise.jpg" "" "")
+ <> softbreak
+ <> (image "sunset.jpg" "" ""))
+
+ , "Image with html attributes" =:
+ T.unlines [ "#+ATTR_HTML: :width 50%"
+ , "[[file:guinea-pig.gif]]"
+ ] =?>
+ para (imageWith ("", [], [("width", "50%")]) "guinea-pig.gif" "" "")
+ ]
+
+ , "Explicit link" =:
+ "[[http://zeitlens.com/][pseudo-random /nonsense/]]" =?>
+ para (link "http://zeitlens.com/" ""
+ ("pseudo-random" <> space <> emph "nonsense"))
+
+ , "Self-link" =:
+ "[[http://zeitlens.com/]]" =?>
+ para (link "http://zeitlens.com/" "" "http://zeitlens.com/")
+
+ , "Absolute file link" =:
+ "[[/url][hi]]" =?>
+ para (link "file:///url" "" "hi")
+
+ , "Link to file in parent directory" =:
+ "[[../file.txt][moin]]" =?>
+ para (link "../file.txt" "" "moin")
+
+ , "Empty link (for gitit interop)" =:
+ "[[][New Link]]" =?>
+ para (link "" "" "New Link")
+
+ , "Image link" =:
+ "[[sunset.png][file:dusk.svg]]" =?>
+ para (link "sunset.png" "" (image "dusk.svg" "" ""))
+
+ , "Image link with non-image target" =:
+ "[[http://example.com][./logo.png]]" =?>
+ para (link "http://example.com" "" (image "./logo.png" "" ""))
+
+ , "Plain link" =:
+ "Posts on http://zeitlens.com/ can be funny at times." =?>
+ para (spcSep [ "Posts", "on"
+ , link "http://zeitlens.com/" "" "http://zeitlens.com/"
+ , "can", "be", "funny", "at", "times."
+ ])
+
+ , "Angle link" =:
+ "Look at <http://moltkeplatz.de> for fnords." =?>
+ para (spcSep [ "Look", "at"
+ , link "http://moltkeplatz.de" "" "http://moltkeplatz.de"
+ , "for", "fnords."
+ ])
+
+ , "Absolute file link" =:
+ "[[file:///etc/passwd][passwd]]" =?>
+ para (link "file:///etc/passwd" "" "passwd")
+
+ , "File link" =:
+ "[[file:target][title]]" =?>
+ para (link "target" "" "title")
+
+ , "Anchor" =:
+ "<<anchor>> Link here later." =?>
+ para (spanWith ("anchor", [], []) mempty <>
+ "Link" <> space <> "here" <> space <> "later.")
+
+ , "Inline code block" =:
+ "src_emacs-lisp{(message \"Hello\")}" =?>
+ para (codeWith ( ""
+ , [ "commonlisp" ]
+ , [ ("org-language", "emacs-lisp") ])
+ "(message \"Hello\")")
+
+ , "Inline code block with arguments" =:
+ "src_sh[:export both :results output]{echo 'Hello, World'}" =?>
+ para (codeWith ( ""
+ , [ "bash" ]
+ , [ ("org-language", "sh")
+ , ("export", "both")
+ , ("results", "output")
+ ]
+ )
+ "echo 'Hello, World'")
+
+ , "Inline code block with toggle" =:
+ "src_sh[:toggle]{echo $HOME}" =?>
+ para (codeWith ( ""
+ , [ "bash" ]
+ , [ ("org-language", "sh")
+ , ("toggle", "yes")
+ ]
+ )
+ "echo $HOME")
+
+ , "Inline LaTeX symbol" =:
+ "\\dots" =?>
+ para "…"
+
+ , "Inline LaTeX command" =:
+ "\\textit{Emphasised}" =?>
+ para (emph "Emphasised")
+
+ , "Inline LaTeX command with spaces" =:
+ "\\emph{Emphasis mine}" =?>
+ para (emph "Emphasis mine")
+
+ , "Inline LaTeX math symbol" =:
+ "\\tau" =?>
+ para (emph "τ")
+
+ , "Unknown inline LaTeX command" =:
+ "\\notacommand{foo}" =?>
+ para (rawInline "latex" "\\notacommand{foo}")
+
+ , "Export snippet" =:
+ "@@html:<kbd>M-x org-agenda</kbd>@@" =?>
+ para (rawInline "html" "<kbd>M-x org-agenda</kbd>")
+
+ , "MathML symbol in LaTeX-style" =:
+ "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: '\\nbsp')." =?>
+ para "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: ' ')."
+
+ , "MathML symbol in LaTeX-style, including braces" =:
+ "\\Aacute{}stor" =?>
+ para "Ástor"
+
+ , "MathML copy sign" =:
+ "\\copy" =?>
+ para "©"
+
+ , "MathML symbols, space separated" =:
+ "\\ForAll \\Auml" =?>
+ para "∀ Ä"
+
+ , "Macro" =:
+ T.unlines [ "#+MACRO: HELLO /Hello, $1/"
+ , "{{{HELLO(World)}}}"
+ ] =?>
+ para (emph "Hello, World")
+
+ , "Macro repeting its argument" =:
+ T.unlines [ "#+MACRO: HELLO $1$1"
+ , "{{{HELLO(moin)}}}"
+ ] =?>
+ para "moinmoin"
+
+ , "Macro called with too few arguments" =:
+ T.unlines [ "#+MACRO: HELLO Foo $1 $2 Bar"
+ , "{{{HELLO()}}}"
+ ] =?>
+ para "Foo Bar"
+
+ , testGroup "Citations" Citation.tests
+ , testGroup "Footnotes" Note.tests
+ , testGroup "Smart punctuation" Smart.tests
+ ]
diff --git a/test/Tests/Readers/Org/Inline/Citation.hs b/test/Tests/Readers/Org/Inline/Citation.hs
new file mode 100644
index 000000000..d7e38a6b0
--- /dev/null
+++ b/test/Tests/Readers/Org/Inline/Citation.hs
@@ -0,0 +1,179 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Inline.Citation (tests) where
+
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:))
+import Text.Pandoc.Builder
+
+tests :: [TestTree]
+tests =
+ [ testGroup "Markdown-style citations"
+ [ "Citation" =:
+ "[@nonexistent]" =?>
+ let citation = Citation
+ { citationId = "nonexistent"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0}
+ in (para $ cite [citation] "[@nonexistent]")
+
+ , "Citation containing text" =:
+ "[see @item1 p. 34-35]" =?>
+ let citation = Citation
+ { citationId = "item1"
+ , citationPrefix = [Str "see"]
+ , citationSuffix = [Space ,Str "p.",Space,Str "34-35"]
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0}
+ in (para $ cite [citation] "[see @item1 p. 34-35]")
+ ]
+
+ , testGroup "org-ref citations"
+ [ "simple citation" =:
+ "cite:pandoc" =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc")
+
+ , "simple citation with underscores" =:
+ "cite:pandoc_org_ref" =?>
+ let citation = Citation
+ { citationId = "pandoc_org_ref"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc_org_ref")
+
+ , "simple citation succeeded by comma" =:
+ "cite:pandoc," =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc" <> str ",")
+
+ , "simple citation succeeded by dot" =:
+ "cite:pandoc." =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc" <> str ".")
+
+ , "simple citation succeeded by colon" =:
+ "cite:pandoc:" =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc" <> str ":")
+
+ , "simple citep citation" =:
+ "citep:pandoc" =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "citep:pandoc")
+
+ , "extended citation" =:
+ "[[citep:Dominik201408][See page 20::, for example]]" =?>
+ let citation = Citation
+ { citationId = "Dominik201408"
+ , citationPrefix = toList "See page 20"
+ , citationSuffix = toList ", for example"
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "[[citep:Dominik201408][See page 20::, for example]]")
+ ]
+
+ , testGroup "Berkeley-style citations" $
+ let pandocCite = Citation
+ { citationId = "Pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ pandocInText = pandocCite { citationMode = AuthorInText }
+ dominikCite = Citation
+ { citationId = "Dominik201408"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ dominikInText = dominikCite { citationMode = AuthorInText }
+ in
+ [ "Berkeley-style in-text citation" =:
+ "See @Dominik201408." =?>
+ para ("See "
+ <> cite [dominikInText] "@Dominik201408"
+ <> ".")
+
+ , "Berkeley-style parenthetical citation list" =:
+ "[(cite): see; @Dominik201408;also @Pandoc; and others]" =?>
+ let pandocCite' = pandocCite {
+ citationPrefix = toList "also"
+ , citationSuffix = toList "and others"
+ }
+ dominikCite' = dominikCite {
+ citationPrefix = toList "see"
+ }
+ in (para $ cite [dominikCite', pandocCite'] "")
+
+ , "Berkeley-style plain citation list" =:
+ "[cite: See; @Dominik201408; and @Pandoc; and others]" =?>
+ let pandocCite' = pandocInText { citationPrefix = toList "and" }
+ in (para $ "See "
+ <> cite [dominikInText] ""
+ <> "," <> space
+ <> cite [pandocCite'] ""
+ <> "," <> space <> "and others")
+ ]
+
+ , "LaTeX citation" =:
+ "\\cite{Coffee}" =?>
+ let citation = Citation
+ { citationId = "Coffee"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0}
+ in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
+
+ ]
diff --git a/test/Tests/Readers/Org/Inline/Note.hs b/test/Tests/Readers/Org/Inline/Note.hs
new file mode 100644
index 000000000..9eb1d02d6
--- /dev/null
+++ b/test/Tests/Readers/Org/Inline/Note.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Inline.Note (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:))
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Footnote" =:
+ T.unlines [ "A footnote[1]"
+ , ""
+ , "[1] First paragraph"
+ , ""
+ , "second paragraph"
+ ] =?>
+ para (mconcat
+ [ "A", space, "footnote"
+ , note $ mconcat [ para ("First" <> space <> "paragraph")
+ , para ("second" <> space <> "paragraph")
+ ]
+ ])
+
+ , "Two footnotes" =:
+ T.unlines [ "Footnotes[fn:1][fn:2]"
+ , ""
+ , "[fn:1] First note."
+ , ""
+ , "[fn:2] Second note."
+ ] =?>
+ para (mconcat
+ [ "Footnotes"
+ , note $ para ("First" <> space <> "note.")
+ , note $ para ("Second" <> space <> "note.")
+ ])
+
+ , "Emphasized text before footnote" =:
+ T.unlines [ "/text/[fn:1]"
+ , ""
+ , "[fn:1] unicorn"
+ ] =?>
+ para (mconcat
+ [ emph "text"
+ , note . para $ "unicorn"
+ ])
+
+ , "Footnote that starts with emphasized text" =:
+ T.unlines [ "text[fn:1]"
+ , ""
+ , "[fn:1] /emphasized/"
+ ] =?>
+ para (mconcat
+ [ "text"
+ , note . para $ emph "emphasized"
+ ])
+
+ , "Footnote followed by header" =:
+ T.unlines [ "Another note[fn:yay]"
+ , ""
+ , "[fn:yay] This is great!"
+ , ""
+ , "** Headline"
+ ] =?>
+ mconcat
+ [ para (mconcat
+ [ "Another", space, "note"
+ , note $ para ("This" <> space <> "is" <> space <> "great!")
+ ])
+ , headerWith ("headline", [], []) 2 "Headline"
+ ]
+
+ , "Footnote followed by two blank lines" =:
+ T.unlines [ "footnote[fn:blanklines]"
+ , ""
+ , "[fn:blanklines] followed by blank lines"
+ , ""
+ , ""
+ , "next"
+ ] =?>
+ mconcat
+ [ para ("footnote" <> note (para "followed by blank lines"))
+ , para "next"
+ ]
+ ]
diff --git a/test/Tests/Readers/Org/Inline/Smart.hs b/test/Tests/Readers/Org/Inline/Smart.hs
new file mode 100644
index 000000000..77f10699d
--- /dev/null
+++ b/test/Tests/Readers/Org/Inline/Smart.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Inline.Smart (tests) where
+
+import Data.Text (Text)
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>), purely, test)
+import Text.Pandoc (ReaderOptions (readerExtensions),
+ Extension (Ext_smart), def, enableExtension,
+ getDefaultExtensions, readOrg)
+import Text.Pandoc.Builder
+
+orgSmart :: Text -> Pandoc
+orgSmart = purely $
+ let extensionsSmart = enableExtension Ext_smart (getDefaultExtensions "org")
+ in readOrg def{ readerExtensions = extensionsSmart }
+
+tests :: [TestTree]
+tests =
+ [ test orgSmart "quote before ellipses"
+ ("'...hi'"
+ =?> para (singleQuoted "…hi"))
+
+ , test orgSmart "apostrophe before emph"
+ ("D'oh! A l'/aide/!"
+ =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
+
+ , test orgSmart "apostrophe in French"
+ ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
+ =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
+
+ , test orgSmart "Quotes cannot occur at the end of emphasized text"
+ ("/say \"yes\"/" =?>
+ para ("/say" <> space <> doubleQuoted "yes" <> "/"))
+
+ , test orgSmart "Dashes are allowed at the borders of emphasis'"
+ ("/foo---/" =?>
+ para (emph "foo—"))
+
+ , test orgSmart "Single quotes can be followed by emphasized text"
+ ("Singles on the '/meat market/'" =?>
+ para ("Singles on the " <> singleQuoted (emph "meat market")))
+
+ , test orgSmart "Double quotes can be followed by emphasized text"
+ ("Double income, no kids: \"/DINK/\"" =?>
+ para ("Double income, no kids: " <> doubleQuoted (emph "DINK")))
+ ]
diff --git a/test/Tests/Readers/Org/Meta.hs b/test/Tests/Readers/Org/Meta.hs
new file mode 100644
index 000000000..6bd1b02e7
--- /dev/null
+++ b/test/Tests/Readers/Org/Meta.hs
@@ -0,0 +1,191 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Meta (tests) where
+
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Comment" =:
+ "# Nothing to see here" =?>
+ (mempty::Blocks)
+
+ , "Not a comment" =:
+ "#-tag" =?>
+ para "#-tag"
+
+ , "Comment surrounded by Text" =:
+ T.unlines [ "Before"
+ , "# Comment"
+ , "After"
+ ] =?>
+ mconcat [ para "Before"
+ , para "After"
+ ]
+
+ , "Title" =:
+ "#+TITLE: Hello, World" =?>
+ let titleInline = toList $ "Hello," <> space <> "World"
+ meta = setMeta "title" (MetaInlines titleInline) nullMeta
+ in Pandoc meta mempty
+
+ , "Author" =:
+ "#+author: John /Emacs-Fanboy/ Doe" =?>
+ let author = toList . spcSep $ [ "John", emph "Emacs-Fanboy", "Doe" ]
+ meta = setMeta "author" (MetaList [MetaInlines author]) nullMeta
+ in Pandoc meta mempty
+
+ , "Multiple authors" =:
+ "#+author: James Dewey Watson, Francis Harry Compton Crick " =?>
+ let watson = MetaInlines $ toList "James Dewey Watson"
+ crick = MetaInlines $ toList "Francis Harry Compton Crick"
+ meta = setMeta "author" (MetaList [watson, crick]) nullMeta
+ in Pandoc meta mempty
+
+ , "Date" =:
+ "#+Date: Feb. *28*, 2014" =?>
+ let date = toList . spcSep $ [ "Feb.", strong "28" <> ",", "2014" ]
+ meta = setMeta "date" (MetaInlines date) nullMeta
+ in Pandoc meta mempty
+
+ , "Description" =:
+ "#+DESCRIPTION: Explanatory text" =?>
+ let description = "Explanatory text"
+ meta = setMeta "description" (MetaString description) nullMeta
+ in Pandoc meta mempty
+
+ , "Properties drawer" =:
+ T.unlines [ " :PROPERTIES:"
+ , " :setting: foo"
+ , " :END:"
+ ] =?>
+ (mempty::Blocks)
+
+ , "LaTeX_headers options are translated to header-includes" =:
+ "#+LaTeX_header: \\usepackage{tikz}" =?>
+ let latexInlines = rawInline "latex" "\\usepackage{tikz}"
+ inclList = MetaList [MetaInlines (toList latexInlines)]
+ meta = setMeta "header-includes" inclList nullMeta
+ in Pandoc meta mempty
+
+ , "LaTeX_class option is translated to documentclass" =:
+ "#+LATEX_CLASS: article" =?>
+ let meta = setMeta "documentclass" (MetaString "article") nullMeta
+ in Pandoc meta mempty
+
+ , "LaTeX_class_options is translated to classoption" =:
+ "#+LATEX_CLASS_OPTIONS: [a4paper]" =?>
+ let meta = setMeta "classoption" (MetaString "a4paper") nullMeta
+ in Pandoc meta mempty
+
+ , "LaTeX_class_options is translated to classoption" =:
+ "#+html_head: <meta/>" =?>
+ let html = rawInline "html" "<meta/>"
+ inclList = MetaList [MetaInlines (toList html)]
+ meta = setMeta "header-includes" inclList nullMeta
+ in Pandoc meta mempty
+
+ , "later meta definitions take precedence" =:
+ T.unlines [ "#+AUTHOR: this will not be used"
+ , "#+author: Max"
+ ] =?>
+ let author = MetaInlines [Str "Max"]
+ meta = setMeta "author" (MetaList [author]) nullMeta
+ in Pandoc meta mempty
+
+ , "Logbook drawer" =:
+ T.unlines [ " :LogBook:"
+ , " - State \"DONE\" from \"TODO\" [2014-03-03 Mon 11:00]"
+ , " :END:"
+ ] =?>
+ (mempty::Blocks)
+
+ , "Drawer surrounded by text" =:
+ T.unlines [ "Before"
+ , ":PROPERTIES:"
+ , ":END:"
+ , "After"
+ ] =?>
+ para "Before" <> para "After"
+
+ , "Drawer markers must be the only text in the line" =:
+ T.unlines [ " :LOGBOOK: foo"
+ , " :END: bar"
+ ] =?>
+ para (":LOGBOOK: foo" <> softbreak <> ":END: bar")
+
+ , "Drawers can be arbitrary" =:
+ T.unlines [ ":FOO:"
+ , "/bar/"
+ , ":END:"
+ ] =?>
+ divWith (mempty, ["FOO", "drawer"], mempty) (para $ emph "bar")
+
+ , "Anchor reference" =:
+ T.unlines [ "<<link-here>> Target."
+ , ""
+ , "[[link-here][See here!]]"
+ ] =?>
+ (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
+ para (link "#link-here" "" ("See" <> space <> "here!")))
+
+ , "Search links are read as emph" =:
+ "[[Wally][Where's Wally?]]" =?>
+ para (emph $ "Where's" <> space <> "Wally?")
+
+ , "Link to nonexistent anchor" =:
+ T.unlines [ "<<link-here>> Target."
+ , ""
+ , "[[link$here][See here!]]"
+ ] =?>
+ (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
+ para (emph ("See" <> space <> "here!")))
+
+ , "Link abbreviation" =:
+ T.unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
+ , "[[wp:Org_mode][Wikipedia on Org-mode]]"
+ ] =?>
+ para (link "https://en.wikipedia.org/wiki/Org_mode" ""
+ ("Wikipedia" <> space <> "on" <> space <> "Org-mode"))
+
+ , "Link abbreviation, defined after first use" =:
+ T.unlines [ "[[zl:non-sense][Non-sense articles]]"
+ , "#+LINK: zl http://zeitlens.com/tags/%s.html"
+ ] =?>
+ para (link "http://zeitlens.com/tags/non-sense.html" ""
+ ("Non-sense" <> space <> "articles"))
+
+ , "Link abbreviation, URL encoded arguments" =:
+ T.unlines [ "#+link: expl http://example.com/%h/foo"
+ , "[[expl:Hello, World!][Moin!]]"
+ ] =?>
+ para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!")
+
+ , "Link abbreviation, append arguments" =:
+ T.unlines [ "#+link: expl http://example.com/"
+ , "[[expl:foo][bar]]"
+ ] =?>
+ para (link "http://example.com/foo" "" "bar")
+
+ , testGroup "emphasis config"
+ [ "Changing pre and post chars for emphasis" =:
+ T.unlines [ "#+pandoc-emphasis-pre: \"[)\""
+ , "#+pandoc-emphasis-post: \"]\\n\""
+ , "([/emph/])*foo*"
+ ] =?>
+ para ("([" <> emph "emph" <> "])" <> strong "foo")
+
+ , "setting an invalid value restores the default" =:
+ T.unlines [ "#+pandoc-emphasis-pre: \"[\""
+ , "#+pandoc-emphasis-post: \"]\""
+ , "#+pandoc-emphasis-pre:"
+ , "#+pandoc-emphasis-post:"
+ , "[/noemph/]"
+ ] =?>
+ para ("[/noemph/]")
+ ]
+ ]
diff --git a/test/Tests/Readers/Org/Shared.hs b/test/Tests/Readers/Org/Shared.hs
new file mode 100644
index 000000000..5e8f6dd54
--- /dev/null
+++ b/test/Tests/Readers/Org/Shared.hs
@@ -0,0 +1,29 @@
+module Tests.Readers.Org.Shared
+ ( (=:)
+ , org
+ , spcSep
+ , tagSpan
+ ) where
+
+import Data.List (intersperse)
+import Data.Text (Text)
+import Tests.Helpers (ToString, purely, test)
+import Test.Tasty (TestTree)
+import Text.Pandoc (Pandoc, ReaderOptions (readerExtensions),
+ def, getDefaultExtensions, readOrg)
+import Text.Pandoc.Builder (Inlines, smallcaps, space, spanWith, str)
+
+org :: Text -> Pandoc
+org = purely $ readOrg def{ readerExtensions = getDefaultExtensions "org" }
+
+infix 4 =:
+(=:) :: ToString c
+ => String -> (Text, c) -> TestTree
+(=:) = test org
+
+spcSep :: [Inlines] -> Inlines
+spcSep = mconcat . intersperse space
+
+-- | Create a span for the given tag.
+tagSpan :: String -> Inlines
+tagSpan t = spanWith ("", ["tag"], [("tag-name", t)]) . smallcaps $ str t
diff --git a/test/Tests/Readers/RST.hs b/test/Tests/Readers/RST.hs
new file mode 100644
index 000000000..3753fbf12
--- /dev/null
+++ b/test/Tests/Readers/RST.hs
@@ -0,0 +1,189 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module Tests.Readers.RST (tests) where
+
+import Data.Text (Text)
+import qualified Data.Text as T
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+rst :: Text -> Pandoc
+rst = purely $ readRST def{ readerStandalone = True }
+
+infix 4 =:
+(=:) :: ToString c
+ => String -> (Text, c) -> TestTree
+(=:) = test rst
+
+tests :: [TestTree]
+tests = [ "line block with blank line" =:
+ "| a\n|\n| b" =?> lineBlock [ "a", mempty, "\160b" ]
+ , testGroup "field list"
+ [ "general" =: T.unlines
+ [ "para"
+ , ""
+ , ":Hostname: media08"
+ , ":IP address: 10.0.0.19"
+ , ":Size: 3ru"
+ , ":Version: 1"
+ , ":Indentation: Since the field marker may be quite long, the second"
+ , " and subsequent lines of the field body do not have to line up"
+ , " with the first line, but they must be indented relative to the"
+ , " field name marker, and they must line up with each other."
+ , ":Parameter i: integer"
+ , ":Final: item"
+ , " on two lines" ]
+ =?>
+ doc (para "para" <>
+ definitionList [ (str "Hostname", [para "media08"])
+ , (text "IP address", [para "10.0.0.19"])
+ , (str "Size", [para "3ru"])
+ , (str "Version", [para "1"])
+ , (str "Indentation", [para "Since the field marker may be quite long, the second\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."])
+ , (text "Parameter i", [para "integer"])
+ , (str "Final", [para "item\non two lines"])
+ ])
+ , "metadata" =: T.unlines
+ [ "====="
+ , "Title"
+ , "====="
+ , "--------"
+ , "Subtitle"
+ , "--------"
+ , ""
+ , ":Version: 1"
+ ]
+ =?>
+ setMeta "version" (para "1") (setMeta "title" ("Title" :: Inlines)
+ $ setMeta "subtitle" ("Subtitle" :: Inlines)
+ $ doc mempty)
+ , "with inline markup" =: T.unlines
+ [ ":*Date*: today"
+ , ""
+ , ".."
+ , ""
+ , ":*one*: emphasis"
+ , ":two_: reference"
+ , ":`three`_: another one"
+ , ":``four``: literal"
+ , ""
+ , ".. _two: http://example.com"
+ , ".. _three: http://example.org"
+ ]
+ =?>
+ setMeta "date" (str "today") (doc
+ $ definitionList [ (emph "one", [para "emphasis"])
+ , (link "http://example.com" "" "two", [para "reference"])
+ , (link "http://example.org" "" "three", [para "another one"])
+ , (code "four", [para "literal"])
+ ])
+ ]
+ , "URLs with following punctuation" =:
+ ("http://google.com, http://yahoo.com; http://foo.bar.baz.\n" <>
+ "http://foo.bar/baz_(bam) (http://foo.bar)") =?>
+ para (link "http://google.com" "" "http://google.com" <> ", " <>
+ link "http://yahoo.com" "" "http://yahoo.com" <> "; " <>
+ link "http://foo.bar.baz" "" "http://foo.bar.baz" <> ". " <>
+ softbreak <>
+ link "http://foo.bar/baz_(bam)" "" "http://foo.bar/baz_(bam)"
+ <> " (" <> link "http://foo.bar" "" "http://foo.bar" <> ")")
+ , "Reference names with special characters" =:
+ ("A-1-B_2_C:3:D+4+E.5.F_\n\n" <>
+ ".. _A-1-B_2_C:3:D+4+E.5.F: https://example.com\n") =?>
+ para (link "https://example.com" "" "A-1-B_2_C:3:D+4+E.5.F")
+ , "Code directive with class and number-lines" =: T.unlines
+ [ ".. code::python"
+ , " :number-lines: 34"
+ , " :class: class1 class2 class3"
+ , ""
+ , " def func(x):"
+ , " return y"
+ ] =?>
+ doc (codeBlockWith
+ ( ""
+ , ["sourceCode", "python", "numberLines", "class1", "class2", "class3"]
+ , [ ("startFrom", "34") ]
+ )
+ "def func(x):\n return y")
+ , "Code directive with number-lines, no line specified" =: T.unlines
+ [ ".. code::python"
+ , " :number-lines: "
+ , ""
+ , " def func(x):"
+ , " return y"
+ ] =?>
+ doc (codeBlockWith
+ ( ""
+ , ["sourceCode", "python", "numberLines"]
+ , [ ("startFrom", "") ]
+ )
+ "def func(x):\n return y")
+ , testGroup "literal / line / code blocks"
+ [ "indented literal block" =: T.unlines
+ [ "::"
+ , ""
+ , " block quotes"
+ , ""
+ , " can go on for many lines"
+ , "but must stop here"]
+ =?>
+ doc (
+ codeBlock "block quotes\n\ncan go on for many lines" <>
+ para "but must stop here")
+ , "line block with 3 lines" =: "| a\n| b\n| c"
+ =?> lineBlock ["a", "b", "c"]
+ , "line blocks with blank lines" =: T.unlines
+ [ "|"
+ , ""
+ , "|"
+ , "| a"
+ , "| b"
+ , "|"
+ , ""
+ , "|"
+ ] =?>
+ lineBlock [""] <>
+ lineBlock ["", "a", "b", ""] <>
+ lineBlock [""]
+ , "quoted literal block using >" =: "::\n\n> quoted\n> block\n\nOrdinary paragraph"
+ =?> codeBlock "> quoted\n> block" <> para "Ordinary paragraph"
+ , "quoted literal block using | (not a line block)" =: "::\n\n| quoted\n| block\n\nOrdinary paragraph"
+ =?> codeBlock "| quoted\n| block" <> para "Ordinary paragraph"
+ , "class directive with single paragraph" =: ".. class:: special\n\nThis is a \"special\" paragraph."
+ =?> divWith ("", ["special"], []) (para "This is a \"special\" paragraph.")
+ , "class directive with two paragraphs" =: ".. class:: exceptional remarkable\n\n First paragraph.\n\n Second paragraph."
+ =?> divWith ("", ["exceptional", "remarkable"], []) (para "First paragraph." <> para "Second paragraph.")
+ , "class directive around literal block" =: ".. class:: classy\n\n::\n\n a\n b"
+ =?> divWith ("", ["classy"], []) (codeBlock "a\nb")]
+ , testGroup "interpreted text roles"
+ [ "literal role prefix" =: ":literal:`a`" =?> para (code "a")
+ , "literal role postfix" =: "`a`:literal:" =?> para (code "a")
+ , "literal text" =: "``text``" =?> para (code "text")
+ , "code role" =: ":code:`a`" =?> para (codeWith ("", ["sourceCode"], []) "a")
+ , "inherited code role" =: ".. role:: codeLike(code)\n\n:codeLike:`a`"
+ =?> para (codeWith ("", ["codeLike", "sourceCode"], []) "a")
+ , "custom code role with language field"
+ =: ".. role:: lhs(code)\n :language: haskell\n\n:lhs:`a`"
+ =?> para (codeWith ("", ["lhs", "haskell","sourceCode"], []) "a")
+ , "custom role with unspecified parent role"
+ =: ".. role:: classy\n\n:classy:`text`"
+ =?> para (spanWith ("", ["classy"], []) "text")
+ , "role with recursive inheritance"
+ =: ".. role:: haskell(code)\n.. role:: lhs(haskell)\n\n:lhs:`text`"
+ =?> para (codeWith ("", ["lhs", "haskell", "sourceCode"], []) "text")
+ , "unknown role" =: ":unknown:`text`" =?>
+ para (spanWith ("",[],[("role","unknown")]) (str "text"))
+ ]
+ , testGroup "footnotes"
+ [ "remove space before note" =: T.unlines
+ [ "foo [1]_"
+ , ""
+ , ".. [1]"
+ , " bar"
+ ] =?>
+ para ("foo" <> (note $ para "bar"))
+ ]
+ ]
diff --git a/test/Tests/Readers/Txt2Tags.hs b/test/Tests/Readers/Txt2Tags.hs
new file mode 100644
index 000000000..435d983a1
--- /dev/null
+++ b/test/Tests/Readers/Txt2Tags.hs
@@ -0,0 +1,437 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Txt2Tags (tests) where
+
+import Data.List (intersperse)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+import Text.Pandoc.Shared (underlineSpan)
+
+t2t :: Text -> Pandoc
+-- t2t = handleError . readTxt2Tags (T2TMeta "date" "mtime" "in" "out") def
+t2t = purely $ \s -> do
+ setInputFiles ["in"]
+ setOutputFile (Just "out")
+ readTxt2Tags def s
+
+infix 4 =:
+(=:) :: ToString c
+ => String -> (Text, c) -> TestTree
+(=:) = test t2t
+
+spcSep :: [Inlines] -> Inlines
+spcSep = mconcat . intersperse space
+
+simpleTable' :: Int
+ -> [Blocks]
+ -> [[Blocks]]
+ -> Blocks
+simpleTable' n = table "" (replicate n (AlignCenter, 0.0))
+
+tests :: [TestTree]
+tests =
+ [ testGroup "Inlines"
+ [ "Plain String" =:
+ "Hello, World" =?>
+ para (spcSep [ "Hello,", "World" ])
+
+ , "Emphasis" =:
+ "//Planet Punk//" =?>
+ para (emph . spcSep $ ["Planet", "Punk"])
+
+ , "Strong" =:
+ "**Cider**" =?>
+ para (strong "Cider")
+
+ , "Strong Emphasis" =:
+ "//**strength**//" =?>
+ para (emph . strong $ "strength")
+
+ , "Strikeout" =:
+ "--Kill Bill--" =?>
+ para (strikeout . spcSep $ [ "Kill", "Bill" ])
+
+ , "Verbatim" =:
+ "``Robot.rock()``" =?>
+ para (code "Robot.rock()")
+
+ , "Symbol" =:
+ "A * symbol" =?>
+ para (str "A" <> space <> str "*" <> space <> "symbol")
+
+ , "No empty markup" =:
+ "//// **** ____ ---- ```` \"\"\"\" ''''" =?>
+ para (spcSep [ "////", "****", "____", "----", "````", "\"\"\"\"", "''''" ])
+
+ , "Inline markup is greedy" =:
+ "***** ///// _____ ----- ````` \"\"\"\"\" '''''" =?>
+ para (spcSep [strong "*", emph "/", underlineSpan "_"
+ , strikeout "-", code "`", text "\""
+ , rawInline "html" "'"])
+ , "Markup must be greedy" =:
+ "********** ////////// __________ ---------- `````````` \"\"\"\"\"\"\"\"\"\" ''''''''''" =?>
+ para (spcSep [strong "******", emph "//////", underlineSpan "______"
+ , strikeout "------", code "``````", text "\"\"\"\"\"\""
+ , rawInline "html" "''''''"])
+ , "Inlines must be glued" =:
+ "** a** **a ** ** a **" =?>
+ para (text "** a** **a ** ** a **")
+
+ , "Macros: Date" =:
+ "%%date" =?>
+ para "1970-01-01"
+ , "Macros: Mod Time" =:
+ "%%mtime" =?>
+ para (str "")
+ , "Macros: Infile" =:
+ "%%infile" =?>
+ para "in"
+ , "Macros: Outfile" =:
+ "%%outfile" =?>
+ para "out"
+ , "Autolink" =:
+ "http://www.google.com" =?>
+ para (link "http://www.google.com" "" (str "http://www.google.com"))
+ , "JPEG Image" =:
+ "[image.jpg]" =?>
+ para (image "image.jpg" "" mempty)
+ , "PNG Image" =:
+ "[image.png]" =?>
+ para (image "image.png" "" mempty)
+
+ , "Link" =:
+ "[title http://google.com]" =?>
+ para (link "http://google.com" "" (str "title"))
+
+ , "Image link" =:
+ "[[image.jpg] abc]" =?>
+ para (link "abc" "" (image "image.jpg" "" mempty))
+ , "Invalid link: No trailing space" =:
+ "[title invalid ]" =?>
+ para (text "[title invalid ]")
+
+
+ ]
+
+ , testGroup "Basic Blocks"
+ ["Paragraph, lines grouped together" =:
+ "A paragraph\n A blank line ends the \n current paragraph\n"
+ =?> para "A paragraph\n A blank line ends the\n current paragraph"
+ , "Paragraph, ignore leading and trailing spaces" =:
+ " Leading and trailing spaces are ignored. \n" =?>
+ para "Leading and trailing spaces are ignored."
+ , "Comment line in paragraph" =:
+ "A comment line can be placed inside a paragraph.\n% this comment will be ignored \nIt will not affect it.\n"
+ =?> para "A comment line can be placed inside a paragraph.\nIt will not affect it."
+ , "Paragraph" =:
+ "Paragraph\n" =?>
+ para "Paragraph"
+
+ , "First Level Header" =:
+ "+ Headline +\n" =?>
+ header 1 "Headline"
+
+ , "Third Level Header" =:
+ "=== Third Level Headline ===\n" =?>
+ header 3 ("Third" <> space <>
+ "Level" <> space <>
+ "Headline")
+
+ , "Header with label" =:
+ "= header =[label]" =?>
+ headerWith ("label", [], []) 1 ("header")
+
+ , "Invalid header, mismatched delimiters" =:
+ "== header =" =?>
+ para (text "== header =")
+
+ , "Invalid header, spaces in label" =:
+ "== header ==[ haha ]" =?>
+ para (text "== header ==[ haha ]")
+
+ , "Invalid header, invalid label character" =:
+ "== header ==[lab/el]" =?>
+ para (text "== header ==[lab/el]")
+ , "Headers not preceded by a blank line" =:
+ T.unlines [ "++ eat dinner ++"
+ , "Spaghetti and meatballs tonight."
+ , "== walk dog =="
+ ] =?>
+ mconcat [ header 2 ("eat" <> space <> "dinner")
+ , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
+ , header 2 ("walk" <> space <> "dog")
+ ]
+
+ , "Paragraph starting with an equals" =:
+ "=five" =?>
+ para "=five"
+
+ , "Paragraph containing asterisk at beginning of line" =:
+ T.unlines [ "lucky"
+ , "*star"
+ ] =?>
+ para ("lucky" <> softbreak <> "*star")
+
+ , "Horizontal Rule" =:
+ T.unlines [ "before"
+ , T.replicate 20 "-"
+ , T.replicate 20 "="
+ , T.replicate 20 "_"
+ , "after"
+ ] =?>
+ mconcat [ para "before"
+ , horizontalRule
+ , horizontalRule
+ , horizontalRule
+ , para "after"
+ ]
+
+ , "Comment Block" =:
+ T.unlines [ "%%%"
+ , "stuff"
+ , "bla"
+ , "%%%"] =?>
+ (mempty::Blocks)
+
+
+ ]
+
+ , testGroup "Lists"
+ [ "Simple Bullet Lists" =:
+ ("- Item1\n" <>
+ "- Item2\n") =?>
+ bulletList [ plain "Item1"
+ , plain "Item2"
+ ]
+
+ , "Indented Bullet Lists" =:
+ (" - Item1\n" <>
+ " - Item2\n") =?>
+ bulletList [ plain "Item1"
+ , plain "Item2"
+ ]
+
+
+
+ , "Nested Bullet Lists" =:
+ ("- Discovery\n" <>
+ " + One More Time\n" <>
+ " + Harder, Better, Faster, Stronger\n" <>
+ "- Homework\n" <>
+ " + Around the World\n"<>
+ "- Human After All\n" <>
+ " + Technologic\n" <>
+ " + Robot Rock\n") =?>
+ bulletList [ mconcat
+ [ plain "Discovery"
+ , orderedList [ plain ("One" <> space <>
+ "More" <> space <>
+ "Time")
+ , plain ("Harder," <> space <>
+ "Better," <> space <>
+ "Faster," <> space <>
+ "Stronger")
+ ]
+ ]
+ , mconcat
+ [ plain "Homework"
+ , orderedList [ plain ("Around" <> space <>
+ "the" <> space <>
+ "World")
+ ]
+ ]
+ , mconcat
+ [ plain ("Human" <> space <> "After" <> space <> "All")
+ , orderedList [ plain "Technologic"
+ , plain ("Robot" <> space <> "Rock")
+ ]
+ ]
+ ]
+
+ , "Simple Ordered List" =:
+ ("+ Item1\n" <>
+ "+ Item2\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ plain "Item1"
+ , plain "Item2"
+ ]
+ in orderedListWith listStyle listStructure
+
+
+ , "Indented Ordered List" =:
+ (" + Item1\n" <>
+ " + Item2\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ plain "Item1"
+ , plain "Item2"
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Nested Ordered Lists" =:
+ ("+ One\n" <>
+ " + One-One\n" <>
+ " + One-Two\n" <>
+ "+ Two\n" <>
+ " + Two-One\n"<>
+ " + Two-Two\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ mconcat
+ [ plain "One"
+ , orderedList [ plain "One-One"
+ , plain "One-Two"
+ ]
+ ]
+ , mconcat
+ [ plain "Two"
+ , orderedList [ plain "Two-One"
+ , plain "Two-Two"
+ ]
+ ]
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Ordered List in Bullet List" =:
+ ("- Emacs\n" <>
+ " + Org\n") =?>
+ bulletList [ (plain "Emacs") <>
+ (orderedList [ plain "Org"])
+ ]
+
+ , "Bullet List in Ordered List" =:
+ ("+ GNU\n" <>
+ " - Freedom\n") =?>
+ orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ]
+
+ , "Definition List" =:
+ T.unlines [ ": PLL"
+ , " phase-locked loop"
+ , ": TTL"
+ , " transistor-transistor logic"
+ , ": PSK"
+ , " a digital"
+ ] =?>
+ definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
+ , ("TTL", [ plain $ "transistor-transistor" <> space <> "logic" ])
+ , ("PSK", [ plain $ "a" <> space <> "digital" ])
+ ]
+
+
+ , "Loose bullet list" =:
+ T.unlines [ "- apple"
+ , ""
+ , "- orange"
+ , ""
+ , "- peach"
+ ] =?>
+ bulletList [ para "apple"
+ , para "orange"
+ , para "peach"
+ ]
+ ]
+
+ , testGroup "Tables"
+ [ "Single cell table" =:
+ "| Test " =?>
+ simpleTable' 1 mempty [[plain "Test"]]
+
+ , "Multi cell table" =:
+ "| One | Two |" =?>
+ simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
+
+ , "Multi line table" =:
+ T.unlines [ "| One |"
+ , "| Two |"
+ , "| Three |"
+ ] =?>
+ simpleTable' 1 mempty
+ [ [ plain "One" ]
+ , [ plain "Two" ]
+ , [ plain "Three" ]
+ ]
+
+ , "Empty table" =:
+ "| |" =?>
+ simpleTable' 1 mempty [[mempty]]
+
+ , "Glider Table" =:
+ T.unlines [ "| 1 | 0 | 0 |"
+ , "| 0 | 1 | 1 |"
+ , "| 1 | 1 | 0 |"
+ ] =?>
+ simpleTable' 3 mempty
+ [ [ plain "1", plain "0", plain "0" ]
+ , [ plain "0", plain "1", plain "1" ]
+ , [ plain "1", plain "1", plain "0" ]
+ ]
+
+
+ , "Table with Header" =:
+ T.unlines [ "|| Species | Status |"
+ , "| cervisiae | domesticated |"
+ , "| paradoxus | wild |"
+ ] =?>
+ simpleTable [ plain "Species", plain "Status" ]
+ [ [ plain "cervisiae", plain "domesticated" ]
+ , [ plain "paradoxus", plain "wild" ]
+ ]
+
+ , "Table alignment determined by spacing" =:
+ T.unlines [ "| Numbers | Text | More |"
+ , "| 1 | One | foo |"
+ , "| 2 | Two | bar |"
+ ] =?>
+ table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
+ []
+ [ [ plain "Numbers", plain "Text", plain "More" ]
+ , [ plain "1" , plain "One" , plain "foo" ]
+ , [ plain "2" , plain "Two" , plain "bar" ]
+ ]
+
+ , "Pipe within text doesn't start a table" =:
+ "Ceci n'est pas une | pipe " =?>
+ para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ])
+
+
+ , "Table with differing row lengths" =:
+ T.unlines [ "|| Numbers | Text "
+ , "| 1 | One | foo |"
+ , "| 2 "
+ ] =?>
+ table "" (zip [AlignCenter, AlignLeft, AlignLeft] [0, 0, 0])
+ [ plain "Numbers", plain "Text" , plain mempty ]
+ [ [ plain "1" , plain "One" , plain "foo" ]
+ , [ plain "2" , plain mempty , plain mempty ]
+ ]
+
+ ]
+
+ , testGroup "Blocks and fragments"
+ [ "Source block" =:
+ T.unlines [ "```"
+ , "main = putStrLn greeting"
+ , " where greeting = \"moin\""
+ , "```" ] =?>
+ let code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"moin\"\n"
+ in codeBlock code'
+
+ , "tagged block" =:
+ T.unlines [ "'''"
+ , "<aside>HTML5 is pretty nice.</aside>"
+ , "'''"
+ ] =?>
+ rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
+
+ , "Quote block" =:
+ T.unlines ["\t//Niemand// hat die Absicht, eine Mauer zu errichten!"
+ ] =?>
+ blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
+ , "eine", "Mauer", "zu", "errichten!"
+ ]))
+
+ ]
+ ]
diff --git a/test/Tests/Shared.hs b/test/Tests/Shared.hs
new file mode 100644
index 000000000..cc448419c
--- /dev/null
+++ b/test/Tests/Shared.hs
@@ -0,0 +1,39 @@
+module Tests.Shared (tests) where
+
+import System.FilePath.Posix (joinPath)
+import Test.Tasty
+import Test.Tasty.HUnit (assertBool, testCase, (@?=))
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+import Text.Pandoc.Shared
+
+tests :: [TestTree]
+tests = [ testGroup "compactifyDL"
+ [ testCase "compactifyDL with empty def" $
+ assertBool "compactifyDL"
+ (let x = [(str "word", [para (str "def"), mempty])]
+ in compactifyDL x == x)
+ ]
+ , testGroup "collapseFilePath" testCollapse
+ ]
+
+testCollapse :: [TestTree]
+testCollapse = map (testCase "collapse")
+ [ collapseFilePath (joinPath [ ""]) @?= (joinPath [ ""])
+ , collapseFilePath (joinPath [ ".","foo"]) @?= (joinPath [ "foo"])
+ , collapseFilePath (joinPath [ ".",".","..","foo"]) @?= (joinPath [ joinPath ["..", "foo"]])
+ , collapseFilePath (joinPath [ "..","foo"]) @?= (joinPath [ "..","foo"])
+ , collapseFilePath (joinPath [ "","bar","..","baz"]) @?= (joinPath [ "","baz"])
+ , collapseFilePath (joinPath [ "","..","baz"]) @?= (joinPath [ "","..","baz"])
+ , collapseFilePath (joinPath [ ".","foo","..",".","bar","..",".",".","baz"]) @?= (joinPath [ "baz"])
+ , collapseFilePath (joinPath [ ".",""]) @?= (joinPath [ ""])
+ , collapseFilePath (joinPath [ ".",".",""]) @?= (joinPath [ ""])
+ , collapseFilePath (joinPath [ "..",""]) @?= (joinPath [ ".."])
+ , collapseFilePath (joinPath [ "..",".",""]) @?= (joinPath [ ".."])
+ , collapseFilePath (joinPath [ ".","..",""]) @?= (joinPath [ ".."])
+ , collapseFilePath (joinPath [ "..","..",""]) @?= (joinPath [ "..",".."])
+ , collapseFilePath (joinPath [ "parent","foo","baz","..","bar"]) @?= (joinPath [ "parent","foo","bar"])
+ , collapseFilePath (joinPath [ "parent","foo","baz","..","..","bar"]) @?= (joinPath [ "parent","bar"])
+ , collapseFilePath (joinPath [ "parent","foo",".."]) @?= (joinPath [ "parent"])
+ , collapseFilePath (joinPath [ "","parent","foo","..","..","bar"]) @?= (joinPath [ "","bar"])
+ , collapseFilePath (joinPath [ "",".","parent","foo"]) @?= (joinPath [ "","parent","foo"])]
diff --git a/test/Tests/Writers/AsciiDoc.hs b/test/Tests/Writers/AsciiDoc.hs
new file mode 100644
index 000000000..6b97c0761
--- /dev/null
+++ b/test/Tests/Writers/AsciiDoc.hs
@@ -0,0 +1,56 @@
+module Tests.Writers.AsciiDoc (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+asciidoc :: (ToPandoc a) => a -> String
+asciidoc = unpack . purely (writeAsciiDoc def{ writerWrapText = WrapNone }) . toPandoc
+
+tests :: [TestTree]
+tests = [ testGroup "emphasis"
+ [ test asciidoc "emph word before" $
+ para (text "foo" <> emph (text "bar")) =?>
+ "foo__bar__"
+ , test asciidoc "emph word after" $
+ para (emph (text "foo") <> text "bar") =?>
+ "__foo__bar"
+ , test asciidoc "emph quoted" $
+ para (doubleQuoted (emph (text "foo"))) =?>
+ "``__foo__''"
+ , test asciidoc "strong word before" $
+ para (text "foo" <> strong (text "bar")) =?>
+ "foo**bar**"
+ , test asciidoc "strong word after" $
+ para (strong (text "foo") <> text "bar") =?>
+ "**foo**bar"
+ , test asciidoc "strong quoted" $
+ para (singleQuoted (strong (text "foo"))) =?>
+ "`**foo**'"
+ ]
+ , testGroup "tables"
+ [ test asciidoc "empty cells" $
+ simpleTable [] [[mempty],[mempty]] =?> unlines
+ [ "[cols=\"\",]"
+ , "|===="
+ , "|"
+ , "|"
+ , "|===="
+ ]
+ , test asciidoc "multiblock cells" $
+ simpleTable [] [[para (text "Para 1") <> para (text "Para 2")]]
+ =?> unlines
+ [ "[cols=\"\",]"
+ , "|====="
+ , "a|"
+ , "Para 1"
+ , ""
+ , "Para 2"
+ , ""
+ , "|====="
+ ]
+ ]
+ ]
diff --git a/test/Tests/Writers/ConTeXt.hs b/test/Tests/Writers/ConTeXt.hs
new file mode 100644
index 000000000..812aab4a6
--- /dev/null
+++ b/test/Tests/Writers/ConTeXt.hs
@@ -0,0 +1,149 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.ConTeXt (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Test.Tasty.QuickCheck
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+context :: (ToPandoc a) => a -> String
+context = unpack . purely (writeConTeXt def) . toPandoc
+
+context' :: (ToPandoc a) => a -> String
+context' = unpack . purely (writeConTeXt def{ writerWrapText = WrapNone }) . toPandoc
+
+contextNtb :: (ToPandoc a) => a -> String
+contextNtb = unpack . purely (writeConTeXt def{ writerExtensions = enableExtension Ext_ntb pandocExtensions }) . toPandoc
+
+contextDiv :: (ToPandoc a) => a -> String
+contextDiv = unpack . purely (writeConTeXt def{ writerSectionDivs = True }) . toPandoc
+
+{-
+ "my test" =: X =?> Y
+
+is shorthand for
+
+ test context "my test" $ X =?> Y
+
+which is in turn shorthand for
+
+ test context "my test" (X,Y)
+-}
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test context
+
+tests :: [TestTree]
+tests = [ testGroup "inline code"
+ [ "with '}'" =: code "}" =?> "\\mono{\\}}"
+ , "without '}'" =: code "]" =?> "\\type{]}"
+ , testProperty "code property" $ \s -> null s ||
+ if '{' `elem` s || '}' `elem` s
+ then context' (code s) == "\\mono{" ++
+ context' (str s) ++ "}"
+ else context' (code s) == "\\type{" ++ s ++ "}"
+ ]
+ , testGroup "headers"
+ [ "level 1" =:
+ headerWith ("my-header",[],[]) 1 "My header" =?> "\\section[title={My header},reference={my-header}]"
+ , test contextDiv "section-divs" $
+ ( headerWith ("header1", [], []) 1 (text "Header1")
+ <> headerWith ("header2", [], []) 2 (text "Header2")
+ <> headerWith ("header3", [], []) 3 (text "Header3")
+ <> headerWith ("header4", [], []) 4 (text "Header4")
+ <> headerWith ("header5", [], []) 5 (text "Header5")
+ <> headerWith ("header6", [], []) 6 (text "Header6"))
+ =?>
+ unlines [ "\\startsection[title={Header1},reference={header1}]\n"
+ , "\\startsubsection[title={Header2},reference={header2}]\n"
+ , "\\startsubsubsection[title={Header3},reference={header3}]\n"
+ , "\\startsubsubsubsection[title={Header4},reference={header4}]\n"
+ , "\\startsubsubsubsubsection[title={Header5},reference={header5}]\n"
+ , "\\startsubsubsubsubsubsection[title={Header6},reference={header6}]\n"
+ , "\\stopsubsubsubsubsubsection\n"
+ , "\\stopsubsubsubsubsection\n"
+ , "\\stopsubsubsubsection\n"
+ , "\\stopsubsubsection\n"
+ , "\\stopsubsection\n"
+ , "\\stopsection" ]
+ ]
+ , testGroup "bullet lists"
+ [ "nested" =:
+ bulletList [
+ plain (text "top")
+ <> bulletList [
+ plain (text "next")
+ <> bulletList [plain (text "bot")]
+ ]
+ ] =?> unlines
+ [ "\\startitemize[packed]"
+ , "\\item"
+ , " top"
+ , " \\startitemize[packed]"
+ , " \\item"
+ , " next"
+ , " \\startitemize[packed]"
+ , " \\item"
+ , " bot"
+ , " \\stopitemize"
+ , " \\stopitemize"
+ , "\\stopitemize" ]
+ ]
+ , testGroup "natural tables"
+ [ test contextNtb "table with header and caption" $
+ let caption = text "Table 1"
+ aligns = [(AlignRight, 0.0), (AlignLeft, 0.0), (AlignCenter, 0.0), (AlignDefault, 0.0)]
+ headers = [plain $ text "Right",
+ plain $ text "Left",
+ plain $ text "Center",
+ plain $ text "Default"]
+ rows = [[plain $ text "1.1",
+ plain $ text "1.2",
+ plain $ text "1.3",
+ plain $ text "1.4"]
+ ,[plain $ text "2.1",
+ plain $ text "2.2",
+ plain $ text "2.3",
+ plain $ text "2.4"]
+ ,[plain $ text "3.1",
+ plain $ text "3.2",
+ plain $ text "3.3",
+ plain $ text "3.4"]]
+ in table caption aligns headers rows
+ =?> unlines [ "\\startplacetable[title={Table 1}]"
+ , "\\startTABLE"
+ , "\\startTABLEhead"
+ , "\\NC[align=left] Right"
+ , "\\NC[align=right] Left"
+ , "\\NC[align=middle] Center"
+ , "\\NC Default"
+ , "\\NC\\NR"
+ , "\\stopTABLEhead"
+ , "\\startTABLEbody"
+ , "\\NC[align=left] 1.1"
+ , "\\NC[align=right] 1.2"
+ , "\\NC[align=middle] 1.3"
+ , "\\NC 1.4"
+ , "\\NC\\NR"
+ , "\\NC[align=left] 2.1"
+ , "\\NC[align=right] 2.2"
+ , "\\NC[align=middle] 2.3"
+ , "\\NC 2.4"
+ , "\\NC\\NR"
+ , "\\stopTABLEbody"
+ , "\\startTABLEfoot"
+ , "\\NC[align=left] 3.1"
+ , "\\NC[align=right] 3.2"
+ , "\\NC[align=middle] 3.3"
+ , "\\NC 3.4"
+ , "\\NC\\NR"
+ , "\\stopTABLEfoot"
+ , "\\stopTABLE"
+ , "\\stopplacetable" ]
+ ]
+ ]
diff --git a/test/Tests/Writers/Docbook.hs b/test/Tests/Writers/Docbook.hs
new file mode 100644
index 000000000..89ea76586
--- /dev/null
+++ b/test/Tests/Writers/Docbook.hs
@@ -0,0 +1,303 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.Docbook (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+docbook :: (ToPandoc a) => a -> String
+docbook = docbookWithOpts def{ writerWrapText = WrapNone }
+
+docbookWithOpts :: ToPandoc a => WriterOptions -> a -> String
+docbookWithOpts opts = unpack . purely (writeDocbook4 opts) . toPandoc
+
+{-
+ "my test" =: X =?> Y
+
+is shorthand for
+
+ test docbook "my test" $ X =?> Y
+
+which is in turn shorthand for
+
+ test docbook "my test" (X,Y)
+-}
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test docbook
+
+lineblock :: Blocks
+lineblock = para ("some text" <> linebreak <>
+ "and more lines" <> linebreak <>
+ "and again")
+lineblock_out :: [String]
+lineblock_out = [ "<literallayout>some text"
+ , "and more lines"
+ , "and again</literallayout>"
+ ]
+
+tests :: [TestTree]
+tests = [ testGroup "line blocks"
+ [ "none" =: para "This is a test"
+ =?> unlines
+ [ "<para>"
+ , " This is a test"
+ , "</para>"
+ ]
+ , "basic" =: lineblock
+ =?> unlines lineblock_out
+ , "blockquote" =: blockQuote lineblock
+ =?> unlines
+ ( [ "<blockquote>" ] ++
+ lineblock_out ++
+ [ "</blockquote>" ]
+ )
+ , "footnote" =: para ("This is a test" <>
+ note lineblock <>
+ " of footnotes")
+ =?> unlines
+ ( [ "<para>"
+ , " This is a test<footnote>" ] ++
+ lineblock_out ++
+ [ " </footnote> of footnotes"
+ , "</para>" ]
+ )
+ ]
+ , testGroup "compact lists"
+ [ testGroup "bullet"
+ [ "compact" =: bulletList [plain "a", plain "b", plain "c"]
+ =?> unlines
+ [ "<itemizedlist spacing=\"compact\">"
+ , " <listitem>"
+ , " <para>"
+ , " a"
+ , " </para>"
+ , " </listitem>"
+ , " <listitem>"
+ , " <para>"
+ , " b"
+ , " </para>"
+ , " </listitem>"
+ , " <listitem>"
+ , " <para>"
+ , " c"
+ , " </para>"
+ , " </listitem>"
+ , "</itemizedlist>"
+ ]
+ , "loose" =: bulletList [para "a", para "b", para "c"]
+ =?> unlines
+ [ "<itemizedlist>"
+ , " <listitem>"
+ , " <para>"
+ , " a"
+ , " </para>"
+ , " </listitem>"
+ , " <listitem>"
+ , " <para>"
+ , " b"
+ , " </para>"
+ , " </listitem>"
+ , " <listitem>"
+ , " <para>"
+ , " c"
+ , " </para>"
+ , " </listitem>"
+ , "</itemizedlist>"
+ ]
+ ]
+ , testGroup "ordered"
+ [ "compact" =: orderedList [plain "a", plain "b", plain "c"]
+ =?> unlines
+ [ "<orderedlist spacing=\"compact\">"
+ , " <listitem>"
+ , " <para>"
+ , " a"
+ , " </para>"
+ , " </listitem>"
+ , " <listitem>"
+ , " <para>"
+ , " b"
+ , " </para>"
+ , " </listitem>"
+ , " <listitem>"
+ , " <para>"
+ , " c"
+ , " </para>"
+ , " </listitem>"
+ , "</orderedlist>"
+ ]
+ , "loose" =: orderedList [para "a", para "b", para "c"]
+ =?> unlines
+ [ "<orderedlist>"
+ , " <listitem>"
+ , " <para>"
+ , " a"
+ , " </para>"
+ , " </listitem>"
+ , " <listitem>"
+ , " <para>"
+ , " b"
+ , " </para>"
+ , " </listitem>"
+ , " <listitem>"
+ , " <para>"
+ , " c"
+ , " </para>"
+ , " </listitem>"
+ , "</orderedlist>"
+ ]
+ ]
+ , testGroup "definition"
+ [ "compact" =: definitionList [ ("an", [plain "apple" ])
+ , ("a", [plain "banana"])
+ , ("an", [plain "orange"])]
+ =?> unlines
+ [ "<variablelist spacing=\"compact\">"
+ , " <varlistentry>"
+ , " <term>"
+ , " an"
+ , " </term>"
+ , " <listitem>"
+ , " <para>"
+ , " apple"
+ , " </para>"
+ , " </listitem>"
+ , " </varlistentry>"
+ , " <varlistentry>"
+ , " <term>"
+ , " a"
+ , " </term>"
+ , " <listitem>"
+ , " <para>"
+ , " banana"
+ , " </para>"
+ , " </listitem>"
+ , " </varlistentry>"
+ , " <varlistentry>"
+ , " <term>"
+ , " an"
+ , " </term>"
+ , " <listitem>"
+ , " <para>"
+ , " orange"
+ , " </para>"
+ , " </listitem>"
+ , " </varlistentry>"
+ , "</variablelist>"
+ ]
+ , "loose" =: definitionList [ ("an", [para "apple" ])
+ , ("a", [para "banana"])
+ , ("an", [para "orange"])]
+ =?> unlines
+ [ "<variablelist>"
+ , " <varlistentry>"
+ , " <term>"
+ , " an"
+ , " </term>"
+ , " <listitem>"
+ , " <para>"
+ , " apple"
+ , " </para>"
+ , " </listitem>"
+ , " </varlistentry>"
+ , " <varlistentry>"
+ , " <term>"
+ , " a"
+ , " </term>"
+ , " <listitem>"
+ , " <para>"
+ , " banana"
+ , " </para>"
+ , " </listitem>"
+ , " </varlistentry>"
+ , " <varlistentry>"
+ , " <term>"
+ , " an"
+ , " </term>"
+ , " <listitem>"
+ , " <para>"
+ , " orange"
+ , " </para>"
+ , " </listitem>"
+ , " </varlistentry>"
+ , "</variablelist>"
+ ]
+ ]
+ ]
+ , testGroup "writer options"
+ [ testGroup "top-level division" $
+ let
+ headers = header 1 (text "header1")
+ <> header 2 (text "header2")
+ <> header 3 (text "header3")
+
+ docbookTopLevelDiv :: (ToPandoc a)
+ => TopLevelDivision -> a -> String
+ docbookTopLevelDiv division =
+ docbookWithOpts def{ writerTopLevelDivision = division }
+ in
+ [ test (docbookTopLevelDiv TopLevelSection) "sections as top-level" $
+ headers =?>
+ unlines [ "<sect1>"
+ , " <title>header1</title>"
+ , " <sect2>"
+ , " <title>header2</title>"
+ , " <sect3>"
+ , " <title>header3</title>"
+ , " <para>"
+ , " </para>"
+ , " </sect3>"
+ , " </sect2>"
+ , "</sect1>"
+ ]
+ , test (docbookTopLevelDiv TopLevelChapter) "chapters as top-level" $
+ headers =?>
+ unlines [ "<chapter>"
+ , " <title>header1</title>"
+ , " <sect1>"
+ , " <title>header2</title>"
+ , " <sect2>"
+ , " <title>header3</title>"
+ , " <para>"
+ , " </para>"
+ , " </sect2>"
+ , " </sect1>"
+ , "</chapter>"
+ ]
+ , test (docbookTopLevelDiv TopLevelPart) "parts as top-level" $
+ headers =?>
+ unlines [ "<part>"
+ , " <title>header1</title>"
+ , " <chapter>"
+ , " <title>header2</title>"
+ , " <sect1>"
+ , " <title>header3</title>"
+ , " <para>"
+ , " </para>"
+ , " </sect1>"
+ , " </chapter>"
+ , "</part>"
+ ]
+ , test (docbookTopLevelDiv TopLevelDefault) "default top-level" $
+ headers =?>
+ unlines [ "<sect1>"
+ , " <title>header1</title>"
+ , " <sect2>"
+ , " <title>header2</title>"
+ , " <sect3>"
+ , " <title>header3</title>"
+ , " <para>"
+ , " </para>"
+ , " </sect3>"
+ , " </sect2>"
+ , "</sect1>"
+ ]
+ ]
+ ]
+ ]
diff --git a/test/Tests/Writers/Docx.hs b/test/Tests/Writers/Docx.hs
new file mode 100644
index 000000000..3ded0aa38
--- /dev/null
+++ b/test/Tests/Writers/Docx.hs
@@ -0,0 +1,157 @@
+module Tests.Writers.Docx (tests) where
+
+import Text.Pandoc
+import Test.Tasty
+import Tests.Writers.OOXML
+import Test.Tasty.HUnit
+import Data.List (isPrefixOf)
+
+-- we add an extra check to make sure that we're not writing in the
+-- toplevel docx directory. We don't want to accidentally overwrite an
+-- Word-generated docx file used to test the reader.
+docxTest :: String -> WriterOptions -> FilePath -> FilePath -> TestTree
+docxTest testName opts nativeFP goldenFP =
+ if "docx/golden/" `isPrefixOf` goldenFP
+ then ooxmlTest writeDocx testName opts nativeFP goldenFP
+ else testCase testName $
+ assertFailure $
+ goldenFP ++ " is not in `test/docx/golden`"
+
+tests :: [TestTree]
+tests = [ testGroup "inlines"
+ [ docxTest
+ "font formatting"
+ def
+ "docx/inline_formatting.native"
+ "docx/golden/inline_formatting.docx"
+ , docxTest
+ "hyperlinks"
+ def
+ "docx/links.native"
+ "docx/golden/links.docx"
+ , docxTest
+ "inline image"
+ def
+ "docx/image_writer_test.native"
+ "docx/golden/image.docx"
+ , docxTest
+ "inline images"
+ def
+ "docx/inline_images_writer_test.native"
+ "docx/golden/inline_images.docx"
+ , docxTest
+ "handling unicode input"
+ def
+ "docx/unicode.native"
+ "docx/golden/unicode.docx"
+ , docxTest
+ "inline code"
+ def
+ "docx/inline_code.native"
+ "docx/golden/inline_code.docx"
+ , docxTest
+ "inline code in subscript and superscript"
+ def
+ "docx/verbatim_subsuper.native"
+ "docx/golden/verbatim_subsuper.docx"
+ ]
+ , testGroup "blocks"
+ [ docxTest
+ "headers"
+ def
+ "docx/headers.native"
+ "docx/golden/headers.docx"
+ , docxTest
+ "nested anchor spans in header"
+ def
+ "docx/nested_anchors_in_header.native"
+ "docx/golden/nested_anchors_in_header.docx"
+ , docxTest
+ "lists"
+ def
+ "docx/lists.native"
+ "docx/golden/lists.docx"
+ , docxTest
+ "lists continuing after interruption"
+ def
+ "docx/lists_continuing.native"
+ "docx/golden/lists_continuing.docx"
+ , docxTest
+ "lists restarting after interruption"
+ def
+ "docx/lists_restarting.native"
+ "docx/golden/lists_restarting.docx"
+ , docxTest
+ "definition lists"
+ def
+ "docx/definition_list.native"
+ "docx/golden/definition_list.docx"
+ , docxTest
+ "footnotes and endnotes"
+ def
+ "docx/notes.native"
+ "docx/golden/notes.docx"
+ , docxTest
+ "links in footnotes and endnotes"
+ def
+ "docx/link_in_notes.native"
+ "docx/golden/link_in_notes.docx"
+ , docxTest
+ "blockquotes"
+ def
+ "docx/block_quotes_parse_indent.native"
+ "docx/golden/block_quotes.docx"
+ , docxTest
+ "tables"
+ def
+ "docx/tables.native"
+ "docx/golden/tables.docx"
+ , docxTest
+ "tables with lists in cells"
+ def
+ "docx/table_with_list_cell.native"
+ "docx/golden/table_with_list_cell.docx"
+ , docxTest
+ "tables with one row"
+ def
+ "docx/table_one_row.native"
+ "docx/golden/table_one_row.docx"
+ , docxTest
+ "code block"
+ def
+ "docx/codeblock.native"
+ "docx/golden/codeblock.docx"
+ ]
+ , testGroup "track changes"
+ [ docxTest
+ "insertion"
+ def
+ "docx/track_changes_insertion_all.native"
+ "docx/golden/track_changes_insertion.docx"
+ , docxTest
+ "deletion"
+ def
+ "docx/track_changes_deletion_all.native"
+ "docx/golden/track_changes_deletion.docx"
+ , docxTest
+ "move text"
+ def
+ "docx/track_changes_move_all.native"
+ "docx/golden/track_changes_move.docx"
+ , docxTest
+ "comments"
+ def
+ "docx/comments.native"
+ "docx/golden/comments.docx"
+ ]
+ , testGroup "custom styles"
+ [ docxTest "custom styles without reference.docx"
+ def
+ "docx/custom_style.native"
+ "docx/golden/custom_style_no_reference.docx"
+ , docxTest "custom styles with reference.docx"
+ def{writerReferenceDoc = Just "docx/custom-style-reference.docx"}
+ "docx/custom_style.native"
+ "docx/golden/custom_style_reference.docx"
+ ]
+ ]
diff --git a/test/Tests/Writers/FB2.hs b/test/Tests/Writers/FB2.hs
new file mode 100644
index 000000000..6663c42f8
--- /dev/null
+++ b/test/Tests/Writers/FB2.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.FB2 (tests) where
+
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+fb2 :: String -> String
+fb2 x = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ++
+ "<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>"
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test (purely (writeFB2 def) . toPandoc)
+
+tests :: [TestTree]
+tests = [ testGroup "block elements"
+ ["para" =: para "Lorem ipsum cetera."
+ =?> fb2 "<p>Lorem ipsum cetera.</p>"
+ ]
+ , testGroup "inlines"
+ [
+ "Emphasis" =: emph "emphasized"
+ =?> fb2 "<emphasis>emphasized</emphasis>"
+ ]
+ , "bullet list" =: bulletList [ plain $ text "first"
+ , plain $ text "second"
+ , plain $ text "third"
+ ]
+ =?> fb2 "<p>\x2022 first</p><p>\x2022 second</p><p>\x2022 third</p>"
+ ]
diff --git a/test/Tests/Writers/HTML.hs b/test/Tests/Writers/HTML.hs
new file mode 100644
index 000000000..23ff718d3
--- /dev/null
+++ b/test/Tests/Writers/HTML.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.HTML (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+html :: (ToPandoc a) => a -> String
+html = unpack . purely (writeHtml4String def{ writerWrapText = WrapNone }) . toPandoc
+
+{-
+ "my test" =: X =?> Y
+
+is shorthand for
+
+ test html "my test" $ X =?> Y
+
+which is in turn shorthand for
+
+ test html "my test" (X,Y)
+-}
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test html
+
+tests :: [TestTree]
+tests = [ testGroup "inline code"
+ [ "basic" =: code "@&" =?> "<code>@&amp;</code>"
+ , "haskell" =: codeWith ("",["haskell"],[]) ">>="
+ =?> "<code class=\"sourceCode haskell\"><span class=\"fu\">&gt;&gt;=</span></code>"
+ , "nolanguage" =: codeWith ("",["nolanguage"],[]) ">>="
+ =?> "<code class=\"nolanguage\">&gt;&gt;=</code>"
+ ]
+ , testGroup "images"
+ [ "alt with formatting" =:
+ image "/url" "title" ("my " <> emph "image")
+ =?> "<img src=\"/url\" title=\"title\" alt=\"my image\" />"
+ ]
+ ]
diff --git a/test/Tests/Writers/JATS.hs b/test/Tests/Writers/JATS.hs
new file mode 100644
index 000000000..572b16451
--- /dev/null
+++ b/test/Tests/Writers/JATS.hs
@@ -0,0 +1,122 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.JATS (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+jats :: (ToPandoc a) => a -> String
+jats = unpack . purely (writeJATS def{ writerWrapText = WrapNone }) . toPandoc
+
+{-
+ "my test" =: X =?> Y
+
+is shorthand for
+
+ test jats "my test" $ X =?> Y
+
+which is in turn shorthand for
+
+ test jats "my test" (X,Y)
+-}
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test jats
+
+tests :: [TestTree]
+tests = [ testGroup "inline code"
+ [ "basic" =: code "@&" =?> "<p>\n <monospace>@&amp;</monospace>\n</p>"
+ , "lang" =: codeWith ("", ["c"], []) "@&" =?> "<p>\n <code language=\"c\">@&amp;</code>\n</p>"
+ ]
+ , testGroup "block code"
+ [ "basic" =: codeBlock "@&" =?> "<preformat>@&amp;</preformat>"
+ , "lang" =: codeBlockWith ("", ["c"], []) "@&" =?> "<code language=\"c\">@&amp;</code>"
+ ]
+ , testGroup "images"
+ [ "basic" =:
+ image "/url" "title" mempty
+ =?> "<graphic mimetype=\"image\" mime-subtype=\"\" xlink:href=\"/url\" xlink:title=\"title\" />"
+ ]
+ , testGroup "inlines"
+ [ "Emphasis" =: emph "emphasized"
+ =?> "<p>\n <italic>emphasized</italic>\n</p>"
+ ]
+ , "bullet list" =: bulletList [ plain $ text "first"
+ , plain $ text "second"
+ , plain $ text "third"
+ ]
+ =?> "<list list-type=\"bullet\">\n\
+ \ <list-item>\n\
+ \ <p>\n\
+ \ first\n\
+ \ </p>\n\
+ \ </list-item>\n\
+ \ <list-item>\n\
+ \ <p>\n\
+ \ second\n\
+ \ </p>\n\
+ \ </list-item>\n\
+ \ <list-item>\n\
+ \ <p>\n\
+ \ third\n\
+ \ </p>\n\
+ \ </list-item>\n\
+ \</list>"
+ , testGroup "definition lists"
+ [ "with internal link" =: definitionList [(link "#go" "" (str "testing"),
+ [plain (text "hi there")])] =?>
+ "<def-list>\n\
+ \ <def-item>\n\
+ \ <term>\n\
+ \ <xref alt=\"testing\" rid=\"go\">testing</xref>\n\
+ \ </term>\n\
+ \ <def>\n\
+ \ <p>\n\
+ \ hi there\n\
+ \ </p>\n\
+ \ </def>\n\
+ \ </def-item>\n\
+ \</def-list>"
+ ]
+ , testGroup "math"
+ [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
+ "<p>\n\
+ \ <inline-formula><alternatives>\n\
+ \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
+ \ <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\
+ \</p>"
+ ]
+ , testGroup "headers"
+ [ "unnumbered header" =:
+ headerWith ("foo",["unnumbered"],[]) 1
+ (text "Header 1" <> note (plain $ text "note")) =?>
+ "<sec id=\"foo\">\n\
+ \ <title>Header 1<fn>\n\
+ \ <p>\n\
+ \ note\n\
+ \ </p>\n\
+ \ </fn></title>\n\
+ \</sec>"
+ , "unnumbered sub header" =:
+ headerWith ("foo",["unnumbered"],[]) 1
+ (text "Header")
+ <> headerWith ("foo",["unnumbered"],[]) 2
+ (text "Sub-Header") =?>
+ "<sec id=\"foo\">\n\
+ \ <title>Header</title>\n\
+ \ <sec id=\"foo\">\n\
+ \ <title>Sub-Header</title>\n\
+ \ </sec>\n\
+ \</sec>"
+ , "containing image" =:
+ header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?>
+ "<sec>\n\
+ \ <title><inline-graphic mimetype=\"image\" mime-subtype=\"jpeg\" xlink:href=\"imgs/foo.jpg\" /></title>\n\
+ \</sec>"
+ ]
+ ]
diff --git a/test/Tests/Writers/LaTeX.hs b/test/Tests/Writers/LaTeX.hs
new file mode 100644
index 000000000..471d9d9e7
--- /dev/null
+++ b/test/Tests/Writers/LaTeX.hs
@@ -0,0 +1,176 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.LaTeX (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+latex :: (ToPandoc a) => a -> String
+latex = latexWithOpts def
+
+latexListing :: (ToPandoc a) => a -> String
+latexListing = latexWithOpts def{ writerListings = True }
+
+latexWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
+latexWithOpts opts = unpack . purely (writeLaTeX opts) . toPandoc
+
+beamerWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
+beamerWithOpts opts = unpack . purely (writeBeamer opts) . toPandoc
+
+{-
+ "my test" =: X =?> Y
+
+is shorthand for
+
+ test latex "my test" $ X =?> Y
+
+which is in turn shorthand for
+
+ test latex "my test" (X,Y)
+-}
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test latex
+
+tests :: [TestTree]
+tests = [ testGroup "code blocks"
+ [ "in footnotes" =: note (para "hi" <> codeBlock "hi") =?>
+ "\\footnote{hi\n\n\\begin{Verbatim}\nhi\n\\end{Verbatim}\n}"
+ , test latexListing "identifier" $ codeBlockWith ("id",[],[]) "hi" =?>
+ ("\\begin{lstlisting}[label=id]\nhi\n\\end{lstlisting}" :: String)
+ , test latexListing "no identifier" $ codeBlock "hi" =?>
+ ("\\begin{lstlisting}\nhi\n\\end{lstlisting}" :: String)
+ ]
+ , testGroup "definition lists"
+ [ "with internal link" =: definitionList [(link "#go" "" (str "testing"),
+ [plain (text "hi there")])] =?>
+ "\\begin{description}\n\\tightlist\n\\item[{\\protect\\hyperlink{go}{testing}}]\nhi there\n\\end{description}"
+ ]
+ , testGroup "math"
+ [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
+ "\\(\\sigma|_{\\{x\\}}\\)"
+ ]
+ , testGroup "headers"
+ [ "unnumbered header" =:
+ headerWith ("foo",["unnumbered"],[]) 1
+ (text "Header 1" <> note (plain $ text "note")) =?>
+ "\\hypertarget{foo}{%\n\\section*{\\texorpdfstring{Header 1\\footnote{note}}{Header 1}}\\label{foo}}\n\\addcontentsline{toc}{section}{Header 1}\n"
+ , "in list item" =:
+ bulletList [header 2 (text "foo")] =?>
+ "\\begin{itemize}\n\\item ~\n \\subsection{foo}\n\\end{itemize}"
+ , "in definition list item" =:
+ definitionList [(text "foo", [header 2 (text "bar"),
+ para $ text "baz"])] =?>
+ "\\begin{description}\n\\item[foo] ~ \n\\subsection{bar}\n\nbaz\n\\end{description}"
+ , "containing image" =:
+ header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?>
+ "\\section{\\texorpdfstring{\\protect\\includegraphics{imgs/foo.jpg}}{Alt text}}"
+ ]
+ , testGroup "inline code"
+ [ "struck out and highlighted" =:
+ strikeout (codeWith ("",["haskell"],[]) "foo" <> space
+ <> str "bar") =?>
+ "\\sout{\\mbox{\\VERB|\\NormalTok{foo}|} bar}"
+ , "struck out and not highlighted" =:
+ strikeout (code "foo" <> space
+ <> str "bar") =?>
+ "\\sout{\\texttt{foo} bar}"
+ , "single quotes" =:
+ code "dog's" =?> "\\texttt{dog\\textquotesingle{}s}"
+ , "backtick" =:
+ code "`nu?`" =?> "\\texttt{\\textasciigrave{}nu?\\textasciigrave{}}"
+ ]
+ , testGroup "writer options"
+ [ testGroup "top-level division" $
+ let
+ headers = header 1 (text "header1")
+ <> header 2 (text "header2")
+ <> header 3 (text "header3")
+
+ latexTopLevelDiv :: (ToPandoc a) => TopLevelDivision -> a -> String
+ latexTopLevelDiv division =
+ latexWithOpts def{ writerTopLevelDivision = division }
+
+ beamerTopLevelDiv :: (ToPandoc a)
+ => TopLevelDivision -> a -> String
+ beamerTopLevelDiv division =
+ beamerWithOpts def { writerTopLevelDivision = division }
+ in
+ [ test (latexTopLevelDiv TopLevelSection)
+ "sections as top-level" $ headers =?>
+ unlines [ "\\section{header1}\n"
+ , "\\subsection{header2}\n"
+ , "\\subsubsection{header3}"
+ ]
+ , test (latexTopLevelDiv TopLevelChapter)
+ "chapters as top-level" $ headers =?>
+ unlines [ "\\chapter{header1}\n"
+ , "\\section{header2}\n"
+ , "\\subsection{header3}"
+ ]
+ , test (latexTopLevelDiv TopLevelPart)
+ "parts as top-level" $ headers =?>
+ unlines [ "\\part{header1}\n"
+ , "\\chapter{header2}\n"
+ , "\\section{header3}"
+ ]
+ , test (latexTopLevelDiv TopLevelDefault)
+ "default top-level" $ headers =?>
+ unlines [ "\\section{header1}\n"
+ , "\\subsection{header2}\n"
+ , "\\subsubsection{header3}"
+ ]
+ , test (beamerTopLevelDiv TopLevelSection)
+ "sections as top-level in beamer" $ headers =?>
+ unlines [ "\\section{header1}\n"
+ , "\\subsection{header2}\n"
+ , "\\subsubsection{header3}"
+ ]
+ , test (beamerTopLevelDiv TopLevelChapter)
+ "chapters are as part in beamer" $ headers =?>
+ unlines [ "\\part{header1}\n"
+ , "\\section{header2}\n"
+ , "\\subsection{header3}"
+ ]
+ , test (beamerTopLevelDiv TopLevelPart)
+ "parts as top-level in beamer" $ headers =?>
+ unlines [ "\\part{header1}\n"
+ , "\\section{header2}\n"
+ , "\\subsection{header3}"
+ ]
+ , test (beamerTopLevelDiv TopLevelDefault)
+ "default top-level in beamer" $ headers =?>
+ unlines [ "\\section{header1}\n"
+ , "\\subsection{header2}\n"
+ , "\\subsubsection{header3}"
+ ]
+ , test (latexTopLevelDiv TopLevelPart)
+ "part top-level, section not in toc" $
+ ( headerWith ("", ["unnumbered"], []) 1 (text "header1")
+ <> headerWith ("", ["unnumbered"], []) 2 (text "header2")
+ <> headerWith ("", ["unnumbered"], []) 3 (text "header3")
+ <> headerWith ("", ["unnumbered"], []) 4 (text "header4")
+ <> headerWith ("", ["unnumbered"], []) 5 (text "header5")
+ <> headerWith ("", ["unnumbered"], []) 6 (text "header6"))
+ =?>
+ unlines [ "\\part*{header1}"
+ , "\\addcontentsline{toc}{part}{header1}\n"
+ , "\\chapter*{header2}"
+ , "\\addcontentsline{toc}{chapter}{header2}\n"
+ , "\\section*{header3}"
+ , "\\addcontentsline{toc}{section}{header3}\n"
+ , "\\subsection*{header4}"
+ , "\\addcontentsline{toc}{subsection}{header4}\n"
+ , "\\subsubsection*{header5}"
+ , "\\addcontentsline{toc}{subsubsection}{header5}\n"
+ , "\\paragraph{header6}"
+ , "\\addcontentsline{toc}{paragraph}{header6}"
+ ]
+ ]
+ ]
+ ]
diff --git a/test/Tests/Writers/Markdown.hs b/test/Tests/Writers/Markdown.hs
new file mode 100644
index 000000000..7f9ac3627
--- /dev/null
+++ b/test/Tests/Writers/Markdown.hs
@@ -0,0 +1,267 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
+module Tests.Writers.Markdown (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+defopts :: WriterOptions
+defopts = def{ writerExtensions = pandocExtensions }
+
+markdown :: (ToPandoc a) => a -> String
+markdown = unpack . purely (writeMarkdown defopts) . toPandoc
+
+markdownWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
+markdownWithOpts opts x = unpack . purely (writeMarkdown opts) $ toPandoc x
+
+{-
+ "my test" =: X =?> Y
+
+is shorthand for
+
+ test markdown "my test" $ X =?> Y
+
+which is in turn shorthand for
+
+ test markdown "my test" (X,Y)
+-}
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test markdown
+
+tests :: [TestTree]
+tests = [ "indented code after list"
+ =: (orderedList [ para "one" <> para "two" ] <> codeBlock "test")
+ =?> "1. one\n\n two\n\n<!-- -->\n\n test"
+ , "list with tight sublist"
+ =: bulletList [ plain "foo" <> bulletList [ plain "bar" ],
+ plain "baz" ]
+ =?> "- foo\n - bar\n- baz\n"
+ ] ++ [noteTests] ++ [shortcutLinkRefsTests]
+
+{-
+
+Testing with the following text:
+
+First Header
+============
+
+This is a footnote.[^1] And this is a [link](https://www.google.com).
+
+> A note inside a block quote.[^2]
+>
+> A second paragraph.
+
+Second Header
+=============
+
+Some more text.
+
+
+[^1]: Down here.
+
+[^2]: The second note.
+
+-}
+
+noteTestDoc :: Blocks
+noteTestDoc =
+ header 1 "First Header" <>
+ para ("This is a footnote." <>
+ note (para "Down here.") <>
+ " And this is a " <>
+ link "https://www.google.com" "" "link" <>
+ ".") <>
+ blockQuote (para ("A note inside a block quote." <>
+ note (para "The second note.")) <>
+ para "A second paragraph.") <>
+ header 1 "Second Header" <>
+ para "Some more text."
+
+
+
+noteTests :: TestTree
+noteTests = testGroup "note and reference location"
+ [ test (markdownWithOpts defopts)
+ "footnotes at the end of a document" $
+ noteTestDoc =?>
+ (unlines [ "First Header"
+ , "============"
+ , ""
+ , "This is a footnote.[^1] And this is a [link](https://www.google.com)."
+ , ""
+ , "> A note inside a block quote.[^2]"
+ , ">"
+ , "> A second paragraph."
+ , ""
+ , "Second Header"
+ , "============="
+ , ""
+ , "Some more text."
+ , ""
+ , "[^1]: Down here."
+ , ""
+ , "[^2]: The second note."
+ ])
+ , test (markdownWithOpts defopts{writerReferenceLocation=EndOfBlock})
+ "footnotes at the end of blocks" $
+ noteTestDoc =?>
+ (unlines [ "First Header"
+ , "============"
+ , ""
+ , "This is a footnote.[^1] And this is a [link](https://www.google.com)."
+ , ""
+ , "[^1]: Down here."
+ , ""
+ , "> A note inside a block quote.[^2]"
+ , ">"
+ , "> A second paragraph."
+ , ""
+ , "[^2]: The second note."
+ , ""
+ , "Second Header"
+ , "============="
+ , ""
+ , "Some more text."
+ ])
+ , test (markdownWithOpts defopts{writerReferenceLocation=EndOfBlock, writerReferenceLinks=True})
+ "footnotes and reference links at the end of blocks" $
+ noteTestDoc =?>
+ (unlines [ "First Header"
+ , "============"
+ , ""
+ , "This is a footnote.[^1] And this is a [link]."
+ , ""
+ , "[^1]: Down here."
+ , ""
+ , " [link]: https://www.google.com"
+ , ""
+ , "> A note inside a block quote.[^2]"
+ , ">"
+ , "> A second paragraph."
+ , ""
+ , "[^2]: The second note."
+ , ""
+ , "Second Header"
+ , "============="
+ , ""
+ , "Some more text."
+ ])
+ , test (markdownWithOpts defopts{writerReferenceLocation=EndOfSection})
+ "footnotes at the end of section" $
+ noteTestDoc =?>
+ (unlines [ "First Header"
+ , "============"
+ , ""
+ , "This is a footnote.[^1] And this is a [link](https://www.google.com)."
+ , ""
+ , "> A note inside a block quote.[^2]"
+ , ">"
+ , "> A second paragraph."
+ , ""
+ , "[^1]: Down here."
+ , ""
+ , "[^2]: The second note."
+ , ""
+ , "Second Header"
+ , "============="
+ , ""
+ , "Some more text."
+ ])
+
+ ]
+
+shortcutLinkRefsTests :: TestTree
+shortcutLinkRefsTests =
+ let infix 4 =:
+ (=:) :: (ToString a, ToPandoc a)
+
+ => String -> (a, String) -> TestTree
+ (=:) = test (purely (writeMarkdown defopts{writerReferenceLinks = True}) . toPandoc)
+ in testGroup "Shortcut reference links"
+ [ "Simple link (shortcutable)"
+ =: para (link "/url" "title" "foo")
+ =?> "[foo]\n\n [foo]: /url \"title\""
+ , "Followed by another link (unshortcutable)"
+ =: para ((link "/url1" "title1" "first")
+ <> (link "/url2" "title2" "second"))
+ =?> unlines [ "[first][][second]"
+ , ""
+ , " [first]: /url1 \"title1\""
+ , " [second]: /url2 \"title2\""
+ ]
+ , "Followed by space and another link (unshortcutable)"
+ =: para ((link "/url1" "title1" "first") <> " "
+ <> (link "/url2" "title2" "second"))
+ =?> unlines [ "[first][] [second]"
+ , ""
+ , " [first]: /url1 \"title1\""
+ , " [second]: /url2 \"title2\""
+ ]
+ , "Reference link is used multiple times (unshortcutable)"
+ =: para ((link "/url1" "" "foo") <> (link "/url2" "" "foo")
+ <> (link "/url3" "" "foo"))
+ =?> unlines [ "[foo][][foo][1][foo][2]"
+ , ""
+ , " [foo]: /url1"
+ , " [1]: /url2"
+ , " [2]: /url3"
+ ]
+ , "Reference link is used multiple times (unshortcutable)"
+ =: para ((link "/url1" "" "foo") <> " " <> (link "/url2" "" "foo")
+ <> " " <> (link "/url3" "" "foo"))
+ =?> unlines [ "[foo][] [foo][1] [foo][2]"
+ , ""
+ , " [foo]: /url1"
+ , " [1]: /url2"
+ , " [2]: /url3"
+ ]
+ , "Reference link is followed by text in brackets"
+ =: para ((link "/url" "" "link") <> "[text in brackets]")
+ =?> unlines [ "[link][]\\[text in brackets\\]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and text in brackets"
+ =: para ((link "/url" "" "link") <> " [text in brackets]")
+ =?> unlines [ "[link][] \\[text in brackets\\]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by RawInline"
+ =: para ((link "/url" "" "link") <> rawInline "markdown" "[rawText]")
+ =?> unlines [ "[link][][rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and RawInline"
+ =: para ((link "/url" "" "link") <> space <> rawInline "markdown" "[rawText]")
+ =?> unlines [ "[link][] [rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by RawInline with space"
+ =: para ((link "/url" "" "link") <> rawInline "markdown" " [rawText]")
+ =?> unlines [ "[link][] [rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by citation"
+ =: para ((link "/url" "" "link") <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]"))
+ =?> unlines [ "[link][][@author]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and citation"
+ =: para ((link "/url" "" "link") <> space <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]"))
+ =?> unlines [ "[link][] [@author]"
+ , ""
+ , " [link]: /url"
+ ]
+ ]
diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs
new file mode 100644
index 000000000..0b8a08258
--- /dev/null
+++ b/test/Tests/Writers/Muse.hs
@@ -0,0 +1,385 @@
+module Tests.Writers.Muse (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+muse :: (ToPandoc a) => a -> String
+muse = museWithOpts def{ writerWrapText = WrapNone,
+ writerExtensions = extensionsFromList [Ext_amuse,
+ Ext_auto_identifiers] }
+
+museWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
+museWithOpts opts = unpack . purely (writeMuse opts) . toPandoc
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test muse
+
+tests :: [TestTree]
+tests = [ testGroup "block elements"
+ [ "plain" =: plain (text "Foo bar.") =?> "Foo bar."
+ , testGroup "paragraphs"
+ [ "single paragraph" =: para (text "Sample paragraph.")
+ =?> "Sample paragraph."
+ , "two paragraphs" =: para (text "First paragraph.") <>
+ para (text "Second paragraph.")
+ =?> unlines [ "First paragraph."
+ , ""
+ , "Second paragraph."
+ ]
+ ]
+ , "line block" =: lineBlock [text "Foo", text "bar", text "baz"]
+ =?> unlines [ "> Foo"
+ , "> bar"
+ , "> baz"
+ ]
+ , "code block" =: codeBlock "int main(void) {\n\treturn 0;\n}"
+ =?> unlines [ "<example>"
+ , "int main(void) {"
+ , "\treturn 0;"
+ , "}"
+ , "</example>"
+ ]
+ , "html raw block" =: rawBlock "html" "<hr>"
+ =?> unlines [ "<literal style=\"html\">"
+ , "<hr>"
+ , "</literal>"
+ ]
+ , "block quote" =: blockQuote (para (text "Foo"))
+ =?> unlines [ "<quote>"
+ , "Foo"
+ , "</quote>"
+ ]
+ , testGroup "lists"
+ [ testGroup "simple lists"
+ [
+ "ordered list" =: orderedList [ plain $ text "first"
+ , plain $ text "second"
+ , plain $ text "third"
+ ]
+ =?> unlines [ " 1. first"
+ , " 2. second"
+ , " 3. third"
+ ]
+ , "ordered list with Roman numerals"
+ =: orderedListWith (1, UpperRoman, DefaultDelim)
+ [ plain $ text "first"
+ , plain $ text "second"
+ , plain $ text "third"
+ ]
+ =?> unlines [ " I. first"
+ , " II. second"
+ , " III. third"
+ ]
+ , "bullet list" =: bulletList [ plain $ text "first"
+ , plain $ text "second"
+ , plain $ text "third"
+ ]
+ =?> unlines [ " - first"
+ , " - second"
+ , " - third"
+ ]
+ , "definition list" =: definitionList [ (text "first definition", [plain $ text "first description"])
+ , (text "second definition", [plain $ text "second description"])
+ , (text "third definition", [plain $ text "third description"])
+ ]
+ =?> unlines [ " first definition :: first description"
+ , " second definition :: second description"
+ , " third definition :: third description"
+ ]
+ , "definition list with multiple descriptions" =:
+ definitionList [ (text "first definition", [plain $ text "first description"
+ ,plain $ text "second description"])
+ , (text "second definition", [plain $ text "third description"])
+ ]
+ =?> unlines [ " first definition :: first description"
+ , " :: second description"
+ , " second definition :: third description"
+ ]
+ ]
+ -- Test that lists of the same type and style are separated with two blanklines
+ , testGroup "sequential lists"
+ [ "bullet lists" =:
+ bulletList [ para $ text "First"
+ , para $ text "Second"
+ , para $ text "Third"
+ ] <>
+ bulletList [ para $ text "Fourth"
+ , para $ text "Fifth"
+ ] =?>
+ unlines [ " - First"
+ , " - Second"
+ , " - Third"
+ , ""
+ , ""
+ , " - Fourth"
+ , " - Fifth"
+ ]
+ , "ordered lists of the same style" =:
+ orderedListWith (1, UpperRoman, DefaultDelim) [ para $ text "First"
+ , para $ text "Second"
+ ] <>
+ orderedListWith (1, UpperRoman, DefaultDelim) [ para $ text "Third"
+ , para $ text "Fourth"
+ ] =?>
+ unlines [ " I. First"
+ , " II. Second"
+ , ""
+ , ""
+ , " I. Third"
+ , " II. Fourth"
+ ]
+ , "ordered lists with equal styles" =:
+ orderedList [ para $ text "First"
+ , para $ text "Second"
+ ] <>
+ orderedListWith (1, Decimal, DefaultDelim) [ para $ text "Third"
+ , para $ text "Fourth"
+ ] =?>
+ unlines [ " 1. First"
+ , " 2. Second"
+ , ""
+ , ""
+ , " 1. Third"
+ , " 2. Fourth"
+ ]
+ , "bullet and ordered lists" =:
+ bulletList [ para $ text "First"
+ , para $ text "Second"
+ ] <>
+ orderedListWith (1, UpperRoman, DefaultDelim) [ para $ text "Third"
+ , para $ text "Fourth"
+ ] =?>
+ unlines [ " - First"
+ , " - Second"
+ , ""
+ , " I. Third"
+ , " II. Fourth"
+ ]
+ , "different style ordered lists" =:
+ orderedListWith (1, UpperRoman, DefaultDelim) [ para $ text "First"
+ , para $ text "Second"
+ ] <>
+ orderedListWith (1, Decimal, DefaultDelim) [ para $ text "Third"
+ , para $ text "Fourth"
+ ] =?>
+ unlines [ " I. First"
+ , " II. Second"
+ , ""
+ , " 1. Third"
+ , " 2. Fourth"
+ ]
+ ]
+ , testGroup "nested lists"
+ [ "nested ordered list" =: orderedList [ plain $ text "First outer"
+ , plain (text "Second outer:") <>
+ orderedList [ plain $ text "first"
+ , plain $ text "second"
+ ]
+ , plain $ text "Third outer"
+ ]
+ =?> unlines [ " 1. First outer"
+ , " 2. Second outer:"
+ , " 1. first"
+ , " 2. second"
+ , " 3. Third outer"
+ ]
+ , "nested bullet lists" =: bulletList [ plain $ text "First outer"
+ , plain (text "Second outer:") <>
+ bulletList [ plain $ text "first"
+ , plain $ text "second"
+ ]
+ , plain $ text "Third outer"
+ ]
+ =?> unlines [ " - First outer"
+ , " - Second outer:"
+ , " - first"
+ , " - second"
+ , " - Third outer"
+ ]
+ , "nested definition lists" =: definitionList [ (text "first definition", [plain $ text "first description"])
+ , (text "second definition",
+ [ plain (text "second description") <>
+ definitionList [ ( text "first inner definition"
+ , [plain $ text "first inner description"])
+ , ( text "second inner definition"
+ , [plain $ text "second inner description"])
+ ]
+ ]
+ )
+ ]
+ =?> unlines [ " first definition :: first description"
+ , " second definition :: second description"
+ , " first inner definition :: first inner description"
+ , " second inner definition :: second inner description"
+ ]
+ ]
+ -- Check that list is intended with one space even inside a quote
+ , "List inside block quote" =: blockQuote (orderedList [ plain $ text "first"
+ , plain $ text "second"
+ , plain $ text "third"
+ ])
+ =?> unlines [ "<quote>"
+ , " 1. first"
+ , " 2. second"
+ , " 3. third"
+ , "</quote>"
+ ]
+ ]
+ , testGroup "headings"
+ [ "normal heading" =:
+ header 1 (text "foo") =?> "* foo"
+ , "heading levels" =:
+ header 1 (text "First level") <>
+ header 3 (text "Third level") =?>
+ unlines [ "* First level"
+ , ""
+ , "*** Third level"
+ ]
+ , "heading with ID" =:
+ headerWith ("bar", [], []) 2 (text "Foo") =?>
+ unlines [ "** Foo"
+ , "#bar"
+ ]
+ ]
+ , "horizontal rule" =: horizontalRule =?> "----"
+ , "escape horizontal rule" =: para (text "----") =?> "<verbatim>----</verbatim>"
+ , "escape nonbreaking space" =: para (text "~~") =?> "<verbatim>~~</verbatim>"
+ , testGroup "tables"
+ [ "table without header" =:
+ let rows = [[para $ text "Para 1.1", para $ text "Para 1.2"]
+ ,[para $ text "Para 2.1", para $ text "Para 2.2"]]
+ in simpleTable [] rows
+ =?>
+ unlines [ " Para 1.1 | Para 1.2"
+ , " Para 2.1 | Para 2.2"
+ ]
+ , "table with header" =:
+ let headers = [plain $ text "header 1", plain $ text "header 2"]
+ rows = [[para $ text "Para 1.1", para $ text "Para 1.2"]
+ ,[para $ text "Para 2.1", para $ text "Para 2.2"]]
+ in simpleTable headers rows
+ =?>
+ unlines [ " header 1 || header 2"
+ , " Para 1.1 | Para 1.2"
+ , " Para 2.1 | Para 2.2"
+ ]
+ , "table with header and caption" =:
+ let caption = text "Table 1"
+ headers = [plain $ text "header 1", plain $ text "header 2"]
+ rows = [[para $ text "Para 1.1", para $ text "Para 1.2"]
+ ,[para $ text "Para 2.1", para $ text "Para 2.2"]]
+ in table caption mempty headers rows
+ =?> unlines [ " header 1 || header 2"
+ , " Para 1.1 | Para 1.2"
+ , " Para 2.1 | Para 2.2"
+ , " |+ Table 1 +|"
+ ]
+ ]
+ , "div with bullet list" =:
+ divWith nullAttr (bulletList [para $ text "foo"]) =?>
+ unlines [ " - foo" ] -- Making sure bullets are indented
+ -- Null is trivial
+ ]
+ , testGroup "inline elements"
+ [ testGroup "string"
+ [ "string" =: str "foo" =?> "foo"
+ , "escape footnote" =: str "[1]" =?> "<verbatim>[1]</verbatim>"
+ , "escape verbatim close tag" =: str "foo</verbatim>bar"
+ =?> "<verbatim>foo<</verbatim><verbatim>/verbatim>bar</verbatim>"
+ , "escape pipe to avoid accidental tables" =: str "foo | bar"
+ =?> "<verbatim>foo | bar</verbatim>"
+ , "escape hash to avoid accidental anchors" =: text "#foo bar"
+ =?> "<verbatim>#foo</verbatim> bar"
+ , "escape definition list markers" =: str "::" =?> "<verbatim>::</verbatim>"
+ , "normalize strings before escaping" =: fromList [Str ":", Str ":"] =?> "<verbatim>::</verbatim>"
+ -- We don't want colons to be escaped if they can't be confused
+ -- with definition list item markers.
+ , "do not escape colon" =: str ":" =?> ":"
+ ]
+ , testGroup "emphasis"
+ [ "emph" =: emph (text "foo") =?> "<em>foo</em>"
+ , "strong" =: strong (text "foo") =?> "<strong>foo</strong>"
+ , "strikeout" =: strikeout (text "foo") =?> "<del>foo</del>"
+ ]
+ , "superscript" =: superscript (text "foo") =?> "<sup>foo</sup>"
+ , "subscript" =: subscript (text "foo") =?> "<sub>foo</sub>"
+ , "smallcaps" =: smallcaps (text "foo") =?> "foo"
+ , "single quoted" =: singleQuoted (text "foo") =?> "‘foo’"
+ , "double quoted" =: doubleQuoted (text "foo") =?> "“foo”"
+ -- Cite is trivial
+ , testGroup "code"
+ [ "simple" =: code "foo" =?> "<code>foo</code>"
+ , "escape tag" =: code "<code>foo = bar</code> baz" =?> "<code><code>foo = bar<</code><code>/code> baz</code>"
+ , "normalization with attributes" =: codeWith ("",["haskell"],[]) "foo" <> code "bar" =?> "<code>foobar</code>"
+ , "normalization" =: code "</co" <> code "de>" =?> "<code><</code><code>/code></code>"
+ , "normalization with empty string" =: code "</co" <> str "" <> code "de>" =?> "<code><</code><code>/code></code>"
+ ]
+ , testGroup "spaces"
+ [ "space" =: text "a" <> space <> text "b" =?> "a b"
+ , "soft break" =: text "a" <> softbreak <> text "b" =?> "a b"
+ , test (museWithOpts def{ writerWrapText = WrapPreserve })
+ "preserve soft break" $ text "a" <> softbreak <> text "b"
+ =?> "a\nb"
+ , "line break" =: text "a" <> linebreak <> text "b" =?> "a<br>\nb"
+ ]
+ , testGroup "math"
+ [ "inline math" =: math "2^3" =?> "2<sup>3</sup>"
+ , "display math" =: displayMath "2^3" =?> "2<sup>3</sup>"
+ , "multiple letters in inline math" =: math "abc" =?> "<em>abc</em>"
+ ]
+ , "raw inline"
+ =: rawInline "html" "<mark>marked text</mark>"
+ =?> "<literal style=\"html\"><mark>marked text</mark></literal>"
+ , testGroup "links"
+ [ "link with description" =: link "https://example.com" "" (str "Link 1")
+ =?> "[[https://example.com][Link 1]]"
+ , "link without description" =: link "https://example.com" "" (str "https://example.com")
+ =?> "[[https://example.com]]"
+ -- Internal links in Muse include '#'
+ , "link to anchor" =: link "#intro" "" (str "Introduction")
+ =?> "[[#intro][Introduction]]"
+ -- According to Emacs Muse manual, links to images should be prefixed with "URL:"
+ , "link to image with description" =: link "1.png" "" (str "Link to image")
+ =?> "[[URL:1.png][Link to image]]"
+ , "link to image without description" =: link "1.png" "" (str "1.png")
+ =?> "[[URL:1.png]]"
+ ]
+ , "image" =: image "image.png" "Image 1" (str "") =?> "[[image.png][Image 1]]"
+ , "image with width" =:
+ imageWith ("", [], [("width", "60%")]) "image.png" "Image" (str "") =?>
+ "[[image.png 60][Image]]"
+ , "note" =: note (plain (text "Foo"))
+ =?> unlines [ "[1]"
+ , ""
+ , "[1] Foo"
+ ]
+ , "span" =: spanWith ("",["foobar"],[]) (str "Some text")
+ =?> "<class name=\"foobar\">Some text</class>"
+ , testGroup "combined"
+ [ "emph word before" =:
+ para (text "foo" <> emph (text "bar")) =?>
+ "foo<em>bar</em>"
+ , "emph word after" =:
+ para (emph (text "foo") <> text "bar") =?>
+ "<em>foo</em>bar"
+ , "emph quoted" =:
+ para (doubleQuoted (emph (text "foo"))) =?>
+ "“<em>foo</em>”"
+ , "strong word before" =:
+ para (text "foo" <> strong (text "bar")) =?>
+ "foo<strong>bar</strong>"
+ , "strong word after" =:
+ para (strong (text "foo") <> text "bar") =?>
+ "<strong>foo</strong>bar"
+ , "strong quoted" =:
+ para (singleQuoted (strong (text "foo"))) =?>
+ "‘<strong>foo</strong>’"
+ ]
+ ]
+ ]
diff --git a/test/Tests/Writers/Native.hs b/test/Tests/Writers/Native.hs
new file mode 100644
index 000000000..0c4bf7623
--- /dev/null
+++ b/test/Tests/Writers/Native.hs
@@ -0,0 +1,22 @@
+module Tests.Writers.Native (tests) where
+
+import Data.Text (unpack)
+import Test.Tasty
+import Test.Tasty.QuickCheck
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+
+p_write_rt :: Pandoc -> Bool
+p_write_rt d =
+ read (unpack $ purely (writeNative def{ writerTemplate = Just "" }) d) == d
+
+p_write_blocks_rt :: [Block] -> Bool
+p_write_blocks_rt bs =
+ read (unpack $ purely (writeNative def) (Pandoc nullMeta bs)) == bs
+
+tests :: [TestTree]
+tests = [ testProperty "p_write_rt" p_write_rt
+ , testProperty "p_write_blocks_rt" $ mapSize
+ (\x -> if x > 3 then 3 else x) p_write_blocks_rt
+ ]
diff --git a/test/Tests/Writers/OOXML.hs b/test/Tests/Writers/OOXML.hs
new file mode 100644
index 000000000..bdfdea145
--- /dev/null
+++ b/test/Tests/Writers/OOXML.hs
@@ -0,0 +1,184 @@
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Tests.Writers.OOXML (ooxmlTest) where
+
+import Text.Pandoc
+import Test.Tasty
+import Test.Tasty.Golden.Advanced
+import Codec.Archive.Zip
+import Text.XML.Light
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text.IO as T
+import Data.List (isSuffixOf, sort, (\\), intercalate, union)
+import Data.Maybe (catMaybes, mapMaybe)
+import Tests.Helpers
+import Data.Algorithm.Diff
+import System.FilePath.Glob (compile, match)
+
+compareXMLBool :: Content -> Content -> Bool
+-- We make a special exception for times at the moment, and just pass
+-- them because we can't control the utctime when running IO. Besides,
+-- so long as we have two times, we're okay.
+compareXMLBool (Elem myElem) (Elem goodElem)
+ | (QName "created" _ (Just "dcterms")) <- elName myElem
+ , (QName "created" _ (Just "dcterms")) <- elName goodElem =
+ True
+compareXMLBool (Elem myElem) (Elem goodElem)
+ | (QName "modified" _ (Just "dcterms")) <- elName myElem
+ , (QName "modified" _ (Just "dcterms")) <- elName goodElem =
+ True
+compareXMLBool (Elem myElem) (Elem goodElem) =
+ elName myElem == elName goodElem &&
+ elAttribs myElem == elAttribs goodElem &&
+ and (zipWith compareXMLBool (elContent myElem) (elContent goodElem))
+compareXMLBool (Text myCData) (Text goodCData) =
+ cdVerbatim myCData == cdVerbatim goodCData &&
+ cdData myCData == cdData goodCData &&
+ cdLine myCData == cdLine goodCData
+compareXMLBool (CRef myStr) (CRef goodStr) =
+ myStr == goodStr
+compareXMLBool _ _ = False
+
+displayDiff :: Content -> Content -> String
+displayDiff elemA elemB =
+ showDiff (1,1) $ getDiff (lines $ ppContent elemA) (lines $ ppContent elemB)
+
+goldenArchive :: FilePath -> IO Archive
+goldenArchive fp = (toArchive . BL.fromStrict) <$> BS.readFile fp
+
+testArchive :: (WriterOptions -> Pandoc -> PandocIO BL.ByteString)
+ -> WriterOptions
+ -> FilePath
+ -> IO Archive
+testArchive writerFn opts fp = do
+ txt <- T.readFile fp
+ bs <- runIOorExplode $ readNative def txt >>= writerFn opts
+ return $ toArchive bs
+
+compareFileList :: FilePath -> Archive -> Archive -> Maybe String
+compareFileList goldenFP goldenArch testArch =
+ let testFiles = filesInArchive testArch
+ goldenFiles = filesInArchive goldenArch
+ diffTestGolden = testFiles \\ goldenFiles
+ diffGoldenTest = goldenFiles \\ testFiles
+
+ results =
+ [ if null diffGoldenTest
+ then Nothing
+ else Just $
+ "Files in " ++ goldenFP ++ " but not in generated archive:\n" ++
+ intercalate ", " diffGoldenTest
+ , if null diffTestGolden
+ then Nothing
+ else Just $
+ "Files in generated archive but not in " ++ goldenFP ++ ":\n" ++
+ intercalate ", " diffTestGolden
+ ]
+ in
+ if null $ catMaybes results
+ then Nothing
+ else Just $ intercalate "\n" $ catMaybes results
+
+compareXMLFile' :: FilePath -> Archive -> Archive -> Either String ()
+compareXMLFile' fp goldenArch testArch = do
+ testEntry <- case findEntryByPath fp testArch of
+ Just entry -> Right entry
+ Nothing -> Left $
+ "Can't extract " ++ fp ++ " from generated archive"
+ testXMLDoc <- case parseXMLDoc $ fromEntry testEntry of
+ Just doc -> Right doc
+ Nothing -> Left $
+ "Can't parse xml in " ++ fp ++ " from generated archive"
+
+ goldenEntry <- case findEntryByPath fp goldenArch of
+ Just entry -> Right entry
+ Nothing -> Left $
+ "Can't extract " ++ fp ++ " from archive in stored file"
+ goldenXMLDoc <- case parseXMLDoc $ fromEntry goldenEntry of
+ Just doc -> Right doc
+ Nothing -> Left $
+ "Can't parse xml in " ++ fp ++ " from archive in stored file"
+
+ let testContent = Elem testXMLDoc
+ goldenContent = Elem goldenXMLDoc
+
+ if compareXMLBool goldenContent testContent
+ then Right ()
+ else Left $
+ "Non-matching xml in " ++ fp ++ ":\n" ++ displayDiff testContent goldenContent
+
+compareXMLFile :: FilePath -> Archive -> Archive -> Maybe String
+compareXMLFile fp goldenArch testArch =
+ case compareXMLFile' fp goldenArch testArch of
+ Right _ -> Nothing
+ Left s -> Just s
+
+compareAllXMLFiles :: Archive -> Archive -> Maybe String
+compareAllXMLFiles goldenArch testArch =
+ let allFiles = filesInArchive goldenArch `union` filesInArchive testArch
+ allXMLFiles = sort $
+ filter
+ (\fp -> ".xml" `isSuffixOf` fp || ".rels" `isSuffixOf` fp)
+ allFiles
+ results =
+ mapMaybe (\fp -> compareXMLFile fp goldenArch testArch) allXMLFiles
+ in
+ if null results
+ then Nothing
+ else Just $ unlines results
+
+compareMediaFile' :: FilePath -> Archive -> Archive -> Either String ()
+compareMediaFile' fp goldenArch testArch = do
+ testEntry <- case findEntryByPath fp testArch of
+ Just entry -> Right entry
+ Nothing -> Left $
+ "Can't extract " ++ fp ++ " from generated archive"
+ goldenEntry <- case findEntryByPath fp goldenArch of
+ Just entry -> Right entry
+ Nothing -> Left $
+ "Can't extract " ++ fp ++ " from archive in stored file"
+
+ if fromEntry testEntry == fromEntry goldenEntry
+ then Right ()
+ else Left $
+ "Non-matching binary file: " ++ fp
+
+compareMediaFile :: FilePath -> Archive -> Archive -> Maybe String
+compareMediaFile fp goldenArch testArch =
+ case compareMediaFile' fp goldenArch testArch of
+ Right _ -> Nothing
+ Left s -> Just s
+
+compareAllMediaFiles :: Archive -> Archive -> Maybe String
+compareAllMediaFiles goldenArch testArch =
+ let allFiles = filesInArchive goldenArch `union` filesInArchive testArch
+ mediaPattern = compile "*/media/*"
+ allMediaFiles = sort $
+ filter (match mediaPattern) allFiles
+ results =
+ mapMaybe (\fp -> compareMediaFile fp goldenArch testArch) allMediaFiles
+ in
+ if null results
+ then Nothing
+ else Just $ unlines results
+
+ooxmlTest :: (WriterOptions -> Pandoc -> PandocIO BL.ByteString)
+ -> String
+ -> WriterOptions
+ -> FilePath
+ -> FilePath
+ -> TestTree
+ooxmlTest writerFn testName opts nativeFP goldenFP =
+ goldenTest
+ testName
+ (goldenArchive goldenFP)
+ (testArchive writerFn opts nativeFP)
+ (\goldenArch testArch ->
+ let res = catMaybes [ compareFileList goldenFP goldenArch testArch
+ , compareAllXMLFiles goldenArch testArch
+ , compareAllMediaFiles goldenArch testArch
+ ]
+ in return $ if null res then Nothing else Just $ unlines res)
+ (\a -> BL.writeFile goldenFP $ fromArchive a)
diff --git a/test/Tests/Writers/Org.hs b/test/Tests/Writers/Org.hs
new file mode 100644
index 000000000..9cbe360da
--- /dev/null
+++ b/test/Tests/Writers/Org.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.Org (tests) where
+
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test (purely (writeOrg def . toPandoc))
+
+tests :: [TestTree]
+tests = [ testGroup "links"
+ -- See http://orgmode.org/manual/Internal-links.html#Internal-links
+ [ "simple link"
+ =: link "/url" "" "foo"
+ =?> "[[/url][foo]]"
+ , "internal link to anchor"
+ =: link "#my-custom-id" "" "#my-custom-id"
+ =?> "[[#my-custom-id]]"
+ ]
+ ]
diff --git a/test/Tests/Writers/Plain.hs b/test/Tests/Writers/Plain.hs
new file mode 100644
index 000000000..ab09bca26
--- /dev/null
+++ b/test/Tests/Writers/Plain.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.Plain (tests) where
+
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test (purely (writePlain def) . toPandoc)
+
+
+tests :: [TestTree]
+tests = [ "strongly emphasized text to uppercase"
+ =: strong "Straße"
+ =?> "STRASSE"
+ ]
diff --git a/test/Tests/Writers/Powerpoint.hs b/test/Tests/Writers/Powerpoint.hs
new file mode 100644
index 000000000..9af8fc471
--- /dev/null
+++ b/test/Tests/Writers/Powerpoint.hs
@@ -0,0 +1,93 @@
+module Tests.Writers.Powerpoint (tests) where
+
+import Tests.Writers.OOXML (ooxmlTest)
+import Text.Pandoc
+import Test.Tasty
+import System.FilePath
+
+-- templating is important enough, and can break enough things, that
+-- we want to run all our tests with both default formatting and a
+-- template.
+
+modifyPptxName :: FilePath -> FilePath
+modifyPptxName fp =
+ addExtension (dropExtension fp ++ "_templated") "pptx"
+
+pptxTests :: String -> WriterOptions -> FilePath -> FilePath -> (TestTree, TestTree)
+pptxTests name opts native pptx =
+ let referenceDoc = "pptx/reference_depth.pptx"
+ in
+ ( ooxmlTest
+ writePowerpoint
+ name
+ opts{writerReferenceDoc=Nothing}
+ native
+ pptx
+ , ooxmlTest
+ writePowerpoint
+ name
+ opts{writerReferenceDoc=Just referenceDoc}
+ native
+ (modifyPptxName pptx)
+ )
+
+groupPptxTests :: [(TestTree, TestTree)] -> [TestTree]
+groupPptxTests pairs =
+ let (noRefs, refs) = unzip pairs
+ in
+ [ testGroup "Default slide formatting" noRefs
+ , testGroup "With `--reference-doc` pptx file" refs
+ ]
+
+
+tests :: [TestTree]
+tests = groupPptxTests [ pptxTests "Inline formatting"
+ def
+ "pptx/inline_formatting.native"
+ "pptx/inline_formatting.pptx"
+ , pptxTests "Slide breaks (default slide-level)"
+ def
+ "pptx/slide_breaks.native"
+ "pptx/slide_breaks.pptx"
+ , pptxTests "slide breaks (slide-level set to 1)"
+ def{ writerSlideLevel = Just 1 }
+ "pptx/slide_breaks.native"
+ "pptx/slide_breaks_slide_level_1.pptx"
+ , pptxTests "lists"
+ def
+ "pptx/lists.native"
+ "pptx/lists.pptx"
+ , pptxTests "tables"
+ def
+ "pptx/tables.native"
+ "pptx/tables.pptx"
+ , pptxTests "table of contents"
+ def{ writerTableOfContents = True }
+ "pptx/slide_breaks.native"
+ "pptx/slide_breaks_toc.pptx"
+ , pptxTests "end notes"
+ def
+ "pptx/endnotes.native"
+ "pptx/endnotes.pptx"
+ , pptxTests "end notes, with table of contents"
+ def { writerTableOfContents = True }
+ "pptx/endnotes.native"
+ "pptx/endnotes_toc.pptx"
+ , pptxTests "images"
+ def
+ "pptx/images.native"
+ "pptx/images.pptx"
+ , pptxTests "two-column layout"
+ def
+ "pptx/two_column.native"
+ "pptx/two_column.pptx"
+ , pptxTests "speaker notes"
+ def
+ "pptx/speaker_notes.native"
+ "pptx/speaker_notes.pptx"
+ , pptxTests "remove empty slides"
+ def
+ "pptx/remove_empty_slides.native"
+ "pptx/remove_empty_slides.pptx"
+
+ ]
diff --git a/test/Tests/Writers/RST.hs b/test/Tests/Writers/RST.hs
new file mode 100644
index 000000000..4c0a926bb
--- /dev/null
+++ b/test/Tests/Writers/RST.hs
@@ -0,0 +1,117 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.RST (tests) where
+
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test (purely (writeRST def . toPandoc))
+
+tests :: [TestTree]
+tests = [ testGroup "rubrics"
+ [ "in list item" =:
+ bulletList [header 2 (text "foo")] =?>
+ "- .. rubric:: foo"
+ , "in definition list item" =:
+ definitionList [(text "foo", [header 2 (text "bar"),
+ para $ text "baz"])] =?>
+ unlines
+ [ "foo"
+ , " .. rubric:: bar"
+ , ""
+ , " baz"]
+ , "in block quote" =:
+ blockQuote (header 1 (text "bar")) =?>
+ " .. rubric:: bar"
+ , "with id" =:
+ blockQuote (headerWith ("foo",[],[]) 1 (text "bar")) =?>
+ unlines
+ [ " .. rubric:: bar"
+ , " :name: foo"]
+ , "with id class" =:
+ blockQuote (headerWith ("foo",["baz"],[]) 1 (text "bar")) =?>
+ unlines
+ [ " .. rubric:: bar"
+ , " :name: foo"
+ , " :class: baz"]
+ ]
+ , testGroup "ligatures" -- handling specific sequences of blocks
+ [ "a list is closed by a comment before a quote" =: -- issue 4248
+ bulletList [plain "bulleted"] <> blockQuote (plain "quoted") =?>
+ unlines
+ [ "- bulleted"
+ , ""
+ , ".."
+ , ""
+ , " quoted"]
+ ]
+ , testGroup "headings"
+ [ "normal heading" =:
+ header 1 (text "foo") =?>
+ unlines
+ [ "foo"
+ , "==="]
+ -- note: heading normalization is only done in standalone mode
+ , test (purely (writeRST def{ writerTemplate = Just "$body$\n" }) . toPandoc)
+ "heading levels" $
+ header 1 (text "Header 1") <>
+ header 3 (text "Header 2") <>
+ header 2 (text "Header 2") <>
+ header 1 (text "Header 1") <>
+ header 4 (text "Header 2") <>
+ header 5 (text "Header 3") <>
+ header 3 (text "Header 2") =?>
+ unlines
+ [ "Header 1"
+ , "========"
+ , ""
+ , "Header 2"
+ , "--------"
+ , ""
+ , "Header 2"
+ , "--------"
+ , ""
+ , "Header 1"
+ , "========"
+ , ""
+ , "Header 2"
+ , "--------"
+ , ""
+ , "Header 3"
+ , "~~~~~~~~"
+ , ""
+ , "Header 2"
+ , "--------"]
+ , test (purely (writeRST def{ writerTemplate = Just "$body$\n" }) . toPandoc)
+ "minimal heading levels" $
+ header 2 (text "Header 1") <>
+ header 3 (text "Header 2") <>
+ header 2 (text "Header 1") <>
+ header 4 (text "Header 2") <>
+ header 5 (text "Header 3") <>
+ header 3 (text "Header 2") =?>
+ unlines
+ [ "Header 1"
+ , "========"
+ , ""
+ , "Header 2"
+ , "--------"
+ , ""
+ , "Header 1"
+ , "========"
+ , ""
+ , "Header 2"
+ , "--------"
+ , ""
+ , "Header 3"
+ , "~~~~~~~~"
+ , ""
+ , "Header 2"
+ , "--------"]
+ ]
+ ]
diff --git a/test/Tests/Writers/TEI.hs b/test/Tests/Writers/TEI.hs
new file mode 100644
index 000000000..fa372909f
--- /dev/null
+++ b/test/Tests/Writers/TEI.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.TEI (tests) where
+
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Arbitrary ()
+import Text.Pandoc.Builder
+
+{-
+ "my test" =: X =?> Y
+
+is shorthand for
+
+ test html "my test" $ X =?> Y
+
+which is in turn shorthand for
+
+ test html "my test" (X,Y)
+-}
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> TestTree
+(=:) = test (purely (writeTEI def) . toPandoc)
+
+tests :: [TestTree]
+tests = [ testGroup "block elements"
+ ["para" =: para "Lorem ipsum cetera."
+ =?> "<p>Lorem ipsum cetera.</p>"
+ ]
+ , testGroup "inlines"
+ [
+ "Emphasis" =: emph "emphasized"
+ =?> "<p><hi rendition=\"simple:italic\">emphasized</hi></p>"
+ ,"SingleQuoted" =: singleQuoted (text "quoted material")
+ =?> "<p><quote>quoted material</quote></p>"
+ ,"DoubleQuoted" =: doubleQuoted (text "quoted material")
+ =?> "<p><quote>quoted material</quote></p>"
+ ,"NestedQuoted" =: doubleQuoted (singleQuoted (text "quoted material"))
+ =?> "<p><quote><quote>quoted material</quote></quote></p>"
+ ]
+ ]
diff --git a/tests/bodybg.gif b/test/bodybg.gif
index 5f448a16f..5f448a16f 100644
--- a/tests/bodybg.gif
+++ b/test/bodybg.gif
Binary files differ
diff --git a/test/command/1166.md b/test/command/1166.md
new file mode 100644
index 000000000..756a065db
--- /dev/null
+++ b/test/command/1166.md
@@ -0,0 +1,48 @@
+See #1166 and <http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#simple-tables>.
+
+```
+% pandoc -f rst -t html5
+===== =====
+col 1 col 2
+===== =====
+1 Second column of row 1.
+2 Second column of row 2.
+ Second line of paragraph.
+3 - Second column of row 3.
+
+ - Second item in bullet
+ list (row 3, column 2).
+\ Row 4; column 1 will be empty.
+===== =====
+^D
+<table>
+<thead>
+<tr class="header">
+<th>col 1</th>
+<th>col 2</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>1</td>
+<td>Second column of row 1.</td>
+</tr>
+<tr class="even">
+<td><p>2</p></td>
+<td><p>Second column of row 2. Second line of paragraph.</p></td>
+</tr>
+<tr class="odd">
+<td><p>3</p></td>
+<td><ul>
+<li>Second column of row 3.</li>
+<li>Second item in bullet list (row 3, column 2).</li>
+</ul></td>
+</tr>
+<tr class="even">
+<td></td>
+<td>Row 4; column 1 will be empty.</td>
+</tr>
+</tbody>
+</table>
+```
+
diff --git a/test/command/1279.md b/test/command/1279.md
new file mode 100644
index 000000000..c8396f217
--- /dev/null
+++ b/test/command/1279.md
@@ -0,0 +1,19 @@
+```
+pandoc -s -t markdown
+---
+author: 'John Doe[^1]'
+date: 2014
+title: My Article
+---
+
+[^1]: Dept. of This and That
+^D
+---
+author: 'John Doe[^1]'
+date: 2014
+title: My Article
+---
+
+[^1]: Dept. of This and That
+```
+
diff --git a/test/command/1390.md b/test/command/1390.md
new file mode 100644
index 000000000..ffd2cef8d
--- /dev/null
+++ b/test/command/1390.md
@@ -0,0 +1,20 @@
+```
+% pandoc -f latex -t native
+\newcommand\foo{+}
+Testing: $\mu\foo\eta$.
+^D
+[Para [Str "Testing:",Space,Math InlineMath "\\mu+\\eta",Str "."]]
+```
+
+<!-- It would be nice to handle this case, but I don't
+know how:
+
+```
+% pandoc -f latex -t native
+\newcommand{\vecx}{a + b}
+$\hat\vecx$
+^D
+[Para [Math InlineMath "\\hat{a+b}"]]
+```
+-->
+
diff --git a/test/command/1592.md b/test/command/1592.md
new file mode 100644
index 000000000..54e59137b
--- /dev/null
+++ b/test/command/1592.md
@@ -0,0 +1,49 @@
+```
+% pandoc -t native
+[hi]{.smallcaps}
+^D
+[Para [SmallCaps [Str "hi"]]]
+```
+
+```
+% pandoc -t native
+[hi]{style="font-variant: small-caps;"}
+^D
+[Para [SmallCaps [Str "hi"]]]
+```
+
+```
+% pandoc -t native
+<span class="smallcaps">hi</span>
+^D
+[Para [SmallCaps [Str "hi"]]]
+```
+
+```
+% pandoc -f html -t native
+<p><span class="smallcaps">hi</span></p>
+^D
+[Para [SmallCaps [Str "hi"]]]
+```
+
+```
+% pandoc -f html -t native
+<p><span style="font-variant:small-caps">hi</span></p>
+^D
+[Para [SmallCaps [Str "hi"]]]
+```
+
+```
+% pandoc -f native -t html
+[Para [SmallCaps [Str "hi"]]]
+^D
+<p><span class="smallcaps">hi</span></p>
+```
+
+```
+pandoc -f native -t markdown
+[Para [SmallCaps [Str "hi"]]]
+^D
+[hi]{.smallcaps}
+```
+
diff --git a/test/command/1629.md b/test/command/1629.md
new file mode 100644
index 000000000..34d529b0d
--- /dev/null
+++ b/test/command/1629.md
@@ -0,0 +1,10 @@
+```
+% pandoc -t latex --listings
+bla bla `a % b`
+
+*bla bla `a % b`*
+^D
+bla bla \passthrough{\lstinline!a \% b!}
+
+\emph{bla bla \passthrough{\lstinline!a \% b!}}
+```
diff --git a/test/command/168.md b/test/command/168.md
new file mode 100644
index 000000000..43c3b865a
--- /dev/null
+++ b/test/command/168.md
@@ -0,0 +1,43 @@
+```
+% pandoc -t native
+:::::::::: warning ::::::::::::
+This is the warning!
+
+1. list
+2. another
+
+::: {#myid .class key=val}
+nested div
+:::
+:::::::::::::::::::::::::::::::
+^D
+[Div ("",["warning"],[])
+ [Para [Str "This",Space,Str "is",Space,Str "the",Space,Str "warning!"]
+ ,OrderedList (1,Decimal,Period)
+ [[Plain [Str "list"]]
+ ,[Plain [Str "another"]]]
+ ,Div ("myid",["class"],[("key","val")])
+ [Para [Str "nested",Space,Str "div"]]]]
+```
+
+```
+% pandoc -t native
+foo
+:::
+bar
+^D
+[Para [Str "foo",SoftBreak,Str ":::",SoftBreak,Str "bar"]]
+```
+
+```
+% pandoc -t native
+::::: Warning
+Here is a paragraph.
+
+And another.
+:::::
+^D
+[Div ("",["Warning"],[])
+ [Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "paragraph."]
+ ,Para [Str "And",Space,Str "another."]]]
+```
diff --git a/test/command/1710.md b/test/command/1710.md
new file mode 100644
index 000000000..d14f1217f
--- /dev/null
+++ b/test/command/1710.md
@@ -0,0 +1,89 @@
+```
+% pandoc -t revealjs
+# Slide one
+
+<div class="columns">
+<div class="column" width="40%">
+- a
+- b
+</div>
+<div class="column" width="40%">
+- c
+- d
+</div>
+<div class="column" width="10%">
+ok
+</div>
+</div>
+^D
+<section id="slide-one" class="slide level1">
+<h1>Slide one</h1>
+<div class="columns">
+<div class="column" style="width:40%;">
+<ul>
+<li>a</li>
+<li>b</li>
+</ul>
+</div><div class="column" style="width:40%;">
+<ul>
+<li>c</li>
+<li>d</li>
+</ul>
+</div><div class="column" style="width:10%;">
+<p>ok</p>
+</div>
+</div>
+</section>
+```
+
+```
+% pandoc -t beamer
+# Slide one
+
+<div class="columns">
+<div class="column" width="40%">
+- a
+- b
+</div>
+<div class="column" width="40%">
+- c
+- d
+</div>
+<div class="column" width="10%">
+ok
+</div>
+</div>
+^D
+\begin{frame}{%
+\protect\hypertarget{slide-one}{%
+Slide one}}
+
+\begin{columns}[T]
+\begin{column}{0.40\textwidth}
+\begin{itemize}
+\tightlist
+\item
+ a
+\item
+ b
+\end{itemize}
+\end{column}
+
+\begin{column}{0.40\textwidth}
+\begin{itemize}
+\tightlist
+\item
+ c
+\item
+ d
+\end{itemize}
+\end{column}
+
+\begin{column}{0.10\textwidth}
+ok
+\end{column}
+\end{columns}
+
+\end{frame}
+```
+
diff --git a/test/command/1718.md b/test/command/1718.md
new file mode 100644
index 000000000..7e07bf1e9
--- /dev/null
+++ b/test/command/1718.md
@@ -0,0 +1,11 @@
+```
+% pandoc -t native
+Note[^1].
+
+[^1]: the first note.
+
+[^2]: the second, unused, note.
+^D
+[WARNING] Note with key '2' defined at line 5 column 1 but not used.
+[Para [Str "Note",Note [Para [Str "the",Space,Str "first",Space,Str "note."]],Str "."]]
+```
diff --git a/test/command/1745.md b/test/command/1745.md
new file mode 100644
index 000000000..cf987c20f
--- /dev/null
+++ b/test/command/1745.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f latex+auto_identifiers -t html
+\section{Six favourite beers}
+\subsection{Jovaru Alus}\label{jovaru-alus}
+\section{Farmhouse brewers}
+\subsection{Jovaru Alus}
+^D
+<h1 id="six-favourite-beers">Six favourite beers</h1>
+<h2 id="jovaru-alus">Jovaru Alus</h2>
+<h1 id="farmhouse-brewers">Farmhouse brewers</h1>
+<h2 id="jovaru-alus-1">Jovaru Alus</h2>
+```
+
diff --git a/test/command/1773.md b/test/command/1773.md
new file mode 100644
index 000000000..b93267287
--- /dev/null
+++ b/test/command/1773.md
@@ -0,0 +1,6 @@
+```
+% pandoc -f latex+raw_tex -t native
+\noindent hi
+^D
+[Para [RawInline (Format "latex") "\\noindent ",Str "hi"]]
+```
diff --git a/test/command/1841.md b/test/command/1841.md
new file mode 100644
index 000000000..408f224bd
--- /dev/null
+++ b/test/command/1841.md
@@ -0,0 +1,42 @@
+```
+% pandoc
+<table>
+<tr>
+<td> *one*</td>
+<td> [a link](http://google.com)</td>
+</tr>
+</table>
+^D
+<table>
+<tr>
+<td>
+<em>one</em>
+</td>
+<td>
+<a href="http://google.com">a link</a>
+</td>
+</tr>
+</table>
+```
+
+```
+% pandoc
+<table>
+ <tr>
+ <td>*one*</td>
+ <td>[a link](http://google.com)</td>
+ </tr>
+</table>
+^D
+<table>
+<tr>
+<td>
+<em>one</em>
+</td>
+<td>
+<a href="http://google.com">a link</a>
+</td>
+</tr>
+</table>
+```
+
diff --git a/test/command/1881.md b/test/command/1881.md
new file mode 100644
index 000000000..c0902de71
--- /dev/null
+++ b/test/command/1881.md
@@ -0,0 +1,55 @@
+```
+% pandoc -f html -t native
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<thead>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th>Default</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td>12</td>
+</tr>
+</tbody>
+</table>
+^D
+[Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]]]
+```
+
+```
+% pandoc -f html -t native
+<table>
+<tr class="odd">
+<td style="text-align: right;">12</td>
+<td style="text-align:left;">12</td>
+<td style="text-align: center">12</td>
+<td style="text-align: right;">12</td>
+</tr>
+</table>
+^D
+[Table [] [AlignRight,AlignLeft,AlignCenter,AlignRight] [0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]]]
+```
+
diff --git a/test/command/1905.md b/test/command/1905.md
new file mode 100644
index 000000000..744d1c4d9
--- /dev/null
+++ b/test/command/1905.md
@@ -0,0 +1,30 @@
+```
+% pandoc -f latex-auto_identifiers -t html
+\chapter{chapone}
+\part{partone}
+\chapter{chaptwo}
+\section{secone}
+^D
+<h2>chapone</h2>
+<h1>partone</h1>
+<h2>chaptwo</h2>
+<h3>secone</h3>
+```
+
+```
+% pandoc -f latex-auto_identifiers -t html
+\chapter{chapone}
+\chapter{chaptwo}
+\section{secone}
+^D
+<h1>chapone</h1>
+<h1>chaptwo</h1>
+<h2>secone</h2>
+```
+
+```
+% pandoc -f latex-auto_identifiers -t html
+\section{secone}
+^D
+<h1>secone</h1>
+```
diff --git a/test/command/2118.md b/test/command/2118.md
new file mode 100644
index 000000000..27b3723d3
--- /dev/null
+++ b/test/command/2118.md
@@ -0,0 +1,11 @@
+```
+% pandoc -f latex -t native
+\newcommand{\inclgraph}{\includegraphics[width=0.8\textwidth]}
+\begin{figure}[ht]
+ \inclgraph{setminus.png}
+ \caption{Set subtraction}
+ \label{fig:setminus}
+\end{figure}
+^D
+[Para [Image ("",[],[("width","80%")]) [Str "Set",Space,Str "subtraction",Span ("",[],[("label","fig:setminus")]) []] ("setminus.png","fig:")]]
+```
diff --git a/test/command/2228.md b/test/command/2228.md
new file mode 100644
index 000000000..589a2350e
--- /dev/null
+++ b/test/command/2228.md
@@ -0,0 +1,6 @@
+```
+% pandoc -f markdown+smart -t latex+smart
+*foo*'s 'foo'
+^D
+\emph{foo}'s `foo'
+```
diff --git a/test/command/2378.md b/test/command/2378.md
new file mode 100644
index 000000000..801c168ad
--- /dev/null
+++ b/test/command/2378.md
@@ -0,0 +1,27 @@
+Ensure that we don't get duplicated footnotes when
+a note occurs in a header cell and `\endfirsthead`
+is used.
+
+```
+% pandoc -t latex
+| x | y[^fn] |
+|-|-|
+|1|2|
+: a table
+
+[^fn]: a footnote
+^D
+\begin{longtable}[]{@{}ll@{}}
+\caption{a table}\tabularnewline
+\toprule
+x & y\footnote{a footnote}\tabularnewline
+\midrule
+\endfirsthead
+\toprule
+x & y{}\tabularnewline
+\midrule
+\endhead
+1 & 2\tabularnewline
+\bottomrule
+\end{longtable}
+```
diff --git a/test/command/2397.md b/test/command/2397.md
new file mode 100644
index 000000000..34d201362
--- /dev/null
+++ b/test/command/2397.md
@@ -0,0 +1,9 @@
+```
+% pandoc -f markdown_mmd
+# Chapter 1: A long name of chapter [Chapter 1]
+
+See [Chapter 1].
+^D
+<h1 id="chapter1">Chapter 1: A long name of chapter</h1>
+<p>See <a href="#chapter1">Chapter 1</a>.</p>
+```
diff --git a/test/command/2434.md b/test/command/2434.md
new file mode 100644
index 000000000..4f12b6f56
--- /dev/null
+++ b/test/command/2434.md
@@ -0,0 +1,59 @@
+```
+% pandoc -t opendocument
+1. a
+2. b
+ 1. alpha
+ 2. beta
+ * gamma
+^D
+<text:list text:style-name="L1">
+ <text:list-item>
+ <text:p text:style-name="P1">a</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P1">b</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P1">alpha</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P1">beta</text:p>
+ </text:list-item>
+ </text:list>
+ <text:list text:style-name="L2">
+ <text:list-item>
+ <text:p text:style-name="P2">gamma</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+</text:list>
+```
+
+```
+% pandoc -t opendocument
+(@) text
+
+ some text
+
+ a) sub item 1
+ b) sub item 2
+
+ more text -- this line is missing in the odt output
+^D
+<text:list text:style-name="L1">
+ <text:list-item>
+ <text:p text:style-name="P1">text</text:p>
+ <text:p text:style-name="P1">some text</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P1">sub item 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P1">sub item 2</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p text:style-name="P1">more text – this line is missing in the
+ odt output</text:p>
+ </text:list-item>
+</text:list>
+```
diff --git a/test/command/2549.md b/test/command/2549.md
new file mode 100644
index 000000000..8f4aea852
--- /dev/null
+++ b/test/command/2549.md
@@ -0,0 +1,38 @@
+```
+% pandoc -f latex -t native
+\hypertarget{foo}{%
+\section{A section}\label{foo}
+}
+^D
+[Header 1 ("foo",[],[]) [Str "A",Space,Str "section"]]
+```
+
+```
+% pandoc -f latex -t native
+\hypertarget{bar}{%
+\section{A section}\label{foo}
+}
+^D
+[Div ("bar",[],[])
+ [Header 1 ("foo",[],[]) [Str "A",Space,Str "section"]]]
+```
+
+```
+% pandoc -f latex -t native
+Bar \hypertarget{foo}{Foo}
+^D
+[Para [Str "Bar",Space,Span ("foo",[],[]) [Str "Foo"]]]
+```
+
+```
+% pandoc -f latex -t native
+\hypertarget{foo}{%
+\begin{verbatim}
+bar
+\end{verbatim}
+}
+^D
+[Div ("foo",[],[])
+ [CodeBlock ("",[],[]) "bar"]]
+```
+
diff --git a/test/command/2552.md b/test/command/2552.md
new file mode 100644
index 000000000..90a3a381c
--- /dev/null
+++ b/test/command/2552.md
@@ -0,0 +1,14 @@
+```
+% pandoc --strip-comments
+Foo
+
+bar
+
+<!-- comment -->
+
+baz<!-- bim -->boop
+^D
+<p>Foo</p>
+<p>bar</p>
+<p>bazboop</p>
+```
diff --git a/test/command/256.md b/test/command/256.md
new file mode 100644
index 000000000..08e483e5c
--- /dev/null
+++ b/test/command/256.md
@@ -0,0 +1,12 @@
+```
+% pandoc --abbreviations=command/abbrevs -t native
+Foo. bar baz h.k. and e.g. and Mr. Brown.
+^D
+[Para [Str "Foo.\160bar",Space,Str "baz",Space,Str "h.k.\160and",Space,Str "e.g.",Space,Str "and",Space,Str "Mr.",Space,Str "Brown."]]
+```
+```
+% pandoc -t native
+Foo. bar baz h.k. and e.g. and Mr. Brown.
+^D
+[Para [Str "Foo.",Space,Str "bar",Space,Str "baz",Space,Str "h.k.",Space,Str "and",Space,Str "e.g.\160and",Space,Str "Mr.\160Brown."]]
+```
diff --git a/test/command/2602.md b/test/command/2602.md
new file mode 100644
index 000000000..5ed4b581c
--- /dev/null
+++ b/test/command/2602.md
@@ -0,0 +1,18 @@
+```
+% pandoc
+[a] [b]
+
+[b]: url
+^D
+<p>[a] <a href="url">b</a></p>
+```
+
+```
+% pandoc -f markdown+spaced_reference_links
+[a] [b]
+
+[b]: url
+^D
+<p><a href="url">a</a></p>
+```
+
diff --git a/test/command/2606.md b/test/command/2606.md
new file mode 100644
index 000000000..53eaa0d06
--- /dev/null
+++ b/test/command/2606.md
@@ -0,0 +1,58 @@
+```
+% pandoc -f mediawiki -t html5
+{|
+| * hello
+|}
+^D
+<table>
+<tbody>
+<tr class="odd">
+<td><p>* hello</p></td>
+</tr>
+</tbody>
+</table>
+```
+
+```
+% pandoc -f mediawiki -t html5
+{|
+|
+* hello
+|}
+^D
+<table>
+<tbody>
+<tr class="odd">
+<td><ul>
+<li>hello</li>
+</ul></td>
+</tr>
+</tbody>
+</table>
+```
+
+```
+% pandoc -f mediawiki -t html5
+{|
+|
+ * hello
+|}
+^D
+<table>
+<tbody>
+<tr class="odd">
+<td><p><code>* hello</code></p></td>
+</tr>
+</tbody>
+</table>
+```
+
+```
+% pandoc -f mediawiki -t html5
+* * hi
+^D
+<ul>
+<li>* hi</li>
+</ul>
+```
+
diff --git a/test/command/262.md b/test/command/262.md
new file mode 100644
index 000000000..bda2acb35
--- /dev/null
+++ b/test/command/262.md
@@ -0,0 +1,26 @@
+```
+% pandoc -f rst
+`hello`_ and `goodbye`_
+
+.. _hello:
+.. _goodbye: example.com
+^D
+<p><a href="example.com">hello</a> and <a href="example.com">goodbye</a></p>
+```
+
+```
+% pandoc -f rst
+`hello`_ `goodbye`_
+
+.. _hello:
+.. _goodbye:
+
+paragraph
+^D
+<p><a href="#hello">hello</a> <a href="#goodbye">goodbye</a></p>
+<div id="hello">
+<div id="goodbye">
+<p>paragraph</p>
+</div>
+</div>
+```
diff --git a/test/command/2649.md b/test/command/2649.md
new file mode 100644
index 000000000..8f594cfe1
--- /dev/null
+++ b/test/command/2649.md
@@ -0,0 +1,106 @@
+```
+% pandoc -f mediawiki -t html5
+{| class="wikitable" style="line-height: 1.0"
+
+|- bgcolor="#efefef"
+|}
+^D
+<table>
+<tbody>
+<tr class="odd">
+</tr>
+</tbody>
+</table>
+```
+
+```
+% pandoc -f mediawiki -t html5
+{| border="4" cellspacing="2" cellpadding="0" WIDTH="100%"
+|-----
+| peildatum Simbase || november 2005 || '''uitslagen Flohrgambiet''' ||
+|-----
+| totaal aantal partijen Simbase || 7.316.773
+| wit wint || 53%
+|-----
+| percentage (en partijen) Flohrgambiet
+| 0.023 % (1.699) || zwart wint || 27%
+|-----
+| percentage Flohrgambiet in aug 2003
+| 0.035 % || remise || 20%
+|}
+^D
+<table>
+<tbody>
+<tr class="odd">
+<td><p>peildatum Simbase</p></td>
+<td><p>november 2005</p></td>
+<td><p><strong>uitslagen Flohrgambiet</strong></p></td>
+<td></td>
+</tr>
+<tr class="even">
+<td><p>totaal aantal partijen Simbase</p></td>
+<td><p>7.316.773</p></td>
+<td><p>wit wint</p></td>
+<td><p>53%</p></td>
+</tr>
+<tr class="odd">
+<td><p>percentage (en partijen) Flohrgambiet</p></td>
+<td><p>0.023 % (1.699)</p></td>
+<td><p>zwart wint</p></td>
+<td><p>27%</p></td>
+</tr>
+<tr class="even">
+<td><p>percentage Flohrgambiet in aug 2003</p></td>
+<td><p>0.035 %</p></td>
+<td><p>remise</p></td>
+<td><p>20%</p></td>
+</tr>
+</tbody>
+</table>
+```
+
+```
+% pandoc -f mediawiki -t html5
+{| class="wikitable" style="text-align:center; font-size:95%" valign="top" |
+! Plaats
+! Rijder
+! Aantal
+|-
+| 1
+|align=left| {{FR-VLAG}} [[Sébastien Loeb]] | 78
+|-
+| 2
+|align=left| {{FR-VLAG}} '''[[Sébastien Ogier]]'''
+| 38
+|-
+| 10
+|align=left| {{FI-VLAG}} [[Hannu Mikkola]]
+| 18
+|}
+^D
+<table>
+<tbody>
+<tr class="odd">
+<td></td>
+<td><p>Plaats</p></td>
+<td><p>Rijder</p></td>
+<td><p>Aantal</p></td>
+</tr>
+<tr class="even">
+<td><p>1</p></td>
+<td><p><a href="Sébastien_Loeb" title="wikilink">Sébastien Loeb</a></p></td>
+<td><p>78</p></td>
+</tr>
+<tr class="odd">
+<td><p>2</p></td>
+<td><p><strong><a href="Sébastien_Ogier" title="wikilink">Sébastien Ogier</a></strong></p></td>
+<td><p>38</p></td>
+</tr>
+<tr class="even">
+<td><p>10</p></td>
+<td><p><a href="Hannu_Mikkola" title="wikilink">Hannu Mikkola</a></p></td>
+<td><p>18</p></td>
+</tr>
+</tbody>
+</table>
+```
diff --git a/test/command/2662.md b/test/command/2662.md
new file mode 100644
index 000000000..543209053
--- /dev/null
+++ b/test/command/2662.md
@@ -0,0 +1,11 @@
+```
+% pandoc -t html -f rst --wrap=none
+.. image:: http://url.to.image/foo.png
+ :align: left
+ :height: 100px
+ :width: 200 px
+ :scale: 300 %
+ :alt: alternate text
+^D
+<p><img src="http://url.to.image/foo.png" alt="alternate text" class="align-left" width="600" height="300" /></p>
+```
diff --git a/test/command/2834.md b/test/command/2834.md
new file mode 100644
index 000000000..850c39254
--- /dev/null
+++ b/test/command/2834.md
@@ -0,0 +1,29 @@
+Nested grid tables.
+```
+% pandoc -f html -t markdown --columns=72
+<table>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td>some text</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+^D
++-----------------------------------------------------------------------+
+| +------------------------------------------------------------------+ |
+| | ----------- | |
+| | some text | |
+| | ----------- | |
+| +------------------------------------------------------------------+ |
++-----------------------------------------------------------------------+
+```
diff --git a/test/command/2874.md b/test/command/2874.md
new file mode 100644
index 000000000..1fb530dc1
--- /dev/null
+++ b/test/command/2874.md
@@ -0,0 +1,14 @@
+```
+% pandoc -f html -t latex
+<a></a>
+<br/>
+^D
+{}~\\
+```
+
+```
+% pandoc -f html -t latex
+<a name="foo"></a><br/>
+^D
+\protect\hypertarget{foo}{}{}~\\
+```
diff --git a/test/command/2994.md b/test/command/2994.md
new file mode 100644
index 000000000..b6b2d1ed9
--- /dev/null
+++ b/test/command/2994.md
@@ -0,0 +1,10 @@
+```
+% pandoc -f markdown -t docx -o - | pandoc -f docx -t markdown --track-changes=all
+I want [I left a comment.]{.comment-start id="0"
+author="Jesse Rosenthal" date="2016-05-09T16:13:00Z"}some text to have a
+comment []{.comment-end id="0"}on it.
+^D
+I want [I left a comment.]{.comment-start id="0"
+author="Jesse Rosenthal" date="2016-05-09T16:13:00Z"}some text to have a
+comment []{.comment-end id="0"}on it.
+```
diff --git a/test/command/3113.md b/test/command/3113.md
new file mode 100644
index 000000000..5ca171d97
--- /dev/null
+++ b/test/command/3113.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f latex -t native
+\begin{eqnarray}
+A&=&B,\\
+C&=&D,\\
+%\end{eqnarray}
+%\begin{eqnarray}
+E&=&F
+\end{eqnarray}
+^D
+[Para [Math DisplayMath "\\begin{aligned}\nA&=&B,\\\\\nC&=&D,\\\\\n%\\end{eqnarray}\n%\\begin{eqnarray}\nE&=&F\\end{aligned}"]]
+```
+
diff --git a/test/command/3236.md b/test/command/3236.md
new file mode 100644
index 000000000..1d1a9b2c3
--- /dev/null
+++ b/test/command/3236.md
@@ -0,0 +1,9 @@
+```
+pandoc -f latex -t native
+\newcommand{\mycolor}{red}
+
+\includegraphics[width=17cm]{\mycolor /header}
+Magnificent \mycolor{} header.
+^D
+[Para [Image ("",[],[("width","17cm")]) [Str "image"] ("red/header",""),SoftBreak,Str "Magnificent",Space,Str "red",Space,Str "header."]]
+```
diff --git a/test/command/3257.md b/test/command/3257.md
new file mode 100644
index 000000000..31d9426ee
--- /dev/null
+++ b/test/command/3257.md
@@ -0,0 +1,13 @@
+```
+% pandoc -t native
+(i<j)
+^D
+[Para [Str "(i<j)"]]
+```
+
+```
+% pandoc -t native
+i<j-1, j>k
+^D
+[Para [Str "i<j-1,",Space,Str "j>k"]]
+```
diff --git a/test/command/3309.md b/test/command/3309.md
new file mode 100644
index 000000000..083ac53c9
--- /dev/null
+++ b/test/command/3309.md
@@ -0,0 +1,52 @@
+Certain environments should be treated as inline unless they
+are surrounded by blank lines:
+
+```
+% pandoc -t latex --wrap=preserve
+Lorem ipsum dolor sit amet,
+
+\begin{equation}
+E = mc^2,
+\end{equation}
+
+consectetur adipiscing elit.
+^D
+Lorem ipsum dolor sit amet,
+
+\begin{equation}
+E = mc^2,
+\end{equation}
+
+consectetur adipiscing elit.
+```
+
+```
+% pandoc -t latex --wrap=preserve
+Lorem ipsum dolor sit amet,
+\begin{equation}
+E = mc^2,
+\end{equation}
+consectetur adipiscing elit.
+^D
+Lorem ipsum dolor sit amet,
+\begin{equation}
+E = mc^2,
+\end{equation}
+consectetur adipiscing elit.
+```
+
+```
+% pandoc -t latex --wrap=preserve
+The formula
+\begin{math}
+x = y
+\end{math}
+should be inline.
+^D
+The formula
+\begin{math}
+x = y
+\end{math}
+should be inline.
+```
+
diff --git a/test/command/3314.md b/test/command/3314.md
new file mode 100644
index 000000000..064b04cbd
--- /dev/null
+++ b/test/command/3314.md
@@ -0,0 +1,34 @@
+See #3315 and <http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#simple-tables>.
+
+```
+% pandoc -f org -t html5
++-----------+-------+----------+
+| First | 12.0 | Example |
+| | | row |
+| | | spanning |
+| | | lines |
++-----------+-------+----------+
+| Second | 5.0 | Another |
++-----------+-------+----------+
+^D
+<table style="width:43%;">
+<colgroup>
+<col style="width: 16%" />
+<col style="width: 11%" />
+<col style="width: 15%" />
+</colgroup>
+<tbody>
+<tr class="odd">
+<td>First</td>
+<td>12.0</td>
+<td>Example row spanning lines</td>
+</tr>
+<tr class="even">
+<td>Second</td>
+<td>5.0</td>
+<td>Another</td>
+</tr>
+</tbody>
+</table>
+```
+
diff --git a/test/command/3337.md b/test/command/3337.md
new file mode 100644
index 000000000..7ba14dcbb
--- /dev/null
+++ b/test/command/3337.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f html -t markdown
+<table>
+<tr><td>a</td></tr>
+<tr><td>1</td><td>2</td></tr>
+</table>
+^D
+ --- ---
+ a
+ 1 2
+ --- ---
+```
+
diff --git a/test/command/3348.md b/test/command/3348.md
new file mode 100644
index 000000000..1457373c8
--- /dev/null
+++ b/test/command/3348.md
@@ -0,0 +1,17 @@
+```
+% pandoc -t native --columns=72
+ ----- ------------------------------------------------
+ foo bar
+
+ foo this is a long
+ line of text
+ ----- ------------------------------------------------
+^D
+[Table [] [AlignRight,AlignLeft] [8.333333333333333e-2,0.6666666666666666]
+ [[]
+ ,[]]
+ [[[Plain [Str "foo"]]
+ ,[Plain [Str "bar"]]]
+ ,[[Plain [Str "foo"]]
+ ,[Plain [Str "this",Space,Str "is",Space,Str "a",Space,Str "long",SoftBreak,Str "line",Space,Str "of",Space,Str "text"]]]]]
+```
diff --git a/test/command/3401.md b/test/command/3401.md
new file mode 100644
index 000000000..99528553a
--- /dev/null
+++ b/test/command/3401.md
@@ -0,0 +1,19 @@
+See #3401 and <http://orgmode.org/manual/Macro-replacement.html>
+
+```
+% pandoc -f org -t native
+#+MACRO: HELLO /Hello, $1/
+{{{HELLO(World)}}}
+^D
+[Para [Emph [Str "Hello,",Space,Str "World"]]]
+```
+
+Inverted argument order
+
+```
+% pandoc -f org -t native
+#+MACRO: A $2,$1
+{{{A(1,2)}}}
+^D
+[Para [Str "2,1"]]
+```
diff --git a/test/command/3407.md b/test/command/3407.md
new file mode 100644
index 000000000..3160d1263
--- /dev/null
+++ b/test/command/3407.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f native -t rst
+[Para [Span ("",[],[("role","foo")]) [Str "text"]]]
+^D
+:foo:`text`
+```
+
+```
+% pandoc -f rst -t native
+:foo:`text`
+^D
+[Para [Span ("",[],[("role","foo")]) [Str "text"]]]
+```
diff --git a/test/command/3422.md b/test/command/3422.md
new file mode 100644
index 000000000..19f1f4462
--- /dev/null
+++ b/test/command/3422.md
@@ -0,0 +1,9 @@
+See #3422
+
+```
+% pandoc -t latex --listings
+`int main(int argc, const char *argv[]);`{.c}
+^D
+\passthrough{\lstinline[language=C]!int main(int argc, const char *argv[]);!}
+```
+
diff --git a/test/command/3432.md b/test/command/3432.md
new file mode 100644
index 000000000..7264d22c3
--- /dev/null
+++ b/test/command/3432.md
@@ -0,0 +1,289 @@
+List-table with header-rows and widths options.
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+ :widths: 15 10 30
+ :header-rows: 1
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<colgroup>
+<col style="width: 27%" />
+<col style="width: 18%" />
+<col style="width: 54%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th>Treat</th>
+<th>Quantity</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+List-table whose widths is "auto".
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+ :header-rows: 1
+ :widths: auto
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<thead>
+<tr class="header">
+<th>Treat</th>
+<th>Quantity</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+
+List-table with header-rows which is bigger than 1. Only the first row is treated as a header.
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+ :header-rows: 2
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<thead>
+<tr class="header">
+<th>Treat</th>
+<th>Quantity</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+List-table without header-rows.
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+List-table with empty cells. You need a space after '-', otherwise the row will disapear. Parser for Bulletlists causes this ristriction.
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+ :header-rows: 2
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ -
+ * - Crunchy Frog
+ -
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<thead>
+<tr class="header">
+<th>Treat</th>
+<th>Quantity</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td></td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td></td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+List-table with a cell having a bulletlist
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+
+ * - Albatross
+ - 2.99
+ - + On a stick!
+ + In a cup!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td><ul>
+<li>On a stick!</li>
+<li>In a cup!</li>
+</ul></td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
diff --git a/test/command/3432a.md b/test/command/3432a.md
new file mode 100644
index 000000000..5f25bce60
--- /dev/null
+++ b/test/command/3432a.md
@@ -0,0 +1,19 @@
+```
+% pandoc -f rst
+* - a
+ - b
+* - c
+ - d
+^D
+<ul>
+<li><ul>
+<li>a</li>
+<li>b</li>
+</ul></li>
+<li><ul>
+<li>c</li>
+<li>d</li>
+</ul></li>
+</ul>
+```
+
diff --git a/test/command/3450.md b/test/command/3450.md
new file mode 100644
index 000000000..5b35e1d9e
--- /dev/null
+++ b/test/command/3450.md
@@ -0,0 +1,12 @@
+```
+% pandoc -fmarkdown-implicit_figures
+![image](lalune.jpg){height=2em}
+^D
+<p><img src="lalune.jpg" alt="image" style="height:2em" /></p>
+```
+```
+% pandoc -fmarkdown-implicit_figures -t latex
+![image](lalune.jpg){height=2em}
+^D
+\includegraphics[width=\textwidth,height=2em]{lalune.jpg}
+```
diff --git a/test/command/3475.md b/test/command/3475.md
new file mode 100644
index 000000000..afba4ea3c
--- /dev/null
+++ b/test/command/3475.md
@@ -0,0 +1,45 @@
+RST implicit internal links to headers:
+
+```
+pandoc -f rst
+Years
+-----
+
+Years_
+^D
+<h1 id="years">Years</h1>
+<p><a href="#years">Years</a></p>
+```
+
+```
+pandoc -f rst
+Years_
+
+Years
+-----
+^D
+<p><a href="#years">Years</a></p>
+<h1 id="years">Years</h1>
+```
+
+```
+pandoc -f rst
+Years and years
+---------------
+
+`Years and years`_
+^D
+<h1 id="years-and-years">Years and years</h1>
+<p><a href="#years-and-years">Years and years</a></p>
+```
+
+```
+pandoc -f rst
+Years and *years*
+-----------------
+
+`Years and years`_
+^D
+<h1 id="years-and-years">Years and <em>years</em></h1>
+<p><a href="#years-and-years">Years and years</a></p>
+```
diff --git a/test/command/3487.md b/test/command/3487.md
new file mode 100644
index 000000000..1d475676f
--- /dev/null
+++ b/test/command/3487.md
@@ -0,0 +1,11 @@
+```
+% pandoc -f html -t markdown
+Some text
+<ul>
+<li>element</li>
+</ul>
+^D
+Some text
+
+- element
+```
diff --git a/test/command/3494.md b/test/command/3494.md
new file mode 100644
index 000000000..249973fb3
--- /dev/null
+++ b/test/command/3494.md
@@ -0,0 +1,40 @@
+```
+% pandoc -f latex --quiet
+\begin{table}[h!]
+\begin{tabular}{r|l|l}
+
+ {\large \textbf{ﺍ}} && \\
+ \textbf{ﺄﺤﺴﻨﺘـ(ﻭﺍ) IV} & \em{ʾaḥsant(ū)} & thank you \\
+ \newpage
+ \emph{blah} & \emph{blah} & \emph{blah} \\
+ blah & blah & blah \\
+
+\end{tabular}
+\end{table}
+^D
+<table>
+<tbody>
+<tr class="odd">
+<td style="text-align: right;"><span><strong>ﺍ</strong></span></td>
+<td style="text-align: left;"></td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: right;"><strong>ﺄﺤﺴﻨﺘـ(ﻭﺍ) IV</strong></td>
+<td style="text-align: left;"><em><span>ʾaḥsant(ū)</span></em></td>
+<td style="text-align: left;">thank you</td>
+</tr>
+<tr class="odd">
+<td style="text-align: right;"><p><em>blah</em></p></td>
+<td style="text-align: left;"><em>blah</em></td>
+<td style="text-align: left;"><em>blah</em></td>
+</tr>
+<tr class="even">
+<td style="text-align: right;">blah</td>
+<td style="text-align: left;">blah</td>
+<td style="text-align: left;">blah</td>
+</tr>
+</tbody>
+</table>
+```
+
diff --git a/test/command/3497.md b/test/command/3497.md
new file mode 100644
index 000000000..ca591cdd6
--- /dev/null
+++ b/test/command/3497.md
@@ -0,0 +1,51 @@
+Escape list markers at beginning of paragraph:
+
+```
+% pandoc -t markdown
+\* ok
+
+\+ ok
+
+\- ok
+
+1\. ok
+
+a\. ok
+^D
+\* ok
+
+\+ ok
+
+\- ok
+
+1\. ok
+
+a\. ok
+```
+
+Here we don't need to escape because there's no space:
+
+```
+% pandoc -t markdown
+\+ok
+
+\-ok
+
+1.ok
+^D
++ok
+
+-ok
+
+1.ok
+```
+
+Also escape things that might become line blocks or tables:
+
+```
+% pandoc -t markdown
+\| hi \|
+^D
+\| hi \|
+```
+
diff --git a/test/command/3499.md b/test/command/3499.md
new file mode 100644
index 000000000..ba9f03589
--- /dev/null
+++ b/test/command/3499.md
@@ -0,0 +1,18 @@
+Org-mode tables can't be on the same line as list markers:
+```
+% pandoc -f org
+- |something|
+-
+ |else|
+^D
+<ul>
+<li>|something|</li>
+<li><table>
+<tbody>
+<tr class="odd">
+<td>else</td>
+</tr>
+</tbody>
+</table></li>
+</ul>
+```
diff --git a/test/command/3510-export.latex b/test/command/3510-export.latex
new file mode 100644
index 000000000..6d8636322
--- /dev/null
+++ b/test/command/3510-export.latex
@@ -0,0 +1 @@
+\emph{Hello} \ No newline at end of file
diff --git a/test/command/3510-src.hs b/test/command/3510-src.hs
new file mode 100644
index 000000000..ad5744b80
--- /dev/null
+++ b/test/command/3510-src.hs
@@ -0,0 +1 @@
+putStrLn outString
diff --git a/test/command/3510-subdoc.org b/test/command/3510-subdoc.org
new file mode 100644
index 000000000..5bcc6678a
--- /dev/null
+++ b/test/command/3510-subdoc.org
@@ -0,0 +1,5 @@
+* Subsection
+
+Included text
+
+Lorem ipsum.
diff --git a/test/command/3510.md b/test/command/3510.md
new file mode 100644
index 000000000..7993db848
--- /dev/null
+++ b/test/command/3510.md
@@ -0,0 +1,20 @@
+See <http://orgmode.org/manual/Include-files.html>
+```
+% pandoc -f org -t native
+Text
+
+#+include: "command/3510-subdoc.org"
+
+#+INCLUDE: "command/3510-src.hs" src haskell
+#+INCLUDE: "command/3510-export.latex" export latex
+
+More text
+^D
+[Para [Str "Text"]
+,Header 1 ("subsection",[],[]) [Str "Subsection"]
+,Para [Str "Included",Space,Str "text"]
+,Plain [Str "Lorem",Space,Str "ipsum."]
+,CodeBlock ("",["haskell"],[]) "putStrLn outString\n"
+,RawBlock (Format "latex") "\\emph{Hello}"
+,Para [Str "More",Space,Str "text"]]
+```
diff --git a/test/command/3511.md b/test/command/3511.md
new file mode 100644
index 000000000..b8bcedbb0
--- /dev/null
+++ b/test/command/3511.md
@@ -0,0 +1,46 @@
+```
+% pandoc -t native
+- a
+ - b
+ - c
+
+- code
+
+1000. one
+
+ not continuation
+^D
+[BulletList
+ [[Plain [Str "a"]
+ ,BulletList
+ [[Plain [Str "b"]
+ ,BulletList
+ [[Plain [Str "c"]]]]]]
+ ,[CodeBlock ("",[],[]) "code"]]
+,OrderedList (1000,Decimal,Period)
+ [[Plain [Str "one"]]]
+,CodeBlock ("",[],[]) "not continuation"]
+```
+
+```
+% pandoc -t native -f markdown+four_space_rule
+- a
+ - b
+ - c
+
+- not code
+
+1000. one
+
+ continuation
+^D
+[BulletList
+ [[Plain [Str "a"]]
+ ,[Plain [Str "b"]
+ ,BulletList
+ [[Plain [Str "c"]]]]
+ ,[CodeBlock ("",[],[]) "not code"]]
+,OrderedList (1000,Decimal,Period)
+ [[Para [Str "one"]
+ ,Para [Str "continuation"]]]]
+```
diff --git a/test/command/3512.md b/test/command/3512.md
new file mode 100644
index 000000000..cf8c72e58
--- /dev/null
+++ b/test/command/3512.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f markdown-auto_identifiers
+#hi
+^D
+<p>#hi</p>
+```
+
+```
+% pandoc -f markdown-auto_identifiers-space_in_atx_header
+#hi
+^D
+<h1>hi</h1>
+```
diff --git a/test/command/3516.md b/test/command/3516.md
new file mode 100644
index 000000000..8c7e478d3
--- /dev/null
+++ b/test/command/3516.md
@@ -0,0 +1,51 @@
+Correctly handle empty row:
+```
+% pandoc -f markdown -t rst
++---+---+
+| 1 | 2 |
++---+---+
+| | |
++---+---+
+^D
++---+---+
+| 1 | 2 |
++---+---+
+| | |
++---+---+
+```
+
+Temporarily added these to figure out what is happening
+on Windows builds.
+```
+% pandoc -f markdown -t native
++---+---+
+| 1 | 2 |
++---+---+
+| | |
++---+---+
+^D
+[Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2]
+ [[]
+ ,[]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]]
+ ,[[]
+ ,[]]]]
+```
+
+```
+% pandoc -f native -t rst
+[Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2]
+ [[]
+ ,[]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]]
+ ,[[]
+ ,[]]]]
+^D
++---+---+
+| 1 | 2 |
++---+---+
+| | |
++---+---+
+```
diff --git a/test/command/3518.md b/test/command/3518.md
new file mode 100644
index 000000000..ec3322192
--- /dev/null
+++ b/test/command/3518.md
@@ -0,0 +1,6 @@
+```
+pandoc -f latex -t plain
+$\alpha^2 \cdot \alpha^{2+3} \equiv \alpha^7$
+^D
+α² ⋅ α² ⁺ ³ ≡ α⁷
+```
diff --git a/test/command/3526.md b/test/command/3526.md
new file mode 100644
index 000000000..e197bcf32
--- /dev/null
+++ b/test/command/3526.md
@@ -0,0 +1,14 @@
+```
+% pandoc -t rst
++--+---+
+| | |
++--+---+
+| | |
++--+---+
+^D
++---+---+
+| | |
++---+---+
+| | |
++---+---+
+```
diff --git a/test/command/3529.md b/test/command/3529.md
new file mode 100644
index 000000000..fdf42f68e
--- /dev/null
+++ b/test/command/3529.md
@@ -0,0 +1,15 @@
+```
+% pandoc -t markdown-simple_tables-pipe_tables-grid_tables+multiline_tables
+A B
+-- --
+7 8
+9 10
+^D
+ --------
+ A B
+ --- ----
+ 7 8
+
+ 9 10
+ --------
+```
diff --git a/test/command/3530.md b/test/command/3530.md
new file mode 100644
index 000000000..66393c856
--- /dev/null
+++ b/test/command/3530.md
@@ -0,0 +1,22 @@
+```
+% pandoc -f latex -t native
+\subfile{command/sub-file-chapter-1}
+\subfile{command/sub-file-chapter-2}
+^D
+[Header 1 ("chapter-1",[],[]) [Str "Chapter",Space,Str "1"]
+,Para [Str "This",Space,Str "is",Space,Str "Chapter",Space,Str "1,",Space,Str "provided",Space,Str "in",Space,Str "a",Space,Str "sub",Space,Str "file."]
+,Header 1 ("chapter-2",[],[]) [Str "Chapter",Space,Str "2"]
+,Para [Str "This",Space,Str "is",Space,Str "Chapter",Space,Str "2,",Space,Str "provided",Space,Str "in",Space,Str "a",Space,Str "second",Space,Str "sub",Space,Str "file."]]
+```
+
+```
+% pandoc -flatex+raw_tex -t native
+\subfile{command/sub-file-chapter-1}
+\subfile{command/sub-file-chapter-2}
+^D
+[Header 1 ("chapter-1",[],[]) [Str "Chapter",Space,Str "1"]
+,Para [Str "This",Space,Str "is",Space,Str "Chapter",Space,Str "1,",Space,Str "provided",Space,Str "in",Space,Str "a",Space,Str "sub",Space,Str "file."]
+,Header 1 ("chapter-2",[],[]) [Str "Chapter",Space,Str "2"]
+,Para [Str "This",Space,Str "is",Space,Str "Chapter",Space,Str "2,",Space,Str "provided",Space,Str "in",Space,Str "a",Space,Str "second",Space,Str "sub",Space,Str "file."]]
+
+```
diff --git a/test/command/3531.md b/test/command/3531.md
new file mode 100644
index 000000000..2a4901a97
--- /dev/null
+++ b/test/command/3531.md
@@ -0,0 +1,21 @@
+```
+% pandoc -t mediawiki --wrap=preserve
+* This is a list item.
+* This is a list item in Markdown. It is
+ continued in the next line.
+ * It has a sub-item.
+* This is the next list item.
+
+A paragraph can span multiple lines
+without being broken into pieces.
+^D
+* This is a list item.
+* This is a list item in Markdown. It is continued in the next line.
+** It has a sub-item.
+* This is the next list item.
+
+A paragraph can span multiple lines
+without being broken into pieces.
+
+
+```
diff --git a/test/command/3533-rst-csv-tables.csv b/test/command/3533-rst-csv-tables.csv
new file mode 100644
index 000000000..efef5e4d5
--- /dev/null
+++ b/test/command/3533-rst-csv-tables.csv
@@ -0,0 +1,4 @@
+"Albatross", 2.99, "On a stick!"
+"Crunchy Frog", 1.49, "If we took the bones out, it wouldn't be
+crunchy, now would it?"
+
diff --git a/test/command/3533-rst-csv-tables.md b/test/command/3533-rst-csv-tables.md
new file mode 100644
index 000000000..181462f7f
--- /dev/null
+++ b/test/command/3533-rst-csv-tables.md
@@ -0,0 +1,56 @@
+```
+% pandoc -f rst -t native
+.. csv-table:: Test
+ :widths: 10, 5, 10
+ :header: Flavor,Price,Slogan
+ :file: command/3533-rst-csv-tables.csv
+^D
+[Table [Str "Test"] [AlignDefault,AlignDefault,AlignDefault] [0.4,0.2,0.4]
+ [[Plain [Str "Flavor"]]
+ ,[Plain [Str "Price"]]
+ ,[Plain [Str "Slogan"]]]
+ [[[Plain [Str "Albatross"]]
+ ,[Plain [Str "2.99"]]
+ ,[Plain [Str "On",Space,Str "a",Space,Str "stick!"]]]
+ ,[[Plain [Str "Crunchy",Space,Str "Frog"]]
+ ,[Plain [Str "1.49"]]
+ ,[Plain [Str "If",Space,Str "we",Space,Str "took",Space,Str "the",Space,Str "bones",Space,Str "out,",Space,Str "it",Space,Str "wouldn't",Space,Str "be",SoftBreak,Str "crunchy,",Space,Str "now",Space,Str "would",Space,Str "it?"]]]]]
+```
+
+```
+% pandoc -f rst -t native
+.. csv-table:: Test
+ :header-rows: 1
+ :quote: '
+ :delim: space
+
+ '' 'a' 'b'
+ 'cat''s' 3 4
+ 'dog''s' 2 3
+^D
+[Table [Str "Test"] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[Plain [Str "a"]]
+ ,[Plain [Str "b"]]]
+ [[[Plain [Str "cat's"]]
+ ,[Plain [Str "3"]]
+ ,[Plain [Str "4"]]]
+ ,[[Plain [Str "dog's"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]]]
+```
+
+```
+% pandoc -f rst -t native
+.. csv-table:: Test
+ :escape: \
+
+ "1","\""
+^D
+[Table [Str "Test"] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "\""]]]]]
+```
+
diff --git a/test/command/3534.md b/test/command/3534.md
new file mode 100644
index 000000000..89224551b
--- /dev/null
+++ b/test/command/3534.md
@@ -0,0 +1,23 @@
+```
+% pandoc -f latex -t html
+I want to explain the interface of \lstinline[language=Java]{public class MyClass}.
+^D
+<p>I want to explain the interface of <code class="sourceCode java"><span class="kw">public</span> <span class="kw">class</span> MyClass</code>.</p>
+
+```
+
+```
+% pandoc -f latex -t html
+I want to explain the interface of \lstinline{public class MyClass}.
+^D
+<p>I want to explain the interface of <code>public class MyClass</code>.</p>
+
+```
+
+```
+% pandoc -f latex -t native
+I want to explain the interface of \lstinline[language=Java]{public class MyClass}.
+^D
+[Para [Str "I",Space,Str "want",Space,Str "to",Space,Str "explain",Space,Str "the",Space,Str "interface",Space,Str "of",Space,Code ("",["java"],[]) "public class MyClass",Str "."]]
+```
+
diff --git a/test/command/3537.md b/test/command/3537.md
new file mode 100644
index 000000000..df4eeba7d
--- /dev/null
+++ b/test/command/3537.md
@@ -0,0 +1,28 @@
+Generalized raw attributes.
+
+````
+% pandoc -t native
+```{=ms}
+.MACRO
+foo bar
+```
+^D
+[RawBlock (Format "ms") ".MACRO\nfoo bar"]
+````
+
+````
+% pandoc -t native
+Hi `there`{=ms}.
+^D
+[Para [Str "Hi",Space,RawInline (Format "ms") "there",Str "."]]
+````
+
+````
+% pandoc -t native
+~~~ {=ms}
+.MACRO
+foo bar
+~~~
+^D
+[RawBlock (Format "ms") ".MACRO\nfoo bar"]
+````
diff --git a/test/command/3539.md b/test/command/3539.md
new file mode 100644
index 000000000..6ef9ffac7
--- /dev/null
+++ b/test/command/3539.md
@@ -0,0 +1,45 @@
+# Commands of [glossaries package](ftp://ftp.tu-chemnitz.de/pub/tex/macros/latex/contrib/glossaries/glossaries-code.pdf)
+
+```
+% pandoc -f latex -t native
+Many programming languages provide \glspl{API}. Each \gls{API} should provide a documentation.
+^D
+[Para [Str "Many",Space,Str "programming",Space,Str "languages",Space,Str "provide",Space,Span ("",[],[("acronym-label","API"),("acronym-form","plural+short")]) [Str "APIs"],Str ".",Space,Str "Each",Space,Span ("",[],[("acronym-label","API"),("acronym-form","singular+short")]) [Str "API"],Space,Str "should",Space,Str "provide",Space,Str "a",Space,Str "documentation."]]
+```
+
+```
+% pandoc -f latex -t native
+\Glsdesc{API} XYZ ist not as performant as \glsdesc{API} ZXY.
+^D
+[Para [Span ("",[],[("acronym-label","API"),("acronym-form","singular+long")]) [Str "API"],Space,Str "XYZ",Space,Str "ist",Space,Str "not",Space,Str "as",Space,Str "performant",Space,Str "as",Space,Span ("",[],[("acronym-label","API"),("acronym-form","singular+long")]) [Str "API"],Space,Str "ZXY."]]
+```
+
+```
+% pandoc -f latex -t native
+\Acrlong{API} XYZ ist not as performant as \acrlong{API} ZXY.
+^D
+[Para [Span ("",[],[("acronym-label","API"),("acronym-form","singular+long")]) [Str "API"],Space,Str "XYZ",Space,Str "ist",Space,Str "not",Space,Str "as",Space,Str "performant",Space,Str "as",Space,Span ("",[],[("acronym-label","API"),("acronym-form","singular+long")]) [Str "API"],Space,Str "ZXY."]]
+```
+
+```
+% pandoc -f latex -t native
+\Acrfull{API} XYZ ist not as performant as \acrfull{API} ZXY.
+^D
+[Para [Span ("",[],[("acronym-label","API"),("acronym-form","singular+full")]) [Str "API"],Space,Str "XYZ",Space,Str "ist",Space,Str "not",Space,Str "as",Space,Str "performant",Space,Str "as",Space,Span ("",[],[("acronym-label","API"),("acronym-form","singular+full")]) [Str "API"],Space,Str "ZXY."]]
+```
+
+```
+% pandoc -f latex -t native
+\Acrshort{API} XYZ ist not as performant as \acrshort{API} ZXY.
+^D
+[Para [Span ("",[],[("acronym-label","API"),("acronym-form","singular+abbrv")]) [Str "API"],Space,Str "XYZ",Space,Str "ist",Space,Str "not",Space,Str "as",Space,Str "performant",Space,Str "as",Space,Span ("",[],[("acronym-label","API"),("acronym-form","singular+abbrv")]) [Str "API"],Space,Str "ZXY."]]
+```
+
+# Commands of [acronym package](ftp://ftp.mpi-sb.mpg.de/pub/tex/mirror/ftp.dante.de/pub/tex/macros/latex/contrib/acronym/acronym.pdf)
+
+```
+% pandoc -f latex -t native
+Many programming languages provide \acp{API}. Each \ac{API} should provide a documentation.
+^D
+[Para [Str "Many",Space,Str "programming",Space,Str "languages",Space,Str "provide",Space,Span ("",[],[("acronym-label","API"),("acronym-form","plural+short")]) [Str "APIs"],Str ".",Space,Str "Each",Space,Span ("",[],[("acronym-label","API"),("acronym-form","singular+short")]) [Str "API"],Space,Str "should",Space,Str "provide",Space,Str "a",Space,Str "documentation."]]
+```
diff --git a/test/command/3558.md b/test/command/3558.md
new file mode 100644
index 000000000..795858b78
--- /dev/null
+++ b/test/command/3558.md
@@ -0,0 +1,12 @@
+```
+% pandoc -t native
+\multi
+
+hello
+
+\endmulti
+^D
+[RawBlock (Format "latex") "\\multi"
+,Para [Str "hello"]
+,RawBlock (Format "latex") "\\endmulti"]
+```
diff --git a/test/command/3568.md b/test/command/3568.md
new file mode 100644
index 000000000..e77c27b78
--- /dev/null
+++ b/test/command/3568.md
@@ -0,0 +1,15 @@
+```
+% pandoc -t man
+normal *italic **bold in the middle** only italic* normal.
+
+normal **bold `code` more bold** normal.
+
+normal `code` normal.
+^D
+.PP
+normal \f[I]italic \f[BI]bold in the middle\f[I] only italic\f[] normal.
+.PP
+normal \f[B]bold \f[BC]code\f[B] more bold\f[] normal.
+.PP
+normal \f[C]code\f[] normal.
+```
diff --git a/test/command/3570.md b/test/command/3570.md
new file mode 100644
index 000000000..8c08a881d
--- /dev/null
+++ b/test/command/3570.md
@@ -0,0 +1,6 @@
+```
+% pandoc -f markdown+autolink_bare_uris
+**Notes:**
+^D
+<p><strong>Notes:</strong></p>
+```
diff --git a/test/command/3577.md b/test/command/3577.md
new file mode 100644
index 000000000..ca9dba97c
--- /dev/null
+++ b/test/command/3577.md
@@ -0,0 +1,37 @@
+```
+% pandoc -f latex -t html5 --quiet
+\begin{figure}[ht]
+ \begin{subfigure}{0.45\textwidth}
+ \centering
+ \includegraphics{img1.jpg}
+ \caption{Caption 1}
+ \end{subfigure}
+
+ \begin{subfigure}{0.45\textwidth}
+ \centering
+ \includegraphics{img2.jpg}
+ \caption{Caption 2}
+ \end{subfigure}
+ \caption{Subfigure with Subfloat}
+\end{figure}
+^D
+
+<figure>
+<img src="img1.jpg" alt="Caption 1" /><figcaption>Caption 1</figcaption>
+</figure>
+
+<figure>
+<img src="img2.jpg" alt="Caption 2" /><figcaption>Caption 2</figcaption>
+</figure>
+```
+```
+% pandoc -f latex -t html5
+\begin{figure}[ht]
+ \includegraphics{img1.jpg}
+ \caption{Caption 3}
+\end{figure}
+^D
+<figure>
+<img src="img1.jpg" alt="Caption 3" /><figcaption>Caption 3</figcaption>
+</figure>
+```
diff --git a/test/command/3585.md b/test/command/3585.md
new file mode 100644
index 000000000..739ddeea4
--- /dev/null
+++ b/test/command/3585.md
@@ -0,0 +1,16 @@
+```
+% pandoc -f mediawiki+smart -t native
+"Hello"
+
+Same but bzip2 it and nice it <tt>zfs send tank/storage/data/svn@daily-2014-03-20_00.00.00--2w | nice -15 bzip2 | ssh user@hyper.somewhere.org "> /storage/c-3po/tank-storage-data-svn.dmp.bz2"</tt>
+^D
+[Para [Quoted DoubleQuote [Str "Hello"]]
+,Para [Str "Same",Space,Str "but",Space,Str "bzip2",Space,Str "it",Space,Str "and",Space,Str "nice",Space,Str "it",Space,Code ("",[],[]) "zfs send tank/storage/data/svn@daily-2014-03-20_00.00.00--2w | nice -15 bzip2 | ssh user@hyper.somewhere.org \"> /storage/c-3po/tank-storage-data-svn.dmp.bz2\""]]
+```
+
+```
+% pandoc -f mediawiki -t native
+"Hello"
+^D
+[Para [Str "\"Hello\""]]
+```
diff --git a/test/command/3587.md b/test/command/3587.md
new file mode 100644
index 000000000..addb6c582
--- /dev/null
+++ b/test/command/3587.md
@@ -0,0 +1,21 @@
+```
+% pandoc -f latex -t native
+\SI[round-precision=2]{1}{m} is equal to \SI{1000}{mm}
+^D
+[Para [Str "1\160m",Space,Str "is",Space,Str "equal",Space,Str "to",Space,Str "1000\160mm"]]
+```
+
+```
+% pandoc -f latex -t native
+\SI[round-precision=2]{1}[\$]{} is equal to \SI{0.938094}{\euro}
+^D
+[Para [Str "$\160\&1",Space,Str "is",Space,Str "equal",Space,Str "to",Space,Str "0.938094\160\8364"]]
+```
+
+
+```
+% pandoc -f latex -t native
+\SI[round-precision=2]{\{\}}[\{\}]{\{\}}
+^D
+[Para [Str "{}\160{}\160{}"]]
+```
diff --git a/test/command/3596.md b/test/command/3596.md
new file mode 100644
index 000000000..01a871e1b
--- /dev/null
+++ b/test/command/3596.md
@@ -0,0 +1,59 @@
+```
+% pandoc -f html -t markdown-raw_html-bracketed_spans-native_spans
+<ul>
+<li>foo</li>
+<li id="id">bar</li>
+<li>baz</li>
+</ul>
+^D
+- foo
+- bar
+- baz
+```
+
+```
+% pandoc -f html -t markdown-raw_html-bracketed_spans-native_spans
+<ul>
+<li>foo</li>
+<li id="id">bar<ul><li>subbar</li></ul></li>
+<li>baz</li>
+</ul>
+^D
+- foo
+- bar
+ - subbar
+- baz
+```
+
+
+```
+% pandoc -f html -t markdown
+<ul>
+<li>foo</li>
+<li id="id">bar</li>
+<li>baz</li>
+</ul>
+^D
+- foo
+- [bar]{#id}
+- baz
+```
+
+
+```
+% pandoc -f html -t markdown
+<ul>
+<li><p>foo</p></li>
+<li id="id"><p>bar</p></li>
+<li><p>baz</p></li>
+</ul>
+^D
+- foo
+
+- ::: {#id}
+ bar
+ :::
+
+- baz
+
+```
diff --git a/test/command/3615.md b/test/command/3615.md
new file mode 100644
index 000000000..5fbd48b3a
--- /dev/null
+++ b/test/command/3615.md
@@ -0,0 +1,18 @@
+```
+% pandoc -f html -t markdown --reference-links
+<a href="a">foo</a> <a href="b">Foo</a>
+^D
+[foo][] [Foo][1]
+
+ [foo]: a
+ [1]: b
+```
+
+```
+% pandoc -f html -t markdown --reference-links
+<a href="a">foo</a> <a href="a">Foo</a>
+^D
+[foo][] [Foo]
+
+ [foo]: a
+```
diff --git a/test/command/3619.md b/test/command/3619.md
new file mode 100644
index 000000000..62962c43b
--- /dev/null
+++ b/test/command/3619.md
@@ -0,0 +1,28 @@
+```
+% pandoc -f html -t markdown --reference-links
+<a href="foo">bar</a>: baz
+^D
+[bar][]: baz
+
+ [bar]: foo
+```
+
+```
+% pandoc -f html -t markdown --reference-links
+<a href="foo">bar</a>(baz)
+^D
+[bar][](baz)
+
+ [bar]: foo
+```
+
+```
+% pandoc -f html -t markdown_strict --reference-links
+<a href="a">foo</a><br/><a href="b">bar</a>
+^D
+[foo][]
+[bar]
+
+ [foo]: a
+ [bar]: b
+```
diff --git a/test/command/3630.md b/test/command/3630.md
new file mode 100644
index 000000000..db3a17dda
--- /dev/null
+++ b/test/command/3630.md
@@ -0,0 +1,8 @@
+```
+% pandoc -f markdown -t markdown --reference-links
+![foo](bar.png){#myId}
+^D
+![foo]
+
+ [foo]: bar.png {#myId}
+```
diff --git a/test/command/3667.md b/test/command/3667.md
new file mode 100644
index 000000000..97de8f598
--- /dev/null
+++ b/test/command/3667.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f textile
+| "link text":http://example.com/ |
+^D
+<table>
+<tbody>
+<tr class="odd">
+<td><a href="http://example.com/">link text</a></td>
+</tr>
+</tbody>
+</table>
+```
+
diff --git a/test/command/3674.md b/test/command/3674.md
new file mode 100644
index 000000000..92ed4bed7
--- /dev/null
+++ b/test/command/3674.md
@@ -0,0 +1,39 @@
+Make sure we don't get duplicate reference links, even with
+`--reference-location=section`.
+
+```
+% pandoc --reference-links -t markdown --reference-location=section --atx-headers
+# a
+
+![](a)
+
+# b
+
+![](b)
+
+^D
+# a
+
+![][1]
+
+ [1]: a
+
+# b
+
+![][2]
+
+ [2]: b
+```
+
+Subsidiary issue: allow line break between reference link
+url/title and attributes:
+
+```
+% pandoc
+[a]
+
+[a]: url
+{.class}
+^D
+<p><a href="url" class="class">a</a></p>
+```
diff --git a/test/command/3675.md b/test/command/3675.md
new file mode 100644
index 000000000..b129c7a63
--- /dev/null
+++ b/test/command/3675.md
@@ -0,0 +1,15 @@
+````
+% pandoc -t rst
+```python
+print("hello")
+```
+> block quote
+^D
+.. code:: python
+
+ print("hello")
+
+..
+
+ block quote
+````
diff --git a/test/command/3681.md b/test/command/3681.md
new file mode 100644
index 000000000..d0805e820
--- /dev/null
+++ b/test/command/3681.md
@@ -0,0 +1,27 @@
+```
+% pandoc -f latex -t native
+\newcommand{\cicd}{CI/CD\xspace}
+
+Software developers create \cicd pipelines to… Following issue can be resolved by \cicd:
+^D
+[Para [Str "Software",Space,Str "developers",Space,Str "create",Space,Str "CI/CD",Space,Str "pipelines",Space,Str "to\8230",Space,Str "Following",Space,Str "issue",Space,Str "can",Space,Str "be",Space,Str "resolved",Space,Str "by",Space,Str "CI/CD:"]]
+```
+
+```
+% pandoc -f latex -t native
+\newcommand{\cicd}{CI/CD\xspace}
+
+\cicd\footnote{\url{https://en.wikipedia.org/wiki/CI/CD}} is awesome.
+^D
+[Para [Str "CI/CD",Note [Para [Link ("",[],[]) [Str "https://en.wikipedia.org/wiki/CI/CD"] ("https://en.wikipedia.org/wiki/CI/CD","")]],Space,Str "is",Space,Str "awesome."]]
+```
+
+```
+% pandoc -f latex -t native
+\newcommand{\cicd}{CI/CD\xspace}
+\newcommand{\pipeline}{pipeline\xspace}
+
+\cicd\pipeline.
+^D
+[Para [Str "CI/CD",Space,Str "pipeline."]]
+```
diff --git a/test/command/3690.md b/test/command/3690.md
new file mode 100644
index 000000000..213b88138
--- /dev/null
+++ b/test/command/3690.md
@@ -0,0 +1,8 @@
+```
+% pandoc
+- [o] _hi_
+^D
+<ul>
+<li>[o] <em>hi</em></li>
+</ul>
+```
diff --git a/test/command/3701.md b/test/command/3701.md
new file mode 100644
index 000000000..01e438639
--- /dev/null
+++ b/test/command/3701.md
@@ -0,0 +1,60 @@
+```
+% pandoc --reference-location=block -t markdown --reference-links --wrap=preserve
+[a](u)
+
+[a](u)
+
+[a](u2)
+[A](u)
+[a](u){.foo}
+
+[a](u3)
+^D
+[a]
+
+ [a]: u
+
+[a]
+
+ [a]: u
+
+[a][1]
+[A][]
+[a][2]
+
+ [1]: u2
+ [A]: u
+ [2]: u {.foo}
+
+[a][3]
+
+ [3]: u3
+```
+
+```
+% pandoc
+[a]
+
+ [a]: u
+
+[a]
+
+ [a]: u
+
+[a][1]
+[A][]
+[a][2]
+
+ [1]: u2
+ [A]: u
+ [2]: u {.foo}
+
+[a][3]
+
+ [3]: u3
+^D
+<p><a href="u">a</a></p>
+<p><a href="u">a</a></p>
+<p><a href="u2">a</a> <a href="u">A</a> <a href="u" class="foo">a</a></p>
+<p><a href="u3">a</a></p>
+```
diff --git a/test/command/3706.md b/test/command/3706.md
new file mode 100644
index 000000000..00f53279e
--- /dev/null
+++ b/test/command/3706.md
@@ -0,0 +1,44 @@
+Results marker can be hidden in block attributes (#3706)
+
+```
+pandoc -f org -t native
+#+BEGIN_SRC R :exports results :colnames yes
+ data.frame(Id = 1:3, Desc = rep("La",3))
+#+END_SRC
+
+#+CAPTION: Lalelu.
+#+LABEL: tab
+#+RESULTS:
+| Id | Desc |
+|----+------|
+| 1 | La |
+| 2 | La |
+| 3 | La |
+^D
+[Table [Str "Lalelu."] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str "Id"]]
+ ,[Plain [Str "Desc"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "La"]]]
+ ,[[Plain [Str "2"]]
+ ,[Plain [Str "La"]]]
+ ,[[Plain [Str "3"]]
+ ,[Plain [Str "La"]]]]]
+```
+
+```
+pandoc -f org -t native
+#+BEGIN_SRC R :exports none :colnames yes
+ data.frame(Id = 1:2, Desc = rep("La",2))
+#+END_SRC
+
+#+CAPTION: Lalelu.
+#+LABEL: tab
+#+RESULTS:
+| Id | Desc |
+|----+------|
+| 1 | La |
+| 2 | La |
+^D
+[]
+```
diff --git a/test/command/3708.md b/test/command/3708.md
new file mode 100644
index 000000000..2cbc82c25
--- /dev/null
+++ b/test/command/3708.md
@@ -0,0 +1,15 @@
+```
+% pandoc -f latex -t native
+\begin{tabular}{cc}
+ A & B\&1 \\
+ C & D
+\end{tabular}
+^D
+[Table [] [AlignCenter,AlignCenter] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "A"]]
+ ,[Plain [Str "B&1"]]]
+ ,[[Plain [Str "C"]]
+ ,[Plain [Str "D"]]]]]
+```
diff --git a/test/command/3715.md b/test/command/3715.md
new file mode 100644
index 000000000..9d74779cb
--- /dev/null
+++ b/test/command/3715.md
@@ -0,0 +1,15 @@
+```
+% pandoc -t markdown -f html --wrap=preserve
+x<em></em>x
+y<strong></strong>y
+z<sup></sup>z
+w<sub></sub>w
+q<s></s>q
+^D
+xx
+yy
+zz
+ww
+qq
+```
+
diff --git a/test/command/3716.md b/test/command/3716.md
new file mode 100644
index 000000000..7e00819da
--- /dev/null
+++ b/test/command/3716.md
@@ -0,0 +1,6 @@
+```
+% pandoc
+<http://example.com>{.foo}
+^D
+<p><a href="http://example.com" class="uri foo">http://example.com</a></p>
+```
diff --git a/test/command/3730.md b/test/command/3730.md
new file mode 100644
index 000000000..fbc06cbce
--- /dev/null
+++ b/test/command/3730.md
@@ -0,0 +1,21 @@
+````
+% pandoc
+nice line\
+```
+code
+```
+^D
+<p>nice line<br />
+</p>
+<pre><code>code</code></pre>
+````
+
+```
+% pandoc
+# hi\
+there
+^D
+<h1 id="hi">hi<br />
+</h1>
+<p>there</p>
+```
diff --git a/test/command/3733.md b/test/command/3733.md
new file mode 100644
index 000000000..b8a326938
--- /dev/null
+++ b/test/command/3733.md
@@ -0,0 +1,13 @@
+````
+% pandoc -t native
+- Item1
+- Item2
+```yaml
+some: code
+```
+^D
+[BulletList
+ [[Plain [Str "Item1"]]
+ ,[Plain [Str "Item2"]]]
+,CodeBlock ("",["yaml"],[]) "some: code"]
+````
diff --git a/test/command/3734.md b/test/command/3734.md
new file mode 100644
index 000000000..16803256b
--- /dev/null
+++ b/test/command/3734.md
@@ -0,0 +1,50 @@
+```
+% pandoc -t markdown_strict+pipe_tables
+| aaaaaaaaaaaa | bbbbb | ccccccccccc |
+|--------------|-------|--------------------------------------------------------------------------|
+| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
+^D
+<table>
+<colgroup>
+<col style="width: 14%" />
+<col style="width: 7%" />
+<col style="width: 77%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th>aaaaaaaaaaaa</th>
+<th>bbbbb</th>
+<th>ccccccccccc</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>aaaaaaaaaaaa</td>
+<td></td>
+<td>cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc</td>
+</tr>
+</tbody>
+</table>
+```
+
+```
+% pandoc -t markdown_strict+pipe_tables-raw_html
+| aaaaaaaaaaaa | bbbbb | ccccccccccc |
+|--------------|-------|--------------------------------------------------------------------------|
+| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
+^D
+| aaaaaaaaaaaa | bbbbb | ccccccccccc |
+|--------------|-------|--------------------------------------------------------------------------|
+| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
+```
+
+```
+% pandoc -t gfm
+| aaaaaaaaaaaa | bbbbb | ccccccccccc |
+|--------------|-------|--------------------------------------------------------------------------|
+| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
+^D
+| aaaaaaaaaaaa | bbbbb | ccccccccccc |
+| ------------ | ----- | ------------------------------------------------------------------------ |
+| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
+```
diff --git a/test/command/3736.md b/test/command/3736.md
new file mode 100644
index 000000000..b66e0a359
--- /dev/null
+++ b/test/command/3736.md
@@ -0,0 +1,25 @@
+```
+% pandoc --wrap=preserve -f html -t markdown
+<h2>hi
+there</h2>
+^D
+hi there
+--------
+```
+
+```
+% pandoc --wrap=preserve -f html -t markdown
+<h2>hi <em>there
+again</em></h2>
+^D
+hi *there again*
+----------------
+```
+
+```
+% pandoc --wrap=preserve -f html -t markdown
+<h2>hi<br>there</h2>
+^D
+hi there
+--------
+```
diff --git a/test/command/3755.md b/test/command/3755.md
new file mode 100644
index 000000000..5e1ffc921
--- /dev/null
+++ b/test/command/3755.md
@@ -0,0 +1,23 @@
+```
+% pandoc -t native -s
+---
+title: 'Titel'
+date: '22. Juni 2017'
+---
+^D
+Pandoc (Meta {unMeta = fromList [("date",MetaInlines [Str "22.",Space,Str "Juni",Space,Str "2017"]),("title",MetaInlines [Str "Titel"])]})
+[]
+```
+
+```
+% pandoc -t native -s
+---
+title: '<div>foo</div>'
+date: |
+ 22. Juni 2017
+---
+^D
+Pandoc (Meta {unMeta = fromList [("date",MetaBlocks [OrderedList (22,Decimal,Period) [[Plain [Str "Juni",Space,Str "2017"]]]]),("title",MetaBlocks [Div ("",[],[]) [Plain [Str "foo"]]])]})
+[]
+```
+
diff --git a/test/command/3771.md b/test/command/3771.md
new file mode 100644
index 000000000..1d3a75ae1
--- /dev/null
+++ b/test/command/3771.md
@@ -0,0 +1,14 @@
+```
+% pandoc -f html -t org
+<div class="Section1">
+ Today is a nice day.
+</div>
+<div id="forecast">
+ Tomorrow will be rainy.
+</div>
+^D
+Today is a nice day.
+
+<<forecast>>
+Tomorrow will be rainy.
+```
diff --git a/test/command/3773.md b/test/command/3773.md
new file mode 100644
index 000000000..7ee8a3941
--- /dev/null
+++ b/test/command/3773.md
@@ -0,0 +1,14 @@
+```
+% pandoc -t markdown
+A. \#
+B. \+
+C. \*
+D. o
+E. o or \*
+^D
+A. \#
+B. \+
+C. \*
+D. o
+E. o or \*
+```
diff --git a/test/command/3779.md b/test/command/3779.md
new file mode 100644
index 000000000..1097123f0
--- /dev/null
+++ b/test/command/3779.md
@@ -0,0 +1,28 @@
+```
+% pandoc -f latex -t native
+\newcommand{\fakeitemize}[1]{
+ \begin{itemize}
+ #1
+ \end{itemize}
+}
+\newcommand{\testcmd}[1]{
+ #1
+}
+\fakeitemize{
+ \item Pandoc is 100\% awesome.
+}
+
+\begin{itemize}
+ \item Pandoc is 200\% awesome.
+\end{itemize}
+
+\testcmd{
+ Pandoc is 300\% awesome.
+}
+^D
+[BulletList
+ [[Para [Str "Pandoc",Space,Str "is",Space,Str "100%",Space,Str "awesome."]]]
+,BulletList
+ [[Para [Str "Pandoc",Space,Str "is",Space,Str "200%",Space,Str "awesome."]]]
+,Para [Str "Pandoc",Space,Str "is",Space,Str "300%",Space,Str "awesome."]]
+```
diff --git a/test/command/3792.md b/test/command/3792.md
new file mode 100644
index 000000000..7c76afee7
--- /dev/null
+++ b/test/command/3792.md
@@ -0,0 +1,13 @@
+Make sure metadata values are treated as strings,
+and properly escaped.
+
+```
+% pandoc -t markdown -s -M title="<this> *that*"
+ok
+^D
+---
+title: '\<this\> \*that\*'
+---
+
+ok
+```
diff --git a/test/command/3794.md b/test/command/3794.md
new file mode 100644
index 000000000..b56e7b504
--- /dev/null
+++ b/test/command/3794.md
@@ -0,0 +1,7 @@
+```
+% pandoc -f html -t native
+<div><p>hello</div>
+^D
+[Div ("",[],[])
+ [Para [Str "hello"]]]
+```
diff --git a/test/command/3803.md b/test/command/3803.md
new file mode 100644
index 000000000..a2e60359d
--- /dev/null
+++ b/test/command/3803.md
@@ -0,0 +1,10 @@
+```
+% pandoc -f markdown+raw_tex -t latex
+\begin{blah*}
+*ok*
+\end{blah*}
+^D
+\begin{blah*}
+*ok*
+\end{blah*}
+```
diff --git a/test/command/3804.md b/test/command/3804.md
new file mode 100644
index 000000000..c13c2ef42
--- /dev/null
+++ b/test/command/3804.md
@@ -0,0 +1,6 @@
+```
+% pandoc -t native
+\titleformat{\chapter}[display]{\normalfont\large\bfseries}{第\thechapter{}章}{20pt}{\Huge}
+^D
+[RawBlock (Format "latex") "\\titleformat{\\chapter}[display]{\\normalfont\\large\\bfseries}{\31532\\thechapter{}\31456}{20pt}{\\Huge}"]
+```
diff --git a/test/command/3816.md b/test/command/3816.md
new file mode 100644
index 000000000..3979ea9ab
--- /dev/null
+++ b/test/command/3816.md
@@ -0,0 +1,32 @@
+```
+% pandoc --mathjax -t html5 --wrap=preserve
+This is an equation:
+\begin{equation}
+y+2 = 3
+\end{equation}
+
+This is a system of equations:
+\begin{align*}
+x^2+y^2 & = 2 \\
+\sin(y) & = 0.5
+\end{align*}
+
+This is Euler's formula:
+\begin{eqnarray*}
+e^{i\pi} + 1 & = & 0.
+\end{eqnarray*}
+^D
+<p>This is an equation:
+<span class="math display">\[\begin{equation}
+y+2 = 3
+\end{equation}\]</span></p>
+<p>This is a system of equations:
+<span class="math display">\[\begin{align*}
+x^2+y^2 &amp; = 2 \\
+\sin(y) &amp; = 0.5
+\end{align*}\]</span></p>
+<p>This is Euler’s formula:
+<span class="math display">\[\begin{eqnarray*}
+e^{i\pi} + 1 &amp; = &amp; 0.
+\end{eqnarray*}\]</span></p>
+```
diff --git a/test/command/3824.md b/test/command/3824.md
new file mode 100644
index 000000000..e479e9e2f
--- /dev/null
+++ b/test/command/3824.md
@@ -0,0 +1,14 @@
+```
+% pandoc -f native -t dokuwiki
+[BulletList
+ [[Para [Str "hi"]
+ ,CodeBlock ("",[],[]) " there"]
+ ,[Para [Str "ok"]]]]
+^D
+ * hi<code>
+ there
+</code>
+ * ok
+
+
+```
diff --git a/test/command/3840.md b/test/command/3840.md
new file mode 100644
index 000000000..ceb1d1e51
--- /dev/null
+++ b/test/command/3840.md
@@ -0,0 +1,15 @@
+```
+% pandoc
+[@Alhazen1572-qk, V.9]: "competentius est"
+^D
+<p><span class="citation" data-cites="Alhazen1572-qk">[@Alhazen1572-qk, V.9]</span>: “competentius est”</p>
+```
+
+```
+% pandoc -f markdown-citations
+[@Alhazen1572-qk, V.9]: "competentius est"
+
+[@Alhazen1572-qk, V.9]
+^D
+<p><a href="" title="competentius est">@Alhazen1572-qk, V.9</a></p>
+```
diff --git a/test/command/3853.md b/test/command/3853.md
new file mode 100644
index 000000000..19e8e2260
--- /dev/null
+++ b/test/command/3853.md
@@ -0,0 +1,26 @@
+```
+% pandoc -f latex -t native
+\newtoggle{ebook}
+\toggletrue{ebook}
+\iftoggle{ebook}{
+ebook
+}%
+{
+not ebook
+}%
+more
+
+\togglefalse{ebook}
+\iftoggle{ebook}{%
+ebook
+}{
+not ebook
+}%
+more
+
+hello \iftoggle{ebook}{ebook}{noebook}
+^D
+[Para [Str "ebook",SoftBreak,Str "more"]
+,Para [Str "not",Space,Str "ebook",SoftBreak,Str "more"]
+,Para [Str "hello",Space,Str "noebook"]]
+```
diff --git a/test/command/3880.md b/test/command/3880.md
new file mode 100644
index 000000000..b8edaf08f
--- /dev/null
+++ b/test/command/3880.md
@@ -0,0 +1,6 @@
+```
+pandoc -f rst -t native
+.. include:: command/3880.txt
+^D
+[Para [Str "hi"]]
+```
diff --git a/test/command/3880.txt b/test/command/3880.txt
new file mode 100644
index 000000000..45b983be3
--- /dev/null
+++ b/test/command/3880.txt
@@ -0,0 +1 @@
+hi
diff --git a/test/command/3916.md b/test/command/3916.md
new file mode 100644
index 000000000..9ac0834d7
--- /dev/null
+++ b/test/command/3916.md
@@ -0,0 +1,11 @@
+```
+% pandoc -f textile -t native
+# text text
+<pre>blabla</pre>
+# more
+^D
+[OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "text",Space,Str "text"]
+ ,CodeBlock ("",[],[]) "blabla"]
+ ,[Plain [Str "more"]]]]
+```
diff --git a/test/command/3937.md b/test/command/3937.md
new file mode 100644
index 000000000..2f32cd172
--- /dev/null
+++ b/test/command/3937.md
@@ -0,0 +1,13 @@
+```
+% pandoc -t rst
+# My Great Section {#mysection}
+# Other section
+^D
+.. _mysection:
+
+My Great Section
+================
+
+Other section
+=============
+```
diff --git a/test/command/3947.md b/test/command/3947.md
new file mode 100644
index 000000000..7ce0be171
--- /dev/null
+++ b/test/command/3947.md
@@ -0,0 +1,11 @@
+```
+% pandoc -t native
+\newpage
+
+ Code block
+
+ Another Code block
+^D
+[RawBlock (Format "latex") "\\newpage"
+,CodeBlock ("",[],[]) "Code block\n\nAnother Code block"]
+```
diff --git a/test/command/3958.md b/test/command/3958.md
new file mode 100644
index 000000000..1793dd05c
--- /dev/null
+++ b/test/command/3958.md
@@ -0,0 +1,20 @@
+```
+% pandoc -f latex -t native
+\texttt{"hi"}
+^D
+[Para [Code ("",[],[]) "\"hi\""]]
+```
+
+```
+% pandoc -f latex -t native
+\texttt{``hi''}
+^D
+[Para [Code ("",[],[]) "\8220hi\8221"]]
+```
+
+```
+% pandoc -f latex -t native
+\texttt{`hi'}
+^D
+[Para [Code ("",[],[]) "\8216hi\8217"]]
+```
diff --git a/test/command/3968.md b/test/command/3968.md
new file mode 100644
index 000000000..c76cfcba4
--- /dev/null
+++ b/test/command/3968.md
@@ -0,0 +1,10 @@
+```
+% pandoc --top-level-division=chapter -t context
+# Chapter
+
+## Section
+^D
+\chapter[title={Chapter},reference={chapter}]
+
+\section[title={Section},reference={section}]
+```
diff --git a/test/command/3971.md b/test/command/3971.md
new file mode 100644
index 000000000..533540743
--- /dev/null
+++ b/test/command/3971.md
@@ -0,0 +1,9 @@
+```
+% pandoc -f latex -t native
+\documentclass{article}
+\include{command/3971b}
+\code{f}
+\end{document}
+^D
+[Para [Code ("",[],[]) "f"]]
+```
diff --git a/test/command/3971b.tex b/test/command/3971b.tex
new file mode 100644
index 000000000..0d1dc3e02
--- /dev/null
+++ b/test/command/3971b.tex
@@ -0,0 +1,2 @@
+\newcommand{\code}[1]{\texttt{#1}}
+\begin{document}
diff --git a/test/command/3974.md b/test/command/3974.md
new file mode 100644
index 000000000..26ab36688
--- /dev/null
+++ b/test/command/3974.md
@@ -0,0 +1,6 @@
+```
+% pandoc -f native -t rst
+[Code ("",[],[]) "``"]
+^D
+:literal:`\`\``
+```
diff --git a/test/command/3978.md b/test/command/3978.md
new file mode 100644
index 000000000..2399ae6e6
--- /dev/null
+++ b/test/command/3978.md
@@ -0,0 +1,6 @@
+```
+% pandoc -t rst
+foo_bar*baz
+^D
+foo_bar*baz
+```
diff --git a/test/command/3983.md b/test/command/3983.md
new file mode 100644
index 000000000..7eaeb99f0
--- /dev/null
+++ b/test/command/3983.md
@@ -0,0 +1,29 @@
+```
+pandoc -f latex -t native
+\def\filename@area{foo:bar:baz}
+\makeatletter
+\graphicspath\expandafter{\expandafter{\filename@area}}%
+\makeatother
+^D
+[RawBlock (Format "latex") "\\makeatletter"
+,RawBlock (Format "latex") "\\makeatother"]
+```
+
+```
+pandoc -f latex -t native
+\makeatletter
+ \newcommand\urlfootnote@[1]{\footnote{\url@{#1}}}
+ \DeclareRobustCommand{\urlfootnote}{\hyper@normalise\urlfootnote@}
+\makeatother
+^D
+[RawBlock (Format "latex") "\\makeatletter"
+,RawBlock (Format "latex") "\\makeatother"]
+```
+
+```
+pandoc -f latex -t native
+\def\foo{bar}
+\expandafter\bam\foo
+^D
+[RawBlock (Format "latex") "\\bambar"]
+```
diff --git a/test/command/3989.md b/test/command/3989.md
new file mode 100644
index 000000000..bf078b2e4
--- /dev/null
+++ b/test/command/3989.md
@@ -0,0 +1,7 @@
+```
+pandoc -f markdown -t native
+<span title="1st line of text <br> 2nd line of text">foo</span>
+ <span title="1st line of text <br> 2nd line of text">foo</span>
+^D
+[Para [Span ("",[],[("title","1st line of text <br> 2nd line of text")]) [Str "foo"],SoftBreak,Span ("",[],[("title","1st line of text <br> 2nd line of text")]) [Str "foo"]]]
+```
diff --git a/test/command/4007.md b/test/command/4007.md
new file mode 100644
index 000000000..c6064e0f2
--- /dev/null
+++ b/test/command/4007.md
@@ -0,0 +1,23 @@
+```
+pandoc -f latex -t native
+\newcommand\arrow\to
+$a\arrow b$
+^D
+[Para [Math InlineMath "a\\to b"]]
+```
+
+```
+pandoc -f latex -t native
+\newcommand\pfeil[1]{\to #1}
+$a\pfeil b$
+^D
+[Para [Math InlineMath "a\\to b"]]
+```
+
+```
+pandoc -f latex -t native
+\newcommand\fleche{\to}
+$a\fleche b$
+^D
+[Para [Math InlineMath "a\\to b"]]
+```
diff --git a/test/command/4012.md b/test/command/4012.md
new file mode 100644
index 000000000..579ee2459
--- /dev/null
+++ b/test/command/4012.md
@@ -0,0 +1,8 @@
+```
+pandoc -f markdown-implicit_figures
+![image]
+
+[image]: http://example.com/image.jpg {height=35mm}
+^D
+<p><img src="http://example.com/image.jpg" alt="image" style="height:35mm" /></p>
+```
diff --git a/test/command/4016.md b/test/command/4016.md
new file mode 100644
index 000000000..69ad1c911
--- /dev/null
+++ b/test/command/4016.md
@@ -0,0 +1,47 @@
+```
+pandoc -t beamer
+# Level 2 blocks
+
+<div class="columns">
+<div class="column" width="40%">
+## Block one
+- Item
+</div>
+<div class="column" width="60%">
+## Block two
+- Item
+</div>
+</div>
+^D
+\begin{frame}{%
+\protect\hypertarget{level-2-blocks}{%
+Level 2 blocks}}
+
+\begin{columns}[T]
+\begin{column}{0.40\textwidth}
+\begin{block}{Block one}
+
+\begin{itemize}
+\tightlist
+\item
+ Item
+\end{itemize}
+
+\end{block}
+\end{column}
+
+\begin{column}{0.60\textwidth}
+\begin{block}{Block two}
+
+\begin{itemize}
+\tightlist
+\item
+ Item
+\end{itemize}
+
+\end{block}
+\end{column}
+\end{columns}
+
+\end{frame}
+```
diff --git a/test/command/4019.md b/test/command/4019.md
new file mode 100644
index 000000000..ab13f0233
--- /dev/null
+++ b/test/command/4019.md
@@ -0,0 +1,8 @@
+```
+pandoc --wrap=preserve
+This <!-- x > 0 --> works!
+This <!-- x > 0 --> fails?
+^D
+<p>This <!-- x > 0 --> works!
+This <!-- x > 0 --> fails?</p>
+```
diff --git a/test/command/4038.md b/test/command/4038.md
new file mode 100644
index 000000000..121760540
--- /dev/null
+++ b/test/command/4038.md
@@ -0,0 +1,6 @@
+```
+% pandoc -f gfm -t gfm
+# ~~Header~~
+^D
+# ~~Header~~
+```
diff --git a/test/command/4054.md b/test/command/4054.md
new file mode 100644
index 000000000..3689773c4
--- /dev/null
+++ b/test/command/4054.md
@@ -0,0 +1,14 @@
+```
+% pandoc -t native -s -M title=New
+% Old
+^D
+Pandoc (Meta {unMeta = fromList [("title",MetaString "New")]})
+[]
+```
+
+```
+% pandoc -t native -s -M foo=1 -M foo=2
+^D
+Pandoc (Meta {unMeta = fromList [("foo",MetaList [MetaString "1",MetaString "2"])]})
+[]
+```
diff --git a/test/command/4056.md b/test/command/4056.md
new file mode 100644
index 000000000..eed4f6d6a
--- /dev/null
+++ b/test/command/4056.md
@@ -0,0 +1,24 @@
+```
+% pandoc -f markdown -t native
+\parbox[t]{0.4\textwidth}{
+\begin{shaded}
+\end{shaded}
+}
+^D
+[RawBlock (Format "latex") "\\parbox[t]{0.4\\textwidth}{\n\\begin{shaded}\n\\end{shaded}\n}"]
+```
+
+```
+% pandoc -f latex -t native
+\begin{tabular}{l*{2}{r}}
+Blah & Foo & Bar \\
+\end{tabular}
+^D
+[Table [] [AlignLeft,AlignRight,AlignRight] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "Blah"]]
+ ,[Plain [Str "Foo"]]
+ ,[Plain [Str "Bar"]]]]]
+```
diff --git a/test/command/4061.md b/test/command/4061.md
new file mode 100644
index 000000000..e850c5e8c
--- /dev/null
+++ b/test/command/4061.md
@@ -0,0 +1,14 @@
+```
+% pandoc -t markdown-simple_tables-multiline_tables-pipe_tables
++-----------------------------------+
+| Text [^1] |
++-----------------------------------+
+
+[^1]: Footnote.
+^D
++-----------------------------------+
+| Text [^1] |
++-----------------------------------+
+
+[^1]: Footnote.
+```
diff --git a/test/command/4062.md b/test/command/4062.md
new file mode 100644
index 000000000..2e212f826
--- /dev/null
+++ b/test/command/4062.md
@@ -0,0 +1,6 @@
+```
+% pandoc -t latex
+Sentence blah.\footnote[][-.5in]{I'm a footnote}
+^D
+Sentence blah.\footnote[][-.5in]{I'm a footnote}
+```
diff --git a/test/command/4068.md b/test/command/4068.md
new file mode 100644
index 000000000..7b43a7084
--- /dev/null
+++ b/test/command/4068.md
@@ -0,0 +1,9 @@
+```
+pandoc -f mediawiki -t native
+[https://domain.com/script.php?a=1&b=2&c=&d=4 open productname bugs]
+
+[http://domain.com?a=. open productname bugs]
+^D
+[Para [Link ("",[],[]) [Str "open",Space,Str "productname",Space,Str "bugs"] ("https://domain.com/script.php?a=1&b=2&c=&d=4","")]
+,Para [Str "[",Link ("",[],[]) [Str "http://domain.com?a="] ("http://domain.com?a=",""),Str ".",Space,Str "open",Space,Str "productname",Space,Str "bugs]"]]
+```
diff --git a/test/command/4091.md b/test/command/4091.md
new file mode 100644
index 000000000..13f3323d1
--- /dev/null
+++ b/test/command/4091.md
@@ -0,0 +1,6 @@
+```
+% pandoc -f latex
+\alert<3>{foo}
+^D
+<p><span class="alert">foo</span></p>
+```
diff --git a/test/command/4113.md b/test/command/4113.md
new file mode 100644
index 000000000..41fbcaf80
--- /dev/null
+++ b/test/command/4113.md
@@ -0,0 +1,12 @@
+```
+% pandoc -t gfm
+::::{.bug}
+I am a [bug]{#bug}.
+::::
+^D
+<div class="bug">
+
+I am a <span id="bug">bug</span>.
+
+</div>
+```
diff --git a/test/command/4119.md b/test/command/4119.md
new file mode 100644
index 000000000..70f008643
--- /dev/null
+++ b/test/command/4119.md
@@ -0,0 +1,18 @@
+```
+pandoc -t native
+| col1 | col2 |
+| ---- | ---- |
+| 1 | 2 |
+
+::: {.notes} :::
+not a caption!
+::::::::::::::::
+^D
+[Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str "col1"]]
+ ,[Plain [Str "col2"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]]]
+,Div ("",["notes"],[])
+ [Para [Str "not",Space,Str "a",Space,Str "caption!"]]]
+```
diff --git a/test/command/4125.md b/test/command/4125.md
new file mode 100644
index 000000000..8bf09d84c
--- /dev/null
+++ b/test/command/4125.md
@@ -0,0 +1,6 @@
+```
+% pandoc
+<?asciidoc-toc?>
+^D
+<?asciidoc-toc?>
+```
diff --git a/test/command/4134.md b/test/command/4134.md
new file mode 100644
index 000000000..b5473d948
--- /dev/null
+++ b/test/command/4134.md
@@ -0,0 +1,25 @@
+```
+% pandoc -f latex -t native
+Hello.\
+world.
+^D
+[Para [Str "Hello.\160world."]]
+```
+
+```
+% pandoc -f latex -t native
+Hello.\
+ world.
+^D
+[Para [Str "Hello.\160world."]]
+```
+
+```
+% pandoc -f latex -t native
+Hello.\
+
+World.
+^D
+[Para [Str "Hello.\160"]
+,Para [Str "World."]]
+```
diff --git a/test/command/4156.md b/test/command/4156.md
new file mode 100644
index 000000000..073537d1f
--- /dev/null
+++ b/test/command/4156.md
@@ -0,0 +1,10 @@
+```
+% pandoc -f rst
+.. _`SOMEID`:
+
+foo
+^D
+<div id="SOMEID">
+<p>foo</p>
+</div>
+```
diff --git a/test/command/4159.md b/test/command/4159.md
new file mode 100644
index 000000000..4881edcc5
--- /dev/null
+++ b/test/command/4159.md
@@ -0,0 +1,8 @@
+```
+% pandoc -f markdown -t native
+\newcommand{\gen}{a\ Gen\ b}
+abc
+^D
+[RawBlock (Format "latex") "\\newcommand{\\gen}{a\\ Gen\\ b}"
+,Para [Str "abc"]]
+```
diff --git a/test/command/4162.md b/test/command/4162.md
new file mode 100644
index 000000000..d88e1ec4e
--- /dev/null
+++ b/test/command/4162.md
@@ -0,0 +1,10 @@
+```
+% pandoc -f html -t native
+<div class="line-block">hi<br /><br>
+ there</div>
+^D
+[LineBlock
+ [[Str "hi"]
+ ,[]
+ ,[Str "\160there"]]]
+```
diff --git a/test/command/4164.md b/test/command/4164.md
new file mode 100644
index 000000000..8cfc960a0
--- /dev/null
+++ b/test/command/4164.md
@@ -0,0 +1,35 @@
+```
+% pandoc -f opml -t markdown
+<?xml version="1.0"?> <opml version="1.0"> <head> <title> test </title> </head> <body> <outline text="test"> <outline text="try" _note="Here is inline html:&#xA;&#xA;&lt;div&gt; &#xA;&lt;balise&gt;&#xA;bla bla&#xA;&lt;/div&gt;"/> </outline> </body> </opml>
+^D
+test
+====
+
+try
+---
+
+Here is inline html:
+
+<div>
+
+<balise> bla bla
+
+</div>
+
+```
+
+```
+% pandoc -f opml-raw_html-native_divs -t markdown
+<?xml version="1.0"?> <opml version="1.0"> <head> <title> test </title> </head> <body> <outline text="test"> <outline text="try" _note="Here is inline html:&#xA;&#xA;&lt;div&gt; &#xA;&lt;balise&gt;&#xA;bla bla&#xA;&lt;/div&gt;"/> </outline> </body> </opml>
+^D
+test
+====
+
+try
+---
+
+Here is inline html:
+
+\<div\> \<balise\> bla bla \</div\>
+
+```
diff --git a/test/command/4171.md b/test/command/4171.md
new file mode 100644
index 000000000..42b4576e3
--- /dev/null
+++ b/test/command/4171.md
@@ -0,0 +1,34 @@
+```
+% pandoc -f org -t org
+Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa [fn:1] a
+
+[fn:1] b
+^D
+Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa [fn:1]
+a
+
+[fn:1] b
+```
+
+
+```
+% pandoc -f org -t org
+Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ [fn:1] a
+
+[fn:1] b
+^D
+Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa [fn:1]
+a
+
+[fn:1] b
+```
+
+Similar bug: "-" should not be wrapped:
+```
+% pandoc -f org -t org
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - abc
+^D
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -
+abc
+```
diff --git a/test/command/4172.md b/test/command/4172.md
new file mode 100644
index 000000000..6b497a87a
--- /dev/null
+++ b/test/command/4172.md
@@ -0,0 +1,29 @@
+Test that text wrapping does not move note reference [1] to the beginning of the line,
+where it would become a note.
+```
+% pandoc -f muse -t muse
+Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa [1] a
+
+[1] b
+^D
+Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa [1]
+a
+
+[1] b
+
+```
+
+SoftBreak test:
+```
+% pandoc -f muse -t muse
+Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ [1] a
+
+[1] b
+^D
+Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa [1]
+a
+
+[1] b
+
+```
diff --git a/test/command/4183.md b/test/command/4183.md
new file mode 100644
index 000000000..c18320882
--- /dev/null
+++ b/test/command/4183.md
@@ -0,0 +1,32 @@
+```
+% pandoc -f html -t native
+<figure>
+ <img src="foo" alt="bar">
+</figure>
+^D
+[Para [Image ("",[],[]) [] ("foo","fig:")]]
+```
+
+```
+% pandoc -f html -t native
+<figure>
+ <img src="foo" alt="bar">
+ <figcaption>
+ <div>
+ baz
+ </div>
+ </figcaption>
+</figure>
+^D
+[Para [Image ("",[],[]) [Str "baz"] ("foo","fig:")]]
+```
+
+```
+% pandoc -f html -t native
+<figure>
+ <img src="foo">
+ <figcaption><p><em>baz</em></p></figcaption>
+</figure>
+^D
+[Para [Image ("",[],[]) [Emph [Str "baz"]] ("foo","fig:")]]
+```
diff --git a/test/command/4193.md b/test/command/4193.md
new file mode 100644
index 000000000..44c7d70cc
--- /dev/null
+++ b/test/command/4193.md
@@ -0,0 +1,10 @@
+```
+% pandoc -f rst -t native
+-
+ a
+- b
+^D
+[BulletList
+ [[Plain [Str "a"]]
+ ,[Plain [Str "b"]]]]
+```
diff --git a/test/command/4199.md b/test/command/4199.md
new file mode 100644
index 000000000..49d2bdbcb
--- /dev/null
+++ b/test/command/4199.md
@@ -0,0 +1,6 @@
+```
+% pandoc -f latex -t native
+\foreignlanguage{ngerman}{foo}
+^D
+[Para [Span ("",[],[("lang","de-DE")]) [Str "foo"]]]
+```
diff --git a/test/command/4208.md b/test/command/4208.md
new file mode 100644
index 000000000..9bc519d90
--- /dev/null
+++ b/test/command/4208.md
@@ -0,0 +1,18 @@
+```
+% pandoc -t latex
+What is a _piffle_? Mark the correct answer(s):
+
+\begin{TAB}(@)[6pt]{|l|c|}{|c|c|c|}
+(a) a subnormal woffle & $\Box$ \\
+(b) an infinite-dimensional baffle & $\Box$ \\
+(c) an inverted first-order triffle & $\Box$ \\
+\end{TAB}
+^D
+What is a \emph{piffle}? Mark the correct answer(s):
+
+\begin{TAB}(@)[6pt]{|l|c|}{|c|c|c|}
+(a) a subnormal woffle & $\Box$ \\
+(b) an infinite-dimensional baffle & $\Box$ \\
+(c) an inverted first-order triffle & $\Box$ \\
+\end{TAB}
+```
diff --git a/test/command/4235.md b/test/command/4235.md
new file mode 100644
index 000000000..a5d545676
--- /dev/null
+++ b/test/command/4235.md
@@ -0,0 +1,12 @@
+```
+% pandoc --id-prefix=foo
+This.^[Has a footnote.]
+^D
+<p>This.<a href="#foofn1" class="footnote-ref" id="foofnref1"><sup>1</sup></a></p>
+<section class="footnotes">
+<hr />
+<ol>
+<li id="foofn1"><p>Has a footnote.<a href="#foofnref1" class="footnote-back">↩</a></p></li>
+</ol>
+</section>
+```
diff --git a/test/command/4240.md b/test/command/4240.md
new file mode 100644
index 000000000..39a7d2adf
--- /dev/null
+++ b/test/command/4240.md
@@ -0,0 +1,33 @@
+```
+% pandoc -f rst -s -t native
+=====
+Title
+=====
+
+--------
+Subtitle
+--------
+
+header1
+=======
+
+header2
+-------
+
+.. _id:
+
+header3
+~~~~~~~
+
+.. _id2:
+.. _id3:
+
+header4
+~~~~~~~
+^D
+Pandoc (Meta {unMeta = fromList [("subtitle",MetaInlines [Str "Subtitle"]),("title",MetaInlines [Str "Title"])]})
+[Header 1 ("header1",[],[]) [Str "header1"]
+,Header 2 ("header2",[],[]) [Str "header2"]
+,Header 3 ("id",[],[]) [Str "header3"]
+,Header 3 ("id3",[],[]) [Str "header4",Span ("id2",[],[]) []]]
+```
diff --git a/test/command/4253.md b/test/command/4253.md
new file mode 100644
index 000000000..01f5eea86
--- /dev/null
+++ b/test/command/4253.md
@@ -0,0 +1,8 @@
+```
+% pandoc -f latex -t native
+\newcommand{\noop}[1]{#1}
+\noop{\newcommand{\foo}[1]{#1}}
+\foo{hi}
+^D
+[Para [Str "hi"]]
+```
diff --git a/test/command/4254.md b/test/command/4254.md
new file mode 100644
index 000000000..e4cc5c6b0
--- /dev/null
+++ b/test/command/4254.md
@@ -0,0 +1,12 @@
+```
+% pandoc -f rst -t latex
+.. math::
+
+ x &= y\\
+ y &= z
+^D
+\[\begin{aligned}
+x &= y\\
+y &= z
+\end{aligned}\]
+```
diff --git a/test/command/4280.md b/test/command/4280.md
new file mode 100644
index 000000000..6a89b5e63
--- /dev/null
+++ b/test/command/4280.md
@@ -0,0 +1,7 @@
+```
+% pandoc -f rst -t native
+Driver
+------
+^D
+[Header 1 ("driver",[],[]) [Str "Driver"]]
+```
diff --git a/test/command/4281.md b/test/command/4281.md
new file mode 100644
index 000000000..9806e8178
--- /dev/null
+++ b/test/command/4281.md
@@ -0,0 +1,18 @@
+```
+% pandoc -t native
+:::: {.a}
+- ::: {.b}
+ text
+ :::
+ ::: {.c}
+ text
+ :::
+::::
+^D
+[Div ("",["a"],[])
+ [BulletList
+ [[Div ("",["b"],[])
+ [Para [Str "text"]]
+ ,Div ("",["c"],[])
+ [Para [Str "text"]]]]]]
+```
diff --git a/test/command/4374.md b/test/command/4374.md
new file mode 100644
index 000000000..296c116a9
--- /dev/null
+++ b/test/command/4374.md
@@ -0,0 +1,7 @@
+```
+% pandoc -f latex -t native
+\cite{a%
+}
+^D
+[Para [Cite [Citation {citationId = "a", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cite{a%\n}"]]]
+```
diff --git a/test/command/4424.md b/test/command/4424.md
new file mode 100644
index 000000000..b0b95510b
--- /dev/null
+++ b/test/command/4424.md
@@ -0,0 +1,10 @@
+```
+% pandoc -f latex -t native
+\documentclass{article}
+\usepackage[sortlocale=en_GB]{biblatex}
+\begin{document}
+Test
+\end{document}
+^D
+[Para [Str "Test"]]
+```
diff --git a/test/command/512.md b/test/command/512.md
new file mode 100644
index 000000000..b95921309
--- /dev/null
+++ b/test/command/512.md
@@ -0,0 +1,42 @@
+```
+% pandoc -f rst
+`click here`__ or `click here`__
+
+.. _link1: http://www.example.com/
+.. _link2: http://johnmacfarlane.net/pandoc/
+
+__ link1_
+__ link2_
+^D
+<p><a href="http://www.example.com/">click here</a> or <a href="http://johnmacfarlane.net/pandoc/">click here</a></p>
+```
+
+Multiple indirection:
+
+```
+% pandoc -f rst
+`click here`__
+
+.. _link1: link2_
+.. _link2: http://johnmacfarlane.net/pandoc/
+
+__ link1_
+^D
+<p><a href="http://johnmacfarlane.net/pandoc/">click here</a></p>
+```
+
+Loop detection:
+
+```
+% pandoc -f rst
+`click here`__
+
+.. _link1: link2_
+.. _link2: link1_
+
+__ link1_
+^D
+[WARNING] Circular reference 'link1' at line 1 column 15
+<p><a href="">click here</a></p>
+```
+
diff --git a/test/command/645.md b/test/command/645.md
new file mode 100644
index 000000000..90b285bed
--- /dev/null
+++ b/test/command/645.md
@@ -0,0 +1,12 @@
+Don't use listings commands in \item[..] context:
+```
+% pandoc -t latex
+`--foo` **BAR**
+
+: Enables the foo feature with **BAR** as its flavour.
+^D
+\begin{description}
+\item[\texttt{-\/-foo} \textbf{BAR}]
+Enables the foo feature with \textbf{BAR} as its flavour.
+\end{description}
+```
diff --git a/test/command/853.md b/test/command/853.md
new file mode 100644
index 000000000..54eb416a9
--- /dev/null
+++ b/test/command/853.md
@@ -0,0 +1,18 @@
+reStructuredText citations.
+
+```
+% pandoc -f rst
+Here is a citation reference: [CIT2002]_.
+
+.. [CIT2002] This is the citation. It's just like a footnote,
+ except the label is textual.
+^D
+<p>Here is a citation reference: <a href="#CIT2002" class="citation">[CIT2002]</a>.</p>
+<div id="citations">
+<dl>
+<dt><span id="CIT2002" class="citation-label">CIT2002</span></dt>
+<dd><p>This is the citation. It's just like a footnote, except the label is textual.</p>
+</dd>
+</dl>
+</div>
+```
diff --git a/test/command/934.md b/test/command/934.md
new file mode 100644
index 000000000..ef99abdf9
--- /dev/null
+++ b/test/command/934.md
@@ -0,0 +1,12 @@
+```
+% pandoc -f latex -t native
+\newcommand{\ddb}[2]{
+ \textit{``#1''}
+
+ \textbf{#2}
+}
+\ddb{This should be italic and in quotes}{And this is the attribution}
+^D
+[Para [Emph [Quoted DoubleQuote [Str "This",Space,Str "should",Space,Str "be",Space,Str "italic",Space,Str "and",Space,Str "in",Space,Str "quotes"]]]
+,Para [Strong [Str "And",Space,Str "this",Space,Str "is",Space,Str "the",Space,Str "attribution"]]]
+```
diff --git a/test/command/982.md b/test/command/982.md
new file mode 100644
index 000000000..5f54f7713
--- /dev/null
+++ b/test/command/982.md
@@ -0,0 +1,11 @@
+```
+% pandoc -f latex -t native
+\newcommand{\BEQ}{\begin{equation}}
+\newcommand{\EEQ}{\end{equation}}
+
+\BEQ
+y=x^2
+\EEQ
+^D
+[Para [Math DisplayMath "y=x^2"]]
+```
diff --git a/test/command/987.md b/test/command/987.md
new file mode 100644
index 000000000..f632231ef
--- /dev/null
+++ b/test/command/987.md
@@ -0,0 +1,12 @@
+```
+pandoc -f latex -t markdown
+\documentclass{article}
+\newenvironment{flubble}{FOO}{BAR}
+\begin{document}
+ \begin{flubble}
+ grr
+ \end{flubble}
+\end{document}
+^D
+FOO grr BAR
+```
diff --git a/test/command/SVG_logo-without-xml-declaration.svg b/test/command/SVG_logo-without-xml-declaration.svg
new file mode 100644
index 000000000..febcab6ca
--- /dev/null
+++ b/test/command/SVG_logo-without-xml-declaration.svg
@@ -0,0 +1,32 @@
+<svg viewBox="-50 -50 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<title>SVG Logo</title>
+<rect id="background" x="-50" y="-50" width="100" height="100" rx="4" fill="#f90"/>
+<rect id="top-left" x="-50" y="-50" width="50" height="50" rx="4" fill="#ffb13b"/>
+<rect id="bottom-right" width="50" height="50" rx="4" fill="#de8500"/>
+<use stroke="#f90" stroke-width="22.6" xlink:href="#a"/>
+<circle r="26"/>
+<use stroke="#000" stroke-width="12" xlink:href="#a"/>
+<g id="a">
+ <g id="b">
+ <g id="c">
+ <circle id="n" cy="-31.6" r="7.1" fill="#fff"/>
+ <path d="m0 31.6v-63.2" stroke="#fff" stroke-width="10"/>
+ <use y="63.2" xlink:href="#n"/>
+ </g>
+ <use transform="rotate(90)" xlink:href="#c"/>
+ </g>
+ <use transform="rotate(45)" xlink:href="#b"/>
+</g>
+<path id="text-backdrop" d="m44.68 0v40c0 3.333-1.667 5-5 5h-79.38c-3.333 0-5-1.667-5-5v-40"/>
+<path id="shine" d="m36 4.21c2.9 0 5.3 2.4 5.3 5.3v18c-27.6-3.4-54.9-8-82-7.7v-10.2c0-2.93 2.4-5.3 5.3-5.3z" fill="#3f3f3f"/>
+<use stroke="#000" stroke-width="7.4" xlink:href="#s"/>
+<g id="svg-text" stroke="#fff" stroke-width="6.4">
+ <g id="s">
+ <path fill="none" d="m-31.74 31.17a8.26 8.26 0 1 0 8.26 -8.26 8.26 8.26 0 1 1 8.26 -8.26M23.23 23h8.288v 8.26a8.26 8.26 0 0 1 -16.52 0v-16.52a8.26 8.26 0 0 1 16.52 0"/>
+ <g stroke-width=".5" stroke="#000">
+ <path d="m4.76 3h6.83l-8.24 39.8h-6.85l-8.26-39.8h6.85l4.84 23.3z" fill="#fff"/>
+ <path d="m23.23 19.55v6.9m4.838-11.71h6.9m-70.16 16.43h6.9m9.62-16.52h6.9" stroke-linecap="square"/>
+ </g>
+ </g>
+</g>
+</svg>
diff --git a/test/command/SVG_logo.svg b/test/command/SVG_logo.svg
new file mode 100644
index 000000000..5333a5ddb
--- /dev/null
+++ b/test/command/SVG_logo.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<svg viewBox="-50 -50 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<title>SVG Logo</title>
+<rect id="background" x="-50" y="-50" width="100" height="100" rx="4" fill="#f90"/>
+<rect id="top-left" x="-50" y="-50" width="50" height="50" rx="4" fill="#ffb13b"/>
+<rect id="bottom-right" width="50" height="50" rx="4" fill="#de8500"/>
+<use stroke="#f90" stroke-width="22.6" xlink:href="#a"/>
+<circle r="26"/>
+<use stroke="#000" stroke-width="12" xlink:href="#a"/>
+<g id="a">
+ <g id="b">
+ <g id="c">
+ <circle id="n" cy="-31.6" r="7.1" fill="#fff"/>
+ <path d="m0 31.6v-63.2" stroke="#fff" stroke-width="10"/>
+ <use y="63.2" xlink:href="#n"/>
+ </g>
+ <use transform="rotate(90)" xlink:href="#c"/>
+ </g>
+ <use transform="rotate(45)" xlink:href="#b"/>
+</g>
+<path id="text-backdrop" d="m44.68 0v40c0 3.333-1.667 5-5 5h-79.38c-3.333 0-5-1.667-5-5v-40"/>
+<path id="shine" d="m36 4.21c2.9 0 5.3 2.4 5.3 5.3v18c-27.6-3.4-54.9-8-82-7.7v-10.2c0-2.93 2.4-5.3 5.3-5.3z" fill="#3f3f3f"/>
+<use stroke="#000" stroke-width="7.4" xlink:href="#s"/>
+<g id="svg-text" stroke="#fff" stroke-width="6.4">
+ <g id="s">
+ <path fill="none" d="m-31.74 31.17a8.26 8.26 0 1 0 8.26 -8.26 8.26 8.26 0 1 1 8.26 -8.26M23.23 23h8.288v 8.26a8.26 8.26 0 0 1 -16.52 0v-16.52a8.26 8.26 0 0 1 16.52 0"/>
+ <g stroke-width=".5" stroke="#000">
+ <path d="m4.76 3h6.83l-8.24 39.8h-6.85l-8.26-39.8h6.85l4.84 23.3z" fill="#fff"/>
+ <path d="m23.23 19.55v6.9m4.838-11.71h6.9m-70.16 16.43h6.9m9.62-16.52h6.9" stroke-linecap="square"/>
+ </g>
+ </g>
+</g>
+</svg>
diff --git a/test/command/abbrevs b/test/command/abbrevs
new file mode 100644
index 000000000..1f8efe68e
--- /dev/null
+++ b/test/command/abbrevs
@@ -0,0 +1,2 @@
+Foo.
+h.k.
diff --git a/test/command/adjacent_latex_blocks.md b/test/command/adjacent_latex_blocks.md
new file mode 100644
index 000000000..3e72f1d4f
--- /dev/null
+++ b/test/command/adjacent_latex_blocks.md
@@ -0,0 +1,9 @@
+```
+% pandoc -f markdown -t native
+\listoffigures
+
+\listoftables
+^D
+[RawBlock (Format "latex") "\\listoffigures"
+,RawBlock (Format "latex") "\\listoftables"]
+```
diff --git a/test/command/cite-in-inline-note.md b/test/command/cite-in-inline-note.md
new file mode 100644
index 000000000..069484eed
--- /dev/null
+++ b/test/command/cite-in-inline-note.md
@@ -0,0 +1,6 @@
+```
+% pandoc -t native
+foo^[bar [@doe]]
+^D
+[Para [Str "foo",Note [Para [Str "bar",Space,Cite [Citation {citationId = "doe", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@doe]"]]]]]
+```
diff --git a/test/command/corrupt.svg b/test/command/corrupt.svg
new file mode 100644
index 000000000..cfaa697f0
--- /dev/null
+++ b/test/command/corrupt.svg
@@ -0,0 +1,5 @@
+Lorem ipsum dolor sit amet etiam. A pede dolor neque pretium luctus pharetra vel rutrum. Orci nonummy ac. At eu est tempor
+proin wisi. Nunc tincidunt proin. Suspendisse lorem commodo. Integer diam diam semper commodo dictum et tellus eu ultrices
+nec erat pulvinar porttitor nulla nulla mauris orci libero eros elementum et possimus voluptate. Velit morbi et. Luctus diam
+in. Lorem tincidunt sem dolor rerum mauris. Dis taciti posuere pellentesque sed rutrum. Lectus donec fusce in dictum pede.
+In etiam congue. Aliquam aliquet elit arcu mauris enim. Risus at enim.
diff --git a/test/command/dots.md b/test/command/dots.md
new file mode 100644
index 000000000..08bc561a8
--- /dev/null
+++ b/test/command/dots.md
@@ -0,0 +1,12 @@
+```
+% pandoc -f latex -t native
+\dots
+
+\ldots
+
+\vdots
+^D
+[Para [Str "\8230"]
+,Para [Str "\8230"]
+,Para [Str "\8942"]]
+```
diff --git a/test/command/empty_paragraphs.md b/test/command/empty_paragraphs.md
new file mode 100644
index 000000000..001aaf1b0
--- /dev/null
+++ b/test/command/empty_paragraphs.md
@@ -0,0 +1,95 @@
+```
+% pandoc -f native -t docx -o - | pandoc -f docx -t native
+[Para [Str "hi"], Para [], Para [], Para [Str "lo"]]
+^D
+[Para [Str "hi"]
+,Para [Str "lo"]]
+```
+
+```
+% pandoc -f native -t docx+empty_paragraphs -o - | pandoc -f docx -t native
+[Para [Str "hi"], Para [], Para [], Para [Str "lo"]]
+^D
+[Para [Str "hi"]
+,Para [Str "lo"]]
+```
+
+```
+% pandoc -f native -t docx -o - | pandoc -f docx+empty_paragraphs -t native
+[Para [Str "hi"], Para [], Para [], Para [Str "lo"]]
+^D
+[Para [Str "hi"]
+,Para [Str "lo"]]
+```
+
+```
+% pandoc -f native -t docx+empty_paragraphs -o - | pandoc -f docx+empty_paragraphs -t native
+[Para [Str "hi"], Para [], Para [], Para [Str "lo"]]
+^D
+[Para [Str "hi"]
+,Para []
+,Para []
+,Para [Str "lo"]]
+```
+
+```
+% pandoc -f native -t html5
+[Para [Str "hi"], Para [], Para [], Para [Str "lo"]]
+^D
+<p>hi</p>
+
+
+<p>lo</p>
+```
+
+```
+% pandoc -f native -t html5+empty_paragraphs
+[Para [Str "hi"], Para [], Para [], Para [Str "lo"]]
+^D
+<p>hi</p>
+<p></p>
+<p></p>
+<p>lo</p>
+```
+
+```
+% pandoc -f html+empty_paragraphs -t native
+<p>hi</p>
+<p></p>
+<p></p>
+<p>lo</p>
+^D
+[Para [Str "hi"]
+,Para []
+,Para []
+,Para [Str "lo"]]
+```
+
+```
+% pandoc -f html -t native
+<p>hi</p>
+<p></p>
+<p></p>
+<p>lo</p>
+^D
+[Para [Str "hi"]
+,Para [Str "lo"]]
+```
+
+```
+% pandoc -f native -t opendocument+empty_paragraphs
+[Para [Str "hi"], Para [], Para [], Para [Str "lo"]]
+^D
+<text:p text:style-name="Text_20_body">hi</text:p>
+<text:p text:style-name="Text_20_body"></text:p>
+<text:p text:style-name="Text_20_body"></text:p>
+<text:p text:style-name="Text_20_body">lo</text:p>
+```
+
+```
+% pandoc -f native -t opendocument
+[Para [Str "hi"], Para [], Para [], Para [Str "lo"]]
+^D
+<text:p text:style-name="Text_20_body">hi</text:p>
+<text:p text:style-name="Text_20_body">lo</text:p>
+```
diff --git a/test/command/gfm.md b/test/command/gfm.md
new file mode 100644
index 000000000..670f3cd6e
--- /dev/null
+++ b/test/command/gfm.md
@@ -0,0 +1,103 @@
+gfm tests:
+
+```
+% pandoc -f gfm -t native
+| Fruit | Price |
+| ----- | ----: |
+| apple | 0.13 |
+| orange|1.12|
+^D
+[Table [] [AlignDefault,AlignRight] [0.0,0.0]
+ [[Plain [Str "Fruit"]]
+ ,[Plain [Str "Price"]]]
+ [[[Plain [Str "apple"]]
+ ,[Plain [Str "0.13"]]]
+ ,[[Plain [Str "orange"]]
+ ,[Plain [Str "1.12"]]]]]
+```
+
+```
+% pandoc -f gfm -t native
+~~stricken out~~
+^D
+[Para [Strikeout [Str "stricken",Space,Str "out"]]]
+```
+
+```
+% pandoc -f gfm -t native
+# Header
+## Header
+# -foo-bar_baz
+^D
+[Header 1 ("header",[],[]) [Str "Header"]
+,Header 2 ("header-1",[],[]) [Str "Header"]
+,Header 1 ("-foo-bar_baz",[],[]) [Str "-foo-bar_baz"]]
+```
+
+```
+% pandoc -f gfm -t native
+My:thumbsup:emoji:heart:
+^D
+[Para [Str "My\128077emoji\10084\65039"]]
+```
+
+```
+% pandoc -f gfm -t native
+"hi"
+^D
+[Para [Str "\"hi\""]]
+```
+
+```
+% pandoc -f gfm+smart -t native
+"hi"
+^D
+[Para [Str "\8220hi\8221"]]
+```
+
+```
+% pandoc -t gfm -f native
+[Table [Str "The",Space,Str "caption."] [AlignDefault,AlignRight] [0.0,0.0]
+ [[Plain [Str "Fruit"]]
+ ,[Plain [Str "Price"]]]
+ [[[Plain [Str "apple"]]
+ ,[Plain [Str "0.13"]]]
+ ,[[Plain [Str "orange"]]
+ ,[Plain [Str "1.12"]]]]]
+^D
+| Fruit | Price |
+| ------ | ----: |
+| apple | 0.13 |
+| orange | 1.12 |
+
+The caption.
+```
+
+```
+% pandoc -f gfm-smart -t gfm+smart
+“hi”
+^D
+"hi"
+```
+
+```
+% pandoc -f gfm+smart -t gfm-smart
+"hi"
+^D
+“hi”
+```
+
+```
+% pandoc -f gfm+smart -t gfm+smart
+"hi"
+^D
+"hi"
+```
+
+```
+% pandoc -f gfm+hard_line_breaks -t native
+hi
+hi
+^D
+[Para [Str "hi",LineBreak,Str "hi"]]
+```
diff --git a/test/command/hspace.md b/test/command/hspace.md
new file mode 100644
index 000000000..ec1669ca5
--- /dev/null
+++ b/test/command/hspace.md
@@ -0,0 +1,56 @@
+`\hspace` and `\vspace` should count as both block and inline.
+
+Here they need to be inline:
+```
+% pandoc -f markdown+raw_tex -t native
+\begin{figure}
+\includegraphics{lalune.jpg}
+\caption{lalune \hspace{2em} \vspace{1em} bloo}
+\end{figure}
+^D
+[RawBlock (Format "latex") "\\begin{figure}\n\\includegraphics{lalune.jpg}\n\\caption{lalune \\hspace{2em} \\vspace{1em} bloo}\n\\end{figure}"]
+```
+
+Here block:
+```
+% pandoc -f markdown+raw_tex -t native
+\begin{tabular}[t]{cc|c}
+\(P\) & \(Q\) & \(P\wedge Q\)\\
+\hline
+T & T &\\
+T & F &\\
+F & T &\\
+F & F &\\
+\end{tabular}
+\hspace{1em}
+\begin{tabular}[t]{cc|c}
+\(P\) & \(Q\) & \(P\vee Q\)\\
+\hline
+T & T &\\
+T & F &\\
+F & T &\\
+F & F &\\
+\end{tabular}
+^D
+[RawBlock (Format "latex") "\\begin{tabular}[t]{cc|c}\n\\(P\\) & \\(Q\\) & \\(P\\wedge Q\\)\\\\\n\\hline\nT & T &\\\\\nT & F &\\\\\nF & T &\\\\\nF & F &\\\\\n\\end{tabular}\n\\hspace{1em}\n\\begin{tabular}[t]{cc|c}\n\\(P\\) & \\(Q\\) & \\(P\\vee Q\\)\\\\\n\\hline\nT & T &\\\\\nT & F &\\\\\nF & T &\\\\\nF & F &\\\\\n\\end{tabular}"]
+```
+
+```
+% pandoc -f markdown+raw_tex -t native
+hi\hspace{1em}there
+^D
+[Para [Str "hi",RawInline (Format "tex") "\\hspace{1em}",Str "there"]]
+```
+
+```
+% pandoc -f markdown+raw_tex -t native
+hi
+
+\hspace{1em}
+
+there
+^D
+[Para [Str "hi"]
+,RawBlock (Format "latex") "\\hspace{1em}"
+,Para [Str "there"]]
+```
diff --git a/test/command/html-read-figure.md b/test/command/html-read-figure.md
new file mode 100644
index 000000000..9c604c706
--- /dev/null
+++ b/test/command/html-read-figure.md
@@ -0,0 +1,45 @@
+```
+% pandoc -f html -t native
+<figure>
+ <img src="foo.png" title="voyage">
+ <figcaption>bar</figcaption>
+</figure>
+^D
+[Para [Image ("",[],[]) [Str "bar"] ("foo.png","fig:voyage")]]
+```
+
+```
+% pandoc -f html -t native
+<figure>
+ <figcaption>bar</figcaption>
+ <img src="foo.png" title="voyage">
+</figure>
+^D
+[Para [Image ("",[],[]) [Str "bar"] ("foo.png","fig:voyage")]]
+```
+
+```
+% pandoc -f html -t native
+<figure>
+ <img src="foo.png" title="voyage">
+</figure>
+^D
+[Para [Image ("",[],[]) [] ("foo.png","fig:voyage")]]
+```
+
+```
+% pandoc -f html -t native
+<figure>
+ <p><img src="foo.png" title="voyage"></p>
+ <figcaption>bar</figcaption>
+</figure>
+^D
+[Para [Image ("",[],[]) [Str "bar"] ("foo.png","fig:voyage")]]
+```
+
+```
+% pandoc -f html -t native
+<figure><img src="foo.png" title="voyage" alt="this is ignored"><figcaption>bar <strong>baz</strong></figcaption></figure>
+^D
+[Para [Image ("",[],[]) [Str "bar",Space,Strong [Str "baz"]] ("foo.png","fig:voyage")]]
+```
diff --git a/test/command/hyphenat.md b/test/command/hyphenat.md
new file mode 100644
index 000000000..3aae85101
--- /dev/null
+++ b/test/command/hyphenat.md
@@ -0,0 +1,49 @@
+```
+% pandoc -f latex -t native
+electromagnetic\hyp{}endioscopy
+^D
+[Para [Str "electromagnetic-endioscopy"]]
+```
+
+```
+% pandoc -f latex -t native
+C\colonhyp\bshyp{}Windows\bshyp
+^D
+[Para [Str "C:\173\\\173Windows\\\173"]]
+```
+
+```
+% pandoc -f latex -t native
+\fshyp{}usr\fshyp{}share\fshyp
+^D
+[Para [Str "/\173usr/\173share/\173"]]
+```
+
+```
+% pandoc -f latex -t native
+\fshyp{}home\fshyp{}schrieveslaach\fshyp\dothyp{}m2
+^D
+[Para [Str "/\173home/\173schrieveslaach/\173.\173m2"]]
+```
+
+```
+% pandoc -f latex -t native
+\nohyphens{Pneumonoultramicroscopicsilicovolcanoconiosis}
+^D
+[Para [Str "Pneumonoultramicroscopicsilicovolcanoconiosis"]]
+```
+
+```
+% pandoc -f latex -t native
+\textnhtt{Pneumonoultramicroscopicsilicovolcanoconiosis}
+^D
+[Para [Code ("",[],[]) "Pneumonoultramicroscopicsilicovolcanoconiosis"]]
+```
+
+```
+% pandoc -f latex -t native
+\nhttfamily{Pneumonoultramicroscopicsilicovolcanoconiosis}
+^D
+[Para [Code ("",[],[]) "Pneumonoultramicroscopicsilicovolcanoconiosis"]]
+```
+
diff --git a/test/command/ifstrequal.md b/test/command/ifstrequal.md
new file mode 100644
index 000000000..4ad04d2e1
--- /dev/null
+++ b/test/command/ifstrequal.md
@@ -0,0 +1,10 @@
+```
+% pandoc -f latex -t native
+\ifstrequal{a}{b}{yes}{\emph{no}}
+\newcommand{\h}[1]{\ifstrequal{#1}{a}{\'a}{#1}}
+\h{a}
+\h{b}
+^D
+[Para [Emph [Str "no"]]
+,Para [Str "\225",SoftBreak,Str "b"]]
+```
diff --git a/test/command/indented-fences.md b/test/command/indented-fences.md
new file mode 100644
index 000000000..eb3b78212
--- /dev/null
+++ b/test/command/indented-fences.md
@@ -0,0 +1,20 @@
+`````
+% pandoc -t native
+ ```haskell
+ let x = y
+in y
+ ```
+^D
+[CodeBlock ("",["haskell"],[]) "let x = y\nin y"]
+`````
+`````
+% pandoc -t native
+ ~~~ {.haskell}
+ let x = y
+ in y +
+y +
+ y
+~~~
+^D
+[CodeBlock ("",["haskell"],[]) " let x = y\nin y +\ny +\ny"]
+`````
diff --git a/test/command/inkscape-cube.svg b/test/command/inkscape-cube.svg
new file mode 100644
index 000000000..995c3c734
--- /dev/null
+++ b/test/command/inkscape-cube.svg
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="38.772217mm"
+ height="46.163891mm"
+ viewBox="0 0 38.772217 46.163891"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.1 r"
+ sodipodi:docname="cube.svg">
+ <defs
+ id="defs2">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="-48.380952 : -45.023815 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="161.61905 : -45.023817 : 1"
+ inkscape:persp3d-origin="56.619048 : -94.523816 : 1"
+ id="perspective4485" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="-63.181251"
+ inkscape:cy="-116.38602"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1136"
+ inkscape:window-x="1920"
+ inkscape:window-y="30"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Ebene 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-149.67857,78.746839)">
+ <g
+ sodipodi:type="inkscape:box3d"
+ id="g4487"
+ style="opacity:0.2;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.53100002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ inkscape:perspectiveID="#perspective4485"
+ inkscape:corner0="1.1045097 : 0.18860662 : 0 : 1"
+ inkscape:corner7="0.52634769 : 0.15538942 : 0.25 : 1">
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4489"
+ style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="6"
+ d="m 151.19047,-53.658435 v 15.783818 l 17.00006,5.342459 v -14.107905 z"
+ points="151.19047,-37.874617 168.19053,-32.532158 168.19053,-46.640063 151.19047,-53.658435 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4499"
+ style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="11"
+ d="m 168.19053,-46.640063 21.77216,-19.229539 v 18.699717 l -21.77216,14.637727 z"
+ points="189.96269,-65.869602 189.96269,-47.169885 168.19053,-32.532158 168.19053,-46.640063 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4491"
+ style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="5"
+ d="m 151.19047,-53.658435 18.89881,-25.037614 19.87341,12.826447 -21.77216,19.229539 z"
+ points="170.08928,-78.696049 189.96269,-65.869602 168.19053,-46.640063 151.19047,-53.658435 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4497"
+ style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="13"
+ d="m 151.19047,-37.874617 18.89881,-19.058894 19.87341,9.763626 -21.77216,14.637727 z"
+ points="170.08928,-56.933511 189.96269,-47.169885 168.19053,-32.532158 151.19047,-37.874617 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4495"
+ style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="14"
+ d="m 170.08928,-78.696049 v 21.762538 l 19.87341,9.763626 v -18.699717 z"
+ points="170.08928,-56.933511 189.96269,-47.169885 189.96269,-65.869602 170.08928,-78.696049 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4493"
+ style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="3"
+ d="m 151.19047,-53.658435 18.89881,-25.037614 v 21.762538 l -18.89881,19.058894 z"
+ points="170.08928,-78.696049 170.08928,-56.933511 151.19047,-37.874617 151.19047,-53.658435 " />
+ </g>
+ </g>
+</svg>
diff --git a/test/command/latex-color.md b/test/command/latex-color.md
new file mode 100644
index 000000000..9fd2585a3
--- /dev/null
+++ b/test/command/latex-color.md
@@ -0,0 +1,127 @@
+# `\textcolor{}{}`
+
+```
+% pandoc -f latex -t native
+Hello \textcolor{red}{World}
+^D
+[Para [Str "Hello",Space,Span ("",[],[("style","color: red")]) [Str "World"]]]
+```
+
+```
+% pandoc -f latex -t native
+\textcolor{red}{Hello} World
+^D
+[Para [Span ("",[],[("style","color: red")]) [Str "Hello"],Space,Str "World"]]
+```
+
+```
+% pandoc -f latex -t native
+Hello \textcolor{blue}{\textbf{World}}
+^D
+[Para [Str "Hello",Space,Span ("",[],[("style","color: blue")]) [Strong [Str "World"]]]]
+```
+
+
+```
+% pandoc -f latex -t native
+Hello \textcolor{blue}{\textbf{World}}.
+^D
+[Para [Str "Hello",Space,Span ("",[],[("style","color: blue")]) [Strong [Str "World"]],Str "."]]
+```
+
+```
+% pandoc -f latex -t native
+\textcolor{orange}{
+\begin{itemize}
+ \item Item 1
+ \item Item 2
+\end{itemize}
+}
+^D
+[Div ("",[],[("style","color: orange")])
+ [BulletList
+ [[Para [Str "Item",Space,Str "1"]]
+ ,[Para [Str "Item",Space,Str "2"]]]]]
+```
+
+```
+% pandoc -f latex -t native
+\textcolor{blue}{
+\begin{itemize}
+ \item Item 1
+ \item Item 2
+\end{itemize}
+} some more text
+^D
+[Div ("",[],[("style","color: blue")])
+ [BulletList
+ [[Para [Str "Item",Space,Str "1"]]
+ ,[Para [Str "Item",Space,Str "2"]]]]
+,Para [Str "some",Space,Str "more",Space,Str "text"]]
+```
+
+# `\colorbox{}{}`
+
+
+```
+% pandoc -f latex -t native
+Hello \colorbox{red}{World}
+^D
+[Para [Str "Hello",Space,Span ("",[],[("style","background-color: red")]) [Str "World"]]]
+```
+
+```
+% pandoc -f latex -t native
+\colorbox{red}{Hello} World
+^D
+[Para [Span ("",[],[("style","background-color: red")]) [Str "Hello"],Space,Str "World"]]
+```
+
+```
+% pandoc -f latex -t native
+Hello \colorbox{blue}{\textbf{World}}
+^D
+[Para [Str "Hello",Space,Span ("",[],[("style","background-color: blue")]) [Strong [Str "World"]]]]
+```
+
+```
+% pandoc -f latex -t native
+Hello \colorbox{blue}{\textbf{World}}.
+^D
+[Para [Str "Hello",Space,Span ("",[],[("style","background-color: blue")]) [Strong [Str "World"]],Str "."]]
+```
+
+```
+% pandoc -f latex -t native
+\colorbox{orange}{
+\begin{minipage}{\textwidth}
+\begin{itemize}
+ \item Item 1
+ \item Item 2
+\end{itemize}
+\end{minipage}
+}
+^D
+[Div ("",[],[("style","background-color: orange")])
+ [BulletList
+ [[Para [Str "Item",Space,Str "1"]]
+ ,[Para [Str "Item",Space,Str "2"]]]]]
+```
+
+```
+% pandoc -f latex -t native
+\colorbox{blue}{
+\begin{minipage}{\textwidth}
+\begin{itemize}
+ \item Item 1
+ \item Item 2
+\end{itemize}
+\end{minipage}
+} some more text
+^D
+[Div ("",[],[("style","background-color: blue")])
+ [BulletList
+ [[Para [Str "Item",Space,Str "1"]]
+ ,[Para [Str "Item",Space,Str "2"]]]]
+,Para [Str "some",Space,Str "more",Space,Str "text"]]
+```
diff --git a/test/command/latex-command-comment.md b/test/command/latex-command-comment.md
new file mode 100644
index 000000000..640277f15
--- /dev/null
+++ b/test/command/latex-command-comment.md
@@ -0,0 +1,7 @@
+```
+pandoc -f latex -t native
+\emph%
+{hi}
+^D
+[Para [Emph [Str "hi"]]]
+```
diff --git a/test/command/latex-fontawesome.md b/test/command/latex-fontawesome.md
new file mode 100644
index 000000000..2a7e91185
--- /dev/null
+++ b/test/command/latex-fontawesome.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f latex -t native
+Check: \faCheck
+^D
+[Para [Str "Check:",Space,Str "\10003"]]
+```
+
+```
+% pandoc -f latex -t native
+Close: \faClose
+^D
+[Para [Str "Close:",Space,Str "\10007"]]
+```
diff --git a/test/command/latex-tabular-column-specs.md b/test/command/latex-tabular-column-specs.md
new file mode 100644
index 000000000..ed44a9980
--- /dev/null
+++ b/test/command/latex-tabular-column-specs.md
@@ -0,0 +1,24 @@
+See https://groups.google.com/forum/#!topic/pandoc-discuss/_VXtqihCyDU.
+
+```
+% pandoc -f latex -t native
+\begin{tabular}{>{$}l<{$}>{$}l<{$} >{$}l<{$}}
+\toprule
+& f1 & f2 \\
+\midrule
+e & 0.5 & 4 \\
+f & 0.5 & 5,5 \\
+\bottomrule
+\end{tabular}
+^D
+[Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Plain [Math InlineMath ""]]
+ ,[Plain [Math InlineMath "f1"]]
+ ,[Plain [Math InlineMath "f2"]]]
+ [[[Plain [Math InlineMath "e"]]
+ ,[Plain [Math InlineMath "0.5"]]
+ ,[Plain [Math InlineMath "4"]]]
+ ,[[Plain [Math InlineMath "f"]]
+ ,[Plain [Math InlineMath "0.5"]]
+ ,[Plain [Math InlineMath "5,5"]]]]]
+```
diff --git a/test/command/lettrine.md b/test/command/lettrine.md
new file mode 100644
index 000000000..0c3c64d66
--- /dev/null
+++ b/test/command/lettrine.md
@@ -0,0 +1,9 @@
+```
+% pandoc -f latex -t native
+\lettrine{A}{category} is
+
+\lettrine[lhang=0.17]{A}{category} is
+^D
+[Para [Span ("",["lettrine"],[]) [Str "A"],Span ("",[],[]) [Str "category"],Space,Str "is"]
+,Para [Span ("",["lettrine"],[]) [Str "A"],Span ("",[],[]) [Str "category"],Space,Str "is"]]
+```
diff --git a/test/command/lstlisting.md b/test/command/lstlisting.md
new file mode 100644
index 000000000..d928cc702
--- /dev/null
+++ b/test/command/lstlisting.md
@@ -0,0 +1,25 @@
+```
+% pandoc -f latex -t native
+\begin{lstlisting}[language=Java, caption={Java Example}, label=lst:Hello-World]
+public class World {
+ public static void main(String[] args) {
+ System.out.println("Hello World");
+ }
+}
+\end{lstlisting}
+^D
+[CodeBlock ("lst:Hello-World",["java"],[("language","Java"),("caption","Java Example"),("label","lst:Hello-World")]) "public class World {\n public static void main(String[] args) {\n System.out.println(\"Hello World\");\n }\n}"]
+```
+
+```
+% pandoc -f latex -t native
+\begin{lstlisting}[language=Java, escapechar=|, caption={Java Example}, label=lst:Hello-World]
+public class World {
+ public static void main(String[] args) {
+ System.out.println("Hello World");
+ }
+}
+\end{lstlisting}
+^D
+[CodeBlock ("lst:Hello-World",["java"],[("language","Java"),("escapechar","|"),("caption","Java Example"),("label","lst:Hello-World")]) "public class World {\n public static void main(String[] args) {\n System.out.println(\"Hello World\");\n }\n}"]
+```
diff --git a/test/command/macros.md b/test/command/macros.md
new file mode 100644
index 000000000..9de87e7a0
--- /dev/null
+++ b/test/command/macros.md
@@ -0,0 +1,103 @@
+```
+% pandoc -f markdown+latex_macros -t markdown
+\newcommand{\my}{\phi}
+$\my+\my$
+^D
+\newcommand{\my}{\phi}
+$\phi+\phi$
+```
+
+```
+% pandoc -f markdown-latex_macros -t markdown
+\newcommand{\my}{\phi}
+$\my+\my$
+^D
+\newcommand{\my}{\phi}
+$\my+\my$
+```
+
+`\let` macros should be expanded at point of
+definition, while `\newcommand` macros should be
+expanded at point of use:
+
+```
+% pandoc -f latex -t latex
+\let\a\b
+\newcommand{\b}{\emph{ouk}}
+\a
+^D
+\b
+```
+
+```
+% pandoc -f latex -t latex
+\newcommand{\a}{\b}
+\newcommand{\b}{\emph{ouk}}
+\a
+^D
+\emph{ouk}
+```
+
+```
+% pandoc -f latex -t latex
+\def\BDpos{}
+\def\BDneg{-}
+\def\beq{\begin{align}}
+\def\eeq{\end{align}}
+\def\e#1{\emph{#1}}
+\def\f#1#2{\emph{#1--#2}}
+
+$5\BDneg 6\BDpos 7$
+
+\beq
+x &= y\\
+\eeq
+
+\e{hi}
+
+\f{hi}{ok}
+^D
+\(5-67\)
+
+\[\begin{aligned}
+x &= y\\\end{aligned}\]
+
+\emph{hi}
+
+\emph{hi--ok}
+```
+
+```
+% pandoc -f markdown+latex_macros -t markdown
+\newcommand{\my}{\phi}
+\begin{equation}
+\my+\my
+\end{equation}
+^D
+\newcommand{\my}{\phi}
+\begin{equation}
+\phi+\phi
+\end{equation}
+```
+
+```
+% pandoc -f markdown-latex_macros -t markdown
+\newcommand{\my}{\phi}
+\begin{equation}
+\my+\my
+\end{equation}
+^D
+\newcommand{\my}{\phi}
+\begin{equation}
+\my+\my
+\end{equation}
+```
+
+```
+% pandoc -f markdown+latex_macros -t markdown
+\newcommand{\my}{\emph{a}}
+\my
+^D
+\newcommand{\my}{\emph{a}}
+\emph{a}
+```
diff --git a/test/command/md-abbrevs.md b/test/command/md-abbrevs.md
new file mode 100644
index 000000000..15f4d6a9a
--- /dev/null
+++ b/test/command/md-abbrevs.md
@@ -0,0 +1,31 @@
+Pandoc recognizes an abbreviation and inserts a nonbreaking
+space (among other things, this prevents a sentence-ending
+space from being inserted in LaTeX output).
+
+```
+% pandoc -t native
+Mr. Bob
+^D
+[Para [Str "Mr.\160Bob"]]
+```
+
+Here pandoc readjusts the softbreak so that the nonbreaking
+space can be inserted:
+
+```
+% pandoc -t native
+Hi Mr.
+Bob
+^D
+[Para [Str "Hi",SoftBreak,Str "Mr.\160Bob"]]
+```
+
+If you don't want this to happen you can escape the period:
+
+```
+% pandoc -t native
+Hi Mr\. Bob
+^D
+[Para [Str "Hi",Space,Str "Mr.",Space,Str "Bob"]]
+```
+
diff --git a/test/command/multiple-metadata-blocks.md b/test/command/multiple-metadata-blocks.md
new file mode 100644
index 000000000..27c5e3dae
--- /dev/null
+++ b/test/command/multiple-metadata-blocks.md
@@ -0,0 +1,15 @@
+If multiple blocks define a field, the first is used.
+
+```
+% pandoc -s -t native
+---
+foo: bar
+...
+
+---
+foo: bim
+...
+^D
+Pandoc (Meta {unMeta = fromList [("foo",MetaInlines [Str "bar"])]})
+[]
+```
diff --git a/test/command/parse-raw.md b/test/command/parse-raw.md
new file mode 100644
index 000000000..f4e493c69
--- /dev/null
+++ b/test/command/parse-raw.md
@@ -0,0 +1,27 @@
+```
+% pandoc -f latex+raw_tex -t markdown
+\emph{Hi \foo{there}}
+^D
+*Hi \foo{there}*
+```
+
+```
+% pandoc -f latex -t markdown
+\emph{Hi \foo{there}}
+^D
+*Hi*
+```
+
+```
+% pandoc -f html+raw_html -t markdown
+<em>Hi <blink>there</blink></em>
+^D
+*Hi <blink>there</blink>*
+```
+
+```
+% pandoc -f html -t markdown
+<em>Hi <blink>there</blink></em>
+^D
+*Hi there*
+```
diff --git a/test/command/refs.md b/test/command/refs.md
new file mode 100644
index 000000000..66959e5c3
--- /dev/null
+++ b/test/command/refs.md
@@ -0,0 +1,54 @@
+```
+% pandoc -f latex -t native
+Figure \ref{fig:1}
+^D
+[Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:1")]) [Str "[fig:1]"] ("#fig:1","")]]
+```
+
+```
+% pandoc -f latex -t native
+Figure \cref{fig:1}
+^D
+[Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:1")]) [Str "[fig:1]"] ("#fig:1","")]]
+```
+
+```
+% pandoc -f latex -t native
+Figure \vref{fig:1}
+^D
+[Para [Str "Figure",Space,Link ("",[],[("reference-type","ref+page"),("reference","fig:1")]) [Str "[fig:1]"] ("#fig:1","")]]
+```
+
+```
+% pandoc -f latex -t native
+Accuracy~\eqref{eq:Accuracy} is the proportion, measuring true results among all results.
+
+\begin{equation}
+ \label{eq:Accuracy}
+ Accuracy = \frac{t_p + t_n}{t_p + f_p + f_n + t_n}
+\end{equation}
+^D
+[Para [Str "Accuracy\160",Link ("",[],[("reference-type","eqref"),("reference","eq:Accuracy")]) [Str "[eq:Accuracy]"] ("#eq:Accuracy",""),Space,Str "is",Space,Str "the",Space,Str "proportion,",Space,Str "measuring",Space,Str "true",Space,Str "results",Space,Str "among",Space,Str "all",Space,Str "results."]
+,Para [Math DisplayMath "\\label{eq:Accuracy}\n Accuracy = \\frac{t_p + t_n}{t_p + f_p + f_n + t_n}"]]
+```
+
+```
+% pandoc -f latex -t native
+\begin{figure}
+ \includegraphics{command/SVG_logo.svg}
+ \caption{Logo}
+ \label{fig:Logo}
+\end{figure}
+
+Figure \ref{fig:Logo} illustrated the SVG logo
+^D
+[Para [Image ("",[],[]) [Str "Logo",Span ("",[],[("label","fig:Logo")]) []] ("command/SVG_logo.svg","fig:")]
+,Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:Logo")]) [Str "[fig:Logo]"] ("#fig:Logo",""),Space,Str "illustrated",Space,Str "the",Space,Str "SVG",Space,Str "logo"]]
+```
+
+```
+% pandoc -f latex -t native
+\label{section} Section \ref{section}
+^D
+[Para [Span ("section",[],[("label","section")]) [Str "[section]"],Space,Str "Section",Space,Link ("",[],[("reference-type","ref"),("reference","section")]) [Str "[section]"] ("#section","")]]
+```
diff --git a/test/command/rst-links.md b/test/command/rst-links.md
new file mode 100644
index 000000000..496bebc54
--- /dev/null
+++ b/test/command/rst-links.md
@@ -0,0 +1,18 @@
+```
+% pandoc -f rst
+`*ab*`_
+
+.. _`*ab*`: foo
+^D
+<p><a href="foo">*ab*</a></p>
+```
+
+```
+% pandoc -f rst
+`A B
+c`_
+
+.. _A B C: foo
+^D
+<p><a href="foo">A B c</a></p>
+```
diff --git a/test/command/smart.md b/test/command/smart.md
new file mode 100644
index 000000000..e64d67de2
--- /dev/null
+++ b/test/command/smart.md
@@ -0,0 +1,45 @@
+```
+% pandoc -f markdown+smart -t markdown-smart
+"hi"...dog's breath---cat 5--6
+^D
+“hi”…dog’s breath—cat 5–6
+```
+
+```
+% pandoc -f markdown+smart -t markdown+smart
+"hi"...dog's breath---cat 5--6
+^D
+"hi"...dog's breath---cat 5--6
+```
+
+When we render literal quotes without smart, we need to escape:
+
+```
+% pandoc -f markdown-smart \
+ -t markdown+smart
+"hi"...dog's breath---cat 5--6
+^D
+\"hi\"\...dog\'s breath\-\--cat 5\--6
+```
+
+```
+% pandoc -f markdown+smart -t rst-smart
+"hi"...dog's breath---cat 5--6
+^D
+“hi”…dog’s breath—cat 5–6
+```
+
+```
+% pandoc -f markdown+smart -t rst+smart
+"hi"...dog's breath---cat 5--6
+^D
+"hi"...dog's breath---cat 5--6
+```
+
+```
+% pandoc -f markdown-smart -t rst+smart
+"hi"...dog's breath---cat 5--6
+^D
+\"hi\"\...dog\'s breath\-\--cat 5\--6
+```
+
diff --git a/test/command/sub-file-chapter-1.tex b/test/command/sub-file-chapter-1.tex
new file mode 100644
index 000000000..9b3f38f58
--- /dev/null
+++ b/test/command/sub-file-chapter-1.tex
@@ -0,0 +1,8 @@
+\documentclass[main.tex]{subfiles}
+\begin{document}
+
+\section{Chapter 1}
+
+This is Chapter 1, provided in a sub file.
+
+\end{document}
diff --git a/test/command/sub-file-chapter-2.tex b/test/command/sub-file-chapter-2.tex
new file mode 100644
index 000000000..88e8a0ecc
--- /dev/null
+++ b/test/command/sub-file-chapter-2.tex
@@ -0,0 +1,8 @@
+\documentclass[main.tex]{subfiles}
+\begin{document}
+
+\section{Chapter 2}
+
+This is Chapter 2, provided in a second sub file.
+
+\end{document}
diff --git a/test/command/svg.md b/test/command/svg.md
new file mode 100644
index 000000000..26a8213f6
--- /dev/null
+++ b/test/command/svg.md
@@ -0,0 +1,132 @@
+```
+% pandoc -f latex -t icml
+\includegraphics{command/corrupt.svg}
+^D
+[WARNING] Could not determine image size for 'command/corrupt.svg': could not determine image type
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 150 -100">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-150 -100" LeftDirection="-150 -100" RightDirection="-150 -100" />
+ <PathPointType Anchor="-150 100" LeftDirection="-150 100" RightDirection="-150 100" />
+ <PathPointType Anchor="150 100" LeftDirection="150 100" RightDirection="150 100" />
+ <PathPointType Anchor="150 -100" LeftDirection="150 -100" RightDirection="150 -100" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -150 -100">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:command/corrupt.svg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+```
+
+```
+% pandoc -f latex -t icml
+\includegraphics{command/SVG_logo.svg}
+^D
+[WARNING] Could not determine image size for 'command/SVG_logo.svg': could not determine SVG size
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 150 -100">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-150 -100" LeftDirection="-150 -100" RightDirection="-150 -100" />
+ <PathPointType Anchor="-150 100" LeftDirection="-150 100" RightDirection="-150 100" />
+ <PathPointType Anchor="150 100" LeftDirection="150 100" RightDirection="150 100" />
+ <PathPointType Anchor="150 -100" LeftDirection="150 -100" RightDirection="150 -100" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -150 -100">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:command/SVG_logo.svg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+```
+
+```
+% pandoc -f latex -t icml
+\includegraphics{command/SVG_logo-without-xml-declaration.svg}
+^D
+[WARNING] Could not determine image size for 'command/SVG_logo-without-xml-declaration.svg': could not determine SVG size
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 150 -100">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-150 -100" LeftDirection="-150 -100" RightDirection="-150 -100" />
+ <PathPointType Anchor="-150 100" LeftDirection="-150 100" RightDirection="-150 100" />
+ <PathPointType Anchor="150 100" LeftDirection="150 100" RightDirection="150 100" />
+ <PathPointType Anchor="150 -100" LeftDirection="150 -100" RightDirection="150 -100" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -150 -100">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:command/SVG_logo-without-xml-declaration.svg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+```
+
+
+```
+% pandoc -f latex -t icml
+\includegraphics{command/inkscape-cube.svg}
+^D
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 54.75 -65.25">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-54.75 -65.25" LeftDirection="-54.75 -65.25" RightDirection="-54.75 -65.25" />
+ <PathPointType Anchor="-54.75 65.25" LeftDirection="-54.75 65.25" RightDirection="-54.75 65.25" />
+ <PathPointType Anchor="54.75 65.25" LeftDirection="54.75 65.25" RightDirection="54.75 65.25" />
+ <PathPointType Anchor="54.75 -65.25" LeftDirection="54.75 -65.25" RightDirection="54.75 -65.25" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -54.75 -65.25">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:command/inkscape-cube.svg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+```
+
diff --git a/test/command/tabularx.md b/test/command/tabularx.md
new file mode 100644
index 000000000..bf7670e9c
--- /dev/null
+++ b/test/command/tabularx.md
@@ -0,0 +1,110 @@
+```
+% pandoc -f latex -t native --quiet
+\begin{tabularx}{\linewidth}{|c|c|c|}
+\hline
+ Column Heading 1
+ & Column Heading 2
+ & Column Heading 3 \\
+\hline
+ Cell 1.1
+ & Cell 1.2
+ & Cell 1.3 \\
+\hline
+ Cell 2.1
+ & Cell 2.2
+ & Cell 2.3 \\
+\hline
+ Cell 3.1
+ & Cell 3.2
+ & Cell 3.3 \\
+\hline
+\end{tabularx}
+^D
+[Table [] [AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0]
+ [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]]
+ [[[Plain [Str "Cell",Space,Str "1.1"]]
+ ,[Plain [Str "Cell",Space,Str "1.2"]]
+ ,[Plain [Str "Cell",Space,Str "1.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "2.1"]]
+ ,[Plain [Str "Cell",Space,Str "2.2"]]
+ ,[Plain [Str "Cell",Space,Str "2.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "3.1"]]
+ ,[Plain [Str "Cell",Space,Str "3.2"]]
+ ,[Plain [Str "Cell",Space,Str "3.3"]]]]]
+```
+
+```
+% pandoc -f latex -t native --quiet
+\begin{tabularx}{\linewidth}{|X|c|p{0.25\linewidth}|}
+\hline
+ Column Heading 1
+ & Column Heading 2
+ & Column Heading 3 \\
+\hline
+ Cell 1.1
+ & Cell 1.2
+ & Cell 1.3 \\
+\hline
+ Cell 2.1
+ & Cell 2.2
+ & Cell 2.3 \\
+\hline
+ Cell 3.1
+ & Cell 3.2
+ & Cell 3.3 \\
+\hline
+\end{tabularx}
+^D
+[Table [] [AlignLeft,AlignCenter,AlignLeft] [0.0,0.0,0.25]
+ [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]]
+ [[[Plain [Str "Cell",Space,Str "1.1"]]
+ ,[Plain [Str "Cell",Space,Str "1.2"]]
+ ,[Plain [Str "Cell",Space,Str "1.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "2.1"]]
+ ,[Plain [Str "Cell",Space,Str "2.2"]]
+ ,[Plain [Str "Cell",Space,Str "2.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "3.1"]]
+ ,[Plain [Str "Cell",Space,Str "3.2"]]
+ ,[Plain [Str "Cell",Space,Str "3.3"]]]]]
+```
+
+```
+% pandoc -f latex -t native --quiet
+\begin{tabularx}{\linewidth}{|b{0.25\linewidth}|c|m{0.25\linewidth}|}
+\hline
+ Column Heading 1
+ & Column Heading 2
+ & Column Heading 3 \\
+\hline
+ Cell 1.1
+ & Cell 1.2
+ & Cell 1.3 \\
+\hline
+ Cell 2.1
+ & Cell 2.2
+ & Cell 2.3 \\
+\hline
+ Cell 3.1
+ & Cell 3.2
+ & Cell 3.3 \\
+\hline
+\end{tabularx}
+^D
+[Table [] [AlignLeft,AlignCenter,AlignLeft] [0.25,0.0,0.25]
+ [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]]
+ [[[Plain [Str "Cell",Space,Str "1.1"]]
+ ,[Plain [Str "Cell",Space,Str "1.2"]]
+ ,[Plain [Str "Cell",Space,Str "1.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "2.1"]]
+ ,[Plain [Str "Cell",Space,Str "2.2"]]
+ ,[Plain [Str "Cell",Space,Str "2.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "3.1"]]
+ ,[Plain [Str "Cell",Space,Str "3.2"]]
+ ,[Plain [Str "Cell",Space,Str "3.3"]]]]]
+```
diff --git a/test/command/translations.md b/test/command/translations.md
new file mode 100644
index 000000000..34531df7c
--- /dev/null
+++ b/test/command/translations.md
@@ -0,0 +1,29 @@
+```
+% pandoc -f latex -t native -M lang=en
+\figurename\ 2
+^D
+[Para [Str "Figure\160\&2"]]
+```
+
+```
+% pandoc -f latex -t native -M lang=de-DE
+\figurename\ 2
+^D
+[Para [Str "Abbildung\160\&2"]]
+```
+
+```
+% pandoc -f latex -t native -M lang=en
+\setmainlanguage{german}
+\figurename 2
+^D
+[Para [Str "Abbildung2"]]
+```
+
+```
+% pandoc -f latex -t native -M lang=sr
+\figurename~2
+\figurename.
+^D
+[Para [Str "Slika\160\&2",SoftBreak,Str "Slika."]]
+```
diff --git a/test/command/vars-and-metadata.md b/test/command/vars-and-metadata.md
new file mode 100644
index 000000000..c3dc895af
--- /dev/null
+++ b/test/command/vars-and-metadata.md
@@ -0,0 +1,15 @@
+Variables should not leak into metadata in the Markdown writer:
+
+```
+% pandoc -t markdown -Vfoo=1 -Vbar=2 -s
+---
+foo: x
+...
+zib
+^D
+---
+foo: x
+---
+
+zib
+```
diff --git a/test/command/write18.md b/test/command/write18.md
new file mode 100644
index 000000000..344dfc8cf
--- /dev/null
+++ b/test/command/write18.md
@@ -0,0 +1,14 @@
+Handle \write18{..} as raw tex:
+```
+% pandoc -t native
+\write18{git --version}
+^D
+[RawBlock (Format "latex") "\\write18{git --version}"]
+```
+
+```
+% pandoc -f latex+raw_tex -t native
+\write18{git --version}
+^D
+[RawBlock (Format "latex") "\\write18{git --version}"]
+```
diff --git a/test/command/yaml-with-chomp.md b/test/command/yaml-with-chomp.md
new file mode 100644
index 000000000..d4c4f7cfd
--- /dev/null
+++ b/test/command/yaml-with-chomp.md
@@ -0,0 +1,12 @@
+```
+% pandoc -s -t native
+---
+ml: |-
+ TEST
+
+ BLOCK
+...
+^D
+Pandoc (Meta {unMeta = fromList [("ml",MetaBlocks [Para [Str "TEST"],Plain [Str "BLOCK"]])]})
+[]
+```
diff --git a/test/creole-reader.native b/test/creole-reader.native
new file mode 100644
index 000000000..a7e85d969
--- /dev/null
+++ b/test/creole-reader.native
@@ -0,0 +1,95 @@
+Pandoc (Meta {unMeta = fromList []})
+[Header 1 ("",[],[]) [Str "Top-level heading (1)"]
+,Header 2 ("",[],[]) [Str "This a test for creole 0.1 (2)"]
+,Header 3 ("",[],[]) [Str "This is a Subheading (3)"]
+,Header 4 ("",[],[]) [Str "Subsub (4)"]
+,Header 5 ("",[],[]) [Str "Subsubsub (5)"]
+,Para [Str "The",Space,Str "ending",Space,Str "equal",Space,Str "signs",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "displayed:"]
+,Header 1 ("",[],[]) [Str "Top-level heading (1)"]
+,Header 2 ("",[],[]) [Str "This a test for creole 0.1 (2)"]
+,Header 3 ("",[],[]) [Str "This is a Subheading (3)"]
+,Header 4 ("",[],[]) [Str "Subsub (4)"]
+,Header 5 ("",[],[]) [Str "Subsubsub (5)"]
+,Para [Str "You",Space,Str "can",Space,Str "make",Space,Str "things",Space,Strong [Str "bold"],Space,Str "or",Space,Emph [Str "italic"],Space,Str "or",Space,Strong [Emph [Str "both"]],Space,Str "or",Space,Emph [Strong [Str "both"]],Str "."]
+,Para [Str "Character",Space,Str "formatting",Space,Str "extends",Space,Str "across",Space,Str "line",Space,Str "breaks:",Space,Strong [Str "bold,",Space,Str "this",Space,Str "is",Space,Str "still",Space,Str "bold.",Space,Str "This",Space,Str "line",Space,Str "deliberately",Space,Str "does",Space,Str "not",Space,Str "end",Space,Str "in",Space,Str "star-star."]]
+,Para [Str "Not",Space,Str "bold.",Space,Str "Character",Space,Str "formatting",Space,Str "does",Space,Str "not",Space,Str "cross",Space,Str "paragraph",Space,Str "boundaries."]
+,Para [Str "You",Space,Str "can",Space,Str "use",Space,Link ("",[],[]) [Str "internal links"] ("internal links",""),Space,Str "or",Space,Link ("",[],[]) [Str "external links"] ("http://www.wikicreole.org",""),Str ",",Space,Str "give",Space,Str "the",Space,Str "link",Space,Str "a",Space,Link ("",[],[]) [Str "different"] ("internal links",""),Space,Str "name."]
+,Para [Str "Here's",Space,Str "another",Space,Str "sentence:",Space,Str "This",Space,Str "wisdom",Space,Str "is",Space,Str "taken",Space,Str "from",Space,Link ("",[],[]) [Str "Ward Cunningham's"] ("Ward Cunningham's",""),Space,Link ("",[],[]) [Str "Presentation at the Wikisym 06"] ("http://www.c2.com/doc/wikisym/WikiSym2006.pdf",""),Str "."]
+,Para [Str "Here's",Space,Str "a",Space,Str "external",Space,Str "link",Space,Str "without",Space,Str "a",Space,Str "description:",Space,Link ("",[],[]) [Str "http://www.wikicreole.org"] ("http://www.wikicreole.org","")]
+,Para [Str "Be",Space,Str "careful",Space,Str "that",Space,Str "italic",Space,Str "links",Space,Str "are",Space,Str "rendered",Space,Str "properly:",Space,Emph [Link ("",[],[]) [Str "My Book Title"] ("http://my.book.example/","")]]
+,Para [Str "Free",Space,Str "links",Space,Str "without",Space,Str "braces",Space,Str "should",Space,Str "be",Space,Str "rendered",Space,Str "as",Space,Str "well,",Space,Str "like",Space,Link ("",[],[]) [Str "http://www.wikicreole.org/"] ("http://www.wikicreole.org/",""),Space,Str "and",Space,Link ("",[],[]) [Str "http://www.wikicreole.org/users/~example"] ("http://www.wikicreole.org/users/~example",""),Str "."]
+,Para [Str "Creole1.0",Space,Str "specifies",Space,Str "that",Space,Link ("",[],[]) [Str "http://bar"] ("http://bar",""),Space,Str "and",Space,Link ("",[],[]) [Str "ftp://bar"] ("ftp://bar",""),Space,Str "should",Space,Str "not",Space,Str "render",Space,Str "italic,",Space,Str "something",Space,Str "like",Space,Str "foo:",Emph [Str "bar",Space,Str "should",Space,Str "render",Space,Str "as",Space,Str "italic."]]
+,Para [Str "You",Space,Str "can",Space,Str "use",Space,Str "this",Space,Str "to",Space,Str "draw",Space,Str "a",Space,Str "line",Space,Str "to",Space,Str "separate",Space,Str "the",Space,Str "page:"]
+,HorizontalRule
+,Para [Str "You",Space,Str "can",Space,Str "use",Space,Str "lists,",Space,Str "start",Space,Str "it",Space,Str "at",Space,Str "the",Space,Str "first",Space,Str "column",Space,Str "for",Space,Str "now,",Space,Str "please..."]
+,Para [Str "unnumbered",Space,Str "lists",Space,Str "are",Space,Str "like"]
+,BulletList
+ [[Plain [Str "item",Space,Str "a"]]
+ ,[Plain [Str "item",Space,Str "b"]]
+ ,[Plain [Strong [Str "bold",Space,Str "item",Space,Str "c"]]]]
+,Para [Str "blank",Space,Str "space",Space,Str "is",Space,Str "also",Space,Str "permitted",Space,Str "before",Space,Str "lists",Space,Str "like:"]
+,BulletList
+ [[Plain [Str "item",Space,Str "a"]]
+ ,[Plain [Str "item",Space,Str "b"]]
+ ,[Plain [Str "item",Space,Str "c"]
+ ,BulletList
+ [[Plain [Str "item",Space,Str "c.a"]]]]]
+,Para [Str "or",Space,Str "you",Space,Str "can",Space,Str "number",Space,Str "them"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Link ("",[],[]) [Str "item 1"] ("item 1","")]]
+ ,[Plain [Str "item",Space,Str "2"]]
+ ,[Plain [Emph [Space,Str "italic",Space,Str "item",Space,Str "3",Space]]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "item",Space,Str "3.1"]]
+ ,[Plain [Str "item",Space,Str "3.2"]]]]]
+,Para [Str "up",Space,Str "to",Space,Str "five",Space,Str "levels"]
+,BulletList
+ [[Plain [Str "1"]
+ ,BulletList
+ [[Plain [Str "2"]
+ ,BulletList
+ [[Plain [Str "3"]
+ ,BulletList
+ [[Plain [Str "4"]
+ ,BulletList
+ [[Plain [Str "5"]]]]]]]]]]]
+,BulletList
+ [[Plain [Str "You",Space,Str "can",Space,Str "have",Space,Str "multiline",Space,Str "list",Space,Str "items"]]
+ ,[Plain [Str "this",Space,Str "is",Space,Str "a",Space,Str "second",Space,Str "multiline",Space,Str "list",Space,Str "item"]]]
+,Para [Str "You",Space,Str "can",Space,Str "use",Space,Str "nowiki",Space,Str "syntax",Space,Str "if",Space,Str "you",Space,Str "would",Space,Str "like",Space,Str "do",Space,Str "stuff",Space,Str "like",Space,Str "this:"]
+,CodeBlock ("",[],[]) "Guitar Chord C:\n\n||---|---|---|\n||-0-|---|---|\n||---|---|---|\n||---|-0-|---|\n||---|---|-0-|\n||---|---|---|"
+,Para [Str "You",Space,Str "can",Space,Str "also",Space,Str "use",Space,Str "it",Space,Str "inline",Space,Str "nowiki",Space,Code ("",[],[]) " in a sentence ",Space,Str "like",Space,Str "this."]
+,Header 1 ("",[],[]) [Str "Escapes"]
+,Para [Str "Normal",Space,Str "Link:",Space,Link ("",[],[]) [Str "http://wikicreole.org/"] ("http://wikicreole.org/",""),Space,Str "-",Space,Str "now",Space,Str "same",Space,Str "link,",Space,Str "but",Space,Str "escaped:",Space,Str "http://wikicreole.org/"]
+,Para [Str "Normal",Space,Str "asterisks:",Space,Str "**not",Space,Str "bold**"]
+,Para [Str "a",Space,Str "tilde",Space,Str "alone:",Space,Str "~"]
+,Para [Str "a",Space,Str "tilde",Space,Str "escapes",Space,Str "itself:",Space,Str "~xxx"]
+,Header 3 ("",[],[]) [Str "Creole 0.2"]
+,Para [Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "flower",Space,Str "with",Space,Str "the",Space,Str "ALT",Space,Str "text",Space,Str "\"this",Space,Str "is",Space,Str "a",Space,Str "flower\"",Space,Str "if",Space,Str "your",Space,Str "wiki",Space,Str "supports",Space,Str "ALT",Space,Str "text",Space,Str "on",Space,Str "images:"]
+,Para [Image ("",[],[]) [Str "here is a red flower"] ("Red-Flower.jpg","")]
+,Header 3 ("",[],[]) [Str "Creole 0.4"]
+,Para [Str "Tables",Space,Str "are",Space,Str "done",Space,Str "like",Space,Str "this:"]
+,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str "header",Space,Str "col1"]]
+ ,[Plain [Str "header",Space,Str "col2"]]]
+ [[[Plain [Str "col1"]]
+ ,[Plain [Str "col2"]]]
+ ,[[Plain [Str "you"]]
+ ,[Plain [Str "can"]]]
+ ,[[Plain [Str "also"]]
+ ,[Plain [Str "align",LineBreak,Str "it."]]]]
+,Para [Str "You",Space,Str "can",Space,Str "format",Space,Str "an",Space,Str "address",Space,Str "by",Space,Str "simply",Space,Str "forcing",Space,Str "linebreaks:"]
+,Para [Str "My",Space,Str "contact",Space,Str "dates:",LineBreak,Str "Pone:",Space,Str "xyz",LineBreak,Str "Fax:",Space,Str "+45",LineBreak,Str "Mobile:",Space,Str "abc"]
+,Header 3 ("",[],[]) [Str "Creole 0.5"]
+,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str "Header",Space,Str "title"]]
+ ,[Plain [Str "Another",Space,Str "header",Space,Str "title"]]]
+ [[[Plain [Code ("",[],[]) " //not italic text// "]]
+ ,[Plain [Code ("",[],[]) " **not bold text** "]]]
+ ,[[Plain [Emph [Str "italic",Space,Str "text"]]]
+ ,[Plain [Strong [Space,Str "bold",Space,Str "text",Space]]]]]
+,Header 3 ("",[],[]) [Str "Creole 1.0"]
+,Para [Str "If",Space,Str "interwiki",Space,Str "links",Space,Str "are",Space,Str "setup",Space,Str "in",Space,Str "your",Space,Str "wiki,",Space,Str "this",Space,Str "links",Space,Str "to",Space,Str "the",Space,Str "WikiCreole",Space,Str "page",Space,Str "about",Space,Str "Creole",Space,Str "1.0",Space,Str "test",Space,Str "cases:",Space,Link ("",[],[]) [Str "WikiCreole:Creole1.0TestCases"] ("WikiCreole:Creole1.0TestCases",""),Str "."]
+,HorizontalRule
+,Para [Str "The",Space,Str "above",Space,Str "test",Space,Str "document",Space,Str "was",Space,Str "found",Space,Str "on",Space,Link ("",[],[]) [Str "http://www.wikicreole.org/wiki/Creole1.0TestCases"] ("http://www.wikicreole.org/wiki/Creole1.0TestCases",""),Space,Str "and",Space,Str "downloaded",Space,Str "from",Space,Link ("",[],[]) [Str "http://www.wikicreole.org/attach/Creole1.0TestCases/creole1.0test.txt"] ("http://www.wikicreole.org/attach/Creole1.0TestCases/creole1.0test.txt",""),Str "."]
+,Para [Str "The",Space,Str "Creole",Space,Str "Wiki",Space,Str "is",Space,Str "licensed:",Space,Str "Copyright",Space,Str "(C)",Space,Str "by",Space,Str "the",Space,Str "contributors.",Space,Str "Some",Space,Str "rights",Space,Str "reserved,",Space,Str "license",Space,Link ("",[],[]) [Str "https://creativecommons.org/licenses/by-sa/1.0/"] ("BY-SA",""),Str "."]]
diff --git a/test/creole-reader.txt b/test/creole-reader.txt
new file mode 100644
index 000000000..efed9cd1d
--- /dev/null
+++ b/test/creole-reader.txt
@@ -0,0 +1,137 @@
+= Top-level heading (1)
+== This a test for creole 0.1 (2)
+=== This is a Subheading (3)
+==== Subsub (4)
+===== Subsubsub (5)
+
+The ending equal signs should not be displayed:
+
+= Top-level heading (1) =
+== This a test for creole 0.1 (2) ==
+=== This is a Subheading (3) ===
+==== Subsub (4) ====
+===== Subsubsub (5) =====
+
+
+You can make things **bold** or //italic// or **//both//** or //**both**//.
+
+Character formatting extends across line breaks: **bold,
+this is still bold. This line deliberately does not end in star-star.
+
+Not bold. Character formatting does not cross paragraph boundaries.
+
+You can use [[internal links]] or [[http://www.wikicreole.org|external links]],
+give the link a [[internal links|different]] name.
+
+Here's another sentence: This wisdom is taken from [[Ward Cunningham's]]
+[[http://www.c2.com/doc/wikisym/WikiSym2006.pdf|Presentation at the Wikisym 06]].
+
+Here's a external link without a description: [[http://www.wikicreole.org]]
+
+Be careful that italic links are rendered properly: //[[http://my.book.example/|My Book Title]]//
+
+Free links without braces should be rendered as well, like http://www.wikicreole.org/ and http://www.wikicreole.org/users/~example.
+
+Creole1.0 specifies that http://bar and ftp://bar should not render italic,
+something like foo://bar should render as italic.
+
+You can use this to draw a line to separate the page:
+----
+
+You can use lists, start it at the first column for now, please...
+
+unnumbered lists are like
+* item a
+* item b
+* **bold item c**
+
+blank space is also permitted before lists like:
+ * item a
+ * item b
+* item c
+ ** item c.a
+
+or you can number them
+# [[item 1]]
+# item 2
+# // italic item 3 //
+ ## item 3.1
+ ## item 3.2
+
+up to five levels
+* 1
+** 2
+*** 3
+**** 4
+***** 5
+
+* You can have
+multiline list items
+* this is a second multiline
+list item
+
+You can use nowiki syntax if you would like do stuff like this:
+
+{{{
+Guitar Chord C:
+
+||---|---|---|
+||-0-|---|---|
+||---|---|---|
+||---|-0-|---|
+||---|---|-0-|
+||---|---|---|
+}}}
+
+You can also use it inline nowiki {{{ in a sentence }}} like this.
+
+= Escapes =
+Normal Link: http://wikicreole.org/ - now same link, but escaped: ~http://wikicreole.org/
+
+Normal asterisks: ~**not bold~**
+
+a tilde alone: ~
+
+a tilde escapes itself: ~~xxx
+
+=== Creole 0.2 ===
+
+This should be a flower with the ALT text "this is a flower" if your wiki supports ALT text on images:
+
+{{Red-Flower.jpg|here is a red flower}}
+
+=== Creole 0.4 ===
+
+Tables are done like this:
+
+|=header col1|=header col2|
+|col1|col2|
+|you |can |
+|also |align\\ it. |
+
+You can format an address by simply forcing linebreaks:
+
+My contact dates:\\
+Pone: xyz\\
+Fax: +45\\
+Mobile: abc
+
+=== Creole 0.5 ===
+
+|= Header title |= Another header title |
+| {{{ //not italic text// }}} | {{{ **not bold text** }}} |
+| //italic text// | ** bold text ** |
+
+=== Creole 1.0 ===
+
+If interwiki links are setup in your wiki, this links to the WikiCreole page about Creole 1.0 test cases: [[WikiCreole:Creole1.0TestCases]].
+
+ ----
+
+The above test document was found on
+http://www.wikicreole.org/wiki/Creole1.0TestCases and downloaded from
+http://www.wikicreole.org/attach/Creole1.0TestCases/creole1.0test.txt.
+
+The Creole Wiki is licensed: Copyright (C) by the contributors. Some
+rights reserved, license
+[[BY-SA|https://creativecommons.org/licenses/by-sa/1.0/]].
diff --git a/tests/docbook-reader.docbook b/test/docbook-reader.docbook
index 3a4fc77c6..3a4fc77c6 100644
--- a/tests/docbook-reader.docbook
+++ b/test/docbook-reader.docbook
diff --git a/tests/docbook-reader.native b/test/docbook-reader.native
index 3cce889f6..3cce889f6 100644
--- a/tests/docbook-reader.native
+++ b/test/docbook-reader.native
diff --git a/tests/docbook-xref.docbook b/test/docbook-xref.docbook
index ebcd94d00..ebcd94d00 100644
--- a/tests/docbook-xref.docbook
+++ b/test/docbook-xref.docbook
diff --git a/tests/docbook-xref.native b/test/docbook-xref.native
index 23bc497b2..23bc497b2 100644
--- a/tests/docbook-xref.native
+++ b/test/docbook-xref.native
diff --git a/test/docx/0_level_headers.docx b/test/docx/0_level_headers.docx
new file mode 100644
index 000000000..7d4699316
--- /dev/null
+++ b/test/docx/0_level_headers.docx
Binary files differ
diff --git a/test/docx/0_level_headers.native b/test/docx/0_level_headers.native
new file mode 100644
index 000000000..804ad8732
--- /dev/null
+++ b/test/docx/0_level_headers.native
@@ -0,0 +1,25 @@
+[Table [] [AlignDefault] [0.0]
+ [[]]
+ [[[]]
+ ,[[Plain [Str "User\8217s",Space,Str "Guide"]]]
+ ,[[]]
+ ,[[]]
+ ,[[]]
+ ,[[Plain [Str "11",Space,Str "August",Space,Str "2017"]]]
+ ,[[]]
+ ,[[]]
+ ,[[]]
+ ,[[]]]
+,Para [Str "CONTENTS"]
+,Para [Strong [Str "Section",Space,Str "Page"]]
+,Para [Str "FIGURES",Space,Str "iv"]
+,Para [Str "TABLES",Space,Str "v"]
+,Para [Str "SECTION",Space,Str "1",Space,Str "Introduction",Space,Str "2"]
+,Header 1 ("figures",["Heading0"],[]) [Str "FIGURES"]
+,Para [Strong [Str "Figure",Space,Str "Page"]]
+,Para [Strong [Str "No",Space,Str "table",Space,Str "of",Space,Str "figures",Space,Str "entries",Space,Str "found."]]
+,Header 1 ("tables",["Heading0"],[]) [Str "TABLES"]
+,Para [Strong [Str "Table",Space,Str "Page"]]
+,Para [Strong [Str "No",Space,Str "table",Space,Str "of",Space,Str "figures",Space,Str "entries",Space,Str "found."]]
+,Header 1 ("introduction",[],[]) [Str "Introduction"]
+,Para [Str "Nothing",Space,Str "to",Space,Str "introduce,",Space,Str "yet."]]
diff --git a/tests/docx/already_auto_ident.docx b/test/docx/already_auto_ident.docx
index ec2b348d7..ec2b348d7 100644
--- a/tests/docx/already_auto_ident.docx
+++ b/test/docx/already_auto_ident.docx
Binary files differ
diff --git a/tests/docx/already_auto_ident.native b/test/docx/already_auto_ident.native
index 67c37298d..67c37298d 100644
--- a/tests/docx/already_auto_ident.native
+++ b/test/docx/already_auto_ident.native
diff --git a/test/docx/block_quotes.docx b/test/docx/block_quotes.docx
new file mode 100644
index 000000000..729ae1f43
--- /dev/null
+++ b/test/docx/block_quotes.docx
Binary files differ
diff --git a/tests/docx/block_quotes_parse_indent.native b/test/docx/block_quotes_parse_indent.native
index 842b3606a..842b3606a 100644
--- a/tests/docx/block_quotes_parse_indent.native
+++ b/test/docx/block_quotes_parse_indent.native
diff --git a/test/docx/char_styles.docx b/test/docx/char_styles.docx
new file mode 100644
index 000000000..05979b9a7
--- /dev/null
+++ b/test/docx/char_styles.docx
Binary files differ
diff --git a/tests/docx/char_styles.native b/test/docx/char_styles.native
index 7dfc208fb..7dfc208fb 100644
--- a/tests/docx/char_styles.native
+++ b/test/docx/char_styles.native
diff --git a/tests/docx/codeblock.docx b/test/docx/codeblock.docx
index 8ec00953c..8ec00953c 100644
--- a/tests/docx/codeblock.docx
+++ b/test/docx/codeblock.docx
Binary files differ
diff --git a/tests/docx/codeblock.native b/test/docx/codeblock.native
index 441e33511..441e33511 100644
--- a/tests/docx/codeblock.native
+++ b/test/docx/codeblock.native
diff --git a/tests/docx/comments.docx b/test/docx/comments.docx
index 9df74cf0a..9df74cf0a 100644
--- a/tests/docx/comments.docx
+++ b/test/docx/comments.docx
Binary files differ
diff --git a/tests/docx/comments.native b/test/docx/comments.native
index 3357bc257..3357bc257 100644
--- a/tests/docx/comments.native
+++ b/test/docx/comments.native
diff --git a/tests/docx/comments_no_comments.native b/test/docx/comments_no_comments.native
index 805e9b562..805e9b562 100644
--- a/tests/docx/comments_no_comments.native
+++ b/test/docx/comments_no_comments.native
diff --git a/tests/docx/comments_warning.docx b/test/docx/comments_warning.docx
index e49642b22..e49642b22 100644
--- a/tests/docx/comments_warning.docx
+++ b/test/docx/comments_warning.docx
Binary files differ
diff --git a/test/docx/custom-style-no-styles.native b/test/docx/custom-style-no-styles.native
new file mode 100644
index 000000000..b024f16b2
--- /dev/null
+++ b/test/docx/custom-style-no-styles.native
@@ -0,0 +1,4 @@
+[Para [Str "This",Space,Str "is",Space,Str "some",Space,Str "text."]
+,Para [Str "This",Space,Str "is",Space,Str "text",Space,Str "with",Space,Str "an",Space,Emph [Str "emphasized"],Space,Str "text",Space,Str "style.",Space,Str "And",Space,Str "this",Space,Str "is",Space,Str "text",Space,Str "with",Space,Str "a",Space,Strong [Str "strengthened"],Space,Str "text",Space,Str "style."]
+,BlockQuote
+ [Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "styled",Space,Str "paragraph",Space,Str "that",Space,Str "inherits",Space,Str "from",Space,Str "Block",Space,Str "Text."]]]
diff --git a/tests/docx/custom-style-reference.docx b/test/docx/custom-style-reference.docx
index 0f53c6c88..0f53c6c88 100644
--- a/tests/docx/custom-style-reference.docx
+++ b/test/docx/custom-style-reference.docx
Binary files differ
diff --git a/tests/docx/custom-style-roundtrip-end.native b/test/docx/custom-style-roundtrip-end.native
index 4313c3595..4313c3595 100644
--- a/tests/docx/custom-style-roundtrip-end.native
+++ b/test/docx/custom-style-roundtrip-end.native
diff --git a/test/docx/custom-style-with-styles.native b/test/docx/custom-style-with-styles.native
new file mode 100644
index 000000000..61f11911d
--- /dev/null
+++ b/test/docx/custom-style-with-styles.native
@@ -0,0 +1,7 @@
+[Div ("",[],[("custom-style","FirstParagraph")])
+ [Para [Str "This",Space,Str "is",Space,Str "some",Space,Str "text."]]
+,Div ("",[],[("custom-style","BodyText")])
+ [Para [Str "This",Space,Str "is",Space,Str "text",Space,Str "with",Space,Str "an",Space,Span ("",[],[("custom-style","Emphatic")]) [Str "emphasized"],Space,Str "text",Space,Str "style.",Space,Str "And",Space,Str "this",Space,Str "is",Space,Str "text",Space,Str "with",Space,Str "a",Space,Span ("",[],[("custom-style","Strengthened")]) [Str "strengthened"],Space,Str "text",Space,Str "style."]]
+,Div ("",[],[("custom-style","MyBlockStyle")])
+ [BlockQuote
+ [Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "styled",Space,Str "paragraph",Space,Str "that",Space,Str "inherits",Space,Str "from",Space,Str "Block",Space,Str "Text."]]]]
diff --git a/tests/docx/custom-style-roundtrip-start.native b/test/docx/custom_style.native
index c4566ed85..c4566ed85 100644
--- a/tests/docx/custom-style-roundtrip-start.native
+++ b/test/docx/custom_style.native
diff --git a/test/docx/deep_normalize.docx b/test/docx/deep_normalize.docx
new file mode 100644
index 000000000..7626d59ce
--- /dev/null
+++ b/test/docx/deep_normalize.docx
Binary files differ
diff --git a/tests/docx/deep_normalize.native b/test/docx/deep_normalize.native
index 9b2089ec8..9b2089ec8 100644
--- a/tests/docx/deep_normalize.native
+++ b/test/docx/deep_normalize.native
diff --git a/tests/docx/definition_list.docx b/test/docx/definition_list.docx
index a19edda45..a19edda45 100644
--- a/tests/docx/definition_list.docx
+++ b/test/docx/definition_list.docx
Binary files differ
diff --git a/tests/docx/definition_list.native b/test/docx/definition_list.native
index 2e08ff1ac..2e08ff1ac 100644
--- a/tests/docx/definition_list.native
+++ b/test/docx/definition_list.native
diff --git a/test/docx/drop_cap.docx b/test/docx/drop_cap.docx
new file mode 100644
index 000000000..19fab4a52
--- /dev/null
+++ b/test/docx/drop_cap.docx
Binary files differ
diff --git a/tests/docx/drop_cap.native b/test/docx/drop_cap.native
index d361cfb0b..d361cfb0b 100644
--- a/tests/docx/drop_cap.native
+++ b/test/docx/drop_cap.native
diff --git a/tests/docx/dummy_item_after_list_item.docx b/test/docx/dummy_item_after_list_item.docx
index 5e29b993c..5e29b993c 100644
--- a/tests/docx/dummy_item_after_list_item.docx
+++ b/test/docx/dummy_item_after_list_item.docx
Binary files differ
diff --git a/tests/docx/dummy_item_after_list_item.native b/test/docx/dummy_item_after_list_item.native
index 3f6231932..3f6231932 100644
--- a/tests/docx/dummy_item_after_list_item.native
+++ b/test/docx/dummy_item_after_list_item.native
diff --git a/tests/docx/dummy_item_after_paragraph.docx b/test/docx/dummy_item_after_paragraph.docx
index b0aee8843..b0aee8843 100644
--- a/tests/docx/dummy_item_after_paragraph.docx
+++ b/test/docx/dummy_item_after_paragraph.docx
Binary files differ
diff --git a/tests/docx/dummy_item_after_paragraph.native b/test/docx/dummy_item_after_paragraph.native
index 2e9b831c4..2e9b831c4 100644
--- a/tests/docx/dummy_item_after_paragraph.native
+++ b/test/docx/dummy_item_after_paragraph.native
diff --git a/tests/docx/enumerated_headings.docx b/test/docx/enumerated_headings.docx
index afa84748a..afa84748a 100644
--- a/tests/docx/enumerated_headings.docx
+++ b/test/docx/enumerated_headings.docx
Binary files differ
diff --git a/tests/docx/enumerated_headings.native b/test/docx/enumerated_headings.native
index 67c0df5e0..67c0df5e0 100644
--- a/tests/docx/enumerated_headings.native
+++ b/test/docx/enumerated_headings.native
diff --git a/tests/docx/german_styled_lists.docx b/test/docx/german_styled_lists.docx
index ce454e9cc..ce454e9cc 100644
--- a/tests/docx/german_styled_lists.docx
+++ b/test/docx/german_styled_lists.docx
Binary files differ
diff --git a/tests/docx/german_styled_lists.native b/test/docx/german_styled_lists.native
index 4d5456dfc..4d5456dfc 100644
--- a/tests/docx/german_styled_lists.native
+++ b/test/docx/german_styled_lists.native
diff --git a/test/docx/golden/block_quotes.docx b/test/docx/golden/block_quotes.docx
new file mode 100644
index 000000000..28d6f035e
--- /dev/null
+++ b/test/docx/golden/block_quotes.docx
Binary files differ
diff --git a/test/docx/golden/codeblock.docx b/test/docx/golden/codeblock.docx
new file mode 100644
index 000000000..af85598dc
--- /dev/null
+++ b/test/docx/golden/codeblock.docx
Binary files differ
diff --git a/test/docx/golden/comments.docx b/test/docx/golden/comments.docx
new file mode 100644
index 000000000..33831dc06
--- /dev/null
+++ b/test/docx/golden/comments.docx
Binary files differ
diff --git a/test/docx/golden/custom_style_no_reference.docx b/test/docx/golden/custom_style_no_reference.docx
new file mode 100644
index 000000000..78f56893c
--- /dev/null
+++ b/test/docx/golden/custom_style_no_reference.docx
Binary files differ
diff --git a/test/docx/golden/custom_style_reference.docx b/test/docx/golden/custom_style_reference.docx
new file mode 100644
index 000000000..dfc2c960b
--- /dev/null
+++ b/test/docx/golden/custom_style_reference.docx
Binary files differ
diff --git a/test/docx/golden/definition_list.docx b/test/docx/golden/definition_list.docx
new file mode 100644
index 000000000..c3f076387
--- /dev/null
+++ b/test/docx/golden/definition_list.docx
Binary files differ
diff --git a/test/docx/golden/headers.docx b/test/docx/golden/headers.docx
new file mode 100644
index 000000000..c2b6206a3
--- /dev/null
+++ b/test/docx/golden/headers.docx
Binary files differ
diff --git a/test/docx/golden/image.docx b/test/docx/golden/image.docx
new file mode 100644
index 000000000..95a28a098
--- /dev/null
+++ b/test/docx/golden/image.docx
Binary files differ
diff --git a/test/docx/golden/inline_code.docx b/test/docx/golden/inline_code.docx
new file mode 100644
index 000000000..1d415e411
--- /dev/null
+++ b/test/docx/golden/inline_code.docx
Binary files differ
diff --git a/test/docx/golden/inline_formatting.docx b/test/docx/golden/inline_formatting.docx
new file mode 100644
index 000000000..367654e53
--- /dev/null
+++ b/test/docx/golden/inline_formatting.docx
Binary files differ
diff --git a/test/docx/golden/inline_images.docx b/test/docx/golden/inline_images.docx
new file mode 100644
index 000000000..62c5943ba
--- /dev/null
+++ b/test/docx/golden/inline_images.docx
Binary files differ
diff --git a/test/docx/golden/link_in_notes.docx b/test/docx/golden/link_in_notes.docx
new file mode 100644
index 000000000..c86f9aecd
--- /dev/null
+++ b/test/docx/golden/link_in_notes.docx
Binary files differ
diff --git a/test/docx/golden/links.docx b/test/docx/golden/links.docx
new file mode 100644
index 000000000..652a93569
--- /dev/null
+++ b/test/docx/golden/links.docx
Binary files differ
diff --git a/test/docx/golden/lists.docx b/test/docx/golden/lists.docx
new file mode 100644
index 000000000..5e900feb1
--- /dev/null
+++ b/test/docx/golden/lists.docx
Binary files differ
diff --git a/test/docx/golden/lists_continuing.docx b/test/docx/golden/lists_continuing.docx
new file mode 100644
index 000000000..278edaa99
--- /dev/null
+++ b/test/docx/golden/lists_continuing.docx
Binary files differ
diff --git a/test/docx/golden/lists_restarting.docx b/test/docx/golden/lists_restarting.docx
new file mode 100644
index 000000000..112b824b5
--- /dev/null
+++ b/test/docx/golden/lists_restarting.docx
Binary files differ
diff --git a/test/docx/golden/nested_anchors_in_header.docx b/test/docx/golden/nested_anchors_in_header.docx
new file mode 100644
index 000000000..c2a10b828
--- /dev/null
+++ b/test/docx/golden/nested_anchors_in_header.docx
Binary files differ
diff --git a/test/docx/golden/notes.docx b/test/docx/golden/notes.docx
new file mode 100644
index 000000000..c6093c18a
--- /dev/null
+++ b/test/docx/golden/notes.docx
Binary files differ
diff --git a/test/docx/golden/table_one_row.docx b/test/docx/golden/table_one_row.docx
new file mode 100644
index 000000000..34de65e2e
--- /dev/null
+++ b/test/docx/golden/table_one_row.docx
Binary files differ
diff --git a/test/docx/golden/table_with_list_cell.docx b/test/docx/golden/table_with_list_cell.docx
new file mode 100644
index 000000000..c27f99736
--- /dev/null
+++ b/test/docx/golden/table_with_list_cell.docx
Binary files differ
diff --git a/test/docx/golden/tables.docx b/test/docx/golden/tables.docx
new file mode 100644
index 000000000..4fcdd73c3
--- /dev/null
+++ b/test/docx/golden/tables.docx
Binary files differ
diff --git a/test/docx/golden/track_changes_deletion.docx b/test/docx/golden/track_changes_deletion.docx
new file mode 100644
index 000000000..7b404dba1
--- /dev/null
+++ b/test/docx/golden/track_changes_deletion.docx
Binary files differ
diff --git a/test/docx/golden/track_changes_insertion.docx b/test/docx/golden/track_changes_insertion.docx
new file mode 100644
index 000000000..500a7c239
--- /dev/null
+++ b/test/docx/golden/track_changes_insertion.docx
Binary files differ
diff --git a/test/docx/golden/track_changes_move.docx b/test/docx/golden/track_changes_move.docx
new file mode 100644
index 000000000..05705c040
--- /dev/null
+++ b/test/docx/golden/track_changes_move.docx
Binary files differ
diff --git a/test/docx/golden/unicode.docx b/test/docx/golden/unicode.docx
new file mode 100644
index 000000000..c1626874d
--- /dev/null
+++ b/test/docx/golden/unicode.docx
Binary files differ
diff --git a/test/docx/golden/verbatim_subsuper.docx b/test/docx/golden/verbatim_subsuper.docx
new file mode 100644
index 000000000..d2ada67fa
--- /dev/null
+++ b/test/docx/golden/verbatim_subsuper.docx
Binary files differ
diff --git a/test/docx/hanging_indent.docx b/test/docx/hanging_indent.docx
new file mode 100644
index 000000000..6f62dc731
--- /dev/null
+++ b/test/docx/hanging_indent.docx
Binary files differ
diff --git a/tests/docx/hanging_indent.native b/test/docx/hanging_indent.native
index 138a6967f..138a6967f 100644
--- a/tests/docx/hanging_indent.native
+++ b/test/docx/hanging_indent.native
diff --git a/test/docx/headers.docx b/test/docx/headers.docx
new file mode 100644
index 000000000..e1fbbcc75
--- /dev/null
+++ b/test/docx/headers.docx
Binary files differ
diff --git a/tests/docx/headers.native b/test/docx/headers.native
index 5d0065239..5d0065239 100644
--- a/tests/docx/headers.native
+++ b/test/docx/headers.native
diff --git a/tests/docx/i18n_blocks.docx b/test/docx/i18n_blocks.docx
index 36341c363..36341c363 100644
--- a/tests/docx/i18n_blocks.docx
+++ b/test/docx/i18n_blocks.docx
Binary files differ
diff --git a/tests/docx/i18n_blocks.native b/test/docx/i18n_blocks.native
index 582a7360d..582a7360d 100644
--- a/tests/docx/i18n_blocks.native
+++ b/test/docx/i18n_blocks.native
diff --git a/tests/docx/image.docx b/test/docx/image.docx
index 674956e7a..674956e7a 100644
--- a/tests/docx/image.docx
+++ b/test/docx/image.docx
Binary files differ
diff --git a/tests/docx/image_no_embed.native b/test/docx/image_no_embed.native
index 5f413dbf8..5f413dbf8 100644
--- a/tests/docx/image_no_embed.native
+++ b/test/docx/image_no_embed.native
diff --git a/tests/docx/image_no_embed_writer.native b/test/docx/image_no_embed_writer.native
index 91e7f6f2b..91e7f6f2b 100644
--- a/tests/docx/image_no_embed_writer.native
+++ b/test/docx/image_no_embed_writer.native
diff --git a/tests/docx/image_vml.docx b/test/docx/image_vml.docx
index 9e4018e00..9e4018e00 100644
--- a/tests/docx/image_vml.docx
+++ b/test/docx/image_vml.docx
Binary files differ
diff --git a/tests/docx/image_vml.native b/test/docx/image_vml.native
index e9fded614..e9fded614 100644
--- a/tests/docx/image_vml.native
+++ b/test/docx/image_vml.native
diff --git a/test/docx/image_writer_test.native b/test/docx/image_writer_test.native
new file mode 100644
index 000000000..a0fb3ee3a
--- /dev/null
+++ b/test/docx/image_writer_test.native
@@ -0,0 +1,8 @@
+[Para [Str "No",Space,Str "width",Space,Str "given:"]
+,Para [Image ("",[],[]) [Str "testimg"] ("lalune.jpg","fig:")]
+,Para [Str "With",Space,Str "height",Space,Str "10cm:"]
+,Para [Image ("",[],[("height","10cm")]) [Str "2testimg"] ("lalune.jpg","fig:")]
+,Para [Str "With",Space,Str "width",Space,Str "6cm:"]
+,Para [Image ("",[],[("width","6cm")]) [Str "3testimg"] ("lalune.jpg","fig:")]
+,Header 1 ("with-height-3in-and-width-6in",[],[]) [Str "With",Space,Str "height",Space,Str "3in",Space,Str "and",Space,Str "width",Space,Str "6in:"]
+,Para [Image ("",[],[("width","6in"),("height","3in")]) [Str "4testimg"] ("lalune.jpg","fig:")]] \ No newline at end of file
diff --git a/tests/docx/inline_code.docx b/test/docx/inline_code.docx
index 75c5ea3cb..75c5ea3cb 100644
--- a/tests/docx/inline_code.docx
+++ b/test/docx/inline_code.docx
Binary files differ
diff --git a/tests/docx/inline_code.native b/test/docx/inline_code.native
index 11cf2777c..11cf2777c 100644
--- a/tests/docx/inline_code.native
+++ b/test/docx/inline_code.native
diff --git a/test/docx/inline_formatting.docx b/test/docx/inline_formatting.docx
new file mode 100644
index 000000000..eccf26425
--- /dev/null
+++ b/test/docx/inline_formatting.docx
Binary files differ
diff --git a/test/docx/inline_formatting.native b/test/docx/inline_formatting.native
new file mode 100644
index 000000000..a7aaf9999
--- /dev/null
+++ b/test/docx/inline_formatting.native
@@ -0,0 +1,5 @@
+[Para [Str "Regular",Space,Str "text",Space,Emph [Str "italics"],Space,Strong [Str "bold",Space,Emph [Str "bold",Space,Str "italics"]],Str "."]
+,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "Small",Space,Str "Caps"],Str ",",Space,Str "and",Space,Str "this",Space,Str "is",Space,Strikeout [Str "strikethrough"],Str "."]
+,Para [Str "Some",Space,Str "people",Space,Str "use",Space,Span ("",["underline"],[]) [Str "single",Space,Str "underlines",Space,Str "for",Space,Emph [Str "emphasis"]],Str "."]
+,Para [Str "Above",Space,Str "the",Space,Str "line",Space,Str "is",Space,Superscript [Str "superscript"],Space,Str "and",Space,Str "below",Space,Str "the",Space,Str "line",Space,Str "is",Space,Subscript [Str "subscript"],Str "."]
+,Para [Str "A",Space,Str "line",LineBreak,Str "break."]]
diff --git a/tests/docx/inline_formatting_writer.native b/test/docx/inline_formatting_writer.native
index be346204e..be346204e 100644
--- a/tests/docx/inline_formatting_writer.native
+++ b/test/docx/inline_formatting_writer.native
diff --git a/test/docx/inline_images.docx b/test/docx/inline_images.docx
new file mode 100644
index 000000000..2f01a251e
--- /dev/null
+++ b/test/docx/inline_images.docx
Binary files differ
diff --git a/tests/docx/inline_images.native b/test/docx/inline_images.native
index 389ae5db6..389ae5db6 100644
--- a/tests/docx/inline_images.native
+++ b/test/docx/inline_images.native
diff --git a/tests/docx/inline_images_writer.native b/test/docx/inline_images_writer.native
index e5dfa5b58..e5dfa5b58 100644
--- a/tests/docx/inline_images_writer.native
+++ b/test/docx/inline_images_writer.native
diff --git a/test/docx/inline_images_writer_test.native b/test/docx/inline_images_writer_test.native
new file mode 100644
index 000000000..921a7aff8
--- /dev/null
+++ b/test/docx/inline_images_writer_test.native
@@ -0,0 +1,2 @@
+[Para [Str "This",Space,Str "picture",Space,Image ("",[],[("width","0.8888888888888888in"),("height","0.8888888888888888in")]) [Str "This",Space,Str "one",Space,Str "is",Space,Str "green",Space,Str "and",Space,Str "looks",Space,Str "like",Space,Str "Sideshow",Space,Str "Bob."] ("lalune.jpg","First identicon"),Space,Str "is",Space,Str "an",Space,Str "identicon."]
+,Para [Str "Here",Space,Str "is",Space,Link ("",[],[]) [Str "one",Space,Image ("",[],[("width","0.8888888888888888in"),("height","0.8888888888888888in")]) [Str "This",Space,Str "one",Space,Str "is",Space,Str "reddish,",Space,Str "and",Space,Str "looks",Space,Str "like",Space,Str "a",Space,Str "heart",Space,Str "that",Space,Str "has",Space,Str "leaked",Space,Str "out."] ("lalune.jpg","Second identicon"),Space,Str "that"] ("http://www.google.com",""),Space,Str "links."]]
diff --git a/test/docx/instrText_hyperlink.docx b/test/docx/instrText_hyperlink.docx
new file mode 100644
index 000000000..9f24b3896
--- /dev/null
+++ b/test/docx/instrText_hyperlink.docx
Binary files differ
diff --git a/test/docx/instrText_hyperlink.native b/test/docx/instrText_hyperlink.native
new file mode 100644
index 000000000..4293c48db
--- /dev/null
+++ b/test/docx/instrText_hyperlink.native
@@ -0,0 +1 @@
+[Para [Str "\24076\26395\28145\20837\20102\35299\30340\35835\32773\21487\20197\21435\30475David",Space,Str "French",Space,Str "Belding\21644Kevin",Space,Str "J.",Space,Str "Mitchell\30340",Link ("",[],[]) [Str "Foundations",Space,Str "of",Space,Str "Analysis,",Space,Str "2nd",Space,Str "Edition"] ("https://books.google.com/books?id=sp_Zcb9ot90C&lpg=PR4&hl=zh-CN&pg=PA19#v=onepage&q&f=true",""),Str ",\21487\20174\&19\39029\30475\36215\65292\25110D.C.",Space,Str "Goldrei\30340",Space,Link ("",[],[]) [Str "Classic",Space,Str "Set",Space,Str "Theory:",Space,Str "For",Space,Str "Guided",Space,Str "Independent",Space,Str "Study"] ("https://books.google.ae/books?id=dlc0DwAAQBAJ&lpg=PT29&hl=zh-CN&pg=PT26#v=onepage&q&f=true",""),Str "\65292\20174\31532\20108\31456\30475\36215\65292\38405\35835\26102\35201\27880\24847\26412\25991\19982\36825\20123\20070\25152\19981\21516\30340\26159\24182\27809\26377\25226\23454\25968\30475\20316\26159\26377\29702\25968\38598\30340\20998\21106\12290"]]
diff --git a/test/docx/link_in_notes.docx b/test/docx/link_in_notes.docx
new file mode 100644
index 000000000..f3398f438
--- /dev/null
+++ b/test/docx/link_in_notes.docx
Binary files differ
diff --git a/tests/docx/link_in_notes.native b/test/docx/link_in_notes.native
index b20358698..b20358698 100644
--- a/tests/docx/link_in_notes.native
+++ b/test/docx/link_in_notes.native
diff --git a/test/docx/links.docx b/test/docx/links.docx
new file mode 100644
index 000000000..80fecacaf
--- /dev/null
+++ b/test/docx/links.docx
Binary files differ
diff --git a/tests/docx/links.native b/test/docx/links.native
index 2c4688629..2c4688629 100644
--- a/tests/docx/links.native
+++ b/test/docx/links.native
diff --git a/tests/docx/links_writer.native b/test/docx/links_writer.native
index 48c1bcd81..48c1bcd81 100644
--- a/tests/docx/links_writer.native
+++ b/test/docx/links_writer.native
diff --git a/test/docx/lists.docx b/test/docx/lists.docx
new file mode 100644
index 000000000..bf7fd8ae4
--- /dev/null
+++ b/test/docx/lists.docx
Binary files differ
diff --git a/tests/docx/lists.native b/test/docx/lists.native
index af922b335..af922b335 100644
--- a/tests/docx/lists.native
+++ b/test/docx/lists.native
diff --git a/test/docx/lists_continuing.docx b/test/docx/lists_continuing.docx
new file mode 100644
index 000000000..e6249260b
--- /dev/null
+++ b/test/docx/lists_continuing.docx
Binary files differ
diff --git a/test/docx/lists_continuing.native b/test/docx/lists_continuing.native
new file mode 100644
index 000000000..24d352ce5
--- /dev/null
+++ b/test/docx/lists_continuing.native
@@ -0,0 +1,7 @@
+[OrderedList (1,Decimal,Period)
+ [[Para [Str "Foo"]]
+ ,[Para [Str "Bar"]]
+ ,[Para [Str "Baz"]]]
+,Para [Str "Interruption."]
+,OrderedList (4,Decimal,Period)
+ [[Para [Str "Bop"]]]]
diff --git a/test/docx/lists_restarting.docx b/test/docx/lists_restarting.docx
new file mode 100644
index 000000000..4acd67fcb
--- /dev/null
+++ b/test/docx/lists_restarting.docx
Binary files differ
diff --git a/test/docx/lists_restarting.native b/test/docx/lists_restarting.native
new file mode 100644
index 000000000..6602f1262
--- /dev/null
+++ b/test/docx/lists_restarting.native
@@ -0,0 +1,8 @@
+[OrderedList (2,Decimal,Period)
+ [[Para [Str "Foo"]]
+ ,[Para [Str "Bar"]]
+ ,[Para [Str "Baz"]]]
+,BlockQuote
+ [Para [Str "Interruption"]]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "Bop."]]]]
diff --git a/tests/docx/lists_writer.native b/test/docx/lists_writer.native
index 4c44ea603..4c44ea603 100644
--- a/tests/docx/lists_writer.native
+++ b/test/docx/lists_writer.native
diff --git a/test/docx/metadata.docx b/test/docx/metadata.docx
new file mode 100644
index 000000000..ccf50b475
--- /dev/null
+++ b/test/docx/metadata.docx
Binary files differ
diff --git a/tests/docx/metadata.native b/test/docx/metadata.native
index ed7ba63cf..ed7ba63cf 100644
--- a/tests/docx/metadata.native
+++ b/test/docx/metadata.native
diff --git a/test/docx/metadata_after_normal.docx b/test/docx/metadata_after_normal.docx
new file mode 100644
index 000000000..b94a016cb
--- /dev/null
+++ b/test/docx/metadata_after_normal.docx
Binary files differ
diff --git a/tests/docx/metadata_after_normal.native b/test/docx/metadata_after_normal.native
index f0e31f8da..f0e31f8da 100644
--- a/tests/docx/metadata_after_normal.native
+++ b/test/docx/metadata_after_normal.native
diff --git a/tests/docx/nested_anchors_in_header.docx b/test/docx/nested_anchors_in_header.docx
index ddebb7ff4..ddebb7ff4 100644
--- a/tests/docx/nested_anchors_in_header.docx
+++ b/test/docx/nested_anchors_in_header.docx
Binary files differ
diff --git a/test/docx/nested_anchors_in_header.native b/test/docx/nested_anchors_in_header.native
new file mode 100644
index 000000000..562f60215
--- /dev/null
+++ b/test/docx/nested_anchors_in_header.native
@@ -0,0 +1,15 @@
+[Header 1 ("\1086\1075\1083\1072\1074\1083\1077\1085\1080\1077",["TOCHeading"],[]) [Str "\1054\1075\1083\1072\1074\1083\1077\1085\1080\1077"]
+,Para [Link ("",[],[]) [Str "Short",Space,Str "instructions",Space,Str "1"] ("#short-instructions","")]
+,Para [Link ("",[],[]) [Str "Some",Space,Str "instructions",Space,Str "1"] ("#some-instructions","")]
+,Para [Link ("",[],[]) [Str "Remote",Space,Str "folder",Space,Str "or",Space,Str "longlonglonglonglong",Space,Str "file",Space,Str "with",Space,Str "manymanymanymany",Space,Str "letters",Space,Str "inside",Space,Str "opening",Space,Str "2"] ("#remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-opening","")]
+,Para [Link ("",[],[]) [Str "Remote",Space,Str "folder",Space,Str "or",Space,Str "longlonglonglonglong",Space,Str "file",Space,Str "with",Space,Str "manymanymanymany",Space,Str "letters",Space,Str "inside",Space,Str "closing",Space,Str "2"] ("#remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-closing","")]
+,Header 1 ("short-instructions",[],[]) [Str "Short",Space,Str "instructions"]
+,Para [Link ("",[],[]) [Str "Open",Space,Str "remote",Space,Str "folder"] ("#remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-opening","")]
+,Para [Str "Do",Space,Str "staff"]
+,Para [Link ("",[],[]) [Str "Close",Space,Str "remote",Space,Str "folder"] ("#remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-closing","")]
+,Header 1 ("some-instructions",[],[]) [Str "Some",Space,Str "instructions"]
+,Para [Str "Lines"]
+,Header 2 ("remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-opening",[],[]) [Str "Remote",Space,Str "folder",Space,Str "or",Space,Str "longlonglonglonglong",Space,Str "file",Space,Str "with",Space,Str "manymanymanymany",Space,Str "letters",Space,Str "inside",Space,Str "opening"]
+,Para [Str "Open",Space,Str "folder"]
+,Header 2 ("remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-closing",[],[]) [Str "Remote",Space,Str "folder",Space,Str "or",Space,Str "longlonglonglonglong",Space,Str "file",Space,Str "with",Space,Str "manymanymanymany",Space,Str "letters",Space,Str "inside",Space,Str "closing"]
+,Para [Str "Close",Space,Str "folder"]]
diff --git a/test/docx/nested_sdt.docx b/test/docx/nested_sdt.docx
new file mode 100644
index 000000000..1a0827db3
--- /dev/null
+++ b/test/docx/nested_sdt.docx
Binary files differ
diff --git a/test/docx/nested_sdt.native b/test/docx/nested_sdt.native
new file mode 100644
index 000000000..d0adc05ac
--- /dev/null
+++ b/test/docx/nested_sdt.native
@@ -0,0 +1,3 @@
+[Para [Str "Test",Space,Str "Paragraph1"]
+,Para [Str "Test",Space,Str "Paragraph2"]
+,Para [Str "Test",Space,Str "Paragraph3"]]
diff --git a/test/docx/normalize.docx b/test/docx/normalize.docx
new file mode 100644
index 000000000..b4fc55818
--- /dev/null
+++ b/test/docx/normalize.docx
Binary files differ
diff --git a/tests/docx/normalize.native b/test/docx/normalize.native
index aeba672c4..aeba672c4 100644
--- a/tests/docx/normalize.native
+++ b/test/docx/normalize.native
diff --git a/test/docx/notes.docx b/test/docx/notes.docx
new file mode 100644
index 000000000..eb6fa12d4
--- /dev/null
+++ b/test/docx/notes.docx
Binary files differ
diff --git a/tests/docx/notes.native b/test/docx/notes.native
index ec1b414b6..ec1b414b6 100644
--- a/tests/docx/notes.native
+++ b/test/docx/notes.native
diff --git a/test/docx/numbered_header.docx b/test/docx/numbered_header.docx
new file mode 100644
index 000000000..66ce7648d
--- /dev/null
+++ b/test/docx/numbered_header.docx
Binary files differ
diff --git a/tests/docx/numbered_header.native b/test/docx/numbered_header.native
index a8dd1e897..a8dd1e897 100644
--- a/tests/docx/numbered_header.native
+++ b/test/docx/numbered_header.native
diff --git a/test/docx/overlapping_targets.docx b/test/docx/overlapping_targets.docx
new file mode 100644
index 000000000..45ae7cd58
--- /dev/null
+++ b/test/docx/overlapping_targets.docx
Binary files differ
diff --git a/test/docx/overlapping_targets.native b/test/docx/overlapping_targets.native
new file mode 100644
index 000000000..17dcafd96
--- /dev/null
+++ b/test/docx/overlapping_targets.native
@@ -0,0 +1,3 @@
+[Para [Link ("",[],[]) [Str "One",Space,Str "link",Space,Str "to",Space,Str "one",Space,Str "target."] ("#Fizz","")]
+,Para [Span ("Fizz",["anchor"],[]) [],Str "This",Space,Str "is",Space,Str "a",Space,Str "target",Space,Str "with",Space,Str "two",Space,Str "names."]
+,Para [Link ("",[],[]) [Str "Another",Space,Str "link",Space,Str "to",Space,Str "the",Space,Str "same",Space,Str "target."] ("#Fizz","")]]
diff --git a/test/docx/paragraph_insertion_deletion.docx b/test/docx/paragraph_insertion_deletion.docx
new file mode 100644
index 000000000..9b62f9036
--- /dev/null
+++ b/test/docx/paragraph_insertion_deletion.docx
Binary files differ
diff --git a/test/docx/paragraph_insertion_deletion_accept.native b/test/docx/paragraph_insertion_deletion_accept.native
new file mode 100644
index 000000000..3b0f3b18a
--- /dev/null
+++ b/test/docx/paragraph_insertion_deletion_accept.native
@@ -0,0 +1,2 @@
+[Para [Str "This",Space,Str "is",Space,Str "a"]
+,Para [Str "split",Space,Str "Paragraph."]]
diff --git a/test/docx/paragraph_insertion_deletion_all.native b/test/docx/paragraph_insertion_deletion_all.native
new file mode 100644
index 000000000..4a12938ee
--- /dev/null
+++ b/test/docx/paragraph_insertion_deletion_all.native
@@ -0,0 +1,3 @@
+[Para [Str "This",Space,Str "is",Space,Str "a",Span ("",["paragraph-insertion"],[("author","Seeley, Jason"),("date","2017-09-17T16:39:00Z")]) []]
+,Para [Str "split",Span ("",["paragraph-deletion"],[("author","Seeley, Jason"),("date","2017-09-17T16:39:00Z")]) []]
+,Para [Str "Paragraph."]]
diff --git a/test/docx/paragraph_insertion_deletion_reject.native b/test/docx/paragraph_insertion_deletion_reject.native
new file mode 100644
index 000000000..ef7b06423
--- /dev/null
+++ b/test/docx/paragraph_insertion_deletion_reject.native
@@ -0,0 +1,2 @@
+[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "split"]
+,Para [Str "Paragraph."]]
diff --git a/test/docx/sdt_elements.docx b/test/docx/sdt_elements.docx
new file mode 100644
index 000000000..9356a6b40
--- /dev/null
+++ b/test/docx/sdt_elements.docx
Binary files differ
diff --git a/test/docx/sdt_elements.native b/test/docx/sdt_elements.native
new file mode 100644
index 000000000..7f7768728
--- /dev/null
+++ b/test/docx/sdt_elements.native
@@ -0,0 +1,10 @@
+[Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Strong [Str "col1Header"]]]
+ ,[Plain [Strong [Str "col2Header"]]]
+ ,[Plain [Strong [Str "col3Header"]]]]
+ ,[[Plain [Str "col1",Space,Str "content"]]
+ ,[Plain [Str "Body",Space,Str "copy"]]
+ ,[Plain [Str "col3",Space,Str "content"]]]]]
diff --git a/tests/docx/special_punctuation.docx b/test/docx/special_punctuation.docx
index 8e0bb55c9..8e0bb55c9 100644
--- a/tests/docx/special_punctuation.docx
+++ b/test/docx/special_punctuation.docx
Binary files differ
diff --git a/tests/docx/special_punctuation.native b/test/docx/special_punctuation.native
index 304289f44..304289f44 100644
--- a/tests/docx/special_punctuation.native
+++ b/test/docx/special_punctuation.native
diff --git a/tests/docx/table_one_row.docx b/test/docx/table_one_row.docx
index f7e0ebe43..f7e0ebe43 100644
--- a/tests/docx/table_one_row.docx
+++ b/test/docx/table_one_row.docx
Binary files differ
diff --git a/tests/docx/table_one_row.native b/test/docx/table_one_row.native
index 1ea1b446c..1ea1b446c 100644
--- a/tests/docx/table_one_row.native
+++ b/test/docx/table_one_row.native
diff --git a/test/docx/table_variable_width.docx b/test/docx/table_variable_width.docx
new file mode 100644
index 000000000..899357968
--- /dev/null
+++ b/test/docx/table_variable_width.docx
Binary files differ
diff --git a/test/docx/table_variable_width.native b/test/docx/table_variable_width.native
new file mode 100644
index 000000000..9d3b961df
--- /dev/null
+++ b/test/docx/table_variable_width.native
@@ -0,0 +1,13 @@
+[Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[Plain [Str "h3"]]
+ ,[Plain [Str "h4"]]
+ ,[Plain [Str "h5"]]]
+ [[[Plain [Str "c11"]]
+ ,[]
+ ,[]]
+ ,[[]
+ ,[Plain [Str "c22"]]
+ ,[Plain [Str "c23"]]
+ ,[]]]]
diff --git a/test/docx/table_with_list_cell.docx b/test/docx/table_with_list_cell.docx
new file mode 100644
index 000000000..1db065770
--- /dev/null
+++ b/test/docx/table_with_list_cell.docx
Binary files differ
diff --git a/tests/docx/table_with_list_cell.native b/test/docx/table_with_list_cell.native
index 81bb15a1e..81bb15a1e 100644
--- a/tests/docx/table_with_list_cell.native
+++ b/test/docx/table_with_list_cell.native
diff --git a/test/docx/tables.docx b/test/docx/tables.docx
new file mode 100644
index 000000000..28087ead5
--- /dev/null
+++ b/test/docx/tables.docx
Binary files differ
diff --git a/tests/docx/tables.native b/test/docx/tables.native
index ae326950a..ae326950a 100644
--- a/tests/docx/tables.native
+++ b/test/docx/tables.native
diff --git a/tests/docx/tabs.docx b/test/docx/tabs.docx
index 6ff5f4bb1..6ff5f4bb1 100644
--- a/tests/docx/tabs.docx
+++ b/test/docx/tabs.docx
Binary files differ
diff --git a/tests/docx/tabs.native b/test/docx/tabs.native
index 05461f20b..05461f20b 100644
--- a/tests/docx/tabs.native
+++ b/test/docx/tabs.native
diff --git a/tests/docx/track_changes_deletion.docx b/test/docx/track_changes_deletion.docx
index 5cfdbeed8..5cfdbeed8 100644
--- a/tests/docx/track_changes_deletion.docx
+++ b/test/docx/track_changes_deletion.docx
Binary files differ
diff --git a/tests/docx/track_changes_deletion_accept.native b/test/docx/track_changes_deletion_accept.native
index 205c67810..205c67810 100644
--- a/tests/docx/track_changes_deletion_accept.native
+++ b/test/docx/track_changes_deletion_accept.native
diff --git a/tests/docx/track_changes_deletion_all.native b/test/docx/track_changes_deletion_all.native
index 7f4ed2a90..7f4ed2a90 100644
--- a/tests/docx/track_changes_deletion_all.native
+++ b/test/docx/track_changes_deletion_all.native
diff --git a/tests/docx/track_changes_deletion_reject.native b/test/docx/track_changes_deletion_reject.native
index 04283bee5..04283bee5 100644
--- a/tests/docx/track_changes_deletion_reject.native
+++ b/test/docx/track_changes_deletion_reject.native
diff --git a/tests/docx/track_changes_insertion.docx b/test/docx/track_changes_insertion.docx
index fbdc9003e..fbdc9003e 100644
--- a/tests/docx/track_changes_insertion.docx
+++ b/test/docx/track_changes_insertion.docx
Binary files differ
diff --git a/tests/docx/track_changes_insertion_accept.native b/test/docx/track_changes_insertion_accept.native
index ca2e46df0..ca2e46df0 100644
--- a/tests/docx/track_changes_insertion_accept.native
+++ b/test/docx/track_changes_insertion_accept.native
diff --git a/tests/docx/track_changes_insertion_all.native b/test/docx/track_changes_insertion_all.native
index 12664e425..12664e425 100644
--- a/tests/docx/track_changes_insertion_all.native
+++ b/test/docx/track_changes_insertion_all.native
diff --git a/tests/docx/track_changes_insertion_reject.native b/test/docx/track_changes_insertion_reject.native
index def000abd..def000abd 100644
--- a/tests/docx/track_changes_insertion_reject.native
+++ b/test/docx/track_changes_insertion_reject.native
diff --git a/tests/docx/track_changes_move.docx b/test/docx/track_changes_move.docx
index b70779fd4..b70779fd4 100644
--- a/tests/docx/track_changes_move.docx
+++ b/test/docx/track_changes_move.docx
Binary files differ
diff --git a/tests/docx/track_changes_move_accept.native b/test/docx/track_changes_move_accept.native
index 0cf276768..0cf276768 100644
--- a/tests/docx/track_changes_move_accept.native
+++ b/test/docx/track_changes_move_accept.native
diff --git a/tests/docx/track_changes_move_all.native b/test/docx/track_changes_move_all.native
index 3afae83a5..3afae83a5 100644
--- a/tests/docx/track_changes_move_all.native
+++ b/test/docx/track_changes_move_all.native
diff --git a/tests/docx/track_changes_move_reject.native b/test/docx/track_changes_move_reject.native
index 9c57871b6..9c57871b6 100644
--- a/tests/docx/track_changes_move_reject.native
+++ b/test/docx/track_changes_move_reject.native
diff --git a/tests/docx/trailing_spaces_in_formatting.docx b/test/docx/trailing_spaces_in_formatting.docx
index ebe7404a9..ebe7404a9 100644
--- a/tests/docx/trailing_spaces_in_formatting.docx
+++ b/test/docx/trailing_spaces_in_formatting.docx
Binary files differ
diff --git a/tests/docx/trailing_spaces_in_formatting.native b/test/docx/trailing_spaces_in_formatting.native
index 46ea9bca8..46ea9bca8 100644
--- a/tests/docx/trailing_spaces_in_formatting.native
+++ b/test/docx/trailing_spaces_in_formatting.native
diff --git a/tests/docx/unicode.docx b/test/docx/unicode.docx
index cf902c6c6..cf902c6c6 100644
--- a/tests/docx/unicode.docx
+++ b/test/docx/unicode.docx
Binary files differ
diff --git a/tests/docx/unicode.native b/test/docx/unicode.native
index aee7ef74b..aee7ef74b 100644
--- a/tests/docx/unicode.native
+++ b/test/docx/unicode.native
diff --git a/test/docx/unused_anchors.docx b/test/docx/unused_anchors.docx
new file mode 100644
index 000000000..416488bbf
--- /dev/null
+++ b/test/docx/unused_anchors.docx
Binary files differ
diff --git a/test/docx/unused_anchors.native b/test/docx/unused_anchors.native
new file mode 100644
index 000000000..051dfe424
--- /dev/null
+++ b/test/docx/unused_anchors.native
@@ -0,0 +1,3 @@
+[Header 1 ("my-section",[],[]) [Str "My",Space,Str "Section"]
+,Para [Link ("",[],[]) [Str "Here",Space,Str "is",Space,Str "a",Space,Str "link."] ("#Foo","")]
+,Para [Span ("Foo",["anchor"],[]) [],Str "Here",Space,Str "is",Space,Str "the",Space,Str "target."]]
diff --git a/tests/docx/verbatim_subsuper.docx b/test/docx/verbatim_subsuper.docx
index 2cb0dc16d..2cb0dc16d 100644
--- a/tests/docx/verbatim_subsuper.docx
+++ b/test/docx/verbatim_subsuper.docx
Binary files differ
diff --git a/tests/docx/verbatim_subsuper.native b/test/docx/verbatim_subsuper.native
index 2e11e646a..2e11e646a 100644
--- a/tests/docx/verbatim_subsuper.native
+++ b/test/docx/verbatim_subsuper.native
diff --git a/tests/dokuwiki_external_images.dokuwiki b/test/dokuwiki_external_images.dokuwiki
index cc7eddcda..cc7eddcda 100644
--- a/tests/dokuwiki_external_images.dokuwiki
+++ b/test/dokuwiki_external_images.dokuwiki
diff --git a/tests/dokuwiki_external_images.native b/test/dokuwiki_external_images.native
index 0f103461e..0f103461e 100644
--- a/tests/dokuwiki_external_images.native
+++ b/test/dokuwiki_external_images.native
diff --git a/tests/dokuwiki_inline_formatting.dokuwiki b/test/dokuwiki_inline_formatting.dokuwiki
index 262094184..262094184 100644
--- a/tests/dokuwiki_inline_formatting.dokuwiki
+++ b/test/dokuwiki_inline_formatting.dokuwiki
diff --git a/tests/dokuwiki_inline_formatting.native b/test/dokuwiki_inline_formatting.native
index 63e85889f..63e85889f 100644
--- a/tests/dokuwiki_inline_formatting.native
+++ b/test/dokuwiki_inline_formatting.native
diff --git a/tests/dokuwiki_multiblock_table.dokuwiki b/test/dokuwiki_multiblock_table.dokuwiki
index 8b913f1f2..8b913f1f2 100644
--- a/tests/dokuwiki_multiblock_table.dokuwiki
+++ b/test/dokuwiki_multiblock_table.dokuwiki
diff --git a/tests/dokuwiki_multiblock_table.native b/test/dokuwiki_multiblock_table.native
index 34824296d..34824296d 100644
--- a/tests/dokuwiki_multiblock_table.native
+++ b/test/dokuwiki_multiblock_table.native
diff --git a/tests/epub/features.epub b/test/epub/features.epub
index 2690eec8b..2690eec8b 100644
--- a/tests/epub/features.epub
+++ b/test/epub/features.epub
Binary files differ
diff --git a/test/epub/features.native b/test/epub/features.native
new file mode 100644
index 000000000..6a400721f
--- /dev/null
+++ b/test/epub/features.native
@@ -0,0 +1,93 @@
+[Para [Span ("front.xhtml",[],[]) []]
+,Div ("",["section"],[])
+ [Header 1 ("",[],[]) [Str "Reflowable",Space,Str "EPUB",Space,Str "3",Space,Str "Conformance",Space,Str "Test",Space,Str "Document:",Space,Str "0100"]
+ ,Div ("",["section"],[])
+ [Header 2 ("",[],[]) [Str "Status",Space,Str "of",Space,Str "this",Space,Str "Document"]
+ ,Para [Str "This",Space,Str "publication",Space,Str "is",Space,Str "currently",Space,Str "considered",Space,Span ("",["status"],[]) [Str "[UNDER",Space,Str "DEVELOPMENT]"],Space,Str "by",Space,Str "the",Space,Str "IDPF."]
+ ,Para [Str "This",Space,Str "publication",Space,Str "is",Space,Str "part",Space,Str "of",Space,Str "version",Space,Span ("",["version"],[]) [Str "X.X"],Space,Str "of",Space,Str "the",Space,Str "EPUB",Space,Str "3.0",Space,Str "Compliance",Space,Str "Test",Space,Str "Suite",Space,Str "released",SoftBreak,Str "on",Space,RawInline (Format "html") "<time class=\"release\">",Str "TBD",RawInline (Format "html") "</time>",Str "."]
+ ,Para [Str "Before",Space,Str "using",Space,Str "this",Space,Str "publication",Space,Str "to",Space,Str "evaluate",Space,Str "reading",Space,Str "systems,",Space,Str "testers",Space,Str "are",Space,Str "strongly",Space,Str "encouraged",Space,Str "to",SoftBreak,Str "verify",Space,Str "that",Space,Str "they",Space,Str "have",Space,Str "the",Space,Str "latest",Space,Str "release",Space,Str "by",Space,Str "checking",Space,Str "the",Space,Str "current",Space,Str "release",Space,Str "version",Space,Str "and",Space,Str "date",Space,Str "of",SoftBreak,Str "the",Space,Str "test",Space,Str "suite",Space,Str "at",Space,Link ("",[],[]) [Str "TBD"] ("http://idpf.org/","")]
+ ,Para [Str "This",Space,Str "publication",Space,Str "is",Space,Str "one",Space,Str "of",Space,Str "several",Space,Str "that",Space,Str "currently",Space,Str "comprise",Space,Str "the",Space,Str "EPUB",Space,Str "3",Space,Str "conformance",Space,Str "test",Space,Str "suite",SoftBreak,Str "for",Space,Str "reflowable",Space,Str "content.",Space,Str "The",Space,Str "complete",Space,Str "test",Space,Str "suite",Space,Str "includes",Space,Str "all",Space,Str "of",Space,Str "the",Space,Str "following",Space,Str "publications:"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "."]]]]
+ ,Div ("",["section"],[])
+ [Header 2 ("",[],[]) [Str "About",Space,Str "this",Space,Str "Document"]
+ ,Para [Str "This",Space,Str "document",Space,Str "focuses",Space,Str "on",Space,Str "human-evaluated",Space,Str "binary",Space,Str "(pass/fail)",Space,Str "tests",Space,Str "in",Space,Str "a",SoftBreak,Str "reflowable",Space,Str "context.",Space,Str "Tests",Space,Str "for",Space,Str "fixed-layout",Space,Str "content",Space,Str "and",Space,Str "other",Space,Str "individual",Space,Str "tests",Space,Str "that",SoftBreak,Str "require",Space,Str "a",Space,Str "dedicated",Space,Str "epub",Space,Str "file",Space,Str "are",Space,Str "available",Space,Str "in",Space,Str "additional",Space,Str "sibling",Space,Str "documents;",Space,Str "refer",Space,Str "to",SoftBreak,Str "the",Space,Link ("",[],[]) [Str "test",Space,Str "suite",SoftBreak,Str "wiki"] ("https://github.com/mgylling/epub-testsuite/wiki/Overview",""),Space,Str "(",Code ("",[],[]) "https://github.com/mgylling/epub-testsuite/wiki/Overview",Str ")",Space,Str "for",Space,Str "additional",SoftBreak,Str "information."]]
+ ,Div ("",["section"],[])
+ [Header 2 ("",[],[]) [Str "Conventions"]
+ ,Para [Str "The",Space,Str "following",Space,Str "conventions",Space,Str "are",Space,Str "used",Space,Str "throughout",Space,Str "the",Space,Str "document:"]
+ ,DefinitionList
+ [([Str "1.",Space,Str "Locating",Space,Str "a",Space,Str "test"],
+ [[Div ("",["ctest"],[])
+ [Para [Str "Tests",Space,Str "for",Space,Emph [Str "required"],Space,Str "Reading",Space,Str "System",Space,Str "functionality",Space,Str "are",SoftBreak,Str "preceded",Space,Str "by",Space,Str "the",Space,Str "label:",Space,Span ("",["nature"],[("style","display: inline; font-size: 100%")]) [Str "[REQUIRED]"]]]
+ ,Div ("",["otest"],[])
+ [Para [Str "Tests",Space,Str "for",Space,Emph [Str "optional"],Space,Str "Reading",Space,Str "System",Space,Str "functionality",Space,Str "are",SoftBreak,Str "preceded",Space,Str "by",Space,Str "the",Space,Str "label:",Space,Span ("",["nature"],[("style","display: inline; font-size: 100%")]) [Str "[OPTIONAL]"]]]]])
+ ,([Str "2.",Space,Str "Performing",Space,Str "the",Space,Str "test"],
+ [[Plain [Str "Each",Space,Str "test",Space,Str "includes",Space,Str "a",Space,Str "description",Space,Str "of",Space,Str "its",Space,Str "purpose",Space,Str "followed",Space,Str "by",Space,Str "the",Space,Str "actual",Space,Strong [Str "test",Space,Str "statement,",SoftBreak,Str "which",Space,Str "can",Space,Str "always",Space,Str "be",Space,Str "evaluated",Space,Str "to",Space,Str "true",Space,Str "or",Space,Str "false"],Str ".",Space,Str "These",Space,Str "statements",Space,Str "typically",Space,Str "have",Space,Str "the",Space,Str "form:",SoftBreak,Str "\"If",Space,Str "[some",Space,Str "condition],",Space,Str "the",Space,Str "test",Space,Str "passes\"."]]])
+ ,([Str "3.",Space,Str "Scoring",Space,Str "in",Space,Str "the",Space,Str "results",Space,Str "form"],
+ [[Plain [Str "@@@TODO",Space,Str "provide",Space,Str "info",Space,Str "on",Space,Str "where",Space,Str "to",Space,Str "get",Space,Str "the",Space,Str "results",Space,Str "form"]]])]]]
+,Para [Span ("content-mathml-001.xhtml",[],[]) []]
+,Div ("",["section"],[])
+ [Header 2 ("content-mathml-001.xhtml#mathml",[],[]) [Str "MathML"]
+ ,Div ("content-mathml-001.xhtml#mathml-010",["section","ctest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-010"],Space,Str "Rendering"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "MathML",Space,Str "equation",Space,Str "rendering",Space,Str "is",Space,Str "supported."]
+ ,Plain [Math DisplayMath "\\int_{- \\infty}^{\\infty}e^{- x^{2}}\\, dx = \\sqrt{\\pi}",SoftBreak,Math DisplayMath "\\sum\\limits_{n = 1}^{\\infty}\\frac{1}{n^{2}} = \\frac{\\pi^{2}}{6}",SoftBreak,Math DisplayMath "x = \\frac{- b \\pm \\sqrt{b^{2} - 4ac}}{2a}"]
+ ,Para [Str "If",Space,Str "the",Space,Str "preceding",Space,Str "equations",Space,Str "are",Space,Str "not",Space,Str "presented",Space,Str "as",Space,Str "linear",Space,Str "text",Space,Str "(e.g.,",Space,Str "x=-b\177b2-4ac2a),",SoftBreak,Str "the",Space,Str "test",Space,Str "passes."]]
+ ,Div ("content-mathml-001.xhtml#mathml-020",["section","otest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-020"],Space,Str "CSS",Space,Str "Styling",Space,Str "of",Space,Str "the",Space,Code ("",[],[]) "math",Space,Str "element"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "basic",Space,Str "CSS",Space,Str "styling",Space,Str "of",Space,Str "MathML",Space,Str "is",Space,Str "supported",Space,Str "on",Space,Str "the",Space,Code ("",[],[]) "math",Space,Str "element."]
+ ,Plain [Math InlineMath "{2x}{+ y - z}"]
+ ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "equation",Space,Str "has",Space,Str "a",Space,Str "yellow",Space,Str "background",Space,Str "and",Space,Str "a",Space,Str "dashed",Space,Str "border."]
+ ,Para [Str "If",Space,Str "the",Space,Str "reading",Space,Str "system",Space,Str "does",Space,Str "not",Space,Str "have",Space,Str "a",Space,Str "viewport,",Space,Str "or",Space,Str "does",Space,Str "not",Space,Str "support",SoftBreak,Str "CSS",Space,Str "styles,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]
+ ,Div ("content-mathml-001.xhtml#mathml-021",["section","otest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-021"],Space,Str "CSS",Space,Str "Styling",Space,Str "of",Space,Str "the",Space,Code ("",[],[]) "mo",Space,Str "element"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "basic",Space,Str "CSS",Space,Str "styling",Space,Str "of",Space,Str "MathML",Space,Str "is",Space,Str "supported",Space,Str "on",Space,Str "the",Space,Code ("",[],[]) "mo",Space,Str "element."]
+ ,Plain [Math InlineMath "{2x}{+ y - z}"]
+ ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "operators",Space,Str "are",Space,Str "enlarged",Space,Str "relative",Space,Str "to",Space,Str "the",Space,Str "other",Space,Str "symbols",Space,Str "and",Space,Str "numbers."]
+ ,Para [Str "If",Space,Str "the",Space,Str "reading",Space,Str "system",Space,Str "does",Space,Str "not",Space,Str "have",Space,Str "a",Space,Str "viewport,",Space,Str "or",Space,Str "does",Space,Str "not",Space,Str "support",SoftBreak,Str "CSS",Space,Str "styles,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]
+ ,Div ("content-mathml-001.xhtml#mathml-022",["section","otest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-022"],Space,Str "CSS",Space,Str "Styling",Space,Str "of",Space,Str "the",Space,Code ("",[],[]) "mi",Space,Str "element"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "basic",Space,Str "CSS",Space,Str "styling",Space,Str "of",Space,Str "MathML",Space,Str "is",Space,Str "supported",Space,Str "on",Space,Str "the",Space,Code ("",[],[]) "mi",Space,Str "element."]
+ ,Plain [Math InlineMath "{2x}{+ y - z}"]
+ ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "identifiers",Space,Str "are",Space,Str "bolded",Space,Str "and",Space,Str "blue."]
+ ,Para [Str "If",Space,Str "the",Space,Str "reading",Space,Str "system",Space,Str "does",Space,Str "not",Space,Str "have",Space,Str "a",Space,Str "viewport,",Space,Str "or",Space,Str "does",Space,Str "not",Space,Str "support",SoftBreak,Str "CSS",Space,Str "styles,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]
+ ,Div ("content-mathml-001.xhtml#mathml-023",["section","otest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-023"],Space,Str "CSS",Space,Str "Styling",Space,Str "of",Space,Str "the",Space,Code ("",[],[]) "mn",Space,Str "element"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "basic",Space,Str "CSS",Space,Str "styling",Space,Str "of",Space,Str "MathML",Space,Str "is",Space,Str "supported",Space,Str "on",Space,Str "the",Space,Code ("",[],[]) "mn",Space,Str "element."]
+ ,Plain [Math InlineMath "{2x}{+ y - z}"]
+ ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "number",Space,Str "2",Space,Str "is",Space,Str "italicized",Space,Str "and",Space,Str "blue."]
+ ,Para [Str "If",Space,Str "the",Space,Str "reading",Space,Str "system",Space,Str "does",Space,Str "not",Space,Str "have",Space,Str "a",Space,Str "viewport,",Space,Str "or",Space,Str "does",Space,Str "not",Space,Str "support",SoftBreak,Str "CSS",Space,Str "styles,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]
+ ,Div ("content-mathml-001.xhtml#mathml-024",["section","ctest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-024"],Str "Horizontal",Space,Str "stretch,",Space,Code ("",[],[]) "mover",Str ",",Space,Code ("",[],[]) "munder",Str ",",Space,Str "and",Space,Code ("",[],[]) "mspace",Space,Str "elements"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "horizontal",Space,Str "stretch,",Space,Code ("",[],[]) "mover",Str ",",Space,Code ("",[],[]) "munder",Str ",",Space,Code ("",[],[]) "mspace",Space,Str "elements",Space,Str "are",Space,Str "supported."]
+ ,Plain [Math DisplayMath "c = \\overset{\\text{complex\\ number}}{\\overbrace{\\underset{\\text{real}}{\\underbrace{\\mspace{20mu} a\\mspace{20mu}}} + \\underset{\\text{imaginary}}{\\underbrace{\\quad b{\\mathbb{i}}\\quad}}}}"]
+ ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "rendering",Space,Str "looks",Space,Str "like",Space,Str "."]]
+ ,Div ("content-mathml-001.xhtml#mathml-025",["section","ctest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-025"],Str "Testing",Space,Code ("",[],[]) "mtable",Space,Str "with",Space,Code ("",[],[]) "colspan",Space,Str "and",Space,Code ("",[],[]) "rowspan",Space,Str "attributes,",Space,Str "Hebrew",Space,Str "and",Space,Str "Script",Space,Str "fonts"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Code ("",[],[]) "mtable",Space,Str "with",Space,Code ("",[],[]) "colspan",Space,Str "and",Space,Code ("",[],[]) "mspace",Space,Str "attributes",Space,Str "(colum",Space,Str "and",Space,Str "row",Space,Str "spanning)",Space,Str "are",Space,Str "supported;",Space,Str "uses",Space,Str "Hebrew",Space,Str "and",Space,Str "Script",Space,Str "alphabets."]
+ ,Plain [Math DisplayMath "\\begin{matrix}\n & {\\operatorname{cov}\\left( \\mathcal{L} \\right)} & \\longrightarrow & {\\operatorname{non}\\left( \\mathcal{K} \\right)} & \\longrightarrow & {\\operatorname{cof}\\left( \\mathcal{K} \\right)} & \\longrightarrow & {\\operatorname{cof}\\left( \\mathcal{L} \\right)} & \\longrightarrow & 2^{\\aleph_{0}} \\\\\n & \\uparrow & & \\uparrow & & \\uparrow & & \\uparrow & & \\\\\n & {\\mathfrak{b}} & \\longrightarrow & {\\mathfrak{d}} & & & & & & \\\\\n & \\uparrow & & \\uparrow & & & & & & \\\\\n\\aleph_{1} & \\longrightarrow & {\\operatorname{add}\\left( \\mathcal{L} \\right)} & \\longrightarrow & {\\operatorname{add}\\left( \\mathcal{K} \\right)} & \\longrightarrow & {\\operatorname{cov}\\left( \\mathcal{K} \\right)} & \\longrightarrow & {\\operatorname{non}\\left( \\mathcal{L} \\right)} & \\\\\n\\end{matrix}"]
+ ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "rendering",Space,Str "looks",Space,Str "like",Space,Link ("",[],[]) [Str "Cicho\324's",Space,Str "Diagram"] ("http://en.wikipedia.org/wiki/Cicho%C5%84's_diagram",""),Str ":",Space,Str "."]]
+ ,Div ("content-mathml-001.xhtml#mathml-026",["section","ctest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-026"],Str "BiDi,",Space,Str "RTL",Space,Str "and",Space,Str "Arabic",Space,Str "alphabets"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "right-to-left",Space,Str "and",Space,Str "Arabic",Space,Str "alphabets",Space,Str "are",Space,Str "supported."]
+ ,Plain [Math DisplayMath "{d\\left( s \\right)} = \\left\\{ \\begin{matrix}\n{\\sum\\limits_{{\\lbrack?\\rbrack} = 1}^{S}s^{\\lbrack?\\rbrack}} & {\\text{\1573\1584\1575\1603\1575\1606}s > 0} \\\\\n{\\int_{1}^{S}{s^{\\lbrack?\\rbrack}s}} & {\\text{\1573\1584\1575\1603\1575\1606}s \\in m} \\\\\n{T\\pi} & {\\text{\1594\1610\1585\1584\1604\1603}\\left( \\text{\1605\1593}\\pi \\simeq 3,141 \\right)} \\\\\n\\end{matrix} \\right."]
+ ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "rendering",Space,Str "looks",Space,Str "like",Space,Str "the",Space,Str "following",Space,Str "image:"]]
+ ,Div ("content-mathml-001.xhtml#mathml-027",["section","ctest"],[])
+ [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-027"],Str "Elementary",Space,Str "math:",Space,Str "long",Space,Str "division",Space,Str "notation"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Code ("",[],[]) "mlongdiv",Space,Str "elements",Space,Str "(from",Space,Str "elementary",Space,Str "math)",Space,Str "are",Space,Str "supported."]
+ ,Plain [Span ("",["math"],[("xmlns","http://www.w3.org/1998/Math/MathML")]) [SoftBreak,Str "3",SoftBreak,Str "435.3",SoftBreak,Str "1306",SoftBreak,Str "12",SoftBreak,Str "10",SoftBreak,Str "9",SoftBreak,Str "16",SoftBreak,Str "15",SoftBreak,Str "1.0",SoftBreak,Str "9",SoftBreak,Str "1",SoftBreak]]
+ ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "rendering",Space,Str "looks",Space,Str "like",Space,Str "the",Space,Str "following",Space,Str "image:",Space,Str "."]]]
+,Para [Span ("content-switch-001.xhtml",[],[]) []]
+,Div ("content-switch-001.xhtml#epub-switch",["section"],[])
+ [Header 3 ("",[],[]) [Code ("",[],[]) "epub:switch"]
+ ,Div ("content-switch-001.xhtml#switch-010",["section","ctest"],[])
+ [Header 4 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],Space,Span ("",["test-id"],[]) [Str "switch-010"],Space,Str "Support"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "the",Space,Code ("",[],[]) "epub:switch",Space,Str "element",Space,Str "is",Space,Str "supported."]
+ ,Para [Str "PASS"]
+ ,Para [Str "If",Space,Str "only",Space,Str "the",Space,Str "word",Space,Str "\"PASS\"",Space,Str "is",Space,Str "rendered",Space,Str "before",Space,Str "this",Space,Str "paragraph,",Space,Str "the",Space,Str "test",Space,Str "passes.",Space,Str "If",Space,Str "both",Space,Str "\"PASS\"",Space,Str "and",Space,Str "\"FAIL\"",Space,Str "are",Space,Str "rendered,",Space,Str "or",Space,Str "neither",SoftBreak,Str "\"PASS\"",Space,Str "nor",Space,Str "\"FAIL\"",Space,Str "is",Space,Str "rendered,",Space,Str "the",Space,Str "test",Space,Str "fails."]]
+ ,Div ("content-switch-001.xhtml#switch-020",["section","otest"],[])
+ [Header 4 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "switch-020"],SoftBreak,Str "MathML",Space,Str "Embedding"]
+ ,Para [Str "Tests",Space,Str "whether",Space,Str "the",Space,Str "MathML",Space,Str "namespace",Space,Str "is",Space,Str "recognized",Space,Str "when",Space,Str "used",Space,Str "in",Space,Str "an",Space,Code ("",[],[]) "epub:case",Space,Str "element."]
+ ,Para [Math InlineMath "{2x}{+ y - z}"]
+ ,Para [Str "If",Space,Str "a",Space,Str "MathML",Space,Str "equation",Space,Str "is",Space,Str "rendered",Space,Str "before",Space,Str "this",Space,Str "paragraph,",Space,Str "the",Space,Str "test",Space,Str "passes."]
+ ,Para [Str "If",Space,Str "test",Space,Code ("",[],[]) "switch-010",Space,Str "did",Space,Str "not",Space,Str "pass,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]]]
diff --git a/tests/epub/formatting.epub b/test/epub/formatting.epub
index f3f9b5b93..f3f9b5b93 100644
--- a/tests/epub/formatting.epub
+++ b/test/epub/formatting.epub
Binary files differ
diff --git a/tests/epub/formatting.native b/test/epub/formatting.native
index e1507ff74..e1507ff74 100644
--- a/tests/epub/formatting.native
+++ b/test/epub/formatting.native
diff --git a/tests/epub/img.epub b/test/epub/img.epub
index ebe80d935..ebe80d935 100644
--- a/tests/epub/img.epub
+++ b/test/epub/img.epub
Binary files differ
diff --git a/tests/epub/wasteland.epub b/test/epub/wasteland.epub
index e4e52db7f..e4e52db7f 100644
--- a/tests/epub/wasteland.epub
+++ b/test/epub/wasteland.epub
Binary files differ
diff --git a/tests/epub/wasteland.native b/test/epub/wasteland.native
index 335c63bf5..335c63bf5 100644
--- a/tests/epub/wasteland.native
+++ b/test/epub/wasteland.native
diff --git a/test/fb2/basic.fb2 b/test/fb2/basic.fb2
new file mode 100644
index 000000000..b6160a9a5
--- /dev/null
+++ b/test/fb2/basic.fb2
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><title><p>Top-level title</p></title><section><title><p>Section</p></title><section><title><p>Subsection</p></title><p>This <emphasis>emphasized</emphasis> <strong>strong</strong> <code>verbatim</code> markdown. See this link<a l:href="#l1" type="note"><sup>[1]</sup></a>.</p><p>Ordered list:</p><p>1. one</p><p>2. two</p><p>3. three</p><cite><p>Blockquote is for citatons.</p></cite><empty-line /><p><code>Code</code></p><p><code>block</code></p><p><code>is</code></p><p><code>for</code></p><p><code>code.</code></p><empty-line /><p><strikethrough>Strikeout</strikethrough> is Pandoc’s extension. Superscript and subscripts too: H<sub>2</sub>O is a liquid<a l:href="#n2" type="note"><sup>[2]</sup></a>. 2<sup>10</sup> is 1024.</p><p>Math is another Pandoc extension: <code>E = m c^2</code>.</p></section></section></section></body><body name="notes"><section id="l1"><title><p>1</p></title><p><code>http://example.com/</code></p></section><section id="n2"><title><p>2</p></title><p>Sometimes.</p></section></body></FictionBook>
+
diff --git a/tests/fb2/basic.markdown b/test/fb2/basic.markdown
index b798b13a4..b798b13a4 100644
--- a/tests/fb2/basic.markdown
+++ b/test/fb2/basic.markdown
diff --git a/test/fb2/images-embedded.fb2 b/test/fb2/images-embedded.fb2
new file mode 100644
index 000000000..d647005ad
--- /dev/null
+++ b/test/fb2/images-embedded.fb2
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><image l:href="#image1" l:type="inlineImageType" alt="This image was embedded using data URI scheme" /><p>This image was embedded using data URI scheme</p></section></body><binary id="image1" content-type="image/png">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</binary></FictionBook>
diff --git a/tests/fb2/images-embedded.html b/test/fb2/images-embedded.html
index 19c8f7c7a..19c8f7c7a 100644
--- a/tests/fb2/images-embedded.html
+++ b/test/fb2/images-embedded.html
diff --git a/test/fb2/images.fb2 b/test/fb2/images.fb2
new file mode 100644
index 000000000..6de9720a0
--- /dev/null
+++ b/test/fb2/images.fb2
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><p>This example test if Pandoc correctly embeds images into FictionBook.</p><p>Small inline image: <image l:href="#image1" l:type="inlineImageType" alt="alt text a small PNG image" />.</p><p>Paragraph image:</p><image l:href="#image2" l:type="imageType" alt="alt text of a big JPEG image" title="image title text" /><p>alt text of a big missing image</p><p>A missing image inline: alt text of missing image.</p></section></body><binary id="image2" content-type="image/jpeg">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</binary><binary id="image1" content-type="image/png">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</binary></FictionBook>
diff --git a/tests/fb2/images.markdown b/test/fb2/images.markdown
index e7d3cc1e6..e7d3cc1e6 100644
--- a/tests/fb2/images.markdown
+++ b/test/fb2/images.markdown
diff --git a/test/fb2/math.fb2 b/test/fb2/math.fb2
new file mode 100644
index 000000000..0f9e11319
--- /dev/null
+++ b/test/fb2/math.fb2
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><p>List math:</p><p>• <code>E = m c^2</code></p><p>• <code>A = \pi r^2</code></p><p>Inline math: <code>x=\frac{-b \pm \sqrt {b^2-4ac}}{2a}</code>.</p><p>Display math:</p><code>\int_a^b \! f(x)\,dx = F(b) - F(a).</code></section></body></FictionBook>
diff --git a/tests/fb2/math.markdown b/test/fb2/math.markdown
index a88fb6cf1..a88fb6cf1 100644
--- a/tests/fb2/math.markdown
+++ b/test/fb2/math.markdown
diff --git a/tests/fb2/test-small.png b/test/fb2/test-small.png
index 16e177219..16e177219 100644
--- a/tests/fb2/test-small.png
+++ b/test/fb2/test-small.png
Binary files differ
diff --git a/tests/fb2/test.jpg b/test/fb2/test.jpg
index 99d57db17..99d57db17 100644
--- a/tests/fb2/test.jpg
+++ b/test/fb2/test.jpg
Binary files differ
diff --git a/test/fb2/titles.fb2 b/test/fb2/titles.fb2
new file mode 100644
index 000000000..49a741b57
--- /dev/null
+++ b/test/fb2/titles.fb2
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><title><p>Simple title</p></title><p>This example tests if Pandoc doesn’t insert forbidden elements in FictionBook titles.</p></section><section><title><p>Emphasized Strong Title</p></title></section></body></FictionBook>
+
diff --git a/test/fb2/titles.markdown b/test/fb2/titles.markdown
new file mode 100644
index 000000000..1eaf2ccd5
--- /dev/null
+++ b/test/fb2/titles.markdown
@@ -0,0 +1,6 @@
+# Simple title
+
+This example tests if Pandoc doesn't insert forbidden elements in FictionBook titles.
+
+# *Emphasized* **Strong** Title
+
diff --git a/tests/haddock-reader.haddock b/test/haddock-reader.haddock
index c3ef0c9fc..c3ef0c9fc 100644
--- a/tests/haddock-reader.haddock
+++ b/test/haddock-reader.haddock
diff --git a/tests/haddock-reader.native b/test/haddock-reader.native
index 7e36b2f72..7e36b2f72 100644
--- a/tests/haddock-reader.native
+++ b/test/haddock-reader.native
diff --git a/test/html-reader.html b/test/html-reader.html
new file mode 100644
index 000000000..a2bca5d2c
--- /dev/null
+++ b/test/html-reader.html
@@ -0,0 +1,710 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<meta name="generator" content="pandoc" />
+<style type="text/css">
+div.pandocNote { border-left: 1px solid grey; padding-left: 1em; }
+span.pandocNoteRef { vertical-align: super; font-size: 80%; }
+span.pandocNoteMarker { }
+</style>
+<title>Pandoc Test Suite</title>
+</head>
+<body>
+<h1 class="title">Pandoc Test Suite</h1>
+<p>This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.</p>
+<hr />
+<h1>Headers</h1>
+<h2>Level 2 with an <a href="/url">embedded link</a></h2>
+<h3>Level 3 with <em>emphasis</em></h3>
+<h4>Level 4</h4>
+<h5>Level 5</h5>
+<h1>Level 1</h1>
+<h2>Level 2 with <em>emphasis</em></h2>
+<h3>Level 3</h3>
+<p>with no blank line</p>
+<h2>Level 2</h2>
+<p>with no blank line</p>
+<hr />
+<h1>Paragraphs</h1>
+<p>Here's a regular paragraph.</p>
+<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p>
+<p>Here's one with a bullet. * criminey.</p>
+<p>There should be a hard line break<br />
+ here.</p>
+<hr />
+<h1>Block Quotes</h1>
+<p>E-mail style:</p>
+<blockquote>
+<p>This is a block quote. It is pretty short.</p>
+</blockquote>
+<blockquote>
+<p>Code in a block quote:</p>
+<pre><code>sub status {
+ print "working";
+}
+</code></pre>
+<p>A list:</p>
+<ol>
+<li>item one</li>
+<li>item two</li>
+</ol>
+<p>Nested block quotes:</p>
+<blockquote>
+<p>nested</p>
+</blockquote>
+<blockquote>
+<p>nested</p>
+</blockquote>
+</blockquote>
+<p>This should not be a block quote: 2 &gt; 1.</p>
+<p>Box-style:</p>
+<blockquote>
+<p>Example:</p>
+<pre><code>sub status {
+ print "working";
+}
+</code></pre>
+</blockquote>
+<blockquote>
+<ol>
+<li>do laundry</li>
+<li>take out the trash</li>
+</ol>
+</blockquote>
+<p>Here's a nested one:</p>
+<blockquote>
+<p>Joe said:</p>
+<blockquote>
+<p>Don't quote me.</p>
+</blockquote>
+</blockquote>
+<p>And a following paragraph.</p>
+<hr />
+<h1>Code Blocks</h1>
+<p>Code:</p>
+<pre><code>---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+</code></pre>
+<p>And:</p>
+<pre><code> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+</code></pre>
+<hr />
+<h1>Lists</h1>
+<h2>Unordered</h2>
+<p>Asterisks tight:</p>
+<ul>
+<li>asterisk 1</li>
+<li>asterisk 2</li>
+<li>asterisk 3</li>
+</ul>
+<p>Asterisks loose:</p>
+<ul>
+<li><p>asterisk 1</p>
+</li>
+<li><p>asterisk 2</p>
+</li>
+<li><p>asterisk 3</p>
+</li>
+</ul>
+<p>Pluses tight:</p>
+<ul>
+<li>Plus 1</li>
+<li>Plus 2</li>
+<li>Plus 3</li>
+</ul>
+<p>Pluses loose:</p>
+<ul>
+<li><p>Plus 1</p>
+</li>
+<li><p>Plus 2</p>
+</li>
+<li><p>Plus 3</p>
+</li>
+</ul>
+<p>Minuses tight:</p>
+<ul>
+<li>Minus 1</li>
+<li>Minus 2</li>
+<li>Minus 3</li>
+</ul>
+<p>Minuses loose:</p>
+<ul>
+<li><p>Minus 1</p>
+</li>
+<li><p>Minus 2</p>
+</li>
+<li><p>Minus 3</p>
+</li>
+</ul>
+<h2>Ordered</h2>
+<p>Tight:</p>
+<ol>
+<li>First</li>
+<li>Second</li>
+<li>Third</li>
+</ol>
+<p>and:</p>
+<ol>
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ol>
+<p>Loose using tabs:</p>
+<ol>
+<li><p>First</p>
+</li>
+<li><p>Second</p>
+</li>
+<li><p>Third</p>
+</li>
+</ol>
+<p>and using spaces:</p>
+<ol>
+<li><p>One</p>
+</li>
+<li><p>Two</p>
+</li>
+<li><p>Three</p>
+</li>
+</ol>
+<p>Multiple paragraphs:</p>
+<ol>
+<li><p>Item 1, graf one.</p>
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog's back.</p>
+</li>
+<li><p>Item 2.</p>
+</li>
+<li><p>Item 3.</p>
+</li>
+</ol>
+<p>List styles:</p>
+<ol></ol>
+<ol type="i"></ol>
+<ol class="lower-roman"></ol>
+<ol style="lower-roman"></ol>
+<ol style="list-style: lower-roman;"></ol>
+<ol style="list-style-type: lower-roman;"></ol>
+<h2>Nested</h2>
+<ul>
+<li>Tab<ul>
+<li>Tab<ul>
+<li>Tab</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+<p>Here's another:</p>
+<ol>
+<li>First</li>
+<li>Second:<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul>
+</li>
+<li>Third</li>
+</ol>
+<p>Same thing but with paragraphs:</p>
+<ol>
+<li><p>First</p>
+</li>
+<li><p>Second:</p>
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul>
+</li>
+<li><p>Third</p>
+</li>
+</ol>
+<h2>Tabs and spaces</h2>
+<ul>
+<li><p>this is a list item indented with tabs</p>
+</li>
+<li><p>this is a list item indented with spaces</p>
+<ul>
+<li><p>this is an example list item indented with tabs</p>
+</li>
+<li><p>this is an example list item indented with spaces</p>
+</li>
+</ul>
+</li>
+</ul>
+<h2 id="fancy-list-markers"
+ >Fancy list markers</h2
+ ><ol start="2" class="decimal"
+ ><li
+ >begins with 2</li
+ ><li
+ ><p
+ >and now 3</p
+ ><p
+ >with a continuation</p
+ ><ol start="4" class="lower-roman"
+ ><li
+ >sublist with roman numerals, starting with 4</li
+ ><li
+ >more items<ol class="upper-alpha"
+ ><li
+ >a subsublist</li
+ ><li
+ >a subsublist</li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ><p
+ >Nesting:</p
+ ><ol type="A"
+ ><li
+ >Upper Alpha<ol class="upper-roman"
+ ><li
+ >Upper Roman.<ol start="6" class="decimal"
+ ><li
+ >Decimal start with 6<ol start="3" type="a"
+ ><li
+ >Lower alpha with paren</li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ></li
+ ></ol
+ ><p
+ >Autonumbering:</p
+ ><ol
+ ><li
+ >Autonumber.</li
+ ><li
+ >More.<ol
+ ><li
+ >Nested.</li
+ ></ol
+ ></li
+ ></ol
+ ><hr
+ />
+<h2>Definition</h2>
+<dl>
+ <dt>Violin</dt>
+ <dd>Stringed musical instrument.</dd>
+ <dd>Torture device.</dd>
+ <dt>Cello</dt>
+ <dt>Violoncello</dt>
+ <dd>Low-voiced stringed instrument.</dd>
+</dl>
+<hr />
+<h1>Inline Markup</h1>
+<p>This is <em>emphasized</em>, and so <em>is this</em>.</p>
+<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
+<p>Empty <strong></strong> and <em></em>.
+<p>An <em><a href="/url">emphasized link</a></em>.</p>
+<p><strong><em>This is strong and em.</em></strong></p>
+<p>So is <strong><em>this</em></strong> word.</p>
+<p><strong><em>This is strong and em.</em></strong></p>
+<p>So is <strong><em>this</em></strong> word.</p>
+<p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p>
+<p>This is <span style="font-variant: small-caps;">small caps</span>.</p>
+<p>These are all underlined: <u>foo</u> and <ins>bar</ins>.</p>
+<p>These are all strikethrough: <s>foo</s>, <strike>bar</strike>, and <del>baz</del>.</p>
+<hr />
+<h1>Smart quotes, ellipses, dashes</h1>
+<p>"Hello," said the spider. "'Shelob' is my name."</p>
+<p>'A', 'B', and 'C' are letters.</p>
+<p>'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'</p>
+<p>'He said, "I want to go."' Were you alive in the 70's?</p>
+<p>Here is some quoted '<code>code</code>' and a "<a href="http://example.com/?foo=1&amp;bar=2">quoted link</a>".</p>
+<p>Some dashes: one---two --- three--four -- five.</p>
+<p>Dashes between numbers: 5-7, 255-66, 1987-1999.</p>
+<p>Ellipses...and. . .and . . . .</p>
+<hr />
+<h1>LaTeX</h1>
+<ul>
+<li>\cite[22-23]{smith.1899}</li>
+<li>\doublespacing</li>
+<li>$2+2=4$</li>
+<li>$x \in y$</li>
+<li>$\alpha \wedge \omega$</li>
+<li>$223$</li>
+<li>$p$-Tree</li>
+<li>$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</li>
+<li>Here's one that has a line break in it: $\alpha + \omega \times x^2$.</li>
+</ul>
+<p>These shouldn't be math:</p>
+<ul>
+<li>To get the famous equation, write <code>$e = mc^2$</code>.</li>
+<li>$22,000 is a <em>lot</em> of money. So is $34,000. (It worked if "lot" is emphasized.)</li>
+<li>Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.</li>
+</ul>
+<p>Here's a LaTeX table:</p>
+<p>\begin{tabular}{|l|l|}\hline Animal &amp; Number \\ \hline Dog &amp; 2 \\ Cat &amp; 1 \\ \hline \end{tabular}</p>
+<hr />
+<h1>Special Characters</h1>
+<p>Here is some unicode:</p>
+<ul>
+<li>I hat: Î</li>
+<li>o umlaut: ö</li>
+<li>section: §</li>
+<li>set membership: ∈</li>
+<li>copyright: ©</li>
+</ul>
+<p>AT&amp;T has an ampersand in their name.</p>
+<p>AT&amp;T is another way to write it.</p>
+<p>This &amp; that.</p>
+<p>4 &lt; 5.</p>
+<p>6 &gt; 5.</p>
+<p>Backslash: \</p>
+<p>Backtick: `</p>
+<p>Asterisk: *</p>
+<p>Underscore: _</p>
+<p>Left brace: {</p>
+<p>Right brace: }</p>
+<p>Left bracket: [</p>
+<p>Right bracket: ]</p>
+<p>Left paren: (</p>
+<p>Right paren: )</p>
+<p>Greater-than: &gt;</p>
+<p>Hash: #</p>
+<p>Period: .</p>
+<p>Bang: !</p>
+<p>Plus: +</p>
+<p>Minus: -</p>
+<hr />
+<h1>Links</h1>
+<h2>Explicit</h2>
+<p>Just a <a href="/url/">URL</a>.</p>
+<p><a href="/url/" title="title">URL and title</a>.</p>
+<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
+<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
+<p><a href="/url/" title="title with &quot;quotes&quot; in it">URL and title</a></p>
+<p><a href="/url/" title="title with single quotes">URL and title</a></p>
+Email link (nobody [at] nowhere.net)<p><a href="">Empty</a>.</p>
+<h2>Reference</h2>
+<p>Foo <a href="/url/">bar</a>.</p>
+<p>Foo <a href="/url/">bar</a>.</p>
+<p>Foo <a href="/url/">bar</a>.</p>
+<p>With <a href="/url/">embedded [brackets]</a>.</p>
+<p><a href="/url/">b</a> by itself should be a link.</p>
+<p>Indented <a href="/url">once</a>.</p>
+<p>Indented <a href="/url">twice</a>.</p>
+<p>Indented <a href="/url">thrice</a>.</p>
+<p>This should [not] be a link.</p>
+<pre><code>[not]: /url
+</code></pre>
+<p>Foo <a href="/url/" title="Title with &quot;quotes&quot; inside">bar</a>.</p>
+<p>Foo <a href="/url/" title="Title with &quot;quote&quot; inside">biz</a>.</p>
+<h2>With ampersands</h2>
+<p>Here's a <a href="http://example.com/?foo=1&amp;bar=2">link with an ampersand in the URL</a>.</p>
+<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&amp;T</a>.</p>
+<p>Here's an <a href="/script?foo=1&amp;bar=2">inline link</a>.</p>
+<p>Here's an <a href="/script?foo=1&amp;bar=2">inline link in pointy braces</a>.</p>
+<h2>Autolinks</h2>
+<p>With an ampersand: <a href="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</a></p>
+<ul>
+<li>In a list?</li>
+<li><a href="http://example.com/">http://example.com/</a></li>
+<li>It should.</li>
+</ul>
+An e-mail address: nobody [at] nowhere.net<blockquote>
+<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>
+</blockquote>
+<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p>
+<pre><code>or here: &lt;http://example.com/&gt;
+</code></pre>
+<hr />
+<h1>Images</h1>
+<p>From "Voyage dans la Lune" by Georges Melies (1902):</p>
+<p><img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune"></p>
+<p>Here is a movie <img src="movie.jpg" alt="movie"> icon.</p>
+<hr />
+<h1>Footnotes</h1>
+<p>Here is a footnote reference<a href="#note_1">(1)</a>, and another<a href="#note_longnote">(longnote)</a>. This should <em>not</em> be a footnote reference, because it contains a space^(my note).</p>
+<p><a href="#ref_1">(1)</a> Here is the footnote. It can go anywhere in the document, not just at the end.</p>
+<p><a href="#ref_longnote">(longnote)</a> Here's the other note. This one contains multiple blocks.</p>
+<p>Caret characters are used to indicate that the blocks all belong to a single footnote (as with block quotes).</p>
+<pre><code> { &lt;code> }
+</code></pre>
+<p>If you want, you can use a caret at the beginning of every line, as with blockquotes, but all that you need is a caret at the beginning of the first line of the block and any preceding blank lines.</p>
+<p>text<em> Leading space</em></p>
+<p><em>Trailing space </em>text</p>
+<p>text<em> Leading spaces</em></p>
+<p><em>Trailing spaces </em>text</p>
+<h1>Tables</h1>
+<h2>Tables with Headers</h2>
+<table>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>1</th>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <th>4</th>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>1</th>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <th>4</th>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tfoot>
+</table>
+<hr />
+<table>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ <tr>
+ <th>1</th>
+ <th>2</th>
+ <th>3</th>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+</table>
+<hr />
+<table>
+ <tbody>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ </thead>
+ <tbody>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ </tbody>
+ <tbody>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td><p>2</p></td>
+ <td>3</td>
+ </tr>
+ </tbody>
+ <tbody>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<h2>Tables without Headers</h2>
+<table>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+</table>
+<hr />
+<table>
+ <thead>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tfoot>
+</table>
+<h2>Empty Tables</h2>
+<p>This section should be empty.</p>
+<table>
+ <tbody>
+ </tbody>
+</table>
+<table>
+</table>
+</body>
+</html>
diff --git a/test/html-reader.native b/test/html-reader.native
new file mode 100644
index 000000000..4203aa3a8
--- /dev/null
+++ b/test/html-reader.native
@@ -0,0 +1,473 @@
+Pandoc (Meta {unMeta = fromList [("generator",MetaInlines [Str "pandoc"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
+[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+,HorizontalRule
+,Header 1 ("headers",[],[]) [Str "Headers"]
+,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
+,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
+,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
+,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
+,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,HorizontalRule
+,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
+,Para [Str "Here's",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
+,Para [Str "Here's",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
+,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
+,HorizontalRule
+,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
+,Para [Str "E-mail",Space,Str "style:"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
+,BlockQuote
+ [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ ,Para [Str "A",Space,Str "list:"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "item",Space,Str "one"]]
+ ,[Plain [Str "item",Space,Str "two"]]]
+ ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ ,BlockQuote
+ [Para [Str "nested"]]
+ ,BlockQuote
+ [Para [Str "nested"]]]
+,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1."]
+,Para [Str "Box-style:"]
+,BlockQuote
+ [Para [Str "Example:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"]
+,BlockQuote
+ [OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "do",Space,Str "laundry"]]
+ ,[Plain [Str "take",Space,Str "out",Space,Str "the",Space,Str "trash"]]]]
+,Para [Str "Here's",Space,Str "a",Space,Str "nested",Space,Str "one:"]
+,BlockQuote
+ [Para [Str "Joe",Space,Str "said:"]
+ ,BlockQuote
+ [Para [Str "Don't",Space,Str "quote",Space,Str "me."]]]
+,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
+,HorizontalRule
+,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+,Para [Str "And:"]
+,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+,HorizontalRule
+,Header 1 ("lists",[],[]) [Str "Lists"]
+,Header 2 ("unordered",[],[]) [Str "Unordered"]
+,Para [Str "Asterisks",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "asterisk",Space,Str "1"]]
+ ,[Plain [Str "asterisk",Space,Str "2"]]
+ ,[Plain [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Asterisks",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "asterisk",Space,Str "1"]]
+ ,[Para [Str "asterisk",Space,Str "2"]]
+ ,[Para [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "Plus",Space,Str "1"]]
+ ,[Plain [Str "Plus",Space,Str "2"]]
+ ,[Plain [Str "Plus",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Plus",Space,Str "1"]]
+ ,[Para [Str "Plus",Space,Str "2"]]
+ ,[Para [Str "Plus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "Minus",Space,Str "1"]]
+ ,[Plain [Str "Minus",Space,Str "2"]]
+ ,[Plain [Str "Minus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Minus",Space,Str "1"]]
+ ,[Para [Str "Minus",Space,Str "2"]]
+ ,[Para [Str "Minus",Space,Str "3"]]]
+,Header 2 ("ordered",[],[]) [Str "Ordered"]
+,Para [Str "Tight:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second"]]
+ ,[Plain [Str "Third"]]]
+,Para [Str "and:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "One"]]
+ ,[Plain [Str "Two"]]
+ ,[Plain [Str "Three"]]]
+,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second"]]
+ ,[Para [Str "Third"]]]
+,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "One"]]
+ ,[Para [Str "Two"]]
+ ,[Para [Str "Three"]]]
+,Para [Str "Multiple",Space,Str "paragraphs:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog's",Space,Str "back."]]
+ ,[Para [Str "Item",Space,Str "2."]]
+ ,[Para [Str "Item",Space,Str "3."]]]
+,Para [Str "List",Space,Str "styles:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ []
+,OrderedList (1,LowerRoman,DefaultDelim)
+ []
+,OrderedList (1,LowerRoman,DefaultDelim)
+ []
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ []
+,OrderedList (1,LowerRoman,DefaultDelim)
+ []
+,OrderedList (1,LowerRoman,DefaultDelim)
+ []
+,Header 2 ("nested",[],[]) [Str "Nested"]
+,BulletList
+ [[Plain [Str "Tab"]
+ ,BulletList
+ [[Plain [Str "Tab"]
+ ,BulletList
+ [[Plain [Str "Tab"]]]]]]]
+,Para [Str "Here's",Space,Str "another:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second:"]
+ ,BulletList
+ [[Plain [Str "Fee"]]
+ ,[Plain [Str "Fie"]]
+ ,[Plain [Str "Foe"]]]]
+ ,[Plain [Str "Third"]]]
+,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second:"]
+ ,BulletList
+ [[Plain [Str "Fee"]]
+ ,[Plain [Str "Fie"]]
+ ,[Plain [Str "Foe"]]]]
+ ,[Para [Str "Third"]]]
+,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
+ ,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
+,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
+,OrderedList (2,Decimal,DefaultDelim)
+ [[Plain [Str "begins",Space,Str "with",Space,Str "2"]]
+ ,[Para [Str "and",Space,Str "now",Space,Str "3"]
+ ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ ,OrderedList (4,LowerRoman,DefaultDelim)
+ [[Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"]]
+ ,[Plain [Str "more",Space,Str "items"]
+ ,OrderedList (1,UpperAlpha,DefaultDelim)
+ [[Plain [Str "a",Space,Str "subsublist"]]
+ ,[Plain [Str "a",Space,Str "subsublist"]]]]]]]
+,Para [Str "Nesting:"]
+,OrderedList (1,UpperAlpha,DefaultDelim)
+ [[Plain [Str "Upper",Space,Str "Alpha"]
+ ,OrderedList (1,UpperRoman,DefaultDelim)
+ [[Plain [Str "Upper",Space,Str "Roman."]
+ ,OrderedList (6,Decimal,DefaultDelim)
+ [[Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ ,OrderedList (3,LowerAlpha,DefaultDelim)
+ [[Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
+,Para [Str "Autonumbering:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Autonumber."]]
+ ,[Plain [Str "More."]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Nested."]]]]]
+,HorizontalRule
+,Header 2 ("definition",[],[]) [Str "Definition"]
+,DefinitionList
+ [([Str "Violin"],
+ [[Plain [Str "Stringed",Space,Str "musical",Space,Str "instrument."]]
+ ,[Plain [Str "Torture",Space,Str "device."]]])
+ ,([Str "Cello",LineBreak,Str "Violoncello"],
+ [[Plain [Str "Low-voiced",Space,Str "stringed",Space,Str "instrument."]]])]
+,HorizontalRule
+,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
+,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
+,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
+,Para [Str "Empty",Space,Strong [],Space,Str "and",Space,Emph [],Str "."]
+,Para [Str "An",Space,Emph [Link ("",[],[]) [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
+,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "small",Space,Str "caps"],Str "."]
+,Para [Str "These",Space,Str "are",Space,Str "all",Space,Str "underlined:",Space,Span ("",["underline"],[]) [Str "foo"],Space,Str "and",Space,Span ("",["underline"],[]) [Str "bar"],Str "."]
+,Para [Str "These",Space,Str "are",Space,Str "all",Space,Str "strikethrough:",Space,Strikeout [Str "foo"],Str ",",Space,Strikeout [Str "bar"],Str ",",Space,Str "and",Space,Strikeout [Str "baz"],Str "."]
+,HorizontalRule
+,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+,Para [Str "\"Hello,\"",Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Str "\"'Shelob'",Space,Str "is",Space,Str "my",Space,Str "name.\""]
+,Para [Str "'A',",Space,Str "'B',",Space,Str "and",Space,Str "'C'",Space,Str "are",Space,Str "letters."]
+,Para [Str "'Oak,'",Space,Str "'elm,'",Space,Str "and",Space,Str "'beech'",Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Str "'pine.'"]
+,Para [Str "'He",Space,Str "said,",Space,Str "\"I",Space,Str "want",Space,Str "to",Space,Str "go.\"'",Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70's?"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Str "'",Code ("",[],[]) "code",Str "'",Space,Str "and",Space,Str "a",Space,Str "\"",Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2",""),Str "\"."]
+,Para [Str "Some",Space,Str "dashes:",Space,Str "one---two",Space,Str "---",Space,Str "three--four",Space,Str "--",Space,Str "five."]
+,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5-7,",Space,Str "255-66,",Space,Str "1987-1999."]
+,Para [Str "Ellipses...and.",Space,Str ".",Space,Str ".and",Space,Str ".",Space,Str ".",Space,Str ".",Space,Str "."]
+,HorizontalRule
+,Header 1 ("latex",[],[]) [Str "LaTeX"]
+,BulletList
+ [[Plain [Str "\\cite[22-23]{smith.1899}"]]
+ ,[Plain [Str "\\doublespacing"]]
+ ,[Plain [Str "$2+2=4$"]]
+ ,[Plain [Str "$x",Space,Str "\\in",Space,Str "y$"]]
+ ,[Plain [Str "$\\alpha",Space,Str "\\wedge",Space,Str "\\omega$"]]
+ ,[Plain [Str "$223$"]]
+ ,[Plain [Str "$p$-Tree"]]
+ ,[Plain [Str "$\\frac{d}{dx}f(x)=\\lim_{h\\to",Space,Str "0}\\frac{f(x+h)-f(x)}{h}$"]]
+ ,[Plain [Str "Here's",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Str "$\\alpha",Space,Str "+",Space,Str "\\omega",Space,Str "\\times",Space,Str "x^2$."]]]
+,Para [Str "These",Space,Str "shouldn't",Space,Str "be",Space,Str "math:"]
+,BulletList
+ [[Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code ("",[],[]) "$e = mc^2$",Str "."]]
+ ,[Plain [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",Space,Str "(It",Space,Str "worked",Space,Str "if",Space,Str "\"lot\"",Space,Str "is",Space,Str "emphasized.)"]]
+ ,[Plain [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]]
+,Para [Str "Here's",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+,Para [Str "\\begin{tabular}{|l|l|}\\hline",Space,Str "Animal",Space,Str "&",Space,Str "Number",Space,Str "\\\\",Space,Str "\\hline",Space,Str "Dog",Space,Str "&",Space,Str "2",Space,Str "\\\\",Space,Str "Cat",Space,Str "&",Space,Str "1",Space,Str "\\\\",Space,Str "\\hline",Space,Str "\\end{tabular}"]
+,HorizontalRule
+,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+,BulletList
+ [[Plain [Str "I",Space,Str "hat:",Space,Str "\206"]]
+ ,[Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
+ ,[Plain [Str "section:",Space,Str "\167"]]
+ ,[Plain [Str "set",Space,Str "membership:",Space,Str "\8712"]]
+ ,[Plain [Str "copyright:",Space,Str "\169"]]]
+,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
+,Para [Str "This",Space,Str "&",Space,Str "that."]
+,Para [Str "4",Space,Str "<",Space,Str "5."]
+,Para [Str "6",Space,Str ">",Space,Str "5."]
+,Para [Str "Backslash:",Space,Str "\\"]
+,Para [Str "Backtick:",Space,Str "`"]
+,Para [Str "Asterisk:",Space,Str "*"]
+,Para [Str "Underscore:",Space,Str "_"]
+,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+,Para [Str "Left",Space,Str "paren:",Space,Str "("]
+,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+,Para [Str "Greater-than:",Space,Str ">"]
+,Para [Str "Hash:",Space,Str "#"]
+,Para [Str "Period:",Space,Str "."]
+,Para [Str "Bang:",Space,Str "!"]
+,Para [Str "Plus:",Space,Str "+"]
+,Para [Str "Minus:",Space,Str "-"]
+,HorizontalRule
+,Header 1 ("links",[],[]) [Str "Links"]
+,Header 2 ("explicit",[],[]) [Str "Explicit"]
+,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
+,Para [Str "Email",Space,Str "link",Space,Str "(nobody",Space,Str "[at]",Space,Str "nowhere.net)"]
+,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
+,Header 2 ("reference",[],[]) [Str "Reference"]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
+,Para [Str "This",Space,Str "should",Space,Str "[not]",Space,Str "be",Space,Str "a",Space,Str "link."]
+,CodeBlock ("",[],[]) "[not]: /url"
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
+,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
+,Para [Str "Here's",Space,Str "a",Space,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+,Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link ("",[],[]) [Str "AT&T"] ("http://att.com/","AT&T"),Str "."]
+,Para [Str "Here's",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+,Para [Str "Here's",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
+,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
+,BulletList
+ [[Plain [Str "In",Space,Str "a",Space,Str "list?"]]
+ ,[Plain [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+ ,[Plain [Str "It",Space,Str "should."]]]
+,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Str "nobody",Space,Str "[at]",Space,Str "nowhere.net"]
+,BlockQuote
+ [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
+,CodeBlock ("",[],[]) "or here: <http://example.com/>"
+,HorizontalRule
+,Header 1 ("images",[],[]) [Str "Images"]
+,Para [Str "From",Space,Str "\"Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune\"",Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+,Para [Image ("",[],[]) [Str "lalune"] ("lalune.jpg","Voyage dans la Lune")]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
+,HorizontalRule
+,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference",Link ("",[],[]) [Str "(1)"] ("#note_1",""),Str ",",Space,Str "and",Space,Str "another",Link ("",[],[]) [Str "(longnote)"] ("#note_longnote",""),Str ".",Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space^(my",Space,Str "note)."]
+,Para [Link ("",[],[]) [Str "(1)"] ("#ref_1",""),Space,Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "in",Space,Str "the",Space,Str "document,",Space,Str "not",Space,Str "just",Space,Str "at",Space,Str "the",Space,Str "end."]
+,Para [Link ("",[],[]) [Str "(longnote)"] ("#ref_longnote",""),Space,Str "Here's",Space,Str "the",Space,Str "other",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."]
+,Para [Str "Caret",Space,Str "characters",Space,Str "are",Space,Str "used",Space,Str "to",Space,Str "indicate",Space,Str "that",Space,Str "the",Space,Str "blocks",Space,Str "all",Space,Str "belong",Space,Str "to",Space,Str "a",Space,Str "single",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "block",Space,Str "quotes)."]
+,CodeBlock ("",[],[]) " { <code> }"
+,Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "use",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "every",Space,Str "line,",Space,Str "as",Space,Str "with",Space,Str "blockquotes,",Space,Str "but",Space,Str "all",Space,Str "that",Space,Str "you",Space,Str "need",Space,Str "is",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "the",Space,Str "block",Space,Str "and",Space,Str "any",Space,Str "preceding",Space,Str "blank",Space,Str "lines."]
+,Para [Str "text",Space,Emph [Str "Leading",Space,Str "space"]]
+,Para [Emph [Str "Trailing",Space,Str "space"],Space,Str "text"]
+,Para [Str "text",Space,Emph [Str "Leading",Space,Str "spaces"]]
+,Para [Emph [Str "Trailing",Space,Str "spaces"],Space,Str "text"]
+,Header 1 ("tables",[],[]) [Str "Tables"]
+,Header 2 ("tables-with-headers",[],[]) [Str "Tables",Space,Str "with",Space,Str "Headers"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.3333333333333333,0.3333333333333333,0.3333333333333333]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,Header 2 ("tables-without-headers",[],[]) [Str "Tables",Space,Str "without",Space,Str "Headers"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,Header 2 ("empty-tables",[],[]) [Str "Empty",Space,Str "Tables"]
+,Para [Str "This",Space,Str "section",Space,Str "should",Space,Str "be",Space,Str "empty."]]
diff --git a/tests/insert b/test/insert
index f06069ede..f06069ede 100644
--- a/tests/insert
+++ b/test/insert
diff --git a/test/jats-reader.native b/test/jats-reader.native
new file mode 100644
index 000000000..a7c349149
--- /dev/null
+++ b/test/jats-reader.native
@@ -0,0 +1,422 @@
+Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"]]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
+[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",SoftBreak,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+,Header 1 ("headers",[],[]) [Str "Headers"]
+,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",SoftBreak,Link ("",[],[]) [Str "embedded",SoftBreak,Str "link"] ("/url","")]
+,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
+,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
+,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
+,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
+,Para [Str "Here's",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",SoftBreak,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",SoftBreak,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
+,Para [Str "Here's",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
+,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
+,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
+,Para [Str "E-mail",Space,Str "style:"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
+,BlockQuote
+ [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ ,Para [Str "A",Space,Str "list:"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "item",Space,Str "one"]]
+ ,[Para [Str "item",Space,Str "two"]]]
+ ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ ,BlockQuote
+ [Para [Str "nested"]]
+ ,BlockQuote
+ [Para [Str "nested"]]]
+,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1."]
+,Para [Str "Box-style:"]
+,BlockQuote
+ [Para [Str "Example:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"]
+,BlockQuote
+ [OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "do",Space,Str "laundry"]]
+ ,[Para [Str "take",Space,Str "out",Space,Str "the",Space,Str "trash"]]]]
+,Para [Str "Here's",Space,Str "a",Space,Str "nested",Space,Str "one:"]
+,BlockQuote
+ [Para [Str "Joe",Space,Str "said:"]
+ ,BlockQuote
+ [Para [Str "Don't",Space,Str "quote",Space,Str "me."]]]
+,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
+,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+,Para [Str "And:"]
+,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+,Header 1 ("lists",[],[]) [Str "Lists"]
+,Header 2 ("unordered",[],[]) [Str "Unordered"]
+,Para [Str "Asterisks",Space,Str "tight:"]
+,BulletList
+ [[Para [Str "asterisk",Space,Str "1"]]
+ ,[Para [Str "asterisk",Space,Str "2"]]
+ ,[Para [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Asterisks",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "asterisk",Space,Str "1"]]
+ ,[Para [Str "asterisk",Space,Str "2"]]
+ ,[Para [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "tight:"]
+,BulletList
+ [[Para [Str "Plus",Space,Str "1"]]
+ ,[Para [Str "Plus",Space,Str "2"]]
+ ,[Para [Str "Plus",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Plus",Space,Str "1"]]
+ ,[Para [Str "Plus",Space,Str "2"]]
+ ,[Para [Str "Plus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "tight:"]
+,BulletList
+ [[Para [Str "Minus",Space,Str "1"]]
+ ,[Para [Str "Minus",Space,Str "2"]]
+ ,[Para [Str "Minus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Minus",Space,Str "1"]]
+ ,[Para [Str "Minus",Space,Str "2"]]
+ ,[Para [Str "Minus",Space,Str "3"]]]
+,Header 2 ("ordered",[],[]) [Str "Ordered"]
+,Para [Str "Tight:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second"]]
+ ,[Para [Str "Third"]]]
+,Para [Str "and:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "One"]]
+ ,[Para [Str "Two"]]
+ ,[Para [Str "Three"]]]
+,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second"]]
+ ,[Para [Str "Third"]]]
+,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "One"]]
+ ,[Para [Str "Two"]]
+ ,[Para [Str "Three"]]]
+,Para [Str "Multiple",Space,Str "paragraphs:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",SoftBreak,Str "dog's",Space,Str "back."]]
+ ,[Para [Str "Item",Space,Str "2."]]
+ ,[Para [Str "Item",Space,Str "3."]]]
+,Para [Str "List",Space,Str "styles:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ []
+,OrderedList (1,LowerRoman,DefaultDelim)
+ []
+,Header 2 ("nested",[],[]) [Str "Nested"]
+,BulletList
+ [[Para [Str "Tab"]
+ ,BulletList
+ [[Para [Str "Tab"]
+ ,BulletList
+ [[Para [Str "Tab"]]]]]]]
+,Para [Str "Here's",Space,Str "another:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second:"]
+ ,BulletList
+ [[Para [Str "Fee"]]
+ ,[Para [Str "Fie"]]
+ ,[Para [Str "Foe"]]]]
+ ,[Para [Str "Third"]]]
+,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second:"]
+ ,BulletList
+ [[Para [Str "Fee"]]
+ ,[Para [Str "Fie"]]
+ ,[Para [Str "Foe"]]]]
+ ,[Para [Str "Third"]]]
+,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
+ ,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
+,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
+,Para [Str "Autonumbering:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "Autonumber."]]
+ ,[Para [Str "More."]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "Nested."]]]]]
+,Header 2 ("definition",[],[]) [Str "Definition"]
+,DefinitionList
+ [([Str "Violin"],
+ [[Para [Str "Stringed",Space,Str "musical",Space,Str "instrument."]
+ ,Para [Str "Torture",Space,Str "device."]]])
+ ,([Str "Cello",LineBreak,Str "Violoncello"],
+ [[Para [Str "Low-voiced",Space,Str "stringed",Space,Str "instrument."]]])]
+,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
+,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",SoftBreak,Str "this"],Str "."]
+,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",SoftBreak,Strong [Str "is",Space,Str "this"],Str "."]
+,Para [Str "Empty",Space,Strong [],Space,Str "and",Space,Emph [],Str "."]
+,Para [Str "An",SoftBreak,Emph [Link ("",[],[]) [Str "emphasized",SoftBreak,Str "link"] ("/url","")],Str "."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",SoftBreak,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",SoftBreak,Code ("",[],[]) "<html>",Str "."]
+,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "small",Space,Str "caps"],Str "."]
+,Para [Str "These",Space,Str "are",Space,Str "all",Space,Str "underlined:",Space,Str "foo",Space,Str "and",Space,Str "bar."]
+,Para [Str "These",Space,Str "are",Space,Str "all",Space,Str "strikethrough:",Space,Strikeout [Str "foo"],Str ",",SoftBreak,Strikeout [Str "bar"],Str ",",Space,Str "and",Space,Strikeout [Str "baz"],Str "."]
+,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+,Para [Str "\"Hello,\"",Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Str "\"'Shelob'",Space,Str "is",Space,Str "my",Space,Str "name.\""]
+,Para [Str "'A',",Space,Str "'B',",Space,Str "and",Space,Str "'C'",Space,Str "are",Space,Str "letters."]
+,Para [Str "'Oak,'",Space,Str "'elm,'",Space,Str "and",Space,Str "'beech'",Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Str "'pine.'"]
+,Para [Str "'He",Space,Str "said,",Space,Str "\"I",Space,Str "want",Space,Str "to",Space,Str "go.\"'",Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70's?"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Str "'",Code ("",[],[]) "code",Str "'",Space,Str "and",Space,Str "a",SoftBreak,Str "\"",Link ("",[],[]) [Str "quoted",SoftBreak,Str "link"] ("http://example.com/?foo=1&bar=2",""),Str "\"."]
+,Para [Str "Some",Space,Str "dashes:",Space,Str "one---two",Space,Str "---",Space,Str "three--four",Space,Str "--",Space,Str "five."]
+,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5-7,",Space,Str "255-66,",Space,Str "1987-1999."]
+,Para [Str "Ellipses...and.",Space,Str ".",Space,Str ".and",Space,Str ".",Space,Str ".",Space,Str ".",Space,Str "."]
+,Header 1 ("latex",[],[]) [Str "LaTeX"]
+,BulletList
+ [[Para [Str "\\cite[22-23]{smith.1899}"]]
+ ,[Para [Str "\\doublespacing"]]
+ ,[Para [Str "$2+2=4$"]]
+ ,[Para [Str "$x",Space,Str "\\in",Space,Str "y$"]]
+ ,[Para [Str "$\\alpha",Space,Str "\\wedge",Space,Str "\\omega$"]]
+ ,[Para [Str "$223$"]]
+ ,[Para [Str "$p$-Tree"]]
+ ,[Para [Str "$\\frac{d}{dx}f(x)=\\lim_{h\\to",Space,Str "0}\\frac{f(x+h)-f(x)}{h}$"]]
+ ,[Para [Str "Here's",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Str "$\\alpha",Space,Str "+",Space,Str "\\omega",Space,Str "\\times",SoftBreak,Str "x^2$."]]]
+,Para [Str "These",Space,Str "shouldn't",Space,Str "be",Space,Str "math:"]
+,BulletList
+ [[Para [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",SoftBreak,Code ("",[],[]) "$e = mc^2$",Str "."]]
+ ,[Para [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",Space,Str "(It",SoftBreak,Str "worked",Space,Str "if",Space,Str "\"lot\"",Space,Str "is",Space,Str "emphasized.)"]]
+ ,[Para [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",SoftBreak,Str "emphasized"],Space,Str "23$."]]]
+,Para [Str "Here's",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+,Para [Str "\\begin{tabular}{|l|l|}\\hline",Space,Str "Animal",Space,Str "&",Space,Str "Number",Space,Str "\\\\",Space,Str "\\hline",Space,Str "Dog",Space,Str "&",SoftBreak,Str "2",Space,Str "\\\\",Space,Str "Cat",Space,Str "&",Space,Str "1",Space,Str "\\\\",Space,Str "\\hline",Space,Str "\\end{tabular}"]
+,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+,BulletList
+ [[Para [Str "I",Space,Str "hat:",Space,Str "\206"]]
+ ,[Para [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
+ ,[Para [Str "section:",Space,Str "\167"]]
+ ,[Para [Str "set",Space,Str "membership:",Space,Str "elem"]]
+ ,[Para [Str "copyright:",Space,Str "\169"]]]
+,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
+,Para [Str "This",Space,Str "&",Space,Str "that."]
+,Para [Str "4",Space,Str "<",Space,Str "5."]
+,Para [Str "6",Space,Str ">",Space,Str "5."]
+,Para [Str "Backslash:",Space,Str "\\"]
+,Para [Str "Backtick:",Space,Str "`"]
+,Para [Str "Asterisk:",Space,Str "*"]
+,Para [Str "Underscore:",Space,Str "_"]
+,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+,Para [Str "Left",Space,Str "paren:",Space,Str "("]
+,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+,Para [Str "Greater-than:",Space,Str ">"]
+,Para [Str "Hash:",Space,Str "#"]
+,Para [Str "Period:",Space,Str "."]
+,Para [Str "Bang:",Space,Str "!"]
+,Para [Str "Plus:",Space,Str "+"]
+,Para [Str "Minus:",Space,Str "-"]
+,Header 1 ("links",[],[]) [Str "Links"]
+,Header 2 ("explicit",[],[]) [Str "Explicit"]
+,Para [Str "Just",Space,Str "a",SoftBreak,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "URL",SoftBreak,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",SoftBreak,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",SoftBreak,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",SoftBreak,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
+,Para [Link ("",[],[]) [Str "URL",SoftBreak,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
+,Para [Str "Email",Space,Str "link",Space,Str "(nobody",Space,Str "[at]",Space,Str "nowhere.net)"]
+,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
+,Header 2 ("reference",[],[]) [Str "Reference"]
+,Para [Str "Foo",SoftBreak,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "Foo",SoftBreak,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "Foo",SoftBreak,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",SoftBreak,Str "[brackets]"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",SoftBreak,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
+,Para [Str "Indented",SoftBreak,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
+,Para [Str "Indented",SoftBreak,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
+,Para [Str "Indented",SoftBreak,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
+,Para [Str "This",Space,Str "should",Space,Str "[not]",Space,Str "be",Space,Str "a",Space,Str "link."]
+,CodeBlock ("",[],[]) "[not]: /url"
+,Para [Str "Foo",SoftBreak,Link ("",[],[]) [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
+,Para [Str "Foo",SoftBreak,Link ("",[],[]) [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
+,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
+,Para [Str "Here's",Space,Str "a",SoftBreak,Link ("",[],[]) [Str "link",SoftBreak,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+,Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",SoftBreak,Link ("",[],[]) [Str "AT&T"] ("http://att.com/","AT&T"),Str "."]
+,Para [Str "Here's",Space,Str "an",SoftBreak,Link ("",[],[]) [Str "inline",SoftBreak,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+,Para [Str "Here's",Space,Str "an",SoftBreak,Link ("",[],[]) [Str "inline",SoftBreak,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
+,Para [Str "With",Space,Str "an",Space,Str "ampersand:",SoftBreak,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
+,BulletList
+ [[Para [Str "In",Space,Str "a",Space,Str "list?"]]
+ ,[Para [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+ ,[Para [Str "It",Space,Str "should."]]]
+,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Str "nobody",Space,Str "[at]",Space,Str "nowhere.net"]
+,BlockQuote
+ [Para [Str "Blockquoted:",SoftBreak,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",SoftBreak,Code ("",[],[]) "<http://example.com/>"]
+,CodeBlock ("",[],[]) "or here: <http://example.com/>"
+,Header 1 ("images",[],[]) [Str "Images"]
+,Para [Str "From",Space,Str "\"Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune\"",Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+,Para [Image ("",[],[]) [] ("lalune.jpg","Voyage dans la Lune")]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",SoftBreak,Image ("",[],[]) [] ("movie.jpg",""),SoftBreak,Str "icon."]
+,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference",Link ("",[],[]) [Str "(1)"] ("#note_1",""),Str ",",SoftBreak,Str "and",SoftBreak,Str "another",Link ("",[],[]) [Str "(longnote)"] ("#note_longnote",""),Str ".",SoftBreak,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",SoftBreak,Str "contains",Space,Str "a",Space,Str "space^(my",Space,Str "note)."]
+,Para [Link ("",[],[]) [Str "(1)"] ("#ref_1",""),Space,Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",SoftBreak,Str "go",Space,Str "anywhere",Space,Str "in",Space,Str "the",Space,Str "document,",Space,Str "not",Space,Str "just",Space,Str "at",Space,Str "the",Space,Str "end."]
+,Para [Link ("",[],[]) [Str "(longnote)"] ("#ref_longnote",""),Space,Str "Here's",SoftBreak,Str "the",Space,Str "other",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."]
+,Para [Str "Caret",Space,Str "characters",Space,Str "are",Space,Str "used",Space,Str "to",Space,Str "indicate",Space,Str "that",Space,Str "the",Space,Str "blocks",Space,Str "all",Space,Str "belong",Space,Str "to",SoftBreak,Str "a",Space,Str "single",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "block",Space,Str "quotes)."]
+,CodeBlock ("",[],[]) " { <code> }"
+,Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "use",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "every",Space,Str "line,",Space,Str "as",SoftBreak,Str "with",Space,Str "blockquotes,",Space,Str "but",Space,Str "all",Space,Str "that",Space,Str "you",Space,Str "need",Space,Str "is",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",SoftBreak,Str "of",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "the",Space,Str "block",Space,Str "and",Space,Str "any",Space,Str "preceding",Space,Str "blank",Space,Str "lines."]
+,Para [Str "text",Space,Emph [Str "Leading",Space,Str "space"]]
+,Para [Emph [Str "Trailing",Space,Str "space"],Space,Str "text"]
+,Para [Str "text",Space,Emph [Str "Leading",Space,Str "spaces"]]
+,Para [Emph [Str "Trailing",Space,Str "spaces"],Space,Str "text"]
+,Header 1 ("tables",[],[]) [Str "Tables"]
+,Header 2 ("tables-with-headers",[],[]) [Str "Tables",Space,Str "with",Space,Str "Headers"]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[Para [Str "X"]]
+ ,[Para [Str "Y"]]
+ ,[Para [Str "Z"]]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Header 2 ("tables-without-headers",[],[]) [Str "Tables",Space,Str "without",Space,Str "Headers"]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Table [] [AlignLeft,AlignLeft,AlignLeft] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Para [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Para [Str "3"]]]
+ ,[[Para [Str "4"]]
+ ,[Para [Str "5"]]
+ ,[Para [Str "6"]]]]
+,Header 2 ("empty-tables",[],[]) [Str "Empty",Space,Str "Tables"]
+,Para [Str "This",Space,Str "section",Space,Str "should",Space,Str "be",Space,Str "empty."]]
diff --git a/test/jats-reader.xml b/test/jats-reader.xml
new file mode 100644
index 000000000..f98caa46e
--- /dev/null
+++ b/test/jats-reader.xml
@@ -0,0 +1,1785 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD v1.0 20120330//EN"
+ "JATS-journalpublishing1.dtd">
+<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.0" article-type="other">
+<front>
+<journal-meta>
+<journal-title-group>
+</journal-title-group>
+<publisher>
+<publisher-name></publisher-name>
+</publisher>
+</journal-meta>
+<article-meta>
+<title-group>
+<article-title>Pandoc Test Suite</article-title>
+</title-group>
+<contrib-group>
+ <contrib contrib-type="author">
+ <name>
+ <surname>MacFarlane</surname>
+ <given-names>John</given-names>
+ </name>
+ <contrib contrib-type="author">
+ <name>
+ <surname>Anonymous</surname>
+ </name>
+ </contrib>
+</contrib-group>
+</article-meta>
+</front>
+<body>
+<p>
+ This is a set of tests for pandoc. Most of them are adapted from John
+ Gruber's markdown test suite.
+</p>
+<sec id="headers">
+ <title>Headers</title>
+ <sec id="level-2-with-an-embedded-link">
+ <title>Level 2 with an
+ <ext-link ext-link-type="uri" xlink:href="/url">embedded
+ link</ext-link></title>
+ <sec id="level-3-with-emphasis">
+ <title>Level 3 with <italic>emphasis</italic></title>
+ <sec id="level-4">
+ <title>Level 4</title>
+ <sec id="level-5">
+ <title>Level 5</title>
+ </sec>
+ </sec>
+ </sec>
+ </sec>
+</sec>
+<sec id="level-1">
+ <title>Level 1</title>
+ <sec id="level-2-with-emphasis">
+ <title>Level 2 with <italic>emphasis</italic></title>
+ <sec id="level-3">
+ <title>Level 3</title>
+ <p>
+ with no blank line
+ </p>
+ </sec>
+ </sec>
+ <sec id="level-2">
+ <title>Level 2</title>
+ <p>
+ with no blank line
+ </p>
+ </sec>
+</sec>
+<sec id="paragraphs">
+ <title>Paragraphs</title>
+ <p>
+ Here's a regular paragraph.
+ </p>
+ <p>
+ In Markdown 1.0.0 and earlier. Version 8. This line turns into a
+ list item. Because a hard-wrapped line in the middle of a paragraph
+ looked like a list item.
+ </p>
+ <p>
+ Here's one with a bullet. * criminey.
+ </p>
+ <p>
+ There should be a hard line break<break />here.
+ </p>
+</sec>
+<sec id="block-quotes">
+ <title>Block Quotes</title>
+ <p>
+ E-mail style:
+ </p>
+ <disp-quote>
+ <p>
+ This is a block quote. It is pretty short.
+ </p>
+ </disp-quote>
+ <disp-quote>
+ <p>
+ Code in a block quote:
+ </p>
+ <preformat>sub status {
+ print &quot;working&quot;;
+}</preformat>
+ <p>
+ A list:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ item one
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ item two
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Nested block quotes:
+ </p>
+ <disp-quote>
+ <p>
+ nested
+ </p>
+ </disp-quote>
+ <disp-quote>
+ <p>
+ nested
+ </p>
+ </disp-quote>
+ </disp-quote>
+ <p>
+ This should not be a block quote: 2 &gt; 1.
+ </p>
+ <p>
+ Box-style:
+ </p>
+ <disp-quote>
+ <p>
+ Example:
+ </p>
+ <preformat>sub status {
+ print &quot;working&quot;;
+}</preformat>
+ </disp-quote>
+ <disp-quote>
+ <list list-type="order">
+ <list-item>
+ <p>
+ do laundry
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ take out the trash
+ </p>
+ </list-item>
+ </list>
+ </disp-quote>
+ <p>
+ Here's a nested one:
+ </p>
+ <disp-quote>
+ <p>
+ Joe said:
+ </p>
+ <disp-quote>
+ <p>
+ Don't quote me.
+ </p>
+ </disp-quote>
+ </disp-quote>
+ <p>
+ And a following paragraph.
+ </p>
+</sec>
+<sec id="code-blocks">
+ <title>Code Blocks</title>
+ <p>
+ Code:
+ </p>
+ <preformat>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</preformat>
+ <p>
+ And:
+ </p>
+ <preformat> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
+</sec>
+<sec id="lists">
+ <title>Lists</title>
+ <sec id="unordered">
+ <title>Unordered</title>
+ <p>
+ Asterisks tight:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ asterisk 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ asterisk 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ asterisk 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Asterisks loose:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ asterisk 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ asterisk 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ asterisk 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Pluses tight:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Plus 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Plus 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Plus 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Pluses loose:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Plus 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Plus 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Plus 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Minuses tight:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Minus 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Minus 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Minus 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Minuses loose:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Minus 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Minus 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Minus 3
+ </p>
+ </list-item>
+ </list>
+ </sec>
+ <sec id="ordered">
+ <title>Ordered</title>
+ <p>
+ Tight:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ First
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Second
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Third
+ </p>
+ </list-item>
+ </list>
+ <p>
+ and:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ One
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Two
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Three
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Loose using tabs:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ First
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Second
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Third
+ </p>
+ </list-item>
+ </list>
+ <p>
+ and using spaces:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ One
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Two
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Three
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Multiple paragraphs:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ Item 1, graf one.
+ </p>
+ <p>
+ Item 1. graf two. The quick brown fox jumped over the lazy
+ dog's back.
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Item 2.
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Item 3.
+ </p>
+ </list-item>
+ </list>
+ <p>
+ List styles:
+ </p>
+ <list list-type="order"></list>
+ <list list-type="roman-lower"></list>
+ </sec>
+ <sec id="nested">
+ <title>Nested</title>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Tab
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Tab
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Tab
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ <p>
+ Here's another:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ First
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Second:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Fee
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Fie
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Foe
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ <list-item>
+ <p>
+ Third
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Same thing but with paragraphs:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ First
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Second:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Fee
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Fie
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Foe
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ <list-item>
+ <p>
+ Third
+ </p>
+ </list-item>
+ </list>
+ </sec>
+ <sec id="tabs-and-spaces">
+ <title>Tabs and spaces</title>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ this is a list item indented with tabs
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ this is a list item indented with spaces
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ this is an example list item indented with tabs
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ this is an example list item indented with spaces
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ </sec>
+ <sec id="fancy-list-markers">
+ <title>Fancy list markers</title>
+ <p>
+ Autonumbering:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ Autonumber.
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ More.
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ Nested.
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ </sec>
+ <sec id="definition">
+ <title>Definition</title>
+ <def-list>
+ <def-item>
+ <term>
+ Violin
+ </term>
+ <def>
+ <p>
+ Stringed musical instrument.
+ </p>
+ <p>
+ Torture device.
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ Cello<break />Violoncello
+ </term>
+ <def>
+ <p>
+ Low-voiced stringed instrument.
+ </p>
+ </def>
+ </def-item>
+ </def-list>
+ </sec>
+</sec>
+<sec id="inline-markup">
+ <title>Inline Markup</title>
+ <p>
+ This is <italic>emphasized</italic>, and so <italic>is
+ this</italic>.
+ </p>
+ <p>
+ This is <bold role="strong">strong</bold>, and so
+ <bold role="strong">is this</bold>.
+ </p>
+ <p>
+ Empty <bold role="strong"></bold> and <italic></italic>.
+ </p>
+ <p>
+ An
+ <italic><ext-link ext-link-type="uri" xlink:href="/url">emphasized
+ link</ext-link></italic>.
+ </p>
+ <p>
+ <bold role="strong"><italic>This is strong and em.</italic></bold>
+ </p>
+ <p>
+ So is <bold role="strong"><italic>this</italic></bold> word.
+ </p>
+ <p>
+ <bold role="strong"><italic>This is strong and em.</italic></bold>
+ </p>
+ <p>
+ So is <bold role="strong"><italic>this</italic></bold> word.
+ </p>
+ <p>
+ This is code: <monospace>&gt;</monospace>, <monospace>$</monospace>,
+ <monospace>\</monospace>, <monospace>\$</monospace>,
+ <monospace>&lt;html&gt;</monospace>.
+ </p>
+ <p>
+ This is <sc role="smallcaps">small caps</sc>.
+ </p>
+ <p>
+ These are all underlined: foo and bar.
+ </p>
+ <p>
+ These are all strikethrough: <strike>foo</strike>,
+ <strike>bar</strike>, and <strike>baz</strike>.
+ </p>
+</sec>
+<sec id="smart-quotes-ellipses-dashes">
+ <title>Smart quotes, ellipses, dashes</title>
+ <p>
+ &quot;Hello,&quot; said the spider. &quot;'Shelob' is my name.&quot;
+ </p>
+ <p>
+ 'A', 'B', and 'C' are letters.
+ </p>
+ <p>
+ 'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
+ </p>
+ <p>
+ 'He said, &quot;I want to go.&quot;' Were you alive in the 70's?
+ </p>
+ <p>
+ Here is some quoted '<monospace>code</monospace>' and a
+ &quot;<ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&amp;bar=2">quoted
+ link</ext-link>&quot;.
+ </p>
+ <p>
+ Some dashes: one---two --- three--four -- five.
+ </p>
+ <p>
+ Dashes between numbers: 5-7, 255-66, 1987-1999.
+ </p>
+ <p>
+ Ellipses...and. . .and . . . .
+ </p>
+</sec>
+<sec id="latex">
+ <title>LaTeX</title>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ \cite[22-23]{smith.1899}
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ \doublespacing
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ $2+2=4$
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ $x \in y$
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ $\alpha \wedge \omega$
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ $223$
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ $p$-Tree
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ $\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Here's one that has a line break in it: $\alpha + \omega \times
+ x^2$.
+ </p>
+ </list-item>
+ </list>
+ <p>
+ These shouldn't be math:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ To get the famous equation, write
+ <monospace>$e = mc^2$</monospace>.
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ $22,000 is a <italic>lot</italic> of money. So is $34,000. (It
+ worked if &quot;lot&quot; is emphasized.)
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Escaped <monospace>$</monospace>: $73 <italic>this should be
+ emphasized</italic> 23$.
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Here's a LaTeX table:
+ </p>
+ <p>
+ \begin{tabular}{|l|l|}\hline Animal &amp; Number \\ \hline Dog &amp;
+ 2 \\ Cat &amp; 1 \\ \hline \end{tabular}
+ </p>
+</sec>
+<sec id="special-characters">
+ <title>Special Characters</title>
+ <p>
+ Here is some unicode:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ I hat: Î
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ o umlaut: ö
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ section: §
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ set membership: elem
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ copyright: ©
+ </p>
+ </list-item>
+ </list>
+ <p>
+ AT&amp;T has an ampersand in their name.
+ </p>
+ <p>
+ AT&amp;T is another way to write it.
+ </p>
+ <p>
+ This &amp; that.
+ </p>
+ <p>
+ 4 &lt; 5.
+ </p>
+ <p>
+ 6 &gt; 5.
+ </p>
+ <p>
+ Backslash: \
+ </p>
+ <p>
+ Backtick: `
+ </p>
+ <p>
+ Asterisk: *
+ </p>
+ <p>
+ Underscore: _
+ </p>
+ <p>
+ Left brace: {
+ </p>
+ <p>
+ Right brace: }
+ </p>
+ <p>
+ Left bracket: [
+ </p>
+ <p>
+ Right bracket: ]
+ </p>
+ <p>
+ Left paren: (
+ </p>
+ <p>
+ Right paren: )
+ </p>
+ <p>
+ Greater-than: &gt;
+ </p>
+ <p>
+ Hash: #
+ </p>
+ <p>
+ Period: .
+ </p>
+ <p>
+ Bang: !
+ </p>
+ <p>
+ Plus: +
+ </p>
+ <p>
+ Minus: -
+ </p>
+</sec>
+<sec id="links">
+ <title>Links</title>
+ <sec id="explicit">
+ <title>Explicit</title>
+ <p>
+ Just a
+ <ext-link ext-link-type="uri" xlink:href="/url/">URL</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title">URL
+ and title</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title preceded by two spaces">URL
+ and title</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title preceded by a tab">URL
+ and title</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title with &quot;quotes&quot; in it">URL
+ and title</ext-link>
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title with single quotes">URL
+ and title</ext-link>
+ </p>
+ <p>
+ Email link (nobody [at] nowhere.net)
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="">Empty</ext-link>.
+ </p>
+ </sec>
+ <sec id="reference">
+ <title>Reference</title>
+ <p>
+ Foo
+ <ext-link ext-link-type="uri" xlink:href="/url/">bar</ext-link>.
+ </p>
+ <p>
+ Foo
+ <ext-link ext-link-type="uri" xlink:href="/url/">bar</ext-link>.
+ </p>
+ <p>
+ Foo
+ <ext-link ext-link-type="uri" xlink:href="/url/">bar</ext-link>.
+ </p>
+ <p>
+ With <ext-link ext-link-type="uri" xlink:href="/url/">embedded
+ [brackets]</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/">b</ext-link> by
+ itself should be a link.
+ </p>
+ <p>
+ Indented
+ <ext-link ext-link-type="uri" xlink:href="/url">once</ext-link>.
+ </p>
+ <p>
+ Indented
+ <ext-link ext-link-type="uri" xlink:href="/url">twice</ext-link>.
+ </p>
+ <p>
+ Indented
+ <ext-link ext-link-type="uri" xlink:href="/url">thrice</ext-link>.
+ </p>
+ <p>
+ This should [not] be a link.
+ </p>
+ <preformat>[not]: /url</preformat>
+ <p>
+ Foo
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="Title with &quot;quotes&quot; inside">bar</ext-link>.
+ </p>
+ <p>
+ Foo
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="Title with &quot;quote&quot; inside">biz</ext-link>.
+ </p>
+ </sec>
+ <sec id="with-ampersands">
+ <title>With ampersands</title>
+ <p>
+ Here's a
+ <ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&amp;bar=2">link
+ with an ampersand in the URL</ext-link>.
+ </p>
+ <p>
+ Here's a link with an amersand in the link text:
+ <ext-link ext-link-type="uri" xlink:href="http://att.com/" xlink:title="AT&amp;T">AT&amp;T</ext-link>.
+ </p>
+ <p>
+ Here's an
+ <ext-link ext-link-type="uri" xlink:href="/script?foo=1&amp;bar=2">inline
+ link</ext-link>.
+ </p>
+ <p>
+ Here's an
+ <ext-link ext-link-type="uri" xlink:href="/script?foo=1&amp;bar=2">inline
+ link in pointy braces</ext-link>.
+ </p>
+ </sec>
+ <sec id="autolinks">
+ <title>Autolinks</title>
+ <p>
+ With an ampersand:
+ <ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</ext-link>
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ In a list?
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link>
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ It should.
+ </p>
+ </list-item>
+ </list>
+ <p>
+ An e-mail address: nobody [at] nowhere.net
+ </p>
+ <disp-quote>
+ <p>
+ Blockquoted:
+ <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link>
+ </p>
+ </disp-quote>
+ <p>
+ Auto-links should not occur here:
+ <monospace>&lt;http://example.com/&gt;</monospace>
+ </p>
+ <preformat>or here: &lt;http://example.com/&gt;</preformat>
+ </sec>
+</sec>
+<sec id="images">
+ <title>Images</title>
+ <p>
+ From &quot;Voyage dans la Lune&quot; by Georges Melies (1902):
+ </p>
+ <p>
+ <inline-graphic mimetype="image" mime-subtype="jpeg" xlink:href="lalune.jpg" xlink:title="Voyage dans la Lune" />
+ </p>
+ <p>
+ Here is a movie
+ <inline-graphic mimetype="image" mime-subtype="jpeg" xlink:href="movie.jpg" />
+ icon.
+ </p>
+</sec>
+<sec id="footnotes">
+ <title>Footnotes</title>
+ <p>
+ Here is a footnote reference<xref alt="(1)" rid="note_1">(1)</xref>,
+ and
+ another<xref alt="(longnote)" rid="note_longnote">(longnote)</xref>.
+ This should <italic>not</italic> be a footnote reference, because it
+ contains a space^(my note).
+ </p>
+ <p>
+ <xref alt="(1)" rid="ref_1">(1)</xref> Here is the footnote. It can
+ go anywhere in the document, not just at the end.
+ </p>
+ <p>
+ <xref alt="(longnote)" rid="ref_longnote">(longnote)</xref> Here's
+ the other note. This one contains multiple blocks.
+ </p>
+ <p>
+ Caret characters are used to indicate that the blocks all belong to
+ a single footnote (as with block quotes).
+ </p>
+ <preformat> { &lt;code&gt; }</preformat>
+ <p>
+ If you want, you can use a caret at the beginning of every line, as
+ with blockquotes, but all that you need is a caret at the beginning
+ of the first line of the block and any preceding blank lines.
+ </p>
+ <p>
+ text <italic>Leading space</italic>
+ </p>
+ <p>
+ <italic>Trailing space</italic> text
+ </p>
+ <p>
+ text <italic>Leading spaces</italic>
+ </p>
+ <p>
+ <italic>Trailing spaces</italic> text
+ </p>
+</sec>
+<sec id="tables">
+ <title>Tables</title>
+ <sec id="tables-with-headers">
+ <title>Tables with Headers</title>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col width="33*" align="left" />
+ <col width="33*" align="left" />
+ <col width="33*" align="left" />
+ <thead>
+ <tr>
+ <th>
+ <p>
+ X
+ </p>
+ </th>
+ <th>
+ <p>
+ Y
+ </p>
+ </th>
+ <th>
+ <p>
+ Z
+ </p>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </sec>
+ <sec id="tables-without-headers">
+ <title>Tables without Headers</title>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <col align="left" />
+ <col align="left" />
+ <col align="left" />
+ <tbody>
+ <tr>
+ <td>
+ <p>
+ 1
+ </p>
+ </td>
+ <td>
+ <p>
+ 2
+ </p>
+ </td>
+ <td>
+ <p>
+ 3
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ 4
+ </p>
+ </td>
+ <td>
+ <p>
+ 5
+ </p>
+ </td>
+ <td>
+ <p>
+ 6
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </sec>
+ <sec id="empty-tables">
+ <title>Empty Tables</title>
+ <p>
+ This section should be empty.
+ </p>
+ </sec>
+</sec>
+</body>
+<back>
+</back>
+</article>
diff --git a/tests/lalune.jpg b/test/lalune.jpg
index 5a50fc088..5a50fc088 100644
--- a/tests/lalune.jpg
+++ b/test/lalune.jpg
Binary files differ
diff --git a/test/latex-reader.latex b/test/latex-reader.latex
new file mode 100644
index 000000000..7cbcc9672
--- /dev/null
+++ b/test/latex-reader.latex
@@ -0,0 +1,847 @@
+\documentclass{article}
+\usepackage[mathletters]{ucs}
+\usepackage[utf8x]{inputenc}
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+
+\usepackage[breaklinks=true,unicode=true]{hyperref}
+\usepackage[normalem]{ulem}
+% avoid problems with \sout in headers with hyperref:
+\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
+\usepackage{enumerate}
+\usepackage{fancyvrb}
+\usepackage{graphicx}
+\usepackage{url}
+
+\setcounter{secnumdepth}{0}
+\VerbatimFootnotes % allows verbatim text in footnotes
+\title{Pandoc Test Suite}
+\author{John MacFarlane \and Anonymous}
+\date{July 17, 2006}
+\begin{document}
+\maketitle
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Headers}
+
+\subsection{Level 2 with an \href{/url}{embedded link}}
+
+\subsubsection{Level 3 with \emph{emphasis}}
+
+Level 4
+
+Level 5
+
+\section[alt title ignored]{Level 1}
+
+\subsection{Level 2 with \emph{emphasis}}
+
+\subsubsection{Level 3}
+
+with no blank line
+
+\subsection{Level 2}
+
+with no blank line
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Paragraphs}
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a
+list item. Because a hard-wrapped line in the middle of a paragraph
+looked like a list item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break\\here.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Block Quotes}
+
+E-mail style:
+
+\begin{quote}
+This is a block quote. It is pretty short.
+
+\end{quote}
+\begin {quote}
+Code in a block quote:
+
+\begin{verbatim}
+sub status {
+ print "working";
+}
+\end{verbatim}
+A list:
+
+\begin{enumerate}[1.]
+\item
+ item one
+\item
+ item two
+\end{enumerate}
+Nested block quotes:
+
+\begin{quote}
+nested
+
+\end{quote}
+\begin{quote}
+nested
+
+\end{quote}
+\end{quote}
+This should not be a block quote: 2 \textgreater{} 1.
+
+Box-style:
+
+\begin{quote}
+Example:
+
+\begin{verbatim}
+sub status {
+ print "working";
+}
+\end{verbatim}
+\end{quote}
+\begin{quote}
+\begin{enumerate}[1.]
+\item
+ do laundry
+\item
+ take out the trash
+\end{enumerate}
+\end{quote}
+Here's a nested one:
+
+\begin{quote}
+Joe said:
+
+\begin{quote}
+Don't quote me.
+
+\end{quote}
+\end{quote}
+And a following paragraph.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Code Blocks}
+
+Code:
+
+\begin{verbatim}
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+\end{verbatim}
+And:
+
+\begin{verbatim}
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+\end{verbatim}
+
+\begin{obeylines}
+this has \emph{two
+lines}
+\end{obeylines}
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Lists}
+
+\subsection{Unordered}
+
+Asterisks tight:
+
+\begin{itemize}
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\end{itemize}
+Asterisks loose:
+
+\begin{itemize}
+\item
+ asterisk 1
+
+\item
+ asterisk 2
+
+\item
+ asterisk 3
+
+\end{itemize}
+Pluses tight:
+
+\begin{itemize}
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\end{itemize}
+Pluses loose:
+
+\begin{itemize}
+\item
+ Plus 1
+
+\item
+ Plus 2
+
+\item
+ Plus 3
+
+\end{itemize}
+Minuses tight:
+
+\begin{itemize}
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\end{itemize}
+Minuses loose:
+
+\begin{itemize}
+\item
+ Minus 1
+
+\item
+ Minus 2
+
+\item
+ Minus 3
+
+\end{itemize}
+\subsection{Ordered}
+
+Tight:
+
+\begin{enumerate}[1.]
+\item
+ First
+\item
+ Second
+\item
+ Third
+\end{enumerate}
+and:
+
+\begin{enumerate}[1.]
+\item
+ One
+\item
+ Two
+\item
+ Three
+\end{enumerate}
+Loose using tabs:
+
+\begin{enumerate}[1.]
+\item
+ First
+
+\item
+ Second
+
+\item
+ Third
+
+\end{enumerate}
+and using spaces:
+
+\begin{enumerate}[1.]
+\item
+ One
+
+\item
+ Two
+
+\item
+ Three
+
+\end{enumerate}
+Multiple paragraphs:
+
+\begin{enumerate}[1.]
+\item
+ Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+\item
+ Item 2.
+
+\item
+ Item 3.
+
+\end{enumerate}
+\subsection{Nested}
+
+\begin{itemize}
+\item
+ Tab
+ \begin{itemize}
+ \item
+ Tab
+ \begin{itemize}
+ \item
+ Tab
+ \end{itemize}
+ \end{itemize}
+\end{itemize}
+Here's another:
+
+\begin{enumerate}[1.]
+\item
+ First
+\item
+ Second:
+ \begin{itemize}
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \end{itemize}
+\item
+ Third
+\end{enumerate}
+Same thing but with paragraphs:
+
+\begin{enumerate}[1.]
+\item
+ First
+
+\item
+ Second:
+
+ \begin{itemize}
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \end{itemize}
+\item
+ Third
+
+\end{enumerate}
+\subsection{Tabs and spaces}
+
+\begin{itemize}
+\item
+ this is a list item indented with tabs
+
+\item
+ this is a list item indented with spaces
+
+ \begin{itemize}
+ \item
+ this is an example list item indented with tabs
+
+ \item
+ this is an example list item indented with spaces
+
+ \end{itemize}
+\end{itemize}
+\subsection{Fancy list markers}
+
+\begin{enumerate}[(1)]
+\setcounter{enumi}{1}
+\item
+ begins with 2
+\item
+ and now 3
+
+ with a continuation
+
+ \begin{enumerate}[i.]
+ \setcounter{enumii}{3}
+ \item
+ sublist with roman numerals, starting with 4
+ \item
+ more items
+ \begin{enumerate}[(A)]
+ \item
+ a subsublist
+ \item
+ a subsublist
+ \end{enumerate}
+ \end{enumerate}
+\end{enumerate}
+Nesting:
+
+\begin{enumerate}[A.]
+\item
+ Upper Alpha
+ \begin{enumerate}[I.]
+ \item
+ Upper Roman.
+ \begin{enumerate}[(1)]
+ \setcounter{enumiii}{5}
+ \item
+ Decimal start with 6
+ \begin{enumerate}[a)]
+ \setcounter{enumiv}{2}
+ \item
+ Lower alpha with paren
+ \end{enumerate}
+ \end{enumerate}
+ \end{enumerate}
+\end{enumerate}
+Autonumbering:
+
+\begin{enumerate}
+\item
+ Autonumber.
+\item
+ More.
+ \begin{enumerate}
+ \item
+ Nested.
+ \end{enumerate}
+\end{enumerate}
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Definition Lists}
+
+Tight using spaces:
+
+\begin{description}
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+Tight using tabs:
+
+\begin{description}
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+Loose:
+
+\begin{description}
+\item[apple]
+red fruit
+
+\item[orange]
+orange fruit
+
+\item[banana]
+yellow fruit
+
+\end{description}
+Multiple blocks with italics:
+
+\begin{description}
+\item[\emph{apple}]
+red fruit
+
+contains seeds, crisp, pleasant to taste
+
+\item[\emph{orange}]
+orange fruit
+
+\begin{verbatim}
+{ orange code block }
+\end{verbatim}
+\begin{quote}
+orange block quote
+
+\end{quote}
+\end{description}
+\section{HTML Blocks}
+
+Simple block on one line:
+
+foo
+And nested without indentation:
+
+foo
+bar
+Interpreted markdown in a table:
+
+This is \emph{emphasized}
+And this is \textbf{strong}
+Here's a simple block:
+
+foo
+This should be a code block, though:
+
+\begin{verbatim}
+<div>
+ foo
+</div>
+\end{verbatim}
+As should this:
+
+\begin{verbatim}
+<div>foo</div>
+\end{verbatim}
+Now, nested:
+
+foo
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+\begin{verbatim}
+<!-- Comment -->
+\end{verbatim}
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+\begin{verbatim}
+<hr />
+\end{verbatim}
+Hr's:
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Inline Markup}
+
+This is \emph{emphasized}, and so \emph{is this}.
+
+This is \textbf{strong}, and so \textbf{is this}.
+
+An \emph{\href{/url}{emphasized link}}.
+
+\textbf{\emph{This is strong and em.}}
+
+So is \textbf{\emph{this}} word.
+
+\textbf{\emph{This is strong and em.}}
+
+So is \textbf{\emph{this}} word.
+
+This is code: \verb!>!, \verb!$!, \verb!\!, \verb!\$!,
+\verb!<html>!.
+
+\sout{This is \emph{strikeout}.}
+
+Superscripts: a\textsuperscript{bc}d
+a\textsuperscript{\emph{hello}} a\textsuperscript{hello there}.
+
+Subscripts: H\textsubscript{2}O, H\textsubscript{23}O,
+H\textsubscript{many of them}O.
+
+These should not be superscripts or subscripts, because of the
+unescaped spaces: a\^{}b c\^{}d, a\ensuremath{\sim}b
+c\ensuremath{\sim}d.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Smart quotes, ellipses, dashes}
+
+``Hello,'' said the spider. ``\,`Shelob' is my name.''
+
+`A', `B', and `C' are letters.
+
+`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
+
+`He said, ``I want to go.''\,' Were you alive in the 70's?
+
+Here is some quoted `\verb!code!' and a
+``\href{http://example.com/?foo=1&bar=2}{quoted link}''.
+
+Some dashes: one---two---three---four---five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses\ldots{}and\ldots{}and\ldots{}.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{LaTeX}
+
+\begin{itemize}
+\item
+ \cite[22-23]{smith.1899}
+\item
+ \doublespacing
+\item
+ $2+2=4$
+\item
+ $x \in y$
+\item
+ $\alpha \wedge \omega$
+\item
+ $223$
+\item
+ $p$-Tree
+\item
+ $\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$
+\item
+ Here's one that has a line break in it:
+ $\alpha + \omega \times x^2$.
+\end{itemize}
+These shouldn't be math:
+
+\begin{itemize}
+\item
+ To get the famous equation, write \verb!$e = mc^2$!.
+\item
+ \$22,000 is a \emph{lot} of money. So is \$34,000. (It worked if
+ ``lot'' is emphasized.)
+\item
+ Escaped \verb!$!: \$73 \emph{this should be emphasized} 23\$.
+\end{itemize}
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+A table with one column:
+
+\begin{tabular}{c}
+Animal \\
+Vegetable
+\end{tabular}
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Special Characters}
+
+Here is some unicode:
+
+\begin{itemize}
+\item
+ I hat: Î
+\item
+ o umlaut: ö
+\item
+ section: §
+\item
+ set membership: ∈
+\item
+ copyright: ©
+\end{itemize}
+AT\&T has an ampersand in their name.
+
+AT\&T is another way to write it.
+
+This \& that.
+
+4 \textless{} 5.
+
+6 \textgreater{} 5.
+
+Backslash: \textbackslash{}
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: \textgreater{}
+
+Hash: \#
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Links}
+
+\subsection{Explicit}
+
+Just a \href{/url/}{URL}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}
+
+\href{/url/}{URL and title}
+
+\href{/url/with_underscore}{with\_underscore}
+
+\href{mailto:nobody@nowhere.net}{Email link}
+
+\href{}{Empty}.
+
+\subsection{Reference}
+
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{bar}.
+
+With \href{/url/}{embedded [brackets]}.
+
+\href{/url/}{b} by itself should be a link.
+
+Indented \href{/url}{once}.
+
+Indented \href{/url}{twice}.
+
+Indented \href{/url}{thrice}.
+
+This should [not][] be a link.
+
+\begin{verbatim}
+[not]: /url
+\end{verbatim}
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{biz}.
+
+\subsection{With ampersands}
+
+Here's a
+\href{http://example.com/?foo=1&bar=2}{link with an ampersand in the URL}.
+
+Here's a link with an amersand in the link text:
+\href{http://att.com/}{AT\&T}.
+
+Here's an \href{/script?foo=1&bar=2}{inline link}.
+
+Here's an
+\href{/script?foo=1&bar=2}{inline link in pointy braces}.
+
+\subsection{Autolinks}
+
+With an ampersand: \url{http://example.com/?foo=1&bar=2}
+
+\begin{itemize}
+\item
+ In a list?
+\item
+ \url{http://example.com/}
+\item
+ It should.
+\end{itemize}
+An e-mail address:
+\href{mailto:nobody@nowhere.net}{nobody@nowhere.net}
+
+\begin{quote}
+Blockquoted: \url{http://example.com/}
+
+\end{quote}
+Auto-links should not occur here: \verb!<http://example.com/>!
+
+\begin{verbatim}
+or here: <http://example.com/>
+\end{verbatim}
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Images}
+
+From ``Voyage dans la Lune'' by Georges Melies (1902):
+
+\includegraphics{lalune.jpg}
+
+Here is a movie \includegraphics{movie.jpg} icon.
+
+\begin{center}\rule{3in}{0.4pt}\end{center}
+
+\section{Footnotes}
+
+Here is a footnote
+reference,\footnote{ Here is the footnote. It can go anywhere after the footnote
+reference. It need not be placed at the end of the document.
+}
+and
+another.\footnote{ Here's the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).
+
+\begin{Verbatim}
+ { <code> }
+\end{Verbatim}
+If you want, you can indent every line, but you can also be lazy
+and just indent the first line of each block.
+}
+This should \emph{not} be a footnote reference, because it contains
+a space.[\^{}my note] Here is an inline
+note.\footnote{ This is \emph{easier} to type. Inline notes may contain
+\href{http://google.com}{links} and \verb!]! verbatim characters,
+as well as [bracketed text].
+}
+
+\begin{quote}
+Notes can go in quotes.\footnote{ In quote.
+}
+
+\end{quote}
+\begin{enumerate}[1.]
+\item
+ And in list items.\footnote{ In list.
+}
+\end{enumerate}
+This paragraph should not be part of the note, as it is not
+indented.
+
+\section{Escaped characters}
+
+\$ \% \& \# \_ \{ \}
+
+\end{document}
diff --git a/test/latex-reader.native b/test/latex-reader.native
new file mode 100644
index 000000000..a62f2069e
--- /dev/null
+++ b/test/latex-reader.native
@@ -0,0 +1,375 @@
+Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
+[RawBlock (Format "latex") "\\maketitle"
+,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",SoftBreak,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+,HorizontalRule
+,Header 1 ("headers",[],[]) [Str "Headers"]
+,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
+,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Para [Str "Level",Space,Str "4"]
+,Para [Str "Level",Space,Str "5"]
+,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
+,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,HorizontalRule
+,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",SoftBreak,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",SoftBreak,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
+,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
+,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
+,HorizontalRule
+,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
+,Para [Str "E-mail",Space,Str "style:"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
+,BlockQuote
+ [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ ,Para [Str "A",Space,Str "list:"]
+ ,OrderedList (1,Decimal,Period)
+ [[Para [Str "item",Space,Str "one"]]
+ ,[Para [Str "item",Space,Str "two"]]]
+ ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ ,BlockQuote
+ [Para [Str "nested"]]
+ ,BlockQuote
+ [Para [Str "nested"]]]
+,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1."]
+,Para [Str "Box-style:"]
+,BlockQuote
+ [Para [Str "Example:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"]
+,BlockQuote
+ [OrderedList (1,Decimal,Period)
+ [[Para [Str "do",Space,Str "laundry"]]
+ ,[Para [Str "take",Space,Str "out",Space,Str "the",Space,Str "trash"]]]]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "nested",Space,Str "one:"]
+,BlockQuote
+ [Para [Str "Joe",Space,Str "said:"]
+ ,BlockQuote
+ [Para [Str "Don\8217t",Space,Str "quote",Space,Str "me."]]]
+,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
+,HorizontalRule
+,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+,Para [Str "And:"]
+,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+,Para [Str "this",Space,Str "has",Space,Emph [Str "two",LineBreak,Str "lines"]]
+,HorizontalRule
+,Header 1 ("lists",[],[]) [Str "Lists"]
+,Header 2 ("unordered",[],[]) [Str "Unordered"]
+,Para [Str "Asterisks",Space,Str "tight:"]
+,BulletList
+ [[Para [Str "asterisk",Space,Str "1"]]
+ ,[Para [Str "asterisk",Space,Str "2"]]
+ ,[Para [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Asterisks",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "asterisk",Space,Str "1"]]
+ ,[Para [Str "asterisk",Space,Str "2"]]
+ ,[Para [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "tight:"]
+,BulletList
+ [[Para [Str "Plus",Space,Str "1"]]
+ ,[Para [Str "Plus",Space,Str "2"]]
+ ,[Para [Str "Plus",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Plus",Space,Str "1"]]
+ ,[Para [Str "Plus",Space,Str "2"]]
+ ,[Para [Str "Plus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "tight:"]
+,BulletList
+ [[Para [Str "Minus",Space,Str "1"]]
+ ,[Para [Str "Minus",Space,Str "2"]]
+ ,[Para [Str "Minus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Minus",Space,Str "1"]]
+ ,[Para [Str "Minus",Space,Str "2"]]
+ ,[Para [Str "Minus",Space,Str "3"]]]
+,Header 2 ("ordered",[],[]) [Str "Ordered"]
+,Para [Str "Tight:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second"]]
+ ,[Para [Str "Third"]]]
+,Para [Str "and:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "One"]]
+ ,[Para [Str "Two"]]
+ ,[Para [Str "Three"]]]
+,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second"]]
+ ,[Para [Str "Third"]]]
+,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "One"]]
+ ,[Para [Str "Two"]]
+ ,[Para [Str "Three"]]]
+,Para [Str "Multiple",Space,Str "paragraphs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",SoftBreak,Str "back."]]
+ ,[Para [Str "Item",Space,Str "2."]]
+ ,[Para [Str "Item",Space,Str "3."]]]
+,Header 2 ("nested",[],[]) [Str "Nested"]
+,BulletList
+ [[Para [Str "Tab"]
+ ,BulletList
+ [[Para [Str "Tab"]
+ ,BulletList
+ [[Para [Str "Tab"]]]]]]]
+,Para [Str "Here\8217s",Space,Str "another:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second:"]
+ ,BulletList
+ [[Para [Str "Fee"]]
+ ,[Para [Str "Fie"]]
+ ,[Para [Str "Foe"]]]]
+ ,[Para [Str "Third"]]]
+,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second:"]
+ ,BulletList
+ [[Para [Str "Fee"]]
+ ,[Para [Str "Fie"]]
+ ,[Para [Str "Foe"]]]]
+ ,[Para [Str "Third"]]]
+,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
+ ,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
+,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
+,OrderedList (2,Decimal,TwoParens)
+ [[Para [Str "begins",Space,Str "with",Space,Str "2"]]
+ ,[Para [Str "and",Space,Str "now",Space,Str "3"]
+ ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ ,OrderedList (4,LowerRoman,Period)
+ [[Para [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"]]
+ ,[Para [Str "more",Space,Str "items"]
+ ,OrderedList (1,UpperAlpha,TwoParens)
+ [[Para [Str "a",Space,Str "subsublist"]]
+ ,[Para [Str "a",Space,Str "subsublist"]]]]]]]
+,Para [Str "Nesting:"]
+,OrderedList (1,UpperAlpha,Period)
+ [[Para [Str "Upper",Space,Str "Alpha"]
+ ,OrderedList (1,UpperRoman,Period)
+ [[Para [Str "Upper",Space,Str "Roman."]
+ ,OrderedList (6,Decimal,TwoParens)
+ [[Para [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ ,OrderedList (3,LowerAlpha,OneParen)
+ [[Para [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
+,Para [Str "Autonumbering:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "Autonumber."]]
+ ,[Para [Str "More."]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Para [Str "Nested."]]]]]
+,Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
+,Para [Str "M.A.",Space,Str "2007"]
+,Para [Str "B.",Space,Str "Williams"]
+,HorizontalRule
+,Header 1 ("definition-lists",[],[]) [Str "Definition",Space,Str "Lists"]
+,Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Para [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Para [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Loose:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Para [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
+,DefinitionList
+ [([Emph [Str "apple"]],
+ [[Para [Str "red",Space,Str "fruit"]
+ ,Para [Str "contains",Space,Str "seeds,",Space,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"]]])
+ ,([Emph [Str "orange"]],
+ [[Para [Str "orange",Space,Str "fruit"]
+ ,CodeBlock ("",[],[]) "{ orange code block }"
+ ,BlockQuote
+ [Para [Str "orange",Space,Str "block",Space,Str "quote"]]]])]
+,Header 1 ("html-blocks",[],[]) [Str "HTML",Space,Str "Blocks"]
+,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
+,Para [Str "foo",SoftBreak,Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
+,Para [Str "foo",SoftBreak,Str "bar",SoftBreak,Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
+,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],SoftBreak,Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"],SoftBreak,Str "Here\8217s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
+,Para [Str "foo",SoftBreak,Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
+,CodeBlock ("",[],[]) "<div>\n foo\n</div>"
+,Para [Str "As",Space,Str "should",Space,Str "this:"]
+,CodeBlock ("",[],[]) "<div>foo</div>"
+,Para [Str "Now,",Space,Str "nested:"]
+,Para [Str "foo",SoftBreak,Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
+,Para [Str "Multiline:"]
+,Para [Str "Code",Space,Str "block:"]
+,CodeBlock ("",[],[]) "<!-- Comment -->"
+,Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "<hr />"
+,Para [Str "Hr\8217s:"]
+,HorizontalRule
+,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
+,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
+,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
+,Para [Str "An",Space,Emph [Link ("",[],[]) [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",SoftBreak,Code ("",[],[]) "<html>",Str "."]
+,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
+,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",SoftBreak,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello",Space,Str "there"],Str "."]
+,Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",SoftBreak,Str "H",Subscript [Str "many",Space,Str "of",Space,Str "them"],Str "O."]
+,Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",Space,Str "because",Space,Str "of",Space,Str "the",SoftBreak,Str "unescaped",Space,Str "spaces:",Space,Str "a^b",Space,Str "c^d,",Space,Str "a",Math InlineMath "\\sim",Str "b",SoftBreak,Str "c",Math InlineMath "\\sim",Str "d."]
+,HorizontalRule
+,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+,Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Str "\8198",Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
+,Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
+,Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine."]]
+,Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."],Str "\8198"],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70\8217s?"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code ("",[],[]) "code"],Space,Str "and",Space,Str "a",SoftBreak,Quoted DoubleQuote [Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
+,Para [Str "Some",Space,Str "dashes:",Space,Str "one\8212two\8212three\8212four\8212five."]
+,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5\8211\&7,",Space,Str "255\8211\&66,",Space,Str "1987\8211\&1999."]
+,Para [Str "Ellipses\8230and\8230and\8230."]
+,HorizontalRule
+,Header 1 ("latex",[],[]) [Str "LaTeX"]
+,BulletList
+ [[Para [Cite [Citation {citationId = "smith.1899", citationPrefix = [], citationSuffix = [Str "22-23"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cite[22-23]{smith.1899}"]]]
+ ,[RawBlock (Format "latex") "\\doublespacing"]
+ ,[Para [Math InlineMath "2+2=4"]]
+ ,[Para [Math InlineMath "x \\in y"]]
+ ,[Para [Math InlineMath "\\alpha \\wedge \\omega"]]
+ ,[Para [Math InlineMath "223"]]
+ ,[Para [Math InlineMath "p",Str "-Tree"]]
+ ,[Para [Math InlineMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"]]
+ ,[Para [Str "Here\8217s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",SoftBreak,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."]]]
+,Para [Str "These",Space,Str "shouldn\8217t",Space,Str "be",Space,Str "math:"]
+,BulletList
+ [[Para [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code ("",[],[]) "$e = mc^2$",Str "."]]
+ ,[Para [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",Space,Str "(It",Space,Str "worked",Space,Str "if",SoftBreak,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized.)"]]
+ ,[Para [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+,Table [] [AlignLeft,AlignLeft] [0.0,0.0]
+ [[Plain [Str "Animal"]]
+ ,[Plain [Str "Number"]]]
+ [[[Plain [Str "Dog"]]
+ ,[Plain [Str "2"]]]
+ ,[[Plain [Str "Cat"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "A",Space,Str "table",Space,Str "with",Space,Str "one",Space,Str "column:"]
+,Table [] [AlignCenter] [0.0]
+ [[]]
+ [[[Plain [Str "Animal"]]]
+ ,[[Plain [Str "Vegetable"]]]]
+,HorizontalRule
+,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+,BulletList
+ [[Para [Str "I",Space,Str "hat:",Space,Str "\206"]]
+ ,[Para [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
+ ,[Para [Str "section:",Space,Str "\167"]]
+ ,[Para [Str "set",Space,Str "membership:",Space,Str "\8712"]]
+ ,[Para [Str "copyright:",Space,Str "\169"]]]
+,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
+,Para [Str "This",Space,Str "&",Space,Str "that."]
+,Para [Str "4",Space,Str "<",Space,Str "5."]
+,Para [Str "6",Space,Str ">",Space,Str "5."]
+,Para [Str "Backslash:",Space,Str "\\"]
+,Para [Str "Backtick:",Space,Str "\8216"]
+,Para [Str "Asterisk:",Space,Str "*"]
+,Para [Str "Underscore:",Space,Str "_"]
+,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+,Para [Str "Left",Space,Str "paren:",Space,Str "("]
+,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+,Para [Str "Greater-than:",Space,Str ">"]
+,Para [Str "Hash:",Space,Str "#"]
+,Para [Str "Period:",Space,Str "."]
+,Para [Str "Bang:",Space,Str "!"]
+,Para [Str "Plus:",Space,Str "+"]
+,Para [Str "Minus:",Space,Str "-"]
+,HorizontalRule
+,Header 1 ("links",[],[]) [Str "Links"]
+,Header 2 ("explicit",[],[]) [Str "Explicit"]
+,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","")]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","")]
+,Para [Link ("",[],[]) [Str "with_underscore"] ("/url/with_underscore","")]
+,Para [Link ("",[],[]) [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
+,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
+,Header 2 ("reference",[],[]) [Str "Reference"]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
+,Para [Str "This",Space,Str "should",Space,Str "[not][]",Space,Str "be",Space,Str "a",Space,Str "link."]
+,CodeBlock ("",[],[]) "[not]: /url"
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "biz"] ("/url/",""),Str "."]
+,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
+,Para [Str "Here\8217s",Space,Str "a",SoftBreak,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",SoftBreak,Link ("",[],[]) [Str "AT&T"] ("http://att.com/",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "an",SoftBreak,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
+,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
+,BulletList
+ [[Para [Str "In",Space,Str "a",Space,Str "list?"]]
+ ,[Para [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+ ,[Para [Str "It",Space,Str "should."]]]
+,Para [Str "An",Space,Str "e-mail",Space,Str "address:",SoftBreak,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
+,BlockQuote
+ [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
+,CodeBlock ("",[],[]) "or here: <http://example.com/>"
+,HorizontalRule
+,Header 1 ("images",[],[]) [Str "Images"]
+,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+,Para [Image ("",[],[]) [Str "image"] ("lalune.jpg","")]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "image"] ("movie.jpg",""),Space,Str "icon."]
+,HorizontalRule
+,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",SoftBreak,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",SoftBreak,Str "reference.",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document."]],SoftBreak,Str "and",SoftBreak,Str "another.",Note [Para [Str "Here\8217s",Space,Str "the",Space,Str "long",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",SoftBreak,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",SoftBreak,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block."]],SoftBreak,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",SoftBreak,Str "a",Space,Str "space.[^my",Space,Str "note]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",SoftBreak,Str "note.",Note [Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type.",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",SoftBreak,Link ("",[],[]) [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code ("",[],[]) "]",Space,Str "verbatim",Space,Str "characters,",SoftBreak,Str "as",Space,Str "well",Space,Str "as",Space,Str "[bracketed",Space,Str "text]."]]]
+,BlockQuote
+ [Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes.",Note [Para [Str "In",Space,Str "quote."]]]]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]]]]
+,Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",SoftBreak,Str "indented."]
+,Header 1 ("escaped-characters",[],[]) [Str "Escaped",Space,Str "characters"]
+,Para [Str "$",Space,Str "%",Space,Str "&",Space,Str "#",Space,Str "_",Space,Str "{",Space,Str "}"]]
diff --git a/tests/lhs-test-markdown.native b/test/lhs-test-markdown.native
index b6d908339..b6d908339 100644
--- a/tests/lhs-test-markdown.native
+++ b/test/lhs-test-markdown.native
diff --git a/tests/lhs-test.fragment.html+lhs b/test/lhs-test.fragment.html+lhs
index 76ba4ef1a..76ba4ef1a 100644
--- a/tests/lhs-test.fragment.html+lhs
+++ b/test/lhs-test.fragment.html+lhs
diff --git a/test/lhs-test.html b/test/lhs-test.html
new file mode 100644
index 000000000..c9777ea7b
--- /dev/null
+++ b/test/lhs-test.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
+<head>
+ <meta charset="utf-8" />
+ <meta name="generator" content="pandoc" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+ <title>lhs-test</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+ </style>
+ <style type="text/css">
+a.sourceLine { display: inline-block; line-height: 1.25; }
+a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
+a.sourceLine:empty { height: 1.2em; position: absolute; }
+.sourceCode { overflow: visible; }
+code.sourceCode { white-space: pre; position: relative; }
+div.sourceCode { margin: 1em 0; }
+pre.sourceCode { margin: 0; }
+@media screen {
+div.sourceCode { overflow: auto; }
+}
+@media print {
+code.sourceCode { white-space: pre-wrap; }
+a.sourceLine { text-indent: -1em; padding-left: 1em; }
+}
+pre.numberSource a.sourceLine
+ { position: relative; }
+pre.numberSource a.sourceLine:empty
+ { position: absolute; }
+pre.numberSource a.sourceLine::before
+ { content: attr(data-line-number);
+ position: absolute; left: -5em; text-align: right; vertical-align: baseline;
+ border: none; pointer-events: all;
+ -webkit-touch-callout: none; -webkit-user-select: none;
+ -khtml-user-select: none; -moz-user-select: none;
+ -ms-user-select: none; user-select: none;
+ padding: 0 4px; width: 4em;
+ color: #aaaaaa;
+ }
+pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
+div.sourceCode
+ { }
+@media screen {
+a.sourceLine::before { text-decoration: underline; }
+}
+code span.al { color: #ff0000; font-weight: bold; } /* Alert */
+code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+code span.at { color: #7d9029; } /* Attribute */
+code span.bn { color: #40a070; } /* BaseN */
+code span.bu { } /* BuiltIn */
+code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+code span.ch { color: #4070a0; } /* Char */
+code span.cn { color: #880000; } /* Constant */
+code span.co { color: #60a0b0; font-style: italic; } /* Comment */
+code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+code span.do { color: #ba2121; font-style: italic; } /* Documentation */
+code span.dt { color: #902000; } /* DataType */
+code span.dv { color: #40a070; } /* DecVal */
+code span.er { color: #ff0000; font-weight: bold; } /* Error */
+code span.ex { } /* Extension */
+code span.fl { color: #40a070; } /* Float */
+code span.fu { color: #06287e; } /* Function */
+code span.im { } /* Import */
+code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
+code span.kw { color: #007020; font-weight: bold; } /* Keyword */
+code span.op { color: #666666; } /* Operator */
+code span.ot { color: #007020; } /* Other */
+code span.pp { color: #bc7a00; } /* Preprocessor */
+code span.sc { color: #4070a0; } /* SpecialChar */
+code span.ss { color: #bb6688; } /* SpecialString */
+code span.st { color: #4070a0; } /* String */
+code span.va { color: #19177c; } /* Variable */
+code span.vs { color: #4070a0; } /* VerbatimString */
+code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+ </style>
+ <!--[if lt IE 9]>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
+ <![endif]-->
+</head>
+<body>
+<h1 id="lhs-test">lhs test</h1>
+<p><code>unsplit</code> is an arrow that takes a pair of values and combines them to
+return a single value:</p>
+<div class="sourceCode" id="cb1"><pre class="sourceCode literate haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="ot">unsplit ::</span> (<span class="dt">Arrow</span> a) <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d) <span class="ot">-&gt;</span> a (b, c) d</a>
+<a class="sourceLine" id="cb1-2" data-line-number="2">unsplit <span class="fu">=</span> arr <span class="fu">.</span> uncurry</a>
+<a class="sourceLine" id="cb1-3" data-line-number="3"> <span class="co">-- arr (\op (x,y) -&gt; x `op` y)</span></a></code></pre></div>
+<p><code>(***)</code> combines two arrows into a new arrow by running the two arrows on a
+pair of values (one arrow on the first item of the pair and one arrow on the
+second item of the pair).</p>
+<pre><code>f *** g = first f &gt;&gt;&gt; second g</code></pre>
+<p>Block quote:</p>
+<blockquote>
+<p>foo bar</p>
+</blockquote>
+</body>
+</html>
diff --git a/test/lhs-test.html+lhs b/test/lhs-test.html+lhs
new file mode 100644
index 000000000..4a121e0d1
--- /dev/null
+++ b/test/lhs-test.html+lhs
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
+<head>
+ <meta charset="utf-8" />
+ <meta name="generator" content="pandoc" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+ <title>lhs-test</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+ </style>
+ <style type="text/css">
+a.sourceLine { display: inline-block; line-height: 1.25; }
+a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
+a.sourceLine:empty { height: 1.2em; position: absolute; }
+.sourceCode { overflow: visible; }
+code.sourceCode { white-space: pre; position: relative; }
+div.sourceCode { margin: 1em 0; }
+pre.sourceCode { margin: 0; }
+@media screen {
+div.sourceCode { overflow: auto; }
+}
+@media print {
+code.sourceCode { white-space: pre-wrap; }
+a.sourceLine { text-indent: -1em; padding-left: 1em; }
+}
+pre.numberSource a.sourceLine
+ { position: relative; }
+pre.numberSource a.sourceLine:empty
+ { position: absolute; }
+pre.numberSource a.sourceLine::before
+ { content: attr(data-line-number);
+ position: absolute; left: -5em; text-align: right; vertical-align: baseline;
+ border: none; pointer-events: all;
+ -webkit-touch-callout: none; -webkit-user-select: none;
+ -khtml-user-select: none; -moz-user-select: none;
+ -ms-user-select: none; user-select: none;
+ padding: 0 4px; width: 4em;
+ color: #aaaaaa;
+ }
+pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
+div.sourceCode
+ { }
+@media screen {
+a.sourceLine::before { text-decoration: underline; }
+}
+code span.al { color: #ff0000; font-weight: bold; } /* Alert */
+code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+code span.at { color: #7d9029; } /* Attribute */
+code span.bn { color: #40a070; } /* BaseN */
+code span.bu { } /* BuiltIn */
+code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+code span.ch { color: #4070a0; } /* Char */
+code span.cn { color: #880000; } /* Constant */
+code span.co { color: #60a0b0; font-style: italic; } /* Comment */
+code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+code span.do { color: #ba2121; font-style: italic; } /* Documentation */
+code span.dt { color: #902000; } /* DataType */
+code span.dv { color: #40a070; } /* DecVal */
+code span.er { color: #ff0000; font-weight: bold; } /* Error */
+code span.ex { } /* Extension */
+code span.fl { color: #40a070; } /* Float */
+code span.fu { color: #06287e; } /* Function */
+code span.im { } /* Import */
+code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
+code span.kw { color: #007020; font-weight: bold; } /* Keyword */
+code span.op { color: #666666; } /* Operator */
+code span.ot { color: #007020; } /* Other */
+code span.pp { color: #bc7a00; } /* Preprocessor */
+code span.sc { color: #4070a0; } /* SpecialChar */
+code span.ss { color: #bb6688; } /* SpecialString */
+code span.st { color: #4070a0; } /* String */
+code span.va { color: #19177c; } /* Variable */
+code span.vs { color: #4070a0; } /* VerbatimString */
+code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+ </style>
+ <!--[if lt IE 9]>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
+ <![endif]-->
+</head>
+<body>
+<h1 id="lhs-test">lhs test</h1>
+<p><code>unsplit</code> is an arrow that takes a pair of values and combines them to
+return a single value:</p>
+<div class="sourceCode" id="cb1"><pre class="sourceCode literate literatehaskell"><code class="sourceCode literatehaskell"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="ot">&gt; unsplit ::</span> (<span class="dt">Arrow</span> a) <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d) <span class="ot">-&gt;</span> a (b, c) d</a>
+<a class="sourceLine" id="cb1-2" data-line-number="2"><span class="ot">&gt;</span> unsplit <span class="fu">=</span> arr <span class="fu">.</span> uncurry</a>
+<a class="sourceLine" id="cb1-3" data-line-number="3"><span class="ot">&gt;</span> <span class="co">-- arr (\op (x,y) -&gt; x `op` y)</span></a></code></pre></div>
+<p><code>(***)</code> combines two arrows into a new arrow by running the two arrows on a
+pair of values (one arrow on the first item of the pair and one arrow on the
+second item of the pair).</p>
+<pre><code>f *** g = first f &gt;&gt;&gt; second g</code></pre>
+<p>Block quote:</p>
+<blockquote>
+<p>foo bar</p>
+</blockquote>
+</body>
+</html>
diff --git a/test/lhs-test.latex b/test/lhs-test.latex
new file mode 100644
index 000000000..ba9d294c0
--- /dev/null
+++ b/test/lhs-test.latex
@@ -0,0 +1,125 @@
+\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+\PassOptionsToPackage{hyphens}{url}
+%
+\documentclass[]{article}
+\usepackage{lmodern}
+\usepackage{amssymb,amsmath}
+\usepackage{ifxetex,ifluatex}
+\usepackage{fixltx2e} % provides \textsubscript
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+ \usepackage[T1]{fontenc}
+ \usepackage[utf8]{inputenc}
+ \usepackage{textcomp} % provides euro and other symbols
+\else % if luatex or xelatex
+ \usepackage{unicode-math}
+ \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
+\fi
+% use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+% use microtype if available
+\IfFileExists{microtype.sty}{%
+\usepackage[]{microtype}
+\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
+\usepackage{hyperref}
+\hypersetup{
+ pdfborder={0 0 0},
+ breaklinks=true}
+\urlstyle{same} % don't use monospace font for urls
+\usepackage{color}
+\usepackage{fancyvrb}
+\newcommand{\VerbBar}{|}
+\newcommand{\VERB}{\Verb[commandchars=\\\{\}]}
+\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
+% Add ',fontsize=\small' for more characters per line
+\newenvironment{Shaded}{}{}
+\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
+\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
+\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{#1}}
+\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
+\newcommand{\BuiltInTok}[1]{#1}
+\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
+\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{#1}}}
+\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
+\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{#1}}
+\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
+\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{#1}}
+\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
+\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{#1}}}
+\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
+\newcommand{\ExtensionTok}[1]{#1}
+\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
+\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{#1}}
+\newcommand{\ImportTok}[1]{#1}
+\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
+\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
+\newcommand{\NormalTok}[1]{#1}
+\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{#1}}
+\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{#1}}
+\newcommand{\RegionMarkerTok}[1]{#1}
+\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
+\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{#1}}
+\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
+\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{#1}}
+\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
+\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+\setcounter{secnumdepth}{0}
+% Redefines (sub)paragraphs to behave more like sections
+\ifx\paragraph\undefined\else
+\let\oldparagraph\paragraph
+\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+\let\oldsubparagraph\subparagraph
+\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+
+% set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+
+
+\date{}
+
+\begin{document}
+
+\hypertarget{lhs-test}{%
+\section{lhs test}\label{lhs-test}}
+
+\texttt{unsplit} is an arrow that takes a pair of values and combines them to
+return a single value:
+
+\begin{Shaded}
+\begin{Highlighting}[]
+\OtherTok{unsplit ::}\NormalTok{ (}\DataTypeTok{Arrow}\NormalTok{ a) }\OtherTok{=>}\NormalTok{ (b }\OtherTok{->}\NormalTok{ c }\OtherTok{->}\NormalTok{ d) }\OtherTok{->}\NormalTok{ a (b, c) d}
+\NormalTok{unsplit }\FunctionTok{=}\NormalTok{ arr }\FunctionTok{.}\NormalTok{ uncurry}
+ \CommentTok{-- arr (\textbackslash{}op (x,y) -> x `op` y)}
+\end{Highlighting}
+\end{Shaded}
+
+\texttt{(***)} combines two arrows into a new arrow by running the two arrows on a
+pair of values (one arrow on the first item of the pair and one arrow on the
+second item of the pair).
+
+\begin{verbatim}
+f *** g = first f >>> second g
+\end{verbatim}
+
+Block quote:
+
+\begin{quote}
+foo bar
+\end{quote}
+
+\end{document}
diff --git a/test/lhs-test.latex+lhs b/test/lhs-test.latex+lhs
new file mode 100644
index 000000000..53ab4f713
--- /dev/null
+++ b/test/lhs-test.latex+lhs
@@ -0,0 +1,88 @@
+\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+\PassOptionsToPackage{hyphens}{url}
+%
+\documentclass[]{article}
+\usepackage{lmodern}
+\usepackage{amssymb,amsmath}
+\usepackage{ifxetex,ifluatex}
+\usepackage{fixltx2e} % provides \textsubscript
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+ \usepackage[T1]{fontenc}
+ \usepackage[utf8]{inputenc}
+ \usepackage{textcomp} % provides euro and other symbols
+\else % if luatex or xelatex
+ \usepackage{unicode-math}
+ \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
+\fi
+% use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+% use microtype if available
+\IfFileExists{microtype.sty}{%
+\usepackage[]{microtype}
+\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
+\usepackage{hyperref}
+\hypersetup{
+ pdfborder={0 0 0},
+ breaklinks=true}
+\urlstyle{same} % don't use monospace font for urls
+\usepackage{listings}
+\newcommand{\passthrough}[1]{#1}
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+\setcounter{secnumdepth}{0}
+% Redefines (sub)paragraphs to behave more like sections
+\ifx\paragraph\undefined\else
+\let\oldparagraph\paragraph
+\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+\let\oldsubparagraph\subparagraph
+\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+
+% set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+
+
+\date{}
+
+\begin{document}
+
+\hypertarget{lhs-test}{%
+\section{lhs test}\label{lhs-test}}
+
+\texttt{unsplit} is an arrow that takes a pair of values and combines them to
+return a single value:
+
+\begin{code}
+unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d
+unsplit = arr . uncurry
+ -- arr (\op (x,y) -> x `op` y)
+\end{code}
+
+\texttt{(***)} combines two arrows into a new arrow by running the two arrows on a
+pair of values (one arrow on the first item of the pair and one arrow on the
+second item of the pair).
+
+\begin{verbatim}
+f *** g = first f >>> second g
+\end{verbatim}
+
+Block quote:
+
+\begin{quote}
+foo bar
+\end{quote}
+
+\end{document}
diff --git a/tests/lhs-test.markdown b/test/lhs-test.markdown
index 20949b75c..20949b75c 100644
--- a/tests/lhs-test.markdown
+++ b/test/lhs-test.markdown
diff --git a/tests/lhs-test.markdown+lhs b/test/lhs-test.markdown+lhs
index a6a894d22..a6a894d22 100644
--- a/tests/lhs-test.markdown+lhs
+++ b/test/lhs-test.markdown+lhs
diff --git a/tests/lhs-test.native b/test/lhs-test.native
index b6d908339..b6d908339 100644
--- a/tests/lhs-test.native
+++ b/test/lhs-test.native
diff --git a/tests/lhs-test.rst b/test/lhs-test.rst
index 3de2d9ff6..3de2d9ff6 100644
--- a/tests/lhs-test.rst
+++ b/test/lhs-test.rst
diff --git a/tests/lhs-test.rst+lhs b/test/lhs-test.rst+lhs
index eec79c546..eec79c546 100644
--- a/tests/lhs-test.rst+lhs
+++ b/test/lhs-test.rst+lhs
diff --git a/test/lua/attr-test.lua b/test/lua/attr-test.lua
new file mode 100644
index 000000000..68dc0012d
--- /dev/null
+++ b/test/lua/attr-test.lua
@@ -0,0 +1,6 @@
+function Div (div)
+ div.attributes.five = ("%d"):format(div.attributes.two + div.attributes.three)
+ div.attributes.two = nil
+ div.attributes.one = "eins"
+ return div
+end
diff --git a/test/lua/block-count.lua b/test/lua/block-count.lua
new file mode 100644
index 000000000..508b05ea8
--- /dev/null
+++ b/test/lua/block-count.lua
@@ -0,0 +1,11 @@
+local num_blocks = 0
+
+function Block(el)
+ num_blocks = num_blocks + 1
+end
+
+function Pandoc(blocks, meta)
+ return pandoc.Pandoc {
+ pandoc.Para{pandoc.Str(num_blocks)}
+ }
+end
diff --git a/test/lua/hello-world-doc.lua b/test/lua/hello-world-doc.lua
new file mode 100644
index 000000000..62236584e
--- /dev/null
+++ b/test/lua/hello-world-doc.lua
@@ -0,0 +1,10 @@
+return {
+ {
+ Pandoc = function(doc)
+ local meta = {}
+ local hello = { pandoc.Str "Hello,", pandoc.Space(), pandoc.Str "World!" }
+ local blocks = { pandoc.Para(hello) }
+ return pandoc.Pandoc(blocks, meta)
+ end
+ }
+}
diff --git a/test/lua/implicit-doc-filter.lua b/test/lua/implicit-doc-filter.lua
new file mode 100644
index 000000000..253462d1c
--- /dev/null
+++ b/test/lua/implicit-doc-filter.lua
@@ -0,0 +1,6 @@
+function Doc (doc)
+ local meta = {}
+ local hello = { pandoc.Str "Hello,", pandoc.Space(), pandoc.Str "World!" }
+ local blocks = { pandoc.Para(hello) }
+ return pandoc.Pandoc(blocks, meta)
+end
diff --git a/test/lua/markdown-reader.lua b/test/lua/markdown-reader.lua
new file mode 100644
index 000000000..1530a15a2
--- /dev/null
+++ b/test/lua/markdown-reader.lua
@@ -0,0 +1,12 @@
+return {
+ {
+ RawBlock = function (elem)
+ if elem.format == "markdown" then
+ local pd = pandoc.read(elem.text, "markdown")
+ return pd.blocks[1]
+ else
+ return elem
+ end
+ end,
+ }
+}
diff --git a/test/lua/metatable-catch-all.lua b/test/lua/metatable-catch-all.lua
new file mode 100644
index 000000000..05df16bbf
--- /dev/null
+++ b/test/lua/metatable-catch-all.lua
@@ -0,0 +1,20 @@
+local num_inlines = 0
+
+function catch_all(el)
+ if el.tag and pandoc.Inline.constructor[el.tag] then
+ num_inlines = num_inlines + 1
+ end
+end
+
+function Pandoc(blocks, meta)
+ return pandoc.Pandoc {
+ pandoc.Para{pandoc.Str(num_inlines)}
+ }
+end
+
+return {
+ setmetatable(
+ {Pandoc = Pandoc},
+ {__index = function(_) return catch_all end}
+ )
+}
diff --git a/test/lua/plain-to-para.lua b/test/lua/plain-to-para.lua
new file mode 100644
index 000000000..aa12a97d3
--- /dev/null
+++ b/test/lua/plain-to-para.lua
@@ -0,0 +1,6 @@
+return {
+ { Plain = function (elem)
+ return pandoc.Para(elem.content)
+ end,
+ }
+}
diff --git a/test/lua/script-name.lua b/test/lua/script-name.lua
new file mode 100644
index 000000000..4b5a223f0
--- /dev/null
+++ b/test/lua/script-name.lua
@@ -0,0 +1,3 @@
+function Para (_)
+ return pandoc.Para{pandoc.Str(PANDOC_SCRIPT_FILE)}
+end
diff --git a/test/lua/single-to-double-quoted.lua b/test/lua/single-to-double-quoted.lua
new file mode 100644
index 000000000..b985b215c
--- /dev/null
+++ b/test/lua/single-to-double-quoted.lua
@@ -0,0 +1,10 @@
+return {
+ {
+ Quoted = function (elem)
+ if elem.quotetype == "SingleQuote" then
+ elem.quotetype = "DoubleQuote"
+ end
+ return elem
+ end,
+ }
+}
diff --git a/test/lua/smallcaps-title.lua b/test/lua/smallcaps-title.lua
new file mode 100644
index 000000000..b839ee131
--- /dev/null
+++ b/test/lua/smallcaps-title.lua
@@ -0,0 +1,12 @@
+return {
+ {
+ Meta = function(meta)
+ -- The call to `MetaInlines` is redundant and used for testing purposes
+ -- only. The explicit use of a MetaValue constructor is only useful when
+ -- used with an empty table: `MetaInlines{}` is read differently than
+ -- `MetaBlocks{}`.
+ meta.title = pandoc.MetaInlines{pandoc.SmallCaps(meta.title)}
+ return meta
+ end
+ }
+}
diff --git a/test/lua/strmacro.lua b/test/lua/strmacro.lua
new file mode 100644
index 000000000..a2711798a
--- /dev/null
+++ b/test/lua/strmacro.lua
@@ -0,0 +1,11 @@
+return {
+ {
+ Str = function (elem)
+ if elem.text == "{{helloworld}}" then
+ return pandoc.Emph {pandoc.Str "Hello, World"}
+ else
+ return elem
+ end
+ end,
+ }
+}
diff --git a/test/lua/test-pandoc-utils.lua b/test/lua/test-pandoc-utils.lua
new file mode 100644
index 000000000..c732d2f85
--- /dev/null
+++ b/test/lua/test-pandoc-utils.lua
@@ -0,0 +1,115 @@
+utils = require 'pandoc.utils'
+
+-- hierarchicalize
+------------------------------------------------------------------------
+function test_hierarchicalize ()
+ local blks = {
+ pandoc.Header(1, {pandoc.Str 'First'}),
+ pandoc.Header(2, {pandoc.Str 'Second'}),
+ pandoc.Header(2, {pandoc.Str 'Third'}),
+ }
+ local hblks = utils.hierarchicalize(blks)
+ return hblks[1].t == "Sec"
+ and hblks[1].contents[1].t == "Sec"
+ and hblks[1].contents[2].numbering[1] == 1
+ and hblks[1].contents[2].numbering[2] == 2
+end
+
+-- SHA1
+------------------------------------------------------------------------
+function test_sha1 ()
+ local ref_hash = '0a0a9f2a6772942557ab5355d76af442f8f65e01'
+ local hash = utils.sha1 'Hello, World!'
+ return hash == ref_hash
+end
+
+-- Pipe
+------------------------------------------------------------------------
+function file_exists (filename)
+ local fh = io.open(filename, 'r')
+ return fh ~= nil and (fh:close() or true)
+end
+
+function warn (...) io.stderr:write(...) end
+
+function test_pipe ()
+ if not file_exists('/bin/sed') then
+ warn 'Did not find /bin/sed, skipping test'
+ return true
+ end
+ local pipe_result = pandoc.pipe('/bin/sed', {'-e', 's/a/b/'}, 'abc')
+ return pipe_result == 'bbc'
+end
+
+function test_failing_pipe ()
+ if not file_exists('/bin/false') then
+ warn 'Did not find /bin/false, skipping test'
+ return true
+ end
+ local res, err = pcall(pandoc.pipe, '/bin/false', {}, 'abc')
+ return not res and
+ err.command == '/bin/false' and
+ err.error_code == 1 and
+ err.output == ''
+end
+
+-- Read
+------------------------------------------------------------------------
+function test_read ()
+ local valid_markdown = '*Hello*, World!\n'
+ local res = pandoc.read(valid_markdown).blocks[1].content
+ return res[1].t == 'Emph' and res[3].t == 'Space' and res[4].t == 'Str'
+end
+
+function test_failing_read ()
+ local res, err = pcall(pandoc.read, 'foo', 'nosuchreader')
+ return not res and err:match 'Unknown reader: nosuchreader'
+end
+
+-- Stringify
+------------------------------------------------------------------------
+function test_stringify ()
+ local inline = pandoc.Emph{
+ pandoc.Str 'Cogito',
+ pandoc.Space(),
+ pandoc.Str 'ergo',
+ pandoc.Space(),
+ pandoc.Str 'sum.',
+ }
+ return utils.stringify(inline) == 'Cogito ergo sum.'
+end
+
+-- to_roman_numeral
+------------------------------------------------------------------------
+function test_to_roman_numeral ()
+ return utils.to_roman_numeral(1888) == 'MDCCCLXXXVIII'
+ -- calling with a string fails
+ and not pcall(utils.to_roman_numeral, 'not a number')
+end
+
+-- normalize_date
+------------------------------------------------------------------------
+function test_normalize_date ()
+ return utils.normalize_date("12/31/2017") == '2017-12-31'
+ and utils.normalize_date("pandoc") == nil
+end
+
+-- Return result
+------------------------------------------------------------------------
+function run(fn)
+ return fn() and "OK" or "FAIL"
+end
+
+function Para (el)
+ return {
+ pandoc.Plain{pandoc.Str("hierarchicalize: " .. run(test_hierarchicalize))},
+ pandoc.Plain{pandoc.Str("normalize_date: " .. run(test_normalize_date))},
+ pandoc.Plain{pandoc.Str("pipe: " .. run(test_pipe))},
+ pandoc.Plain{pandoc.Str("failing pipe: " .. run(test_failing_pipe))},
+ pandoc.Plain{pandoc.Str("read: " .. run(test_read))},
+ pandoc.Plain{pandoc.Str("failing read: " .. run(test_failing_read))},
+ pandoc.Plain{pandoc.Str("sha1: " .. run(test_sha1))},
+ pandoc.Plain{pandoc.Str("stringify: " .. run(test_stringify))},
+ pandoc.Plain{pandoc.Str("to_roman_numeral: " .. run(test_to_roman_numeral))},
+ }
+end
diff --git a/test/lua/undiv.lua b/test/lua/undiv.lua
new file mode 100644
index 000000000..1cbb6d30e
--- /dev/null
+++ b/test/lua/undiv.lua
@@ -0,0 +1,3 @@
+function Div(el)
+ return el.content
+end
diff --git a/test/lua/uppercase-header.lua b/test/lua/uppercase-header.lua
new file mode 100644
index 000000000..8e86911c0
--- /dev/null
+++ b/test/lua/uppercase-header.lua
@@ -0,0 +1,9 @@
+local text = require 'text'
+
+local function str_to_uppercase (s)
+ return pandoc.Str(text.upper(s.text))
+end
+
+function Header (el)
+ return pandoc.walk_block(el, {Str = str_to_uppercase})
+end
diff --git a/test/markdown-citations.native b/test/markdown-citations.native
new file mode 100644
index 000000000..c77ccbbfc
--- /dev/null
+++ b/test/markdown-citations.native
@@ -0,0 +1,17 @@
+[Header 1 ("pandoc-with-citeproc-hs",[],[]) [Str "Pandoc",Space,Str "with",Space,Str "citeproc-hs"]
+,BulletList
+ [[Para [Cite [Citation {citationId = "nonexistent", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@nonexistent]"]]]
+ ,[Para [Cite [Citation {citationId = "nonexistent", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@nonexistent"]]]
+ ,[Para [Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@item1"],Space,Str "says",Space,Str "blah."]]
+ ,[Para [Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [Str "p.\160\&30"], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@item1",Space,Str "[p.",Space,Str "30]"],Space,Str "says",Space,Str "blah."]]
+ ,[Para [Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [Str "p.\160\&30,",Space,Str "with",Space,Str "suffix"], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@item1",Space,Str "[p.",Space,Str "30,",Space,Str "with",Space,Str "suffix]"],Space,Str "says",Space,Str "blah."]]
+ ,[Para [Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0},Citation {citationId = "item2", citationPrefix = [], citationSuffix = [Space,Str "p.\160\&30"], citationMode = SuppressAuthor, citationNoteNum = 0, citationHash = 0},Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [Str "see",Space,Str "also"], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "@item1",Space,Str "[-@item2",Space,Str "p.",Space,Str "30;",Space,Str "see",Space,Str "also",Space,Str "@\1087\1091\1085\1082\1090\&3]"],Space,Str "says",Space,Str "blah."]]
+ ,[Para [Str "In",Space,Str "a",Space,Str "note.",Note [Para [Cite [Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [], citationSuffix = [Str "p.\160\&12"], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@\1087\1091\1085\1082\1090\&3",Space,Str "[p.",Space,Str "12]"],Space,Str "and",Space,Str "a",Space,Str "citation",Space,Str "without",Space,Str "locators",Space,Cite [Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@\1087\1091\1085\1082\1090\&3]"],Str "."]]]]
+ ,[Para [Str "A",Space,Str "citation",Space,Str "group",Space,Cite [Citation {citationId = "item1", citationPrefix = [Str "see"], citationSuffix = [Space,Str "chap.",Space,Str "3"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [Str "also"], citationSuffix = [Space,Str "p.\160\&34-35"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[see",Space,Str "@item1",Space,Str "chap.",Space,Str "3;",Space,Str "also",Space,Str "@\1087\1091\1085\1082\1090\&3",Space,Str "p.",Space,Str "34-35]"],Str "."]]
+ ,[Para [Str "Another",Space,Str "one",Space,Cite [Citation {citationId = "item1", citationPrefix = [Str "see"], citationSuffix = [Space,Str "p.\160\&34-35"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[see",Space,Str "@item1",Space,Str "p.",Space,Str "34-35]"],Str "."]]
+ ,[Para [Str "And",Space,Str "another",Space,Str "one",Space,Str "in",Space,Str "a",Space,Str "note.",Note [Para [Str "Some",Space,Str "citations",Space,Cite [Citation {citationId = "item1", citationPrefix = [Str "see"], citationSuffix = [Space,Str "chap.",Space,Str "3"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "item2", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[see",Space,Str "@item1",Space,Str "chap.",Space,Str "3;",Space,Str "@\1087\1091\1085\1082\1090\&3;",Space,Str "@item2]"],Str "."]]]]
+ ,[Para [Str "Citation",Space,Str "with",Space,Str "a",Space,Str "suffix",Space,Str "and",Space,Str "locator",Space,Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [Space,Str "pp.\160\&33,",Space,Str "35-37,",Space,Str "and",Space,Str "nowhere",Space,Str "else"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@item1",Space,Str "pp.",Space,Str "33,",Space,Str "35-37,",Space,Str "and",Space,Str "nowhere",Space,Str "else]"],Str "."]]
+ ,[Para [Str "Citation",Space,Str "with",Space,Str "suffix",Space,Str "only",Space,Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [Space,Str "and",Space,Str "nowhere",Space,Str "else"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@item1",Space,Str "and",Space,Str "nowhere",Space,Str "else]"],Str "."]]
+ ,[Para [Str "Now",Space,Str "some",Space,Str "modifiers.",Note [Para [Str "Like",Space,Str "a",Space,Str "citation",Space,Str "without",Space,Str "author:",Space,Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [], citationMode = SuppressAuthor, citationNoteNum = 0, citationHash = 0}] [Str "[-@item1]"],Str ",",Space,Str "and",Space,Str "now",Space,Str "Doe",Space,Str "with",Space,Str "a",Space,Str "locator",Space,Cite [Citation {citationId = "item2", citationPrefix = [], citationSuffix = [Space,Str "p.\160\&44"], citationMode = SuppressAuthor, citationNoteNum = 0, citationHash = 0}] [Str "[-@item2",Space,Str "p.",Space,Str "44]"],Str "."]]]]
+ ,[Para [Str "With",Space,Str "some",Space,Str "markup",Space,Cite [Citation {citationId = "item1", citationPrefix = [Emph [Str "see"]], citationSuffix = [Space,Str "p.",Space,Strong [Str "32"]], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[*see*",Space,Str "@item1",Space,Str "p.",Space,Str "**32**]"],Str "."]]]
+,Header 1 ("references",[],[]) [Str "References"]]
diff --git a/tests/markdown-citations.txt b/test/markdown-citations.txt
index dcc7985d2..dcc7985d2 100644
--- a/tests/markdown-citations.txt
+++ b/test/markdown-citations.txt
diff --git a/test/markdown-reader-more.native b/test/markdown-reader-more.native
new file mode 100644
index 000000000..17e91bb89
--- /dev/null
+++ b/test/markdown-reader-more.native
@@ -0,0 +1,198 @@
+Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",Space,Str "One"],MetaInlines [Str "Author",Space,Str "Two"],MetaInlines [Str "Author",Space,Str "Three"],MetaInlines [Str "Author",Space,Str "Four"]]),("title",MetaInlines [Str "Title",SoftBreak,Str "spanning",Space,Str "multiple",Space,Str "lines"])]})
+[Header 1 ("additional-markdown-reader-tests",[],[]) [Str "Additional",Space,Str "markdown",Space,Str "reader",Space,Str "tests"]
+,Header 2 ("blank-line-before-url-in-link-reference",[],[]) [Str "Blank",Space,Str "line",Space,Str "before",Space,Str "URL",Space,Str "in",Space,Str "link",Space,Str "reference"]
+,Para [Link ("",[],[]) [Str "foo"] ("/url",""),Space,Str "and",Space,Link ("",[],[]) [Str "bar"] ("/url","title")]
+,Header 2 ("raw-context-environments",[],[]) [Str "Raw",Space,Str "ConTeXt",Space,Str "environments"]
+,RawBlock (Format "context") "\\placeformula \\startformula\n L_{1} = L_{2}\n \\stopformula"
+,RawBlock (Format "context") "\\start[a2]\n\\start[a2]\n\\stop[a2]\n\\stop[a2]"
+,Header 2 ("raw-latex-environments",[],[]) [Str "Raw",Space,Str "LaTeX",Space,Str "environments"]
+,RawBlock (Format "latex") "\\begin{center}\n\\begin{tikzpicture}[baseline={([yshift=+-.5ex]current bounding box.center)}, level distance=24pt]\n\\Tree [.{S} [.NP John\\index{i} ] [.VP [.V likes ] [.NP himself\\index{i,*j} ]]]\n\\end{tikzpicture}\n\\end{center}"
+,Header 2 ("urls-with-spaces-and-punctuation",[],[]) [Str "URLs",Space,Str "with",Space,Str "spaces",Space,Str "and",Space,Str "punctuation"]
+,Para [Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("bar%20baz","title")]
+,Para [Link ("",[],[]) [Str "baz"] ("/foo%20foo",""),Space,Link ("",[],[]) [Str "bam"] ("/foo%20fee",""),Space,Link ("",[],[]) [Str "bork"] ("/foo/zee%20zob","title")]
+,Para [Link ("",[],[]) [Str "Ward\8217s",Space,Str "method."] ("http://en.wikipedia.org/wiki/Ward's_method","")]
+,Header 2 ("horizontal-rules-with-spaces-at-end",[],[]) [Str "Horizontal",Space,Str "rules",Space,Str "with",Space,Str "spaces",Space,Str "at",Space,Str "end"]
+,HorizontalRule
+,HorizontalRule
+,Header 2 ("raw-html-before-header",[],[]) [Str "Raw",Space,Str "HTML",Space,Str "before",Space,Str "header"]
+,Para [RawInline (Format "html") "<a>",RawInline (Format "html") "</a>"]
+,Header 3 ("my-header",[],[]) [Str "my",Space,Str "header"]
+,Header 2 ("in-math",[],[]) [Str "$",Space,Str "in",Space,Str "math"]
+,Para [Math InlineMath "\\$2 + \\$3"]
+,Para [Math InlineMath "x = \\text{the $n$th root of $y$}"]
+,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "math:"]
+,Para [Str "$PATH",Space,Str "90",Space,Str "$PATH"]
+,Header 2 ("commented-out-list-item",[],[]) [Str "Commented-out",Space,Str "list",Space,Str "item"]
+,BulletList
+ [[Plain [Str "one",SoftBreak,RawInline (Format "html") "<!--\n- two\n-->"]]
+ ,[Plain [Str "three"]]]
+,Header 2 ("indented-code-at-beginning-of-list",[],[]) [Str "Indented",Space,Str "code",Space,Str "at",Space,Str "beginning",Space,Str "of",Space,Str "list"]
+,BulletList
+ [[CodeBlock ("",[],[]) "code\ncode"
+ ,OrderedList (1,Decimal,Period)
+ [[CodeBlock ("",[],[]) "code\ncode"]
+ ,[CodeBlock ("",[],[]) "code\ncode"]]
+ ,BulletList
+ [[CodeBlock ("",[],[]) "code\ncode"]
+ ,[Plain [Str "no",Space,Str "code"]]]]]
+,Header 2 ("backslash-newline",[],[]) [Str "Backslash",Space,Str "newline"]
+,Para [Str "hi",LineBreak,Str "there"]
+,Header 2 ("code-spans",[],[]) [Str "Code",Space,Str "spans"]
+,Para [Code ("",[],[]) "hi\\"]
+,Para [Code ("",[],[]) "hi there"]
+,Para [Code ("",[],[]) "hi````there"]
+,Para [Str "`hi"]
+,Para [Str "there`"]
+,Header 2 ("multilingual-urls",[],[]) [Str "Multilingual",Space,Str "URLs"]
+,Para [Link ("",[],[]) [Str "http://\27979.com?\27979=\27979"] ("http://\27979.com?\27979=\27979","")]
+,Para [Link ("",[],[]) [Str "foo"] ("/bar/\27979?x=\27979","title")]
+,Para [Link ("",[],[]) [Str "\27979@foo.\27979.baz"] ("mailto:\27979@foo.\27979.baz","")]
+,Header 2 ("numbered-examples",[],[]) [Str "Numbered",Space,Str "examples"]
+,OrderedList (1,Example,TwoParens)
+ [[Plain [Str "First",Space,Str "example."]]
+ ,[Plain [Str "Second",Space,Str "example."]]]
+,Para [Str "Explanation",Space,Str "of",Space,Str "examples",Space,Str "(2)",Space,Str "and",Space,Str "(3)."]
+,OrderedList (3,Example,TwoParens)
+ [[Plain [Str "Third",Space,Str "example."]]]
+,Header 2 ("macros",[],[]) [Str "Macros"]
+,RawBlock (Format "latex") "\\newcommand{\\tuple}[1]{\\langle #1 \\rangle}"
+,Para [Math InlineMath "\\langle x,y \\rangle"]
+,Header 2 ("case-insensitive-references",[],[]) [Str "Case-insensitive",Space,Str "references"]
+,Para [Link ("",[],[]) [Str "Fum"] ("/fum","")]
+,Para [Link ("",[],[]) [Str "FUM"] ("/fum","")]
+,Para [Link ("",[],[]) [Str "bat"] ("/bat","")]
+,Header 2 ("curly-smart-quotes",[],[]) [Str "Curly",Space,Str "smart",Space,Str "quotes"]
+,Para [Quoted DoubleQuote [Str "Hi"]]
+,Para [Quoted SingleQuote [Str "Hi"]]
+,Header 2 ("consecutive-lists",[],[]) [Str "Consecutive",Space,Str "lists"]
+,BulletList
+ [[Plain [Str "one"]]
+ ,[Plain [Str "two"]]]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "one"]]
+ ,[Plain [Str "two"]]]
+,OrderedList (1,LowerAlpha,Period)
+ [[Plain [Str "one"]]
+ ,[Plain [Str "two"]]]
+,Header 2 ("implicit-header-references",[],[]) [Str "Implicit",Space,Str "header",Space,Str "references"]
+,Header 3 ("my-header-1",[],[]) [Str "My",Space,Str "header"]
+,Header 3 ("my-other-header",[],[]) [Str "My",Space,Str "other",Space,Str "header"]
+,Para [Str "A",Space,Str "link",Space,Str "to",Space,Link ("",[],[]) [Str "My",Space,Str "header"] ("#my-header-1",""),Str "."]
+,Para [Str "Another",Space,Str "link",Space,Str "to",Space,Link ("",[],[]) [Str "it"] ("#my-header-1",""),Str "."]
+,Para [Str "Should",Space,Str "be",Space,Link ("",[],[]) [Str "case",Space,Str "insensitive"] ("#my-header-1",""),Str "."]
+,Para [Str "Link",Space,Str "to",Space,Link ("",[],[]) [Str "Explicit",Space,Str "header",Space,Str "attributes"] ("#foobar",""),Str "."]
+,Para [Str "But",Space,Str "this",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "link",Space,Str "to",Space,Link ("",[],[]) [Str "My",Space,Str "other",Space,Str "header"] ("/foo",""),Str ",",Space,Str "since",Space,Str "the",Space,Str "reference",Space,Str "is",Space,Str "defined."]
+,Header 2 ("foobar",["baz"],[("key","val")]) [Str "Explicit",Space,Str "header",Space,Str "attributes"]
+,BlockQuote
+ [Header 2 ("foobar",["baz"],[("key","val")]) [Str "Header",Space,Str "attributes",Space,Str "inside",Space,Str "block",Space,Str "quote"]]
+,Header 2 ("line-blocks",[],[]) [Str "Line",Space,Str "blocks"]
+,LineBlock
+ [[Str "But",Space,Str "can",Space,Str "a",Space,Str "bee",Space,Str "be",Space,Str "said",Space,Str "to",Space,Str "be"]
+ ,[Str "\160\160\160\160or",Space,Str "not",Space,Str "to",Space,Str "be",Space,Str "an",Space,Str "entire",Space,Str "bee,"]
+ ,[Str "\160\160\160\160\160\160\160\160when",Space,Str "half",Space,Str "the",Space,Str "bee",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "bee,"]
+ ,[Str "\160\160\160\160\160\160\160\160\160\160\160\160due",Space,Str "to",Space,Str "some",Space,Str "ancient",Space,Str "injury?"]
+ ,[]
+ ,[Str "Continuation",Space,Str "line"]
+ ,[Str "\160\160and",Space,Str "another"]]
+,Header 2 ("grid-tables",[],[]) [Str "Grid",Space,Str "Tables"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
+ [[Plain [Str "col",Space,Str "1"]]
+ ,[Plain [Str "col",Space,Str "2"]]
+ ,[Plain [Str "col",Space,Str "3"]]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "Headless"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "With",Space,Str "alignments"]
+,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
+ [[Plain [Str "col",Space,Str "1"]]
+ ,[Plain [Str "col",Space,Str "2"]]
+ ,[Plain [Str "col",Space,Str "3"]]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "Headless",Space,Str "with",Space,Str "alignments"]
+,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "Spaces",Space,Str "at",Space,Str "ends",Space,Str "of",Space,Str "lines"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "Multiple",Space,Str "blocks",Space,Str "in",Space,Str "a",Space,Str "cell"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
+ [[]
+ ,[]
+ ,[]]
+ [[[Header 1 ("col-1",[],[]) [Str "col",Space,Str "1"]
+ ,Plain [Str "col",Space,Str "1"]]
+ ,[Header 1 ("col-2",[],[]) [Str "col",Space,Str "2"]
+ ,Plain [Str "col",Space,Str "2"]]
+ ,[Header 1 ("col-3",[],[]) [Str "col",Space,Str "3"]
+ ,Plain [Str "col",Space,Str "3"]]]
+ ,[[Para [Str "r1",Space,Str "a"]
+ ,Para [Str "r1",Space,Str "bis"]]
+ ,[BulletList
+ [[Plain [Str "b"]]
+ ,[Plain [Str "b",Space,Str "2"]]
+ ,[Plain [Str "b",Space,Str "2"]]]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]]
+,Para [Str "Empty",Space,Str "cells"]
+,Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2]
+ [[]
+ ,[]]
+ [[[]
+ ,[]]]
+,Header 2 ("entities-in-links-and-titles",[],[]) [Str "Entities",Space,Str "in",Space,Str "links",Space,Str "and",Space,Str "titles"]
+,Para [Link ("",[],[]) [Str "link"] ("/\252rl","\246\246!")]
+,Para [Link ("",[],[]) [Str "http://g\246\246gle.com"] ("http://g\246\246gle.com","")]
+,Para [Link ("",[],[]) [Str "me@ex\228mple.com"] ("mailto:me@ex\228mple.com","")]
+,Para [Link ("",[],[]) [Str "foobar"] ("/\252rl","\246\246!")]
+,Header 2 ("parentheses-in-urls",[],[]) [Str "Parentheses",Space,Str "in",Space,Str "URLs"]
+,Para [Link ("",[],[]) [Str "link"] ("/hi(there)","")]
+,Para [Link ("",[],[]) [Str "link"] ("/hithere)","")]
+,Para [Link ("",[],[]) [Str "linky"] ("hi_(there_(nested))","")]
+,Header 2 ("backslashes-in-link-references",[],[]) [Str "Backslashes",Space,Str "in",Space,Str "link",Space,Str "references"]
+,Para [Link ("",[],[]) [Str "*",RawInline (Format "tex") "\\a"] ("b","")]
+,Header 2 ("reference-link-fallbacks",[],[]) [Str "Reference",Space,Str "link",Space,Str "fallbacks"]
+,Para [Str "[",Emph [Str "not",Space,Str "a",Space,Str "link"],Str "]",Space,Str "[",Emph [Str "nope"],Str "]\8230"]
+,Header 2 ("reference-link-followed-by-a-citation",[],[]) [Str "Reference",Space,Str "link",Space,Str "followed",Space,Str "by",Space,Str "a",Space,Str "citation"]
+,Para [Str "MapReduce",Space,Str "is",Space,Str "a",Space,Str "paradigm",Space,Str "popularized",Space,Str "by",Space,Link ("",[],[]) [Str "Google"] ("http://google.com",""),Space,Cite [Citation {citationId = "mapreduce", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@mapreduce]"],Space,Str "as",Space,Str "its",SoftBreak,Str "most",Space,Str "vocal",Space,Str "proponent."]
+,Header 2 ("empty-reference-links",[],[]) [Str "Empty",Space,Str "reference",Space,Str "links"]
+,Para [Str "bar"]
+,Para [Link ("",[],[]) [Str "foo2"] ("","")]
+,Header 2 ("wrapping-shouldnt-introduce-new-list-items",[],[]) [Str "Wrapping",Space,Str "shouldn\8217t",Space,Str "introduce",Space,Str "new",Space,Str "list",Space,Str "items"]
+,BulletList
+ [[Plain [Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "2015."]]]
+,Header 2 ("bracketed-spans",[],[]) [Str "Bracketed",Space,Str "spans"]
+,Para [Span ("id",["class"],[("key","val")]) [Emph [Str "foo"],Space,Str "bar",Space,Str "baz",Space,Link ("",[],[]) [Str "link"] ("url","")]]]
diff --git a/test/markdown-reader-more.txt b/test/markdown-reader-more.txt
new file mode 100644
index 000000000..0480e41cc
--- /dev/null
+++ b/test/markdown-reader-more.txt
@@ -0,0 +1,320 @@
+% Title
+ spanning multiple lines
+% Author One
+ Author Two; Author Three;
+ Author Four
+
+# Additional markdown reader tests
+
+## Blank line before URL in link reference
+
+[foo] and [bar]
+
+[foo]:
+ /url
+
+[bar]:
+/url
+"title"
+
+## Raw ConTeXt environments
+
+\placeformula \startformula
+ L_{1} = L_{2}
+ \stopformula
+
+\start[a2]
+\start[a2]
+\stop[a2]
+\stop[a2]
+
+## Raw LaTeX environments
+
+\begin{center}
+\begin{tikzpicture}[baseline={([yshift=+-.5ex]current bounding box.center)}, level distance=24pt]
+\Tree [.{S} [.NP John\index{i} ] [.VP [.V likes ] [.NP himself\index{i,*j} ]]]
+\end{tikzpicture}
+\end{center}
+
+## URLs with spaces and punctuation
+
+[foo](/bar and baz)
+[foo](/bar
+ and baz )
+[foo]( /bar and baz )
+[foo](bar baz "title" )
+
+[baz][] [bam][] [bork][]
+
+[baz]: /foo foo
+[bam]: /foo fee
+[bork]: /foo/zee zob (title)
+
+[Ward's method.](http://en.wikipedia.org/wiki/Ward's_method)
+
+## Horizontal rules with spaces at end
+
+* * * * *
+
+-- - -- -- -
+
+## Raw HTML before header
+
+<a></a>
+
+### my header
+
+## $ in math
+
+$\$2 + \$3$
+
+$x = \text{the $n$th root of $y$}$
+
+This should not be math:
+
+$PATH 90 $PATH
+
+## Commented-out list item
+
+- one
+<!--
+- two
+-->
+- three
+
+## Indented code at beginning of list
+
+- code
+ code
+
+ 1. code
+ code
+
+ 12345678. code
+ code
+
+ - code
+ code
+
+ - no code
+
+## Backslash newline
+
+hi\
+there
+
+## Code spans
+
+`hi\`
+
+`hi
+there`
+
+`` hi````there ``
+
+`hi
+
+there`
+
+## Multilingual URLs
+
+<http://测.com?测=测>
+
+[foo](/bar/测?x=测 "title")
+
+<测@foo.测.baz>
+
+## Numbered examples
+
+(@) First example.
+(@foo) Second example.
+
+Explanation of examples (@foo) and (@bar).
+
+(@bar) Third example.
+
+## Macros
+
+\newcommand{\tuple}[1]{\langle #1 \rangle}
+
+$\tuple{x,y}$
+
+## Case-insensitive references
+
+[Fum]
+
+[FUM]
+
+[bat]
+
+[fum]: /fum
+[BAT]: /bat
+
+## Curly smart quotes
+
+“Hi”
+
+‘Hi’
+
+## Consecutive lists
+
+- one
+- two
+1. one
+2. two
+
+ a. one
+ b. two
+
+## Implicit header references
+
+### My header
+
+### My other header
+
+A link to [My header].
+
+Another link to [it][My header].
+
+Should be [case insensitive][my header].
+
+Link to [Explicit header attributes].
+
+[my other header]: /foo
+
+But this is not a link to [My other header], since the reference is defined.
+
+## Explicit header attributes {#foobar .baz key="val"}
+
+> ## Header attributes inside block quote {#foobar .baz key="val"}
+
+## Line blocks
+
+| But can a bee be said to be
+| or not to be an entire bee,
+| when half the bee is not a bee,
+| due to some ancient injury?
+|
+| Continuation
+ line
+| and
+ another
+
+## Grid Tables
+
++------------------+-----------+------------+
+| col 1 | col 2 | col 3 |
++==================+===========+============+
+| r1 a | b | c |
+| r1 bis | b 2 | c 2 |
++------------------+-----------+------------+
+| r2 d | e | f |
++------------------+-----------+------------+
+
+Headless
+
++------------------+-----------+------------+
+| r1 a | b | c |
+| r1 bis | b 2 | c 2 |
++------------------+-----------+------------+
+| r2 d | e | f |
++------------------+-----------+------------+
+
+With alignments
+
++------------------+-----------+------------+
+| col 1 | col 2 | col 3 |
++=================:+:==========+:==========:+
+| r1 a | b | c |
+| r1 bis | b 2 | c 2 |
++------------------+-----------+------------+
+| r2 d | e | f |
++------------------+-----------+------------+
+
+Headless with alignments
+
++-----------------:+:----------+:----------:+
+| r1 a | b | c |
+| r1 bis | b 2 | c 2 |
++------------------+-----------+------------+
+| r2 d | e | f |
++------------------+-----------+------------+
+
+Spaces at ends of lines
+
++------------------+-----------+------------+
+| r1 a | b | c |
+| r1 bis | b 2 | c 2 |
++------------------+-----------+------------+
+| r2 d | e | f |
++------------------+-----------+------------+
+
+Multiple blocks in a cell
+
++------------------+-----------+------------+
+| # col 1 | # col 2 | # col 3 |
+| col 1 | col 2 | col 3 |
++------------------+-----------+------------+
+| r1 a | - b | c |
+| | - b 2 | c 2 |
+| r1 bis | - b 2 | c 2 |
++------------------+-----------+------------+
+
+Empty cells
+
++---+---+
+| | |
++---+---+
+
+## Entities in links and titles
+
+[link](/&uuml;rl "&ouml;&ouml;!")
+
+<http://g&ouml;&ouml;gle.com>
+
+<me@ex&auml;mple.com>
+
+[foobar]
+
+[foobar]: /&uuml;rl "&ouml;&ouml;!"
+
+## Parentheses in URLs
+
+[link](/hi(there))
+
+[link](/hithere\))
+
+[linky]
+
+[linky]: hi_(there_(nested))
+
+## Backslashes in link references
+
+[\*\a](b)
+
+## Reference link fallbacks
+
+[*not a link*] [*nope*]...
+
+## Reference link followed by a citation
+
+MapReduce is a paradigm popularized by [Google] [@mapreduce] as its
+most vocal proponent.
+
+[Google]: http://google.com
+
+## Empty reference links
+
+[foo2]:
+
+bar
+
+[foo2]
+
+## Wrapping shouldn't introduce new list items
+
+- blah blah blah blah blah blah blah blah blah blah blah blah blah blah 2015.
+
+## Bracketed spans
+
+[*foo* bar baz [link](url)]{.class #id key=val}
diff --git a/tests/media/rId25.jpg b/test/media/rId25.jpg
index 277ace7d1..277ace7d1 100644
--- a/tests/media/rId25.jpg
+++ b/test/media/rId25.jpg
Binary files differ
diff --git a/tests/media/rId26.jpg b/test/media/rId26.jpg
index 277ace7d1..277ace7d1 100644
--- a/tests/media/rId26.jpg
+++ b/test/media/rId26.jpg
Binary files differ
diff --git a/tests/media/rId27.jpg b/test/media/rId27.jpg
index 277ace7d1..277ace7d1 100644
--- a/tests/media/rId27.jpg
+++ b/test/media/rId27.jpg
Binary files differ
diff --git a/tests/mediawiki-reader.native b/test/mediawiki-reader.native
index 6afeb602c..6afeb602c 100644
--- a/tests/mediawiki-reader.native
+++ b/test/mediawiki-reader.native
diff --git a/tests/mediawiki-reader.wiki b/test/mediawiki-reader.wiki
index 11cd52d9c..11cd52d9c 100644
--- a/tests/mediawiki-reader.wiki
+++ b/test/mediawiki-reader.wiki
diff --git a/tests/movie.jpg b/test/movie.jpg
index 7240efa3b..7240efa3b 100644
--- a/tests/movie.jpg
+++ b/test/movie.jpg
Binary files differ
diff --git a/tests/odt/markdown/bold.md b/test/odt/markdown/bold.md
index fa4eb0431..fa4eb0431 100644
--- a/tests/odt/markdown/bold.md
+++ b/test/odt/markdown/bold.md
diff --git a/tests/odt/markdown/citation.md b/test/odt/markdown/citation.md
index adcc9f0ff..adcc9f0ff 100644
--- a/tests/odt/markdown/citation.md
+++ b/test/odt/markdown/citation.md
diff --git a/tests/odt/markdown/endnote.md b/test/odt/markdown/endnote.md
index 679af3fdc..679af3fdc 100644
--- a/tests/odt/markdown/endnote.md
+++ b/test/odt/markdown/endnote.md
diff --git a/tests/odt/markdown/externalLink.md b/test/odt/markdown/externalLink.md
index 14f48d0f5..14f48d0f5 100644
--- a/tests/odt/markdown/externalLink.md
+++ b/test/odt/markdown/externalLink.md
diff --git a/tests/odt/markdown/footnote.md b/test/odt/markdown/footnote.md
index 973ae2d3a..973ae2d3a 100644
--- a/tests/odt/markdown/footnote.md
+++ b/test/odt/markdown/footnote.md
diff --git a/tests/odt/markdown/headers.md b/test/odt/markdown/headers.md
index ea5d4452c..ea5d4452c 100644
--- a/tests/odt/markdown/headers.md
+++ b/test/odt/markdown/headers.md
diff --git a/tests/odt/markdown/horizontalRule.md b/test/odt/markdown/horizontalRule.md
index 73b314ff7..73b314ff7 100644
--- a/tests/odt/markdown/horizontalRule.md
+++ b/test/odt/markdown/horizontalRule.md
diff --git a/tests/odt/markdown/image.md b/test/odt/markdown/image.md
index 3862d709e..3862d709e 100644
--- a/tests/odt/markdown/image.md
+++ b/test/odt/markdown/image.md
diff --git a/tests/odt/markdown/imageIndex.md b/test/odt/markdown/imageIndex.md
index 6719ab8a8..6719ab8a8 100644
--- a/tests/odt/markdown/imageIndex.md
+++ b/test/odt/markdown/imageIndex.md
diff --git a/tests/odt/markdown/imageWithCaption.md b/test/odt/markdown/imageWithCaption.md
index 0046ae141..0046ae141 100644
--- a/tests/odt/markdown/imageWithCaption.md
+++ b/test/odt/markdown/imageWithCaption.md
diff --git a/tests/odt/markdown/italic.md b/test/odt/markdown/italic.md
index b4d2f3d40..b4d2f3d40 100644
--- a/tests/odt/markdown/italic.md
+++ b/test/odt/markdown/italic.md
diff --git a/tests/odt/markdown/listBlocks.md b/test/odt/markdown/listBlocks.md
index 22c77bb2b..22c77bb2b 100644
--- a/tests/odt/markdown/listBlocks.md
+++ b/test/odt/markdown/listBlocks.md
diff --git a/tests/odt/markdown/paragraph.md b/test/odt/markdown/paragraph.md
index 0a822e322..0a822e322 100644
--- a/tests/odt/markdown/paragraph.md
+++ b/test/odt/markdown/paragraph.md
diff --git a/tests/odt/markdown/strikeout.md b/test/odt/markdown/strikeout.md
index 6ae4571dd..6ae4571dd 100644
--- a/tests/odt/markdown/strikeout.md
+++ b/test/odt/markdown/strikeout.md
diff --git a/tests/odt/markdown/trackedChanges.md b/test/odt/markdown/trackedChanges.md
index f0bd478a3..f0bd478a3 100644
--- a/tests/odt/markdown/trackedChanges.md
+++ b/test/odt/markdown/trackedChanges.md
diff --git a/tests/odt/markdown/underlined.md b/test/odt/markdown/underlined.md
index 05fb92379..05fb92379 100644
--- a/tests/odt/markdown/underlined.md
+++ b/test/odt/markdown/underlined.md
diff --git a/tests/odt/native/blockquote.native b/test/odt/native/blockquote.native
index 8c9409dde..8c9409dde 100644
--- a/tests/odt/native/blockquote.native
+++ b/test/odt/native/blockquote.native
diff --git a/tests/odt/native/image.native b/test/odt/native/image.native
index 667442539..667442539 100644
--- a/tests/odt/native/image.native
+++ b/test/odt/native/image.native
diff --git a/tests/odt/native/imageIndex.native b/test/odt/native/imageIndex.native
index fe7b69c16..fe7b69c16 100644
--- a/tests/odt/native/imageIndex.native
+++ b/test/odt/native/imageIndex.native
diff --git a/tests/odt/native/imageWithCaption.native b/test/odt/native/imageWithCaption.native
index fe7b69c16..fe7b69c16 100644
--- a/tests/odt/native/imageWithCaption.native
+++ b/test/odt/native/imageWithCaption.native
diff --git a/tests/odt/native/inlinedCode.native b/test/odt/native/inlinedCode.native
index 6e32ff7a9..6e32ff7a9 100644
--- a/tests/odt/native/inlinedCode.native
+++ b/test/odt/native/inlinedCode.native
diff --git a/tests/odt/native/orderedListMixed.native b/test/odt/native/orderedListMixed.native
index c2c8586af..c2c8586af 100644
--- a/tests/odt/native/orderedListMixed.native
+++ b/test/odt/native/orderedListMixed.native
diff --git a/tests/odt/native/orderedListRoman.native b/test/odt/native/orderedListRoman.native
index 73bbbf1c9..73bbbf1c9 100644
--- a/tests/odt/native/orderedListRoman.native
+++ b/test/odt/native/orderedListRoman.native
diff --git a/tests/odt/native/orderedListSimple.native b/test/odt/native/orderedListSimple.native
index 0b1f85231..0b1f85231 100644
--- a/tests/odt/native/orderedListSimple.native
+++ b/test/odt/native/orderedListSimple.native
diff --git a/tests/odt/native/referenceToChapter.native b/test/odt/native/referenceToChapter.native
index 544fcaaf1..544fcaaf1 100644
--- a/tests/odt/native/referenceToChapter.native
+++ b/test/odt/native/referenceToChapter.native
diff --git a/tests/odt/native/referenceToListItem.native b/test/odt/native/referenceToListItem.native
index e64389ce6..e64389ce6 100644
--- a/tests/odt/native/referenceToListItem.native
+++ b/test/odt/native/referenceToListItem.native
diff --git a/tests/odt/native/referenceToText.native b/test/odt/native/referenceToText.native
index a2c3e588d..a2c3e588d 100644
--- a/tests/odt/native/referenceToText.native
+++ b/test/odt/native/referenceToText.native
diff --git a/tests/odt/native/simpleTable.native b/test/odt/native/simpleTable.native
index 0a9b380a5..0a9b380a5 100644
--- a/tests/odt/native/simpleTable.native
+++ b/test/odt/native/simpleTable.native
diff --git a/tests/odt/native/simpleTableWithCaption.native b/test/odt/native/simpleTableWithCaption.native
index 18d68b772..18d68b772 100644
--- a/tests/odt/native/simpleTableWithCaption.native
+++ b/test/odt/native/simpleTableWithCaption.native
diff --git a/tests/odt/native/tableWithContents.native b/test/odt/native/tableWithContents.native
index b1d3c5765..b1d3c5765 100644
--- a/tests/odt/native/tableWithContents.native
+++ b/test/odt/native/tableWithContents.native
diff --git a/tests/odt/native/textMixedStyles.native b/test/odt/native/textMixedStyles.native
index 1347867c6..1347867c6 100644
--- a/tests/odt/native/textMixedStyles.native
+++ b/test/odt/native/textMixedStyles.native
diff --git a/tests/odt/native/unicode.native b/test/odt/native/unicode.native
index b6ac9760c..b6ac9760c 100644
--- a/tests/odt/native/unicode.native
+++ b/test/odt/native/unicode.native
diff --git a/tests/odt/native/unorderedList.native b/test/odt/native/unorderedList.native
index a8c083d13..a8c083d13 100644
--- a/tests/odt/native/unorderedList.native
+++ b/test/odt/native/unorderedList.native
diff --git a/tests/odt/odt/blockquote.odt b/test/odt/odt/blockquote.odt
index 0114e308f..0114e308f 100644
--- a/tests/odt/odt/blockquote.odt
+++ b/test/odt/odt/blockquote.odt
Binary files differ
diff --git a/tests/odt/odt/bold.odt b/test/odt/odt/bold.odt
index 49285722e..49285722e 100644
--- a/tests/odt/odt/bold.odt
+++ b/test/odt/odt/bold.odt
Binary files differ
diff --git a/tests/odt/odt/citation.odt b/test/odt/odt/citation.odt
index b6dbe649e..b6dbe649e 100644
--- a/tests/odt/odt/citation.odt
+++ b/test/odt/odt/citation.odt
Binary files differ
diff --git a/tests/odt/odt/endnote.odt b/test/odt/odt/endnote.odt
index c1aba45da..c1aba45da 100644
--- a/tests/odt/odt/endnote.odt
+++ b/test/odt/odt/endnote.odt
Binary files differ
diff --git a/tests/odt/odt/expression.odt b/test/odt/odt/expression.odt
index 1085d7008..1085d7008 100644
--- a/tests/odt/odt/expression.odt
+++ b/test/odt/odt/expression.odt
Binary files differ
diff --git a/tests/odt/odt/expressionUnevaluated.odt b/test/odt/odt/expressionUnevaluated.odt
index 64df660b6..64df660b6 100644
--- a/tests/odt/odt/expressionUnevaluated.odt
+++ b/test/odt/odt/expressionUnevaluated.odt
Binary files differ
diff --git a/tests/odt/odt/externalLink.odt b/test/odt/odt/externalLink.odt
index 1d8f55489..1d8f55489 100644
--- a/tests/odt/odt/externalLink.odt
+++ b/test/odt/odt/externalLink.odt
Binary files differ
diff --git a/tests/odt/odt/footnote.odt b/test/odt/odt/footnote.odt
index 74915c33c..74915c33c 100644
--- a/tests/odt/odt/footnote.odt
+++ b/test/odt/odt/footnote.odt
Binary files differ
diff --git a/tests/odt/odt/formula.odt b/test/odt/odt/formula.odt
index 5cf5f3451..5cf5f3451 100644
--- a/tests/odt/odt/formula.odt
+++ b/test/odt/odt/formula.odt
Binary files differ
diff --git a/tests/odt/odt/headers.odt b/test/odt/odt/headers.odt
index 9212e9fb1..9212e9fb1 100644
--- a/tests/odt/odt/headers.odt
+++ b/test/odt/odt/headers.odt
Binary files differ
diff --git a/tests/odt/odt/hiddenTextByStyle.odt b/test/odt/odt/hiddenTextByStyle.odt
index 79c40ca98..79c40ca98 100644
--- a/tests/odt/odt/hiddenTextByStyle.odt
+++ b/test/odt/odt/hiddenTextByStyle.odt
Binary files differ
diff --git a/tests/odt/odt/hiddenTextByVariable.odt b/test/odt/odt/hiddenTextByVariable.odt
index ec793d466..ec793d466 100644
--- a/tests/odt/odt/hiddenTextByVariable.odt
+++ b/test/odt/odt/hiddenTextByVariable.odt
Binary files differ
diff --git a/tests/odt/odt/horizontalRule.odt b/test/odt/odt/horizontalRule.odt
index df09386bc..df09386bc 100644
--- a/tests/odt/odt/horizontalRule.odt
+++ b/test/odt/odt/horizontalRule.odt
Binary files differ
diff --git a/tests/odt/odt/image.odt b/test/odt/odt/image.odt
index c2fd1e407..c2fd1e407 100644
--- a/tests/odt/odt/image.odt
+++ b/test/odt/odt/image.odt
Binary files differ
diff --git a/tests/odt/odt/imageIndex.odt b/test/odt/odt/imageIndex.odt
index 220a49047..220a49047 100644
--- a/tests/odt/odt/imageIndex.odt
+++ b/test/odt/odt/imageIndex.odt
Binary files differ
diff --git a/tests/odt/odt/imageWithCaption.odt b/test/odt/odt/imageWithCaption.odt
index 99b5b7af1..99b5b7af1 100644
--- a/tests/odt/odt/imageWithCaption.odt
+++ b/test/odt/odt/imageWithCaption.odt
Binary files differ
diff --git a/tests/odt/odt/inlinedCode.odt b/test/odt/odt/inlinedCode.odt
index 320375cc9..320375cc9 100644
--- a/tests/odt/odt/inlinedCode.odt
+++ b/test/odt/odt/inlinedCode.odt
Binary files differ
diff --git a/tests/odt/odt/italic.odt b/test/odt/odt/italic.odt
index d05cfeade..d05cfeade 100644
--- a/tests/odt/odt/italic.odt
+++ b/test/odt/odt/italic.odt
Binary files differ
diff --git a/tests/odt/odt/listBlocks.odt b/test/odt/odt/listBlocks.odt
index 5855e9920..5855e9920 100644
--- a/tests/odt/odt/listBlocks.odt
+++ b/test/odt/odt/listBlocks.odt
Binary files differ
diff --git a/tests/odt/odt/orderedListMixed.odt b/test/odt/odt/orderedListMixed.odt
index 2b593d635..2b593d635 100644
--- a/tests/odt/odt/orderedListMixed.odt
+++ b/test/odt/odt/orderedListMixed.odt
Binary files differ
diff --git a/tests/odt/odt/orderedListRoman.odt b/test/odt/odt/orderedListRoman.odt
index 0acfe92ce..0acfe92ce 100644
--- a/tests/odt/odt/orderedListRoman.odt
+++ b/test/odt/odt/orderedListRoman.odt
Binary files differ
diff --git a/tests/odt/odt/orderedListSimple.odt b/test/odt/odt/orderedListSimple.odt
index 7af312fcc..7af312fcc 100644
--- a/tests/odt/odt/orderedListSimple.odt
+++ b/test/odt/odt/orderedListSimple.odt
Binary files differ
diff --git a/tests/odt/odt/paragraph.odt b/test/odt/odt/paragraph.odt
index b635b2164..b635b2164 100644
--- a/tests/odt/odt/paragraph.odt
+++ b/test/odt/odt/paragraph.odt
Binary files differ
diff --git a/tests/odt/odt/referenceAllInOne.odt b/test/odt/odt/referenceAllInOne.odt
index e9f38e359..e9f38e359 100644
--- a/tests/odt/odt/referenceAllInOne.odt
+++ b/test/odt/odt/referenceAllInOne.odt
Binary files differ
diff --git a/tests/odt/odt/referenceToChapter.odt b/test/odt/odt/referenceToChapter.odt
index d4be67b0b..d4be67b0b 100644
--- a/tests/odt/odt/referenceToChapter.odt
+++ b/test/odt/odt/referenceToChapter.odt
Binary files differ
diff --git a/tests/odt/odt/referenceToListItem.odt b/test/odt/odt/referenceToListItem.odt
index be3aed245..be3aed245 100644
--- a/tests/odt/odt/referenceToListItem.odt
+++ b/test/odt/odt/referenceToListItem.odt
Binary files differ
diff --git a/tests/odt/odt/referenceToText.odt b/test/odt/odt/referenceToText.odt
index 19237e6f1..19237e6f1 100644
--- a/tests/odt/odt/referenceToText.odt
+++ b/test/odt/odt/referenceToText.odt
Binary files differ
diff --git a/tests/odt/odt/simpleTable.odt b/test/odt/odt/simpleTable.odt
index a00622918..a00622918 100644
--- a/tests/odt/odt/simpleTable.odt
+++ b/test/odt/odt/simpleTable.odt
Binary files differ
diff --git a/tests/odt/odt/simpleTableWithCaption.odt b/test/odt/odt/simpleTableWithCaption.odt
index ec6fac894..ec6fac894 100644
--- a/tests/odt/odt/simpleTableWithCaption.odt
+++ b/test/odt/odt/simpleTableWithCaption.odt
Binary files differ
diff --git a/tests/odt/odt/strikeout.odt b/test/odt/odt/strikeout.odt
index 3a3f1543a..3a3f1543a 100644
--- a/tests/odt/odt/strikeout.odt
+++ b/test/odt/odt/strikeout.odt
Binary files differ
diff --git a/tests/odt/odt/table.odt b/test/odt/odt/table.odt
index 7a2b1cfae..7a2b1cfae 100644
--- a/tests/odt/odt/table.odt
+++ b/test/odt/odt/table.odt
Binary files differ
diff --git a/tests/odt/odt/tableWithCaption.odt b/test/odt/odt/tableWithCaption.odt
index d44654460..d44654460 100644
--- a/tests/odt/odt/tableWithCaption.odt
+++ b/test/odt/odt/tableWithCaption.odt
Binary files differ
diff --git a/tests/odt/odt/tableWithContents.odt b/test/odt/odt/tableWithContents.odt
index 392e4202c..392e4202c 100644
--- a/tests/odt/odt/tableWithContents.odt
+++ b/test/odt/odt/tableWithContents.odt
Binary files differ
diff --git a/tests/odt/odt/textMixedStyles.odt b/test/odt/odt/textMixedStyles.odt
index 382b338ad..382b338ad 100644
--- a/tests/odt/odt/textMixedStyles.odt
+++ b/test/odt/odt/textMixedStyles.odt
Binary files differ
diff --git a/tests/odt/odt/trackedChanges.odt b/test/odt/odt/trackedChanges.odt
index 5ac493ed7..5ac493ed7 100644
--- a/tests/odt/odt/trackedChanges.odt
+++ b/test/odt/odt/trackedChanges.odt
Binary files differ
diff --git a/tests/odt/odt/underlined.odt b/test/odt/odt/underlined.odt
index d645717b8..d645717b8 100644
--- a/tests/odt/odt/underlined.odt
+++ b/test/odt/odt/underlined.odt
Binary files differ
diff --git a/tests/odt/odt/unicode.odt b/test/odt/odt/unicode.odt
index 07e200425..07e200425 100644
--- a/tests/odt/odt/unicode.odt
+++ b/test/odt/odt/unicode.odt
Binary files differ
diff --git a/tests/odt/odt/unorderedList.odt b/test/odt/odt/unorderedList.odt
index 50a950024..50a950024 100644
--- a/tests/odt/odt/unorderedList.odt
+++ b/test/odt/odt/unorderedList.odt
Binary files differ
diff --git a/tests/odt/odt/variable.odt b/test/odt/odt/variable.odt
index 73ff5f648..73ff5f648 100644
--- a/tests/odt/odt/variable.odt
+++ b/test/odt/odt/variable.odt
Binary files differ
diff --git a/tests/opml-reader.native b/test/opml-reader.native
index 0819116ab..0819116ab 100644
--- a/tests/opml-reader.native
+++ b/test/opml-reader.native
diff --git a/tests/opml-reader.opml b/test/opml-reader.opml
index 18436e675..18436e675 100644
--- a/tests/opml-reader.opml
+++ b/test/opml-reader.opml
diff --git a/test/pipe-tables.native b/test/pipe-tables.native
new file mode 100644
index 000000000..ca9858d1f
--- /dev/null
+++ b/test/pipe-tables.native
@@ -0,0 +1,115 @@
+[Para [Str "Simplest",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "Default1"]]
+ ,[Plain [Str "Default2"]]
+ ,[Plain [Str "Default3"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"]
+,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignRight,AlignLeft,AlignDefault,AlignCenter] [0.0,0.0,0.0,0.0]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Default"]]
+ ,[Plain [Str "Center"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Simple",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+,Table [] [AlignRight,AlignLeft,AlignCenter] [0.0,0.0,0.0]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Headerless",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+,Table [] [AlignRight,AlignLeft,AlignCenter] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Table",Space,Str "without",Space,Str "sides:"]
+,Table [] [AlignDefault,AlignRight] [0.0,0.0]
+ [[Plain [Str "Fruit"]]
+ ,[Plain [Str "Quantity"]]]
+ [[[Plain [Str "apple"]]
+ ,[Plain [Str "5"]]]
+ ,[[Plain [Str "orange"]]
+ ,[Plain [Str "17"]]]
+ ,[[Plain [Str "pear"]]
+ ,[Plain [Str "302"]]]]
+,Para [Str "One-column:"]
+,Table [] [AlignDefault] [0.0]
+ [[Plain [Str "hi"]]]
+ [[[Plain [Str "lo"]]]]
+,Para [Str "Header-less",Space,Str "one-column:"]
+,Table [] [AlignCenter] [0.0]
+ [[]]
+ [[[Plain [Str "hi"]]]]
+,Para [Str "Indented",Space,Str "left",Space,Str "column:"]
+,Table [] [AlignRight,AlignLeft] [0.0,0.0]
+ [[Plain [Str "Number",Space,Str "of",Space,Str "siblings"]]
+ ,[Plain [Str "Salary"]]]
+ [[[Plain [Str "3"]]
+ ,[Plain [Str "33"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "44"]]]]
+,Para [Str "Long",Space,Str "pipe",Space,Str "table",Space,Str "with",Space,Str "relative",Space,Str "widths:"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.15517241379310345,0.1724137931034483,0.6724137931034483]
+ [[Plain [Str "Default1"]]
+ ,[Plain [Str "Default2"]]
+ ,[Plain [Str "Default3"]]]
+ [[[Plain [Str "123"]]
+ ,[Plain [Str "this",Space,Str "is",Space,Str "a",Space,Str "table",Space,Str "cell"]]
+ ,[Plain [Str "and",Space,Str "this",Space,Str "is",Space,Str "a",Space,Str "really",Space,Str "long",Space,Str "table",Space,Str "cell",Space,Str "that",Space,Str "will",Space,Str "probably",Space,Str "need",Space,Str "wrapping"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]]
+,Para [Str "Pipe",Space,Str "table",Space,Str "with",Space,Str "no",Space,Str "body:"]
+,Table [] [AlignDefault] [0.0]
+ [[Plain [Str "Header"]]]
+ []
+,Para [Str "Pipe",Space,Str "table",Space,Str "with",Space,Str "tricky",Space,Str "cell",Space,Str "contents",Space,Str "(see",Space,Str "#2765):"]
+,Table [] [AlignLeft,AlignRight,AlignRight] [0.0,0.0,0.0]
+ [[]
+ ,[Plain [Str "IP_gene8-_1st"]]
+ ,[Plain [Str "IP_gene8+_1st"]]]
+ [[[Plain [Str "IP_gene8-_1st"]]
+ ,[Plain [Str "1.0000000"]]
+ ,[Plain [Str "0.4357325"]]]
+ ,[[Plain [Str "IP_gene8+_1st"]]
+ ,[Plain [Str "0.4357325"]]
+ ,[Plain [Str "1.0000000"]]]
+ ,[[Plain [Str "foo",Code ("",[],[]) "bar|baz"]]
+ ,[Plain [Str "and|escaped"]]
+ ,[Plain [Str "3.0000000"]]]]]
diff --git a/tests/pipe-tables.txt b/test/pipe-tables.txt
index c27c71113..c27c71113 100644
--- a/tests/pipe-tables.txt
+++ b/test/pipe-tables.txt
diff --git a/test/pptx/endnotes.native b/test/pptx/endnotes.native
new file mode 100644
index 000000000..f6caeb62f
--- /dev/null
+++ b/test/pptx/endnotes.native
@@ -0,0 +1,2 @@
+Pandoc (Meta {unMeta = fromList []})
+[Para [Str "Here",Space,Str "is",Space,Str "one",Space,Str "note.",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "note."]],Space,Str "And",Space,Str "one",Space,Str "more",Space,Str "note.",Note [Para [Str "And",Space,Str "another",Space,Str "note."]]]]
diff --git a/test/pptx/endnotes.pptx b/test/pptx/endnotes.pptx
new file mode 100644
index 000000000..f9bb17937
--- /dev/null
+++ b/test/pptx/endnotes.pptx
Binary files differ
diff --git a/test/pptx/endnotes_templated.pptx b/test/pptx/endnotes_templated.pptx
new file mode 100644
index 000000000..51501ec8c
--- /dev/null
+++ b/test/pptx/endnotes_templated.pptx
Binary files differ
diff --git a/test/pptx/endnotes_toc.pptx b/test/pptx/endnotes_toc.pptx
new file mode 100644
index 000000000..ec09e6f9d
--- /dev/null
+++ b/test/pptx/endnotes_toc.pptx
Binary files differ
diff --git a/test/pptx/endnotes_toc_templated.pptx b/test/pptx/endnotes_toc_templated.pptx
new file mode 100644
index 000000000..77cd3ba58
--- /dev/null
+++ b/test/pptx/endnotes_toc_templated.pptx
Binary files differ
diff --git a/test/pptx/images.native b/test/pptx/images.native
new file mode 100644
index 000000000..54827e5cc
--- /dev/null
+++ b/test/pptx/images.native
@@ -0,0 +1,5 @@
+Pandoc (Meta {unMeta = fromList []})
+[Para [Image ("",[],[]) [] ("lalune.jpg","")]
+,Para [Image ("",[],[]) [Str "The",Space,Str "Moon"] ("lalune.jpg","fig:")]
+,Header 1 ("one-more",[],[]) [Str "One",Space,Str "More"]
+,Para [Image ("",[],[]) [Str "The",Space,Str "Moon"] ("lalune.jpg","fig:")]]
diff --git a/test/pptx/images.pptx b/test/pptx/images.pptx
new file mode 100644
index 000000000..c9798422f
--- /dev/null
+++ b/test/pptx/images.pptx
Binary files differ
diff --git a/test/pptx/images_templated.pptx b/test/pptx/images_templated.pptx
new file mode 100644
index 000000000..76825e891
--- /dev/null
+++ b/test/pptx/images_templated.pptx
Binary files differ
diff --git a/test/pptx/inline_formatting.native b/test/pptx/inline_formatting.native
new file mode 100644
index 000000000..d79220e4f
--- /dev/null
+++ b/test/pptx/inline_formatting.native
@@ -0,0 +1,5 @@
+Pandoc (Meta {unMeta = fromList []})
+[Para [Str "Here",Space,Str "are",Space,Str "examples",Space,Str "of",Space,Emph [Str "italics"],Str ",",Space,Strong [Str "bold"],Str ",",Space,Str "and",Space,Strong [Emph [Str "bold",Space,Str "italics"]],Str "."]
+,Para [Str "Here",Space,Str "is",Space,Strikeout [Str "strook-three"],Space,Str "strike-through",Space,Str "and",Space,SmallCaps [Str "small",Space,Str "caps"],Str "."]
+,Para [Str "We",Space,Str "can",Space,Str "also",Space,Str "do",Space,Str "subscripts",Space,Str "(H",Subscript [Str "2"],Str "0)",Space,Str "and",Space,Str "super",Superscript [Str "script"],Str "."]
+,RawBlock (Format "html") "<!-- Comments don't show up. -->"]
diff --git a/test/pptx/inline_formatting.pptx b/test/pptx/inline_formatting.pptx
new file mode 100644
index 000000000..3a69400ff
--- /dev/null
+++ b/test/pptx/inline_formatting.pptx
Binary files differ
diff --git a/test/pptx/inline_formatting_templated.pptx b/test/pptx/inline_formatting_templated.pptx
new file mode 100644
index 000000000..ca44d82e6
--- /dev/null
+++ b/test/pptx/inline_formatting_templated.pptx
Binary files differ
diff --git a/test/pptx/lists.native b/test/pptx/lists.native
new file mode 100644
index 000000000..e08580cd5
--- /dev/null
+++ b/test/pptx/lists.native
@@ -0,0 +1,18 @@
+[Header 1 ("lists",[],[]) [Str "Lists"]
+,BulletList
+ [[Para [Str "Bulleted",Space,Str "bulleted",Space,Str "lists."]]
+ ,[Para [Str "And",Space,Str "go",Space,Str "to",Space,Str "aribtrary",Space,Str "depth."]
+ ,BulletList
+ [[Para [Str "Like",Space,Str "this"]
+ ,BulletList
+ [[Plain [Str "Or",Space,Str "this"]]]]
+ ,[Para [Str "Back",Space,Str "to",Space,Str "here."]]]]]
+,Header 1 ("lists-continued",[],[]) [Str "Lists",Space,Str "(continued)"]
+,Para [Str "Lists",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "numbered:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "Tomatoes"]]
+ ,[Para [Str "Potatoes",Space,Str "of",Space,Str "various",Space,Str "sorts"]
+ ,OrderedList (1,LowerAlpha,Period)
+ [[Para [Str "sweet",Space,Str "potatoes"]]
+ ,[Para [Str "russet",Space,Str "potates"]]]]
+ ,[Para [Str "Tornadoes,",Space,Str "for",Space,Str "the",Space,Str "rhyme."]]]]
diff --git a/test/pptx/lists.pptx b/test/pptx/lists.pptx
new file mode 100644
index 000000000..acb0841ce
--- /dev/null
+++ b/test/pptx/lists.pptx
Binary files differ
diff --git a/test/pptx/lists_templated.pptx b/test/pptx/lists_templated.pptx
new file mode 100644
index 000000000..14570c951
--- /dev/null
+++ b/test/pptx/lists_templated.pptx
Binary files differ
diff --git a/test/pptx/reference_depth.pptx b/test/pptx/reference_depth.pptx
new file mode 100644
index 000000000..6906cf49d
--- /dev/null
+++ b/test/pptx/reference_depth.pptx
Binary files differ
diff --git a/test/pptx/remove_empty_slides.native b/test/pptx/remove_empty_slides.native
new file mode 100644
index 000000000..51c042281
--- /dev/null
+++ b/test/pptx/remove_empty_slides.native
@@ -0,0 +1,5 @@
+[Para [Str "Content"]
+,Para [Image ("",[],[]) [] ("lalune.jpg",""),Space,RawInline (Format "html") "<!-- -->"]
+,HorizontalRule
+,HorizontalRule
+,Para [Str "More",Space,Str "content"]]
diff --git a/test/pptx/remove_empty_slides.pptx b/test/pptx/remove_empty_slides.pptx
new file mode 100644
index 000000000..3b4843aa6
--- /dev/null
+++ b/test/pptx/remove_empty_slides.pptx
Binary files differ
diff --git a/test/pptx/remove_empty_slides_templated.pptx b/test/pptx/remove_empty_slides_templated.pptx
new file mode 100644
index 000000000..1efe33212
--- /dev/null
+++ b/test/pptx/remove_empty_slides_templated.pptx
Binary files differ
diff --git a/test/pptx/slide_breaks.native b/test/pptx/slide_breaks.native
new file mode 100644
index 000000000..084c61737
--- /dev/null
+++ b/test/pptx/slide_breaks.native
@@ -0,0 +1,7 @@
+Pandoc (Meta {unMeta = fromList []})
+[Para [Str "Break",Space,Str "with",Space,Str "a",Space,Str "new",Space,Str "section-level",Space,Str "header"]
+,Header 1 ("below-section-level",[],[]) [Str "Below",Space,Str "section-level"]
+,Header 2 ("section-level",[],[]) [Str "Section-level"]
+,Para [Str "Third",Space,Str "slide",Space,Str "(with",Space,Str "a",Space,Str "section-level",Space,Str "of",Space,Str "2)"]
+,HorizontalRule
+,Para [Str "This",Space,Str "is",Space,Str "another",Space,Str "slide."]]
diff --git a/test/pptx/slide_breaks.pptx b/test/pptx/slide_breaks.pptx
new file mode 100644
index 000000000..dabb58117
--- /dev/null
+++ b/test/pptx/slide_breaks.pptx
Binary files differ
diff --git a/test/pptx/slide_breaks_slide_level_1.pptx b/test/pptx/slide_breaks_slide_level_1.pptx
new file mode 100644
index 000000000..65a44737d
--- /dev/null
+++ b/test/pptx/slide_breaks_slide_level_1.pptx
Binary files differ
diff --git a/test/pptx/slide_breaks_slide_level_1_templated.pptx b/test/pptx/slide_breaks_slide_level_1_templated.pptx
new file mode 100644
index 000000000..3e0009c76
--- /dev/null
+++ b/test/pptx/slide_breaks_slide_level_1_templated.pptx
Binary files differ
diff --git a/test/pptx/slide_breaks_templated.pptx b/test/pptx/slide_breaks_templated.pptx
new file mode 100644
index 000000000..6df99735d
--- /dev/null
+++ b/test/pptx/slide_breaks_templated.pptx
Binary files differ
diff --git a/test/pptx/slide_breaks_toc.pptx b/test/pptx/slide_breaks_toc.pptx
new file mode 100644
index 000000000..b51e94fbd
--- /dev/null
+++ b/test/pptx/slide_breaks_toc.pptx
Binary files differ
diff --git a/test/pptx/slide_breaks_toc_templated.pptx b/test/pptx/slide_breaks_toc_templated.pptx
new file mode 100644
index 000000000..472f41cf4
--- /dev/null
+++ b/test/pptx/slide_breaks_toc_templated.pptx
Binary files differ
diff --git a/test/pptx/speaker_notes.native b/test/pptx/speaker_notes.native
new file mode 100644
index 000000000..4eeca2107
--- /dev/null
+++ b/test/pptx/speaker_notes.native
@@ -0,0 +1,17 @@
+[Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "slide."]
+,Div ("",["notes"],[])
+ [Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "note."]
+ ,Para [Str "Here",Space,Str "is",Space,Emph [Str "some"],Space,Strong [Str "other"],Space,Str "formatting."]]
+,HorizontalRule
+,Para [Str "A",Space,Str "page",Space,Str "with",Space,Str "no",Space,Str "speaker",Space,Str "notes"]
+,HorizontalRule
+,Div ("",["notes"],[])
+ [Para [Str "The",Space,Str "first",Space,Str "note",Space,Str "div"]]
+,Para [Str "A",Space,Str "page",Space,Str "with",Space,Str "two",Space,Str "notes."]
+,Div ("",["notes"],[])
+ [Para [Str "The",Space,Str "second",Space,Str "note",Space,Str "div"]]
+,HorizontalRule
+,Para [Str "Strip",Space,Str "links",Space,Str "and",Space,Str "footnotes."]
+,Div ("",["notes"],[])
+ [Para [Str "No",Space,Link ("",[],[]) [Str "link"] ("https://www.google.com",""),Space,Str "here."]
+ ,Para [Str "No",Space,Str "note",Space,Str "here.",Note [Para [Str "You\8217ll",Space,Str "never",Space,Str "read",Space,Str "this"]]]]]
diff --git a/test/pptx/speaker_notes.pptx b/test/pptx/speaker_notes.pptx
new file mode 100644
index 000000000..a9fad5ae4
--- /dev/null
+++ b/test/pptx/speaker_notes.pptx
Binary files differ
diff --git a/test/pptx/speaker_notes_templated.pptx b/test/pptx/speaker_notes_templated.pptx
new file mode 100644
index 000000000..9ae8ea1db
--- /dev/null
+++ b/test/pptx/speaker_notes_templated.pptx
Binary files differ
diff --git a/test/pptx/tables.native b/test/pptx/tables.native
new file mode 100644
index 000000000..e41b7bc8d
--- /dev/null
+++ b/test/pptx/tables.native
@@ -0,0 +1,35 @@
+[Header 2 ("a-table-with-a-caption",[],[]) [Str "A",Space,Str "Table,",Space,Str "with",Space,Str "a",Space,Str "caption"]
+,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax,",Space,Str "with",Space,Str "alignment"] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Table [] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]]
diff --git a/test/pptx/tables.pptx b/test/pptx/tables.pptx
new file mode 100644
index 000000000..c3e215a30
--- /dev/null
+++ b/test/pptx/tables.pptx
Binary files differ
diff --git a/test/pptx/tables_templated.pptx b/test/pptx/tables_templated.pptx
new file mode 100644
index 000000000..46f72edab
--- /dev/null
+++ b/test/pptx/tables_templated.pptx
Binary files differ
diff --git a/test/pptx/two_column.native b/test/pptx/two_column.native
new file mode 100644
index 000000000..086f74889
--- /dev/null
+++ b/test/pptx/two_column.native
@@ -0,0 +1,9 @@
+Pandoc (Meta {unMeta = fromList []})
+[Header 1 ("two-column-layout",[],[]) [Str "Two-Column",Space,Str "Layout"]
+,Div ("",["columns"],[])
+ [Div ("",["column"],[])
+ [Para [Str "One",Space,Str "paragraph."]
+ ,Para [Str "Another",Space,Str "paragraph."]]
+ ,Div ("",["column"],[])
+ [Para [Str "Second",Space,Str "column",Space,Str "paragraph."]
+ ,Para [Str "Another",Space,Str "second",Space,Str "paragraph."]]]]
diff --git a/test/pptx/two_column.pptx b/test/pptx/two_column.pptx
new file mode 100644
index 000000000..68b390bb7
--- /dev/null
+++ b/test/pptx/two_column.pptx
Binary files differ
diff --git a/test/pptx/two_column_templated.pptx b/test/pptx/two_column_templated.pptx
new file mode 100644
index 000000000..f74be1956
--- /dev/null
+++ b/test/pptx/two_column_templated.pptx
Binary files differ
diff --git a/test/rst-reader.native b/test/rst-reader.native
new file mode 100644
index 000000000..b0e51bd3f
--- /dev/null
+++ b/test/rst-reader.native
@@ -0,0 +1,335 @@
+Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("revision",MetaBlocks [Para [Str "3"]]),("subtitle",MetaInlines [Str "Subtitle"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
+[Header 1 ("level-one-header",[],[]) [Str "Level",Space,Str "one",Space,Str "header"]
+,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",SoftBreak,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+,Header 2 ("level-two-header",[],[]) [Str "Level",Space,Str "two",Space,Str "header"]
+,Header 3 ("level-three",[],[]) [Str "Level",Space,Str "three"]
+,Header 4 ("level-four-with-emphasis",[],[]) [Str "Level",Space,Str "four",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 5 ("level-five",[],[]) [Str "Level",Space,Str "five"]
+,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",SoftBreak,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",SoftBreak,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",SoftBreak,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",SoftBreak,Str "list",Space,Str "item."]
+,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",SoftBreak,Str "*",Space,Str "criminey."]
+,Para [Str "Horizontal",Space,Str "rule:"]
+,HorizontalRule
+,Para [Str "Another:"]
+,HorizontalRule
+,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",SoftBreak,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
+,Para [Str "Here\8217s",Space,Str "another,",Space,Str "differently",Space,Str "indented:"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",SoftBreak,Str "It\8217s",Space,Str "indented",Space,Str "with",Space,Str "a",Space,Str "tab."]
+ ,Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ ,Para [Str "List",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ ,OrderedList (1,Decimal,Period)
+ [[Plain [Str "item",Space,Str "one"]]
+ ,[Plain [Str "item",Space,Str "two"]]]
+ ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ ,BlockQuote
+ [Para [Str "nested"]
+ ,BlockQuote
+ [Para [Str "nested"]]]]
+,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}"
+,CodeBlock ("",[],[]) "this code block is indented by one tab"
+,Para [Str "And:"]
+,CodeBlock ("",[],[]) "this block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+,Para [Str "And:"]
+,CodeBlock ("",["sourceCode","python"],[]) "def my_function(x):\n return x + 1"
+,Header 1 ("lists",[],[]) [Str "Lists"]
+,Header 2 ("unordered",[],[]) [Str "Unordered"]
+,Para [Str "Asterisks",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "asterisk",Space,Str "1"]]
+ ,[Plain [Str "asterisk",Space,Str "2"]]
+ ,[Plain [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Asterisks",Space,Str "loose:"]
+,BulletList
+ [[Plain [Str "asterisk",Space,Str "1"]]
+ ,[Plain [Str "asterisk",Space,Str "2"]]
+ ,[Plain [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "Plus",Space,Str "1"]]
+ ,[Plain [Str "Plus",Space,Str "2"]]
+ ,[Plain [Str "Plus",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "loose:"]
+,BulletList
+ [[Plain [Str "Plus",Space,Str "1"]]
+ ,[Plain [Str "Plus",Space,Str "2"]]
+ ,[Plain [Str "Plus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "Minus",Space,Str "1"]]
+ ,[Plain [Str "Minus",Space,Str "2"]]
+ ,[Plain [Str "Minus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "loose:"]
+,BulletList
+ [[Plain [Str "Minus",Space,Str "1"]]
+ ,[Plain [Str "Minus",Space,Str "2"]]
+ ,[Plain [Str "Minus",Space,Str "3"]]]
+,Header 2 ("ordered",[],[]) [Str "Ordered"]
+,Para [Str "Tight:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second"]]
+ ,[Plain [Str "Third"]]]
+,Para [Str "and:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "One"]]
+ ,[Plain [Str "Two"]]
+ ,[Plain [Str "Three"]]]
+,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second"]]
+ ,[Plain [Str "Third"]]]
+,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "One"]]
+ ,[Plain [Str "Two"]]
+ ,[Plain [Str "Three"]]]
+,Para [Str "Multiple",Space,Str "paragraphs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",SoftBreak,Str "back."]]
+ ,[Plain [Str "Item",Space,Str "2."]]
+ ,[Plain [Str "Item",Space,Str "3."]]]
+,Para [Str "Nested:"]
+,BulletList
+ [[Plain [Str "Tab"]
+ ,BulletList
+ [[Plain [Str "Tab"]
+ ,BulletList
+ [[Plain [Str "Tab"]]]]]]]
+,Para [Str "Here\8217s",Space,Str "another:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "First"]]
+ ,[Para [Str "Second:"]
+ ,BlockQuote
+ [BulletList
+ [[Plain [Str "Fee"]]
+ ,[Plain [Str "Fie"]]
+ ,[Plain [Str "Foe"]]]]]
+ ,[Plain [Str "Third"]]]
+,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
+,OrderedList (2,Decimal,TwoParens)
+ [[Plain [Str "begins",Space,Str "with",Space,Str "2"]]
+ ,[Para [Str "and",Space,Str "now",Space,Str "3"]
+ ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ ,OrderedList (4,LowerRoman,Period)
+ [[Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"]]
+ ,[Plain [Str "more",Space,Str "items"]
+ ,OrderedList (1,UpperAlpha,TwoParens)
+ [[Plain [Str "a",Space,Str "subsublist"]]
+ ,[Plain [Str "a",Space,Str "subsublist"]]]]]]]
+,Para [Str "Nesting:"]
+,OrderedList (1,UpperAlpha,Period)
+ [[Plain [Str "Upper",Space,Str "Alpha"]
+ ,OrderedList (1,UpperRoman,Period)
+ [[Plain [Str "Upper",Space,Str "Roman."]
+ ,OrderedList (6,Decimal,TwoParens)
+ [[Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ ,OrderedList (3,LowerAlpha,OneParen)
+ [[Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
+,Para [Str "Autonumbering:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Autonumber."]]
+ ,[Plain [Str "More."]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Nested."]]]]]
+,Para [Str "Autonumbering",Space,Str "with",Space,Str "explicit",Space,Str "start:"]
+,OrderedList (4,LowerAlpha,TwoParens)
+ [[Plain [Str "item",Space,Str "1"]]
+ ,[Plain [Str "item",Space,Str "2"]]]
+,Header 2 ("definition",[],[]) [Str "Definition"]
+,DefinitionList
+ [([Str "term",Space,Str "1"],
+ [[Para [Str "Definition",Space,Str "1."]]])
+ ,([Str "term",Space,Str "2"],
+ [[Para [Str "Definition",Space,Str "2,",Space,Str "paragraph",Space,Str "1."]
+ ,Para [Str "Definition",Space,Str "2,",Space,Str "paragraph",Space,Str "2."]]])
+ ,([Str "term",Space,Str "with",Space,Emph [Str "emphasis"]],
+ [[Para [Str "Definition",Space,Str "3."]]])]
+,Header 1 ("field-lists",[],[]) [Str "Field",Space,Str "Lists"]
+,BlockQuote
+ [DefinitionList
+ [([Str "address"],
+ [[Para [Str "61",Space,Str "Main",Space,Str "St."]]])
+ ,([Str "city"],
+ [[Para [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",SoftBreak,Str "USA"]]])
+ ,([Str "phone"],
+ [[Para [Str "123-4567"]]])]]
+,DefinitionList
+ [([Str "address"],
+ [[Para [Str "61",Space,Str "Main",Space,Str "St."]]])
+ ,([Str "city"],
+ [[Para [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",SoftBreak,Str "USA"]]])
+ ,([Str "phone"],
+ [[Para [Str "123-4567"]]])]
+,Header 1 ("html-blocks",[],[]) [Str "HTML",Space,Str "Blocks"]
+,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
+,RawBlock (Format "html") "<div>foo</div>"
+,Para [Str "Now,",Space,Str "nested:"]
+,RawBlock (Format "html") "<div>\n <div>\n <div>\n foo\n </div>\n </div>\n</div>"
+,Header 1 ("latex-block",[],[]) [Str "LaTeX",Space,Str "Block"]
+,RawBlock (Format "latex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"
+,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
+,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ".",Space,Str "This",Space,Str "is",Space,Strong [Str "strong"],Str "."]
+,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
+,Para [Str "This",Space,Str "is",Subscript [Str "subscripted"],Space,Str "and",Space,Str "this",Space,Str "is",Space,Superscript [Str "superscripted"],Str "."]
+,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+,BulletList
+ [[Plain [Str "I",Space,Str "hat:",Space,Str "\206"]]
+ ,[Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
+ ,[Plain [Str "section:",Space,Str "\167"]]
+ ,[Plain [Str "set",Space,Str "membership:",Space,Str "\8712"]]
+ ,[Plain [Str "copyright:",Space,Str "\169"]]]
+,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+,Para [Str "This",Space,Str "&",Space,Str "that."]
+,Para [Str "4",Space,Str "<",Space,Str "5."]
+,Para [Str "6",Space,Str ">",Space,Str "5."]
+,Para [Str "Backslash:",Space,Str "\\"]
+,Para [Str "Backtick:",Space,Str "`"]
+,Para [Str "Asterisk:",Space,Str "*"]
+,Para [Str "Underscore:",Space,Str "_"]
+,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+,Para [Str "Left",Space,Str "paren:",Space,Str "("]
+,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+,Para [Str "Greater-than:",Space,Str ">"]
+,Para [Str "Hash:",Space,Str "#"]
+,Para [Str "Period:",Space,Str "."]
+,Para [Str "Bang:",Space,Str "!"]
+,Para [Str "Plus:",Space,Str "+"]
+,Para [Str "Minus:",Space,Str "-"]
+,Header 1 ("links",[],[]) [Str "Links"]
+,Para [Str "Explicit:",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
+,Para [Str "Explicit",Space,Str "with",Space,Str "no",Space,Str "label:",Space,Link ("",[],[]) [Str "foo"] ("foo",""),Str "."]
+,Para [Str "Two",Space,Str "anonymous",Space,Str "links:",Space,Link ("",[],[]) [Str "the",Space,Str "first"] ("/url1/",""),Space,Str "and",Space,Link ("",[],[]) [Str "the",Space,Str "second"] ("/url2/","")]
+,Para [Str "Reference",Space,Str "links:",Space,Link ("",[],[]) [Str "link1"] ("/url1/",""),Space,Str "and",Space,Link ("",[],[]) [Str "link2"] ("/url2/",""),Space,Str "and",Space,Link ("",[],[]) [Str "link1"] ("/url1/",""),Space,Str "again."]
+,Para [Str "Another",Space,Link ("",[],[]) [Str "style",Space,Str "of",Space,Str "reference",Space,Str "link"] ("/url1/",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "a",Space,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link ("",[],[]) [Str "AT&T"] ("/url/",""),Str "."]
+,Para [Str "Autolinks:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2",""),Space,Str "and",Space,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net",""),Str "."]
+,Para [Str "But",Space,Str "not",Space,Str "here:"]
+,CodeBlock ("",[],[]) "http://example.com/"
+,Header 1 ("images",[],[]) [Str "Images"]
+,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+,Para [Image ("",[],[]) [Str "image"] ("lalune.jpg","")]
+,Para [Image ("",[],[("height","2343px")]) [Str "Voyage dans la Lune"] ("lalune.jpg","")]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
+,Para [Str "And",Space,Str "an",Space,Link ("",[],[]) [Image ("",[],[]) [Str "A movie"] ("movie.jpg","")] ("/url",""),Str "."]
+,Header 1 ("comments",[],[]) [Str "Comments"]
+,Para [Str "First",Space,Str "paragraph"]
+,Para [Str "Another",Space,Str "paragraph"]
+,Para [Str "A",Space,Str "third",Space,Str "paragraph"]
+,Header 1 ("line-blocks",[],[]) [Str "Line",Space,Str "blocks"]
+,LineBlock
+ [[Str "But",Space,Str "can",Space,Str "a",Space,Str "bee",Space,Str "be",Space,Str "said",Space,Str "to",Space,Str "be"]
+ ,[Str "\160\160\160\160or",Space,Str "not",Space,Str "to",Space,Str "be",Space,Str "an",Space,Str "entire",Space,Str "bee,"]
+ ,[Str "\160\160\160\160\160\160\160\160when",Space,Str "half",Space,Str "the",Space,Str "bee",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "bee,"]
+ ,[Str "\160\160\160\160\160\160\160\160\160\160\160\160due",Space,Str "to",Space,Str "some",Space,Str "ancient",Space,Str "injury?"]
+ ,[]
+ ,[Str "Continuation",Space,Str "line"]
+ ,[Str "\160\160and",Space,Str "another"]]
+,Header 1 ("simple-tables",[],[]) [Str "Simple",Space,Str "Tables"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "col",Space,Str "1"]]
+ ,[Plain [Str "col",Space,Str "2"]]
+ ,[Plain [Str "col",Space,Str "3"]]]
+ [[[Plain [Str "r1",Space,Str "a"]]
+ ,[Plain [Str "b"]]
+ ,[Plain [Str "c"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "Headless"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "r1",Space,Str "a"]]
+ ,[Plain [Str "b"]]
+ ,[Plain [Str "c"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Header 1 ("grid-tables",[],[]) [Str "Grid",Space,Str "Tables"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2375,0.15,0.1625]
+ [[Plain [Str "col",Space,Str "1"]]
+ ,[Plain [Str "col",Space,Str "2"]]
+ ,[Plain [Str "col",Space,Str "3"]]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "Headless"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2375,0.15,0.1625]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "Spaces",Space,Str "at",Space,Str "ends",Space,Str "of",Space,Str "lines"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2375,0.15,0.1625]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "Multiple",Space,Str "blocks",Space,Str "in",Space,Str "a",Space,Str "cell"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2375,0.15,0.1625]
+ [[]
+ ,[]
+ ,[]]
+ [[[Para [Str "r1",Space,Str "a"]
+ ,Para [Str "r1",Space,Str "bis"]]
+ ,[BulletList
+ [[Plain [Str "b"]]
+ ,[Plain [Str "b",Space,Str "2"]]
+ ,[Plain [Str "b",Space,Str "2"]]]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]]
+,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
+,Para [Note [Para [Str "Note",Space,Str "with",Space,Str "one",Space,Str "line."]]]
+,Para [Note [Para [Str "Note",Space,Str "with",SoftBreak,Str "continuation",Space,Str "line."]]]
+,Para [Note [Para [Str "Note",Space,Str "with"],Para [Str "continuation",Space,Str "block."]]]
+,Para [Note [Para [Str "Note",Space,Str "with",SoftBreak,Str "continuation",Space,Str "line"],Para [Str "and",Space,Str "a",Space,Str "second",Space,Str "para."]]]
+,Para [Str "Not",Space,Str "in",Space,Str "note."]
+,Header 1 ("math",[],[]) [Str "Math"]
+,Para [Str "Some",Space,Str "inline",Space,Str "math",Space,Math InlineMath "E=mc^2",Str ".",Space,Str "Now",Space,Str "some",SoftBreak,Str "display",Space,Str "math:"]
+,Para [Math DisplayMath "E=mc^2"]
+,Para [Math DisplayMath "E = mc^2"]
+,Para [Math DisplayMath "E = mc^2",Math DisplayMath "\\alpha = \\beta"]
+,Para [Math DisplayMath "\\begin{aligned}\nE &= mc^2\\\\\nF &= \\pi E\n\\end{aligned}",Math DisplayMath "F &= \\gamma \\alpha^2"]
+,Para [Str "All",Space,Str "done."]
+,Header 1 ("default-role",[],[]) [Str "Default-Role"]
+,Para [Str "Try",Space,Str "changing",Space,Str "the",Space,Str "default",Space,Str "role",Space,Str "to",Space,Str "a",Space,Str "few",Space,Str "different",Space,Str "things."]
+,Header 2 ("doesnt-break-title-parsing",[],[]) [Str "Doesn\8217t",Space,Str "Break",Space,Str "Title",Space,Str "Parsing"]
+,Para [Str "Inline",Space,Str "math:",Space,Math InlineMath "E=mc^2",Space,Str "or",Space,Math InlineMath "E=mc^2",Space,Str "or",Space,Math InlineMath "E=mc^2",Str ".",SoftBreak,Str "Other",Space,Str "roles:",Space,Superscript [Str "super"],Str ",",Space,Subscript [Str "sub"],Str "."]
+,Para [Math DisplayMath "\\alpha = beta",Math DisplayMath "E = mc^2"]
+,Para [Str "Some",Space,Superscript [Str "of"],Space,Str "these",Space,Superscript [Str "words"],Space,Str "are",Space,Str "in",Space,Superscript [Str "superscript"],Str "."]
+,Para [Str "Reset",Space,Str "default-role",Space,Str "to",Space,Str "the",Space,Str "default",Space,Str "default."]
+,Para [Str "And",Space,Str "now",Space,Str "some-invalid-string-3231231",Space,Str "is",Space,Str "nonsense."]
+,Para [Str "And",Space,Str "now",Space,Str "with",Space,RawInline (Format "html") "<b>inline</b> <span id=\"test\">HTML</span>",Str "."]
+,Para [Str "And",Space,Str "some",Space,Str "inline",Space,Str "haskell",Space,Code ("",["haskell","sourceCode"],[]) "fmap id [1,2..10]",Str "."]
+,Para [Str "Indirect",Space,Str "python",Space,Str "role",Space,Code ("",["py","python","indirect","sourceCode"],[]) "[x*x for x in [1,2,3,4,5]]",Str "."]
+,Para [Str "Different",Space,Str "indirect",Space,Str "C",Space,Code ("",["c","different-indirect","sourceCode"],[]) "int x = 15;",Str "."]
+,Header 2 ("literal-symbols",[],[]) [Str "Literal",Space,Str "symbols"]
+,Para [Str "2*2",Space,Str "=",Space,Str "4*1"]]
diff --git a/tests/rst-reader.rst b/test/rst-reader.rst
index cfe959f2d..cfe959f2d 100644
--- a/tests/rst-reader.rst
+++ b/test/rst-reader.rst
diff --git a/test/s5-basic.html b/test/s5-basic.html
new file mode 100644
index 000000000..b3b950327
--- /dev/null
+++ b/test/s5-basic.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <meta name="generator" content="pandoc" />
+ <meta name="version" content="S5 1.1" />
+ <meta name="author" content="Sam Smith" />
+ <meta name="version" content="S5 1.1" />
+ <meta name="author" content="Jen Jones" />
+ <meta name="date" content="2006-07-15" />
+ <title>My S5 Document</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+ </style>
+ <!-- configuration parameters -->
+ <meta name="defaultView" content="slideshow" />
+ <meta name="controlVis" content="hidden" />
+ <!-- style sheet links -->
+ <link rel="stylesheet" href="s5/default/slides.css" type="text/css" media="projection" id="slideProj" />
+ <link rel="stylesheet" href="s5/default/outline.css" type="text/css" media="screen" id="outlineStyle" />
+ <link rel="stylesheet" href="s5/default/print.css" type="text/css" media="print" id="slidePrint" />
+ <link rel="stylesheet" href="s5/default/opera.css" type="text/css" media="projection" id="operaFix" />
+ <!-- S5 JS -->
+ <script src="s5/default/slides.js" type="text/javascript"></script>
+</head>
+<body>
+<div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header"></div>
+<div id="footer">
+ <h1>July 15, 2006</h1>
+ <h2>My S5 Document</h2>
+</div>
+</div>
+<div class="presentation">
+<div class="title-slide slide">
+ <h1 class="title">My S5 Document</h1>
+ <h3 class="author">Sam Smith<br/>Jen Jones</h3>
+ <h4 class="date">July 15, 2006</h4>
+</div>
+<div id="first-slide" class="slide section level1">
+<h1>First slide</h1>
+<ul>
+<li>first bullet</li>
+<li>second bullet</li>
+</ul>
+</div>
+<div id="math" class="slide section level1">
+<h1>Math</h1>
+<ul>
+<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
+</ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/test/s5-fancy.html b/test/s5-fancy.html
new file mode 100644
index 000000000..9f724af96
--- /dev/null
+++ b/test/s5-fancy.html
@@ -0,0 +1,262 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <meta name="generator" content="pandoc" />
+ <meta name="version" content="S5 1.1" />
+ <meta name="author" content="Sam Smith" />
+ <meta name="version" content="S5 1.1" />
+ <meta name="author" content="Jen Jones" />
+ <meta name="date" content="2006-07-15" />
+ <title>My S5 Document</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+ </style>
+ <!-- configuration parameters -->
+ <meta name="defaultView" content="slideshow" />
+ <meta name="controlVis" content="hidden" />
+ <!-- style sheet links -->
+ <link rel="stylesheet" href="s5/default/slides.css" type="text/css" media="projection" id="slideProj" />
+ <link rel="stylesheet" href="s5/default/outline.css" type="text/css" media="screen" id="outlineStyle" />
+ <link rel="stylesheet" href="s5/default/print.css" type="text/css" media="print" id="slidePrint" />
+ <link rel="stylesheet" href="s5/default/opera.css" type="text/css" media="projection" id="operaFix" />
+ <!-- S5 JS -->
+ <script src="s5/default/slides.js" type="text/javascript"></script>
+ <script type="text/javascript">/*<![CDATA[*/
+ /*
+ LaTeXMathML.js from http://math.etsu.edu/LaTeXMathML/
+ Adapted by Jeff Knisely and Douglas Woodall from ASCIIMathML.js v. 1.4.7,
+ (c) 2005 Peter Jipsen http://www.chapman.edu/~jipsen.
+ Released under the GNU General Public License version 2 or later.
+ See the GNU General Public License (at http://www.gnu.org/copyleft/gpl.html)
+ for more details.
+ */
+ 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)
+ alert("This webpage requires a recent browser such as \nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer")
+ function AMcreateElementXHTML(t){if(isIE)return document.createElement(t);else return document.createElementNS("http://www.w3.org/1999/xhtml",t);}
+ function AMnoMathMLNote(){var nd=AMcreateElementXHTML("h3");nd.setAttribute("align","center")
+ 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;}
+ function AMisMathMLavailable(){if(navigator.appName.slice(0,8)=="Netscape")
+ if(navigator.appVersion.slice(0,1)>="5")return null;else return AMnoMathMLNote();else if(navigator.appName.slice(0,9)=="Microsoft")
+ try{var ActiveX=new ActiveXObject("MathPlayer.Factory.1");return null;}catch(e){return AMnoMathMLNote();}
+ else return AMnoMathMLNote();}
+ 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
+ else return-1;}
+ var AMnames=[];function AMinitSymbols(){AMsymbols.sort(compareNames);for(i=0;i<AMsymbols.length;i++)AMnames[i]=AMsymbols[i].input;}
+ 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);}
+ function AMcreateMmlNode(t,frag){if(isIE)var node=document.createElement("m:"+t);else var node=document.createElementNS(AMmathml,t);node.appendChild(frag);return node;}
+ function newcommand(oldstr,newstr){AMsymbols=AMsymbols.concat([{input:oldstr,tag:"mo",output:newstr,ttype:DEFINITION}]);}
+ 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);}
+ 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;}
+ return h;}else
+ for(var i=n;i<arr.length&&arr[i]<str;i++);return i;}
+ 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;}
+ more=k<AMnames.length&&str.slice(0,AMnames[k].length)>=AMnames[k];}
+ AMpreviousSymbol=AMcurrentSymbol;if(match!=""){AMcurrentSymbol=AMsymbols[mk].ttype;return AMsymbols[mk];}
+ 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};}
+ 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)
+ 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)
+ return[null,str,null];}
+ 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);}}
+ return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];case CONST:var output=symbol.output;if(isIE){if(symbol.input=="'")
+ output="\u2032";else if(symbol.input=="''")
+ output="\u2033";else if(symbol.input=="'''")
+ output="\u2033\u2032";else if(symbol.input=="''''")
+ output="\u2033\u2033";else if(symbol.input=="\\square")
+ 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];}}}
+ 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")
+ 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");}
+ node.setAttribute("maxsize",symbol.atval);if(symbol.rtag!=null)
+ return[node,str,symbol.rtag];else
+ return[node,str,symbol.tag];case BIG:var atval=symbol.atval;if(isIE)
+ atval=symbol.ieval;symbol=AMgetSymbol(str);if(symbol==null)
+ 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);}
+ return[node,str,symbol.tag];case LEFTBRACKET:if(symbol.input=="\\left"){symbol=AMgetSymbol(str);if(symbol!=null){if(symbol.input==".")
+ symbol.invisible=true;str=AMremoveCharsAndBlanks(str,symbol.input.length);}}
+ result=AMparseExpr(str,true,false);if(symbol==null||(typeof symbol.invisible=="boolean"&&symbol.invisible))
+ node=AMcreateMmlNode("mrow",result[0]);else{node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));node=AMcreateMmlNode("mrow",node);node.appendChild(result[0]);}
+ 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)
+ mask="l";else{str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="{")
+ mask="l";else do{symbol=AMgetSymbol(str);if(symbol!=null){str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="}")
+ mask=mask+symbol.input;}}while(symbol!=null&&symbol.input!=""&&symbol.input!="}");}
+ 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)
+ 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)
+ node.setAttribute("columnspacing","0.25em");else
+ node.setAttribute("columnspacing","0.167em");node.setAttribute("columnalign","right center left");node.setAttribute("displaystyle","true");node=AMcreateMmlNode("mrow",node);return[node,result[1],null];}
+ case TEXT:if(str.charAt(0)=="{")i=str.indexOf("}");else i=0;if(i==-1)
+ i=str.length;st=str.slice(1,i);if(st.charAt(0)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);}
+ 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);}
+ 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);}
+ node.appendChild(result[0]);return[node,result[1],symbol.tag];}}
+ 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])
+ node.appendChild(space);return[node,result[1],symbol.tag];}else
+ 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")
+ output="\u0302";else if(symbol.input=="\\widehat")
+ output="\u005E";else if(symbol.input=="\\bar")
+ output="\u00AF";else if(symbol.input=="\\grave")
+ output="\u0300";else if(symbol.input=="\\tilde")
+ output="\u0303";}
+ var node1=AMcreateMmlNode("mo",document.createTextNode(output));if(symbol.input=="\\vec"||symbol.input=="\\check")
+ node1.setAttribute("maxsize","1.2");if(isIE&&symbol.input=="\\bar")
+ node1.setAttribute("maxsize","0.5");if(symbol.input=="\\underbrace"||symbol.input=="\\underline")
+ node1.setAttribute("accentunder","true");else
+ node1.setAttribute("accent","true");node.appendChild(node1);if(symbol.input=="\\overbrace"||symbol.input=="\\underbrace")
+ 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++)
+ 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++)
+ if(st.charCodeAt(j)>64&&st.charCodeAt(j)<91)newst=newst+
+ String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);else newst=newst+st.charAt(j);if(result[0].nodeName=="mi")
+ result[0]=AMcreateElementMathML("mo").appendChild(document.createTextNode(newst));else result[0].replaceChild(AMcreateElementMathML("mo").appendChild(document.createTextNode(newst)),result[0].childNodes[i]);}}
+ node=AMcreateMmlNode(symbol.tag,result[0]);node.setAttribute(symbol.atname,symbol.atval);if(symbol.input=="\\scriptstyle"||symbol.input=="\\scriptscriptstyle")
+ node.setAttribute("displaystyle","false");return[node,result[1],symbol.tag];}
+ 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];}
+ node=AMcreateElementMathML("mstyle");node.setAttribute(symbol.atval,tclr);node.appendChild(result2[0]);return[node,result2[1],symbol.tag];}}
+ 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];}}
+ 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)
+ 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]);}
+ node=AMcreateMmlNode("mrow",node);}else{node=AMcreateMmlNode(symbol.tag,node);if(symbol.input=="\\atop"||symbol.input=="\\choose")
+ node.setAttribute("linethickness","0ex");node.appendChild(result[0]);if(symbol.input=="\\choose")
+ node=AMcreateMmlNode("mfenced",node);}}
+ return[node,str,tag];}
+ 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);}
+ 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==".")
+ symbol.invisible=true;if(symbol!=null)
+ tag=symbol.rtag;}
+ if(symbol!=null)
+ 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++)
+ if(node.childNodes[j].firstChild.nodeValue=="&")
+ pos[i][pos[i].length]=j;}
+ 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);}
+ row.appendChild(AMcreateMmlNode("mtd",frag));if(newFrag.childNodes.length>2){newFrag.removeChild(newFrag.firstChild);newFrag.removeChild(newFrag.firstChild);}
+ table.appendChild(AMcreateMmlNode("mtr",row));}
+ return[table,str];}
+ if(typeof symbol.invisible!="boolean"||!symbol.invisible){node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));newFrag.appendChild(node);}}
+ return[newFrag,str,tag];}
+ 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];}
+ 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)
+ node.setAttribute("title",str.replace(/\s+/g," "));if(false){var fnode=AMcreateElementXHTML("font");fnode.setAttribute("face",mathfontfamily);fnode.appendChild(node);return fnode;}
+ return node;}
+ 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])));}}
+ expr=!expr;}
+ return newFrag;}
+ 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++)
+ arr[i]=arr[i].replace(/\\\$/g,"\$");if(arr.length>1||mtch){if(checkForMathML){checkForMathML=false;var nd=AMisMathMLavailable();AMnoMathML=nd!=null;if(AMnoMathML&&notifyIfNoMathML)
+ if(alertIfNoMathML)
+ 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]);}
+ 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++)
+ i+=AMprocessNodeR(n.childNodes[i],linebreaks);}
+ return 0;}
+ function AMprocessNode(n,linebreaks,spanclassAM){var frag,st;if(spanclassAM!=null){frag=document.getElementsByTagName("span")
+ for(var i=0;i<frag.length;i++)
+ if(frag[i].className=="AM")
+ AMprocessNodeR(frag[i],linebreaks);}else{try{st=n.innerHTML;}catch(err){}
+ if(st==null||st.indexOf("\$")!=-1)
+ AMprocessNodeR(n,linebreaks);}
+ if(isIE){frag=document.getElementsByTagName('math');for(var i=0;i<frag.length;i++)frag[i].update()}}
+ 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)))
+ {for(var i=0;i<TheBody.childNodes.length;i++){LaTeXpreProcess(TheBody.childNodes[i])}}}
+ else{if(TheBody.nodeType==3&&!(IsTextOnlyArea.test(TheBody.parentNode.nodeName)))
+ {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]*$/,"")
+ 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;}
+ 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);}
+ 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);}
+ DEQtbody.appendChild(DEQtr);DEQtable.appendChild(DEQtbody);newFrag.appendChild(DEQtable);}
+ 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," ");}
+ 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\\] \\[ ");}
+ 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]+\}/);}
+ 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]+\}/);}
+ 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]+\}/);}
+ 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';}
+ 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}}}
+ 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];}
+ 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*\}/);}
+ 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);}
+ 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}}}
+ 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];}
+ 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);}
+ 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);}
+ TABtbody.appendChild(TABrow);}
+ nodeTmp.appendChild(TABtbody);}
+ 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);}
+ 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+"]"));}
+ 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);}
+ 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);}}
+ if(strtmparray[0]=="endenumerate"||strtmparray[0]=="enditemize"||strtmparray[0]=="enddescription"){var endDiv=document.createElement("div");endDiv.className="endlistitem";newFrag.appendChild(endDiv);}
+ 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\\]|");}}
+ 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;}}
+ 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;}
+ if(TagIndex<strtmptmp[jjj].length){tmpIndex=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\\\w+/);}
+ else{tmpIndex=-1};TagIndex+=tmpIndex;}
+ 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]))
+ newFrag.appendChild(nodeTmp);}}else{newFrag.appendChild(document.createTextNode(strlbls[jj]));}}}}}}}};TheBody.parentNode.replaceChild(newFrag,TheBody);}}}
+ return TheBody;}
+ 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;}}
+ 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=""}
+ 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);}}
+ 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;}}}
+ 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");}
+ 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);}
+ if(DIV2LI.firstChild.className=="listitemmarker"){DIV2LI.style.listStyleType="none";}
+ RootNode.appendChild(DIV2LI)}
+ AllDivs[i].removeChild(AllDivs[i].firstChild);}
+ AllDivs[i].appendChild(RootNode);}}
+ 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"
+ refNode.className=AllAnchors[i].className;AllAnchors[i].appendChild(refNode);}}}}}
+ return TheBody;}
+ 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");}
+ if(AMbody.tagName=="PRE"){var PreChilds=document.createDocumentFragment();var DivChilds=document.createElement("DIV");while(AMbody.hasChildNodes()){DivChilds.appendChild(AMbody.firstChild);}
+ PreChilds.appendChild(DivChilds);AMbody.parentNode.replaceChild(PreChilds,AMbody);AMbody=DivChilds;}
+ AMprocessNode(AMbody,false,spanclassAM);}}else{AMbody=document.getElementsByTagName("body")[0];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");}
+ AMprocessNode(AMbody,false,spanclassAM);}}}
+ if(isIE){document.write("<object id=\"mathplayer\" classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");}
+ function generic()
+ {translate();};if(typeof window.addEventListener!='undefined')
+ {window.addEventListener('load',generic,false);}
+ else if(typeof document.addEventListener!='undefined')
+ {document.addEventListener('load',generic,false);}
+ else if(typeof window.attachEvent!='undefined')
+ {window.attachEvent('onload',generic);}
+ else
+ {if(typeof window.onload=='function')
+ {var existing=onload;window.onload=function()
+ {existing();generic();};}
+ else
+ {window.onload=generic;}}
+ /*]]>*/
+ </script>
+</head>
+<body>
+<div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header"></div>
+<div id="footer">
+ <h1>July 15, 2006</h1>
+ <h2>My S5 Document</h2>
+</div>
+</div>
+<div class="presentation">
+<div class="title-slide slide">
+ <h1 class="title">My S5 Document</h1>
+ <h3 class="author">Sam Smith<br/>Jen Jones</h3>
+ <h4 class="date">July 15, 2006</h4>
+</div>
+<div id="first-slide" class="slide section level1">
+<h1>First slide</h1>
+<ul class="incremental">
+<li>first bullet</li>
+<li>second bullet</li>
+</ul>
+</div>
+<div id="math" class="slide section level1">
+<h1>Math</h1>
+<ul class="incremental">
+<li><span class="LaTeX">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
+</ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/tests/s5-fragment.html b/test/s5-fragment.html
index 81c578d25..81c578d25 100644
--- a/tests/s5-fragment.html
+++ b/test/s5-fragment.html
diff --git a/test/s5-inserts.html b/test/s5-inserts.html
new file mode 100644
index 000000000..efde179d2
--- /dev/null
+++ b/test/s5-inserts.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <meta name="generator" content="pandoc" />
+ <meta name="author" content="Sam Smith" />
+ <meta name="author" content="Jen Jones" />
+ <meta name="date" content="2006-07-15" />
+ <title>My S5 Document</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+ </style>
+ <link rel="stylesheet" href="main.css" type="text/css" />
+ STUFF INSERTED
+</head>
+<body>
+STUFF INSERTED
+<div id="header">
+<h1 class="title">My S5 Document</h1>
+<h2 class="author">Sam Smith</h2>
+<h2 class="author">Jen Jones</h2>
+<h3 class="date">July 15, 2006</h3>
+</div>
+<h1 id="first-slide">First slide</h1>
+<ul>
+<li>first bullet</li>
+<li>second bullet</li>
+</ul>
+<h1 id="math">Math</h1>
+<ul>
+<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
+</ul>
+STUFF INSERTED
+</body>
+</html>
diff --git a/tests/s5.native b/test/s5.native
index 5796b74a0..5796b74a0 100644
--- a/tests/s5.native
+++ b/test/s5.native
diff --git a/test/tables-rstsubset.native b/test/tables-rstsubset.native
new file mode 100644
index 000000000..8b7ccdf76
--- /dev/null
+++ b/test/tables-rstsubset.native
@@ -0,0 +1,114 @@
+[Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"]
+,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1,8.75e-2,0.1125,0.125]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Simple",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1,8.75e-2,0.1125,0.125]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Simple",Space,Str "table",Space,Str "indented",Space,Str "two",Space,Str "spaces:"]
+,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1,8.75e-2,0.1125,0.125]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"]
+,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325]
+ [[Plain [Str "Centered",SoftBreak,Str "Header"]]
+ ,[Plain [Str "Left",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Right",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Default",Space,Str "aligned"]]]
+ [[[Plain [Str "First"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "12.0"]]
+ ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",SoftBreak,Str "spans",Space,Str "multiple",Space,Str "lines."]]]
+ ,[[Plain [Str "Second"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "5.0"]]
+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]]
+,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325]
+ [[Plain [Str "Centered",SoftBreak,Str "Header"]]
+ ,[Plain [Str "Left",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Right",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Default",Space,Str "aligned"]]]
+ [[[Plain [Str "First"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "12.0"]]
+ ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",SoftBreak,Str "spans",Space,Str "multiple",Space,Str "lines."]]]
+ ,[[Plain [Str "Second"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "5.0"]]
+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]]
+,Para [Str "Table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [7.5e-2,7.5e-2,7.5e-2,7.5e-2]
+ [[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325]
+ [[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "First"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "12.0"]]
+ ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",SoftBreak,Str "spans",Space,Str "multiple",Space,Str "lines."]]]
+ ,[[Plain [Str "Second"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "5.0"]]
+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]]]
diff --git a/test/tables.asciidoc b/test/tables.asciidoc
new file mode 100644
index 000000000..91490a27a
--- /dev/null
+++ b/test/tables.asciidoc
@@ -0,0 +1,67 @@
+Simple table with caption:
+
+.Demonstration of simple table syntax.
+[cols=">,<,^,",options="header",]
+|============================
+|Right |Left |Center |Default
+|12 |12 |12 |12
+|123 |123 |123 |123
+|1 |1 |1 |1
+|============================
+
+Simple table without caption:
+
+[cols=">,<,^,",options="header",]
+|============================
+|Right |Left |Center |Default
+|12 |12 |12 |12
+|123 |123 |123 |123
+|1 |1 |1 |1
+|============================
+
+Simple table indented two spaces:
+
+.Demonstration of simple table syntax.
+[cols=">,<,^,",options="header",]
+|============================
+|Right |Left |Center |Default
+|12 |12 |12 |12
+|123 |123 |123 |123
+|1 |1 |1 |1
+|============================
+
+Multiline table with caption:
+
+.Here’s the caption. It may span multiple lines.
+[width="78%",cols="^21%,<17%,>20%,<42%",options="header",]
+|=======================================================================
+|Centered Header |Left Aligned |Right Aligned |Default aligned
+|First |row |12.0 |Example of a row that spans multiple lines.
+|Second |row |5.0 |Here’s another one. Note the blank line between rows.
+|=======================================================================
+
+Multiline table without caption:
+
+[width="78%",cols="^21%,<17%,>20%,<42%",options="header",]
+|=======================================================================
+|Centered Header |Left Aligned |Right Aligned |Default aligned
+|First |row |12.0 |Example of a row that spans multiple lines.
+|Second |row |5.0 |Here’s another one. Note the blank line between rows.
+|=======================================================================
+
+Table without column headers:
+
+[cols=">,<,^,>",]
+|==================
+|12 |12 |12 |12
+|123 |123 |123 |123
+|1 |1 |1 |1
+|==================
+
+Multiline table without column headers:
+
+[width="78%",cols="^21%,<17%,>20%,42%",]
+|=======================================================================
+|First |row |12.0 |Example of a row that spans multiple lines.
+|Second |row |5.0 |Here’s another one. Note the blank line between rows.
+|=======================================================================
diff --git a/test/tables.context b/test/tables.context
new file mode 100644
index 000000000..11dffc065
--- /dev/null
+++ b/test/tables.context
@@ -0,0 +1,230 @@
+Simple table with caption:
+
+\startplacetable[title={Demonstration of simple table syntax.}]
+\startxtable
+\startxtablehead[head]
+\startxrow
+\startxcell[align=left] Right \stopxcell
+\startxcell[align=right] Left \stopxcell
+\startxcell[align=middle] Center \stopxcell
+\startxcell Default \stopxcell
+\stopxrow
+\stopxtablehead
+\startxtablebody[body]
+\startxrow
+\startxcell[align=left] 12 \stopxcell
+\startxcell[align=right] 12 \stopxcell
+\startxcell[align=middle] 12 \stopxcell
+\startxcell 12 \stopxcell
+\stopxrow
+\startxrow
+\startxcell[align=left] 123 \stopxcell
+\startxcell[align=right] 123 \stopxcell
+\startxcell[align=middle] 123 \stopxcell
+\startxcell 123 \stopxcell
+\stopxrow
+\stopxtablebody
+\startxtablefoot[foot]
+\startxrow
+\startxcell[align=left] 1 \stopxcell
+\startxcell[align=right] 1 \stopxcell
+\startxcell[align=middle] 1 \stopxcell
+\startxcell 1 \stopxcell
+\stopxrow
+\stopxtablefoot
+\stopxtable
+\stopplacetable
+
+Simple table without caption:
+
+\startplacetable[location=none]
+\startxtable
+\startxtablehead[head]
+\startxrow
+\startxcell[align=left] Right \stopxcell
+\startxcell[align=right] Left \stopxcell
+\startxcell[align=middle] Center \stopxcell
+\startxcell Default \stopxcell
+\stopxrow
+\stopxtablehead
+\startxtablebody[body]
+\startxrow
+\startxcell[align=left] 12 \stopxcell
+\startxcell[align=right] 12 \stopxcell
+\startxcell[align=middle] 12 \stopxcell
+\startxcell 12 \stopxcell
+\stopxrow
+\startxrow
+\startxcell[align=left] 123 \stopxcell
+\startxcell[align=right] 123 \stopxcell
+\startxcell[align=middle] 123 \stopxcell
+\startxcell 123 \stopxcell
+\stopxrow
+\stopxtablebody
+\startxtablefoot[foot]
+\startxrow
+\startxcell[align=left] 1 \stopxcell
+\startxcell[align=right] 1 \stopxcell
+\startxcell[align=middle] 1 \stopxcell
+\startxcell 1 \stopxcell
+\stopxrow
+\stopxtablefoot
+\stopxtable
+\stopplacetable
+
+Simple table indented two spaces:
+
+\startplacetable[title={Demonstration of simple table syntax.}]
+\startxtable
+\startxtablehead[head]
+\startxrow
+\startxcell[align=left] Right \stopxcell
+\startxcell[align=right] Left \stopxcell
+\startxcell[align=middle] Center \stopxcell
+\startxcell Default \stopxcell
+\stopxrow
+\stopxtablehead
+\startxtablebody[body]
+\startxrow
+\startxcell[align=left] 12 \stopxcell
+\startxcell[align=right] 12 \stopxcell
+\startxcell[align=middle] 12 \stopxcell
+\startxcell 12 \stopxcell
+\stopxrow
+\startxrow
+\startxcell[align=left] 123 \stopxcell
+\startxcell[align=right] 123 \stopxcell
+\startxcell[align=middle] 123 \stopxcell
+\startxcell 123 \stopxcell
+\stopxrow
+\stopxtablebody
+\startxtablefoot[foot]
+\startxrow
+\startxcell[align=left] 1 \stopxcell
+\startxcell[align=right] 1 \stopxcell
+\startxcell[align=middle] 1 \stopxcell
+\startxcell 1 \stopxcell
+\stopxrow
+\stopxtablefoot
+\stopxtable
+\stopplacetable
+
+Multiline table with caption:
+
+\startplacetable[title={Here's the caption. It may span multiple lines.}]
+\startxtable
+\startxtablehead[head]
+\startxrow
+\startxcell[align=middle,width={0.15\textwidth}] Centered Header \stopxcell
+\startxcell[align=right,width={0.14\textwidth}] Left Aligned \stopxcell
+\startxcell[align=left,width={0.16\textwidth}] Right Aligned \stopxcell
+\startxcell[align=right,width={0.34\textwidth}] Default aligned \stopxcell
+\stopxrow
+\stopxtablehead
+\startxtablebody[body]
+\startxrow
+\startxcell[align=middle,width={0.15\textwidth}] First \stopxcell
+\startxcell[align=right,width={0.14\textwidth}] row \stopxcell
+\startxcell[align=left,width={0.16\textwidth}] 12.0 \stopxcell
+\startxcell[align=right,width={0.34\textwidth}] Example of a row that spans
+multiple lines. \stopxcell
+\stopxrow
+\stopxtablebody
+\startxtablefoot[foot]
+\startxrow
+\startxcell[align=middle,width={0.15\textwidth}] Second \stopxcell
+\startxcell[align=right,width={0.14\textwidth}] row \stopxcell
+\startxcell[align=left,width={0.16\textwidth}] 5.0 \stopxcell
+\startxcell[align=right,width={0.34\textwidth}] Here's another one. Note the
+blank line between rows. \stopxcell
+\stopxrow
+\stopxtablefoot
+\stopxtable
+\stopplacetable
+
+Multiline table without caption:
+
+\startplacetable[location=none]
+\startxtable
+\startxtablehead[head]
+\startxrow
+\startxcell[align=middle,width={0.15\textwidth}] Centered Header \stopxcell
+\startxcell[align=right,width={0.14\textwidth}] Left Aligned \stopxcell
+\startxcell[align=left,width={0.16\textwidth}] Right Aligned \stopxcell
+\startxcell[align=right,width={0.34\textwidth}] Default aligned \stopxcell
+\stopxrow
+\stopxtablehead
+\startxtablebody[body]
+\startxrow
+\startxcell[align=middle,width={0.15\textwidth}] First \stopxcell
+\startxcell[align=right,width={0.14\textwidth}] row \stopxcell
+\startxcell[align=left,width={0.16\textwidth}] 12.0 \stopxcell
+\startxcell[align=right,width={0.34\textwidth}] Example of a row that spans
+multiple lines. \stopxcell
+\stopxrow
+\stopxtablebody
+\startxtablefoot[foot]
+\startxrow
+\startxcell[align=middle,width={0.15\textwidth}] Second \stopxcell
+\startxcell[align=right,width={0.14\textwidth}] row \stopxcell
+\startxcell[align=left,width={0.16\textwidth}] 5.0 \stopxcell
+\startxcell[align=right,width={0.34\textwidth}] Here's another one. Note the
+blank line between rows. \stopxcell
+\stopxrow
+\stopxtablefoot
+\stopxtable
+\stopplacetable
+
+Table without column headers:
+
+\startplacetable[location=none]
+\startxtable
+\startxtablebody[body]
+\startxrow
+\startxcell[align=left] 12 \stopxcell
+\startxcell[align=right] 12 \stopxcell
+\startxcell[align=middle] 12 \stopxcell
+\startxcell[align=left] 12 \stopxcell
+\stopxrow
+\startxrow
+\startxcell[align=left] 123 \stopxcell
+\startxcell[align=right] 123 \stopxcell
+\startxcell[align=middle] 123 \stopxcell
+\startxcell[align=left] 123 \stopxcell
+\stopxrow
+\stopxtablebody
+\startxtablefoot[foot]
+\startxrow
+\startxcell[align=left] 1 \stopxcell
+\startxcell[align=right] 1 \stopxcell
+\startxcell[align=middle] 1 \stopxcell
+\startxcell[align=left] 1 \stopxcell
+\stopxrow
+\stopxtablefoot
+\stopxtable
+\stopplacetable
+
+Multiline table without column headers:
+
+\startplacetable[location=none]
+\startxtable
+\startxtablebody[body]
+\startxrow
+\startxcell[align=middle,width={0.15\textwidth}] First \stopxcell
+\startxcell[align=right,width={0.14\textwidth}] row \stopxcell
+\startxcell[align=left,width={0.16\textwidth}] 12.0 \stopxcell
+\startxcell[width={0.34\textwidth}] Example of a row that spans multiple
+lines. \stopxcell
+\stopxrow
+\stopxtablebody
+\startxtablefoot[foot]
+\startxrow
+\startxcell[align=middle,width={0.15\textwidth}] Second \stopxcell
+\startxcell[align=right,width={0.14\textwidth}] row \stopxcell
+\startxcell[align=left,width={0.16\textwidth}] 5.0 \stopxcell
+\startxcell[width={0.34\textwidth}] Here's another one. Note the blank line
+between rows. \stopxcell
+\stopxrow
+\stopxtablefoot
+\stopxtable
+\stopplacetable
diff --git a/test/tables.custom b/test/tables.custom
new file mode 100644
index 000000000..410b68d3f
--- /dev/null
+++ b/test/tables.custom
@@ -0,0 +1,201 @@
+<p>Simple table with caption:</p>
+
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th align="left">Default</th>
+</tr>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table
+
+<p>Simple table without caption:</p>
+
+<table>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th align="left">Default</th>
+</tr>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table
+
+<p>Simple table indented two spaces:</p>
+
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th align="left">Default</th>
+</tr>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table
+
+<p>Multiline table with caption:</p>
+
+<table>
+<caption>Here’s the caption.
+It may span multiple lines.</caption>
+<col width="15%" />
+<col width="14%" />
+<col width="16%" />
+<col width="34%" />
+<tr class="header">
+<th align="center">Centered
+Header</th>
+<th align="left">Left
+Aligned</th>
+<th align="right">Right
+Aligned</th>
+<th align="left">Default aligned</th>
+</tr>
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans
+multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here’s another one. Note
+the blank line between rows.</td>
+</tr>
+</table
+
+<p>Multiline table without caption:</p>
+
+<table>
+<col width="15%" />
+<col width="14%" />
+<col width="16%" />
+<col width="34%" />
+<tr class="header">
+<th align="center">Centered
+Header</th>
+<th align="left">Left
+Aligned</th>
+<th align="right">Right
+Aligned</th>
+<th align="left">Default aligned</th>
+</tr>
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans
+multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here’s another one. Note
+the blank line between rows.</td>
+</tr>
+</table
+
+<p>Table without column headers:</p>
+
+<table>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="right">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="right">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="right">1</td>
+</tr>
+</table
+
+<p>Multiline table without column headers:</p>
+
+<table>
+<col width="15%" />
+<col width="14%" />
+<col width="16%" />
+<col width="34%" />
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans
+multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here’s another one. Note
+the blank line between rows.</td>
+</tr>
+</table
+
diff --git a/test/tables.docbook4 b/test/tables.docbook4
new file mode 100644
index 000000000..f86b1c390
--- /dev/null
+++ b/test/tables.docbook4
@@ -0,0 +1,432 @@
+<para>
+ Simple table with caption:
+</para>
+<table>
+ <title>
+ Demonstration of simple table syntax.
+ </title>
+ <tgroup cols="4">
+ <colspec align="right" />
+ <colspec align="left" />
+ <colspec align="center" />
+ <colspec align="left" />
+ <thead>
+ <row>
+ <entry>
+ Right
+ </entry>
+ <entry>
+ Left
+ </entry>
+ <entry>
+ Center
+ </entry>
+ <entry>
+ Default
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+<para>
+ Simple table without caption:
+</para>
+<informaltable>
+ <tgroup cols="4">
+ <colspec align="right" />
+ <colspec align="left" />
+ <colspec align="center" />
+ <colspec align="left" />
+ <thead>
+ <row>
+ <entry>
+ Right
+ </entry>
+ <entry>
+ Left
+ </entry>
+ <entry>
+ Center
+ </entry>
+ <entry>
+ Default
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</informaltable>
+<para>
+ Simple table indented two spaces:
+</para>
+<table>
+ <title>
+ Demonstration of simple table syntax.
+ </title>
+ <tgroup cols="4">
+ <colspec align="right" />
+ <colspec align="left" />
+ <colspec align="center" />
+ <colspec align="left" />
+ <thead>
+ <row>
+ <entry>
+ Right
+ </entry>
+ <entry>
+ Left
+ </entry>
+ <entry>
+ Center
+ </entry>
+ <entry>
+ Default
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+<para>
+ Multiline table with caption:
+</para>
+<table>
+ <title>
+ Here’s the caption. It may span multiple lines.
+ </title>
+ <tgroup cols="4">
+ <colspec colwidth="15*" align="center" />
+ <colspec colwidth="13*" align="left" />
+ <colspec colwidth="16*" align="right" />
+ <colspec colwidth="33*" align="left" />
+ <thead>
+ <row>
+ <entry>
+ Centered Header
+ </entry>
+ <entry>
+ Left Aligned
+ </entry>
+ <entry>
+ Right Aligned
+ </entry>
+ <entry>
+ Default aligned
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ First
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 12.0
+ </entry>
+ <entry>
+ Example of a row that spans multiple lines.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ Second
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 5.0
+ </entry>
+ <entry>
+ Here’s another one. Note the blank line between rows.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+<para>
+ Multiline table without caption:
+</para>
+<informaltable>
+ <tgroup cols="4">
+ <colspec colwidth="15*" align="center" />
+ <colspec colwidth="13*" align="left" />
+ <colspec colwidth="16*" align="right" />
+ <colspec colwidth="33*" align="left" />
+ <thead>
+ <row>
+ <entry>
+ Centered Header
+ </entry>
+ <entry>
+ Left Aligned
+ </entry>
+ <entry>
+ Right Aligned
+ </entry>
+ <entry>
+ Default aligned
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ First
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 12.0
+ </entry>
+ <entry>
+ Example of a row that spans multiple lines.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ Second
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 5.0
+ </entry>
+ <entry>
+ Here’s another one. Note the blank line between rows.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</informaltable>
+<para>
+ Table without column headers:
+</para>
+<informaltable>
+ <tgroup cols="4">
+ <colspec align="right" />
+ <colspec align="left" />
+ <colspec align="center" />
+ <colspec align="right" />
+ <tbody>
+ <row>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</informaltable>
+<para>
+ Multiline table without column headers:
+</para>
+<informaltable>
+ <tgroup cols="4">
+ <colspec colwidth="15*" align="center" />
+ <colspec colwidth="13*" align="left" />
+ <colspec colwidth="16*" align="right" />
+ <colspec colwidth="33*" align="left" />
+ <tbody>
+ <row>
+ <entry>
+ First
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 12.0
+ </entry>
+ <entry>
+ Example of a row that spans multiple lines.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ Second
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 5.0
+ </entry>
+ <entry>
+ Here’s another one. Note the blank line between rows.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</informaltable>
diff --git a/test/tables.docbook5 b/test/tables.docbook5
new file mode 100644
index 000000000..f86b1c390
--- /dev/null
+++ b/test/tables.docbook5
@@ -0,0 +1,432 @@
+<para>
+ Simple table with caption:
+</para>
+<table>
+ <title>
+ Demonstration of simple table syntax.
+ </title>
+ <tgroup cols="4">
+ <colspec align="right" />
+ <colspec align="left" />
+ <colspec align="center" />
+ <colspec align="left" />
+ <thead>
+ <row>
+ <entry>
+ Right
+ </entry>
+ <entry>
+ Left
+ </entry>
+ <entry>
+ Center
+ </entry>
+ <entry>
+ Default
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+<para>
+ Simple table without caption:
+</para>
+<informaltable>
+ <tgroup cols="4">
+ <colspec align="right" />
+ <colspec align="left" />
+ <colspec align="center" />
+ <colspec align="left" />
+ <thead>
+ <row>
+ <entry>
+ Right
+ </entry>
+ <entry>
+ Left
+ </entry>
+ <entry>
+ Center
+ </entry>
+ <entry>
+ Default
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</informaltable>
+<para>
+ Simple table indented two spaces:
+</para>
+<table>
+ <title>
+ Demonstration of simple table syntax.
+ </title>
+ <tgroup cols="4">
+ <colspec align="right" />
+ <colspec align="left" />
+ <colspec align="center" />
+ <colspec align="left" />
+ <thead>
+ <row>
+ <entry>
+ Right
+ </entry>
+ <entry>
+ Left
+ </entry>
+ <entry>
+ Center
+ </entry>
+ <entry>
+ Default
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+<para>
+ Multiline table with caption:
+</para>
+<table>
+ <title>
+ Here’s the caption. It may span multiple lines.
+ </title>
+ <tgroup cols="4">
+ <colspec colwidth="15*" align="center" />
+ <colspec colwidth="13*" align="left" />
+ <colspec colwidth="16*" align="right" />
+ <colspec colwidth="33*" align="left" />
+ <thead>
+ <row>
+ <entry>
+ Centered Header
+ </entry>
+ <entry>
+ Left Aligned
+ </entry>
+ <entry>
+ Right Aligned
+ </entry>
+ <entry>
+ Default aligned
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ First
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 12.0
+ </entry>
+ <entry>
+ Example of a row that spans multiple lines.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ Second
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 5.0
+ </entry>
+ <entry>
+ Here’s another one. Note the blank line between rows.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+<para>
+ Multiline table without caption:
+</para>
+<informaltable>
+ <tgroup cols="4">
+ <colspec colwidth="15*" align="center" />
+ <colspec colwidth="13*" align="left" />
+ <colspec colwidth="16*" align="right" />
+ <colspec colwidth="33*" align="left" />
+ <thead>
+ <row>
+ <entry>
+ Centered Header
+ </entry>
+ <entry>
+ Left Aligned
+ </entry>
+ <entry>
+ Right Aligned
+ </entry>
+ <entry>
+ Default aligned
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ First
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 12.0
+ </entry>
+ <entry>
+ Example of a row that spans multiple lines.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ Second
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 5.0
+ </entry>
+ <entry>
+ Here’s another one. Note the blank line between rows.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</informaltable>
+<para>
+ Table without column headers:
+</para>
+<informaltable>
+ <tgroup cols="4">
+ <colspec align="right" />
+ <colspec align="left" />
+ <colspec align="center" />
+ <colspec align="right" />
+ <tbody>
+ <row>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ <entry>
+ 12
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ <entry>
+ 123
+ </entry>
+ </row>
+ <row>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ <entry>
+ 1
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</informaltable>
+<para>
+ Multiline table without column headers:
+</para>
+<informaltable>
+ <tgroup cols="4">
+ <colspec colwidth="15*" align="center" />
+ <colspec colwidth="13*" align="left" />
+ <colspec colwidth="16*" align="right" />
+ <colspec colwidth="33*" align="left" />
+ <tbody>
+ <row>
+ <entry>
+ First
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 12.0
+ </entry>
+ <entry>
+ Example of a row that spans multiple lines.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ Second
+ </entry>
+ <entry>
+ row
+ </entry>
+ <entry>
+ 5.0
+ </entry>
+ <entry>
+ Here’s another one. Note the blank line between rows.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</informaltable>
diff --git a/test/tables.dokuwiki b/test/tables.dokuwiki
new file mode 100644
index 000000000..23c0d22cb
--- /dev/null
+++ b/test/tables.dokuwiki
@@ -0,0 +1,47 @@
+Simple table with caption:
+
+Demonstration of simple table syntax.
+^ Right^Left ^ Center ^Default^
+| 12|12 | 12 |12 |
+| 123|123 | 123 |123 |
+| 1|1 | 1 |1 |
+
+Simple table without caption:
+
+^ Right^Left ^ Center ^Default^
+| 12|12 | 12 |12 |
+| 123|123 | 123 |123 |
+| 1|1 | 1 |1 |
+
+Simple table indented two spaces:
+
+Demonstration of simple table syntax.
+^ Right^Left ^ Center ^Default^
+| 12|12 | 12 |12 |
+| 123|123 | 123 |123 |
+| 1|1 | 1 |1 |
+
+Multiline table with caption:
+
+Here’s the caption. It may span multiple lines.
+^ Centered Header ^Left Aligned ^ Right Aligned^Default aligned ^
+| First |row | 12.0|Example of a row that spans multiple lines. |
+| Second |row | 5.0|Here’s another one. Note the blank line between rows. |
+
+Multiline table without caption:
+
+^ Centered Header ^Left Aligned ^ Right Aligned^Default aligned ^
+| First |row | 12.0|Example of a row that spans multiple lines. |
+| Second |row | 5.0|Here’s another one. Note the blank line between rows. |
+
+Table without column headers:
+
+| 12|12 | 12 | 12|
+| 123|123 | 123 | 123|
+| 1|1 | 1 | 1|
+
+Multiline table without column headers:
+
+| First |row | 12.0|Example of a row that spans multiple lines. |
+| Second |row | 5.0|Here’s another one. Note the blank line between rows.|
+
diff --git a/test/tables.fb2 b/test/tables.fb2
new file mode 100644
index 000000000..56ed5316b
--- /dev/null
+++ b/test/tables.fb2
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><p>Simple table with caption:</p><table><tr><th align="right">Right</th><th align="left">Left</th><th align="center">Center</th><th align="left">Default</th></tr><tr><td align="right">12</td><td align="left">12</td><td align="center">12</td><td align="left">12</td></tr><tr><td align="right">123</td><td align="left">123</td><td align="center">123</td><td align="left">123</td></tr><tr><td align="right">1</td><td align="left">1</td><td align="center">1</td><td align="left">1</td></tr></table><p><emphasis>Demonstration of simple table syntax.</emphasis></p><p>Simple table without caption:</p><table><tr><th align="right">Right</th><th align="left">Left</th><th align="center">Center</th><th align="left">Default</th></tr><tr><td align="right">12</td><td align="left">12</td><td align="center">12</td><td align="left">12</td></tr><tr><td align="right">123</td><td align="left">123</td><td align="center">123</td><td align="left">123</td></tr><tr><td align="right">1</td><td align="left">1</td><td align="center">1</td><td align="left">1</td></tr></table><p><emphasis /></p><p>Simple table indented two spaces:</p><table><tr><th align="right">Right</th><th align="left">Left</th><th align="center">Center</th><th align="left">Default</th></tr><tr><td align="right">12</td><td align="left">12</td><td align="center">12</td><td align="left">12</td></tr><tr><td align="right">123</td><td align="left">123</td><td align="center">123</td><td align="left">123</td></tr><tr><td align="right">1</td><td align="left">1</td><td align="center">1</td><td align="left">1</td></tr></table><p><emphasis>Demonstration of simple table syntax.</emphasis></p><p>Multiline table with caption:</p><table><tr><th align="center">Centered Header</th><th align="left">Left Aligned</th><th align="right">Right Aligned</th><th align="left">Default aligned</th></tr><tr><td align="center">First</td><td align="left">row</td><td align="right">12.0</td><td align="left">Example of a row that spans multiple lines.</td></tr><tr><td align="center">Second</td><td align="left">row</td><td align="right">5.0</td><td align="left">Here’s another one. Note the blank line between rows.</td></tr></table><p><emphasis>Here’s the caption. It may span multiple lines.</emphasis></p><p>Multiline table without caption:</p><table><tr><th align="center">Centered Header</th><th align="left">Left Aligned</th><th align="right">Right Aligned</th><th align="left">Default aligned</th></tr><tr><td align="center">First</td><td align="left">row</td><td align="right">12.0</td><td align="left">Example of a row that spans multiple lines.</td></tr><tr><td align="center">Second</td><td align="left">row</td><td align="right">5.0</td><td align="left">Here’s another one. Note the blank line between rows.</td></tr></table><p><emphasis /></p><p>Table without column headers:</p><table><tr><th align="right" /><th align="left" /><th align="center" /><th align="right" /></tr><tr><td align="right">12</td><td align="left">12</td><td align="center">12</td><td align="right">12</td></tr><tr><td align="right">123</td><td align="left">123</td><td align="center">123</td><td align="right">123</td></tr><tr><td align="right">1</td><td align="left">1</td><td align="center">1</td><td align="right">1</td></tr></table><p><emphasis /></p><p>Multiline table without column headers:</p><table><tr><th align="center" /><th align="left" /><th align="right" /><th align="left" /></tr><tr><td align="center">First</td><td align="left">row</td><td align="right">12.0</td><td align="left">Example of a row that spans multiple lines.</td></tr><tr><td align="center">Second</td><td align="left">row</td><td align="right">5.0</td><td align="left">Here’s another one. Note the blank line between rows.</td></tr></table><p><emphasis /></p></section></body></FictionBook>
+
diff --git a/test/tables.haddock b/test/tables.haddock
new file mode 100644
index 000000000..84a15cce8
--- /dev/null
+++ b/test/tables.haddock
@@ -0,0 +1,76 @@
+Simple table with caption:
+
+> Right Left Center Default
+> ------- ------ -------- ---------
+> 12 12 12 12
+> 123 123 123 123
+> 1 1 1 1
+>
+> Demonstration of simple table syntax.
+
+Simple table without caption:
+
+> Right Left Center Default
+> ------- ------ -------- ---------
+> 12 12 12 12
+> 123 123 123 123
+> 1 1 1 1
+
+Simple table indented two spaces:
+
+> Right Left Center Default
+> ------- ------ -------- ---------
+> 12 12 12 12
+> 123 123 123 123
+> 1 1 1 1
+>
+> Demonstration of simple table syntax.
+
+Multiline table with caption:
+
+> --------------------------------------------------------------
+> Centered Left Right Default aligned
+> Header Aligned Aligned
+> ----------- ---------- ------------ --------------------------
+> First row 12.0 Example of a row that
+> spans multiple lines.
+>
+> Second row 5.0 Here’s another one. Note
+> the blank line between
+> rows.
+> --------------------------------------------------------------
+>
+> Here’s the caption. It may span multiple lines.
+
+Multiline table without caption:
+
+> --------------------------------------------------------------
+> Centered Left Right Default aligned
+> Header Aligned Aligned
+> ----------- ---------- ------------ --------------------------
+> First row 12.0 Example of a row that
+> spans multiple lines.
+>
+> Second row 5.0 Here’s another one. Note
+> the blank line between
+> rows.
+> --------------------------------------------------------------
+
+Table without column headers:
+
+> ----- ----- ----- -----
+> 12 12 12 12
+> 123 123 123 123
+> 1 1 1 1
+> ----- ----- ----- -----
+
+Multiline table without column headers:
+
+> ----------- ---------- ------------ --------------------------
+> First row 12.0 Example of a row that
+> spans multiple lines.
+>
+> Second row 5.0 Here’s another one. Note
+> the blank line between
+> rows.
+> ----------- ---------- ------------ --------------------------
diff --git a/test/tables.html4 b/test/tables.html4
new file mode 100644
index 000000000..5bb7a7de2
--- /dev/null
+++ b/test/tables.html4
@@ -0,0 +1,204 @@
+<p>Simple table with caption:</p>
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<thead>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th>Default</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td>12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td>123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td>1</td>
+</tr>
+</tbody>
+</table>
+<p>Simple table without caption:</p>
+<table>
+<thead>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th>Default</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td>12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td>123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td>1</td>
+</tr>
+</tbody>
+</table>
+<p>Simple table indented two spaces:</p>
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<thead>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th>Default</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td>12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td>123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td>1</td>
+</tr>
+</tbody>
+</table>
+<p>Multiline table with caption:</p>
+<table style="width:79%;">
+<caption>Here’s the caption. It may span multiple lines.</caption>
+<colgroup>
+<col width="15%" />
+<col width="13%" />
+<col width="16%" />
+<col width="33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th align="center">Centered Header</th>
+<th align="left">Left Aligned</th>
+<th align="right">Right Aligned</th>
+<th align="left">Default aligned</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here’s another one. Note the blank line between rows.</td>
+</tr>
+</tbody>
+</table>
+<p>Multiline table without caption:</p>
+<table style="width:79%;">
+<colgroup>
+<col width="15%" />
+<col width="13%" />
+<col width="16%" />
+<col width="33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th align="center">Centered Header</th>
+<th align="left">Left Aligned</th>
+<th align="right">Right Aligned</th>
+<th align="left">Default aligned</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here’s another one. Note the blank line between rows.</td>
+</tr>
+</tbody>
+</table>
+<p>Table without column headers:</p>
+<table>
+<tbody>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="right">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="right">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="right">1</td>
+</tr>
+</tbody>
+</table>
+<p>Multiline table without column headers:</p>
+<table style="width:79%;">
+<colgroup>
+<col width="15%" />
+<col width="13%" />
+<col width="16%" />
+<col width="33%" />
+</colgroup>
+<tbody>
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td>Example of a row that spans multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td>Here’s another one. Note the blank line between rows.</td>
+</tr>
+</tbody>
+</table>
diff --git a/test/tables.html5 b/test/tables.html5
new file mode 100644
index 000000000..17a82110f
--- /dev/null
+++ b/test/tables.html5
@@ -0,0 +1,204 @@
+<p>Simple table with caption:</p>
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<thead>
+<tr class="header">
+<th style="text-align: right;">Right</th>
+<th style="text-align: left;">Left</th>
+<th style="text-align: center;">Center</th>
+<th>Default</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: right;">12</td>
+<td style="text-align: left;">12</td>
+<td style="text-align: center;">12</td>
+<td>12</td>
+</tr>
+<tr class="even">
+<td style="text-align: right;">123</td>
+<td style="text-align: left;">123</td>
+<td style="text-align: center;">123</td>
+<td>123</td>
+</tr>
+<tr class="odd">
+<td style="text-align: right;">1</td>
+<td style="text-align: left;">1</td>
+<td style="text-align: center;">1</td>
+<td>1</td>
+</tr>
+</tbody>
+</table>
+<p>Simple table without caption:</p>
+<table>
+<thead>
+<tr class="header">
+<th style="text-align: right;">Right</th>
+<th style="text-align: left;">Left</th>
+<th style="text-align: center;">Center</th>
+<th>Default</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: right;">12</td>
+<td style="text-align: left;">12</td>
+<td style="text-align: center;">12</td>
+<td>12</td>
+</tr>
+<tr class="even">
+<td style="text-align: right;">123</td>
+<td style="text-align: left;">123</td>
+<td style="text-align: center;">123</td>
+<td>123</td>
+</tr>
+<tr class="odd">
+<td style="text-align: right;">1</td>
+<td style="text-align: left;">1</td>
+<td style="text-align: center;">1</td>
+<td>1</td>
+</tr>
+</tbody>
+</table>
+<p>Simple table indented two spaces:</p>
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<thead>
+<tr class="header">
+<th style="text-align: right;">Right</th>
+<th style="text-align: left;">Left</th>
+<th style="text-align: center;">Center</th>
+<th>Default</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: right;">12</td>
+<td style="text-align: left;">12</td>
+<td style="text-align: center;">12</td>
+<td>12</td>
+</tr>
+<tr class="even">
+<td style="text-align: right;">123</td>
+<td style="text-align: left;">123</td>
+<td style="text-align: center;">123</td>
+<td>123</td>
+</tr>
+<tr class="odd">
+<td style="text-align: right;">1</td>
+<td style="text-align: left;">1</td>
+<td style="text-align: center;">1</td>
+<td>1</td>
+</tr>
+</tbody>
+</table>
+<p>Multiline table with caption:</p>
+<table style="width:79%;">
+<caption>Here’s the caption. It may span multiple lines.</caption>
+<colgroup>
+<col style="width: 15%" />
+<col style="width: 13%" />
+<col style="width: 16%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: center;">Centered Header</th>
+<th style="text-align: left;">Left Aligned</th>
+<th style="text-align: right;">Right Aligned</th>
+<th style="text-align: left;">Default aligned</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: center;">First</td>
+<td style="text-align: left;">row</td>
+<td style="text-align: right;">12.0</td>
+<td style="text-align: left;">Example of a row that spans multiple lines.</td>
+</tr>
+<tr class="even">
+<td style="text-align: center;">Second</td>
+<td style="text-align: left;">row</td>
+<td style="text-align: right;">5.0</td>
+<td style="text-align: left;">Here’s another one. Note the blank line between rows.</td>
+</tr>
+</tbody>
+</table>
+<p>Multiline table without caption:</p>
+<table style="width:79%;">
+<colgroup>
+<col style="width: 15%" />
+<col style="width: 13%" />
+<col style="width: 16%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: center;">Centered Header</th>
+<th style="text-align: left;">Left Aligned</th>
+<th style="text-align: right;">Right Aligned</th>
+<th style="text-align: left;">Default aligned</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: center;">First</td>
+<td style="text-align: left;">row</td>
+<td style="text-align: right;">12.0</td>
+<td style="text-align: left;">Example of a row that spans multiple lines.</td>
+</tr>
+<tr class="even">
+<td style="text-align: center;">Second</td>
+<td style="text-align: left;">row</td>
+<td style="text-align: right;">5.0</td>
+<td style="text-align: left;">Here’s another one. Note the blank line between rows.</td>
+</tr>
+</tbody>
+</table>
+<p>Table without column headers:</p>
+<table>
+<tbody>
+<tr class="odd">
+<td style="text-align: right;">12</td>
+<td style="text-align: left;">12</td>
+<td style="text-align: center;">12</td>
+<td style="text-align: right;">12</td>
+</tr>
+<tr class="even">
+<td style="text-align: right;">123</td>
+<td style="text-align: left;">123</td>
+<td style="text-align: center;">123</td>
+<td style="text-align: right;">123</td>
+</tr>
+<tr class="odd">
+<td style="text-align: right;">1</td>
+<td style="text-align: left;">1</td>
+<td style="text-align: center;">1</td>
+<td style="text-align: right;">1</td>
+</tr>
+</tbody>
+</table>
+<p>Multiline table without column headers:</p>
+<table style="width:79%;">
+<colgroup>
+<col style="width: 15%" />
+<col style="width: 13%" />
+<col style="width: 16%" />
+<col style="width: 33%" />
+</colgroup>
+<tbody>
+<tr class="odd">
+<td style="text-align: center;">First</td>
+<td style="text-align: left;">row</td>
+<td style="text-align: right;">12.0</td>
+<td>Example of a row that spans multiple lines.</td>
+</tr>
+<tr class="even">
+<td style="text-align: center;">Second</td>
+<td style="text-align: left;">row</td>
+<td style="text-align: right;">5.0</td>
+<td>Here’s another one. Note the blank line between rows.</td>
+</tr>
+</tbody>
+</table>
diff --git a/test/tables.icml b/test/tables.icml
new file mode 100644
index 000000000..0280cafed
--- /dev/null
+++ b/test/tables.icml
@@ -0,0 +1,757 @@
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Simple table with caption:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="3" ColumnCount="4">
+ <Column Name="0" />
+ <Column Name="1" />
+ <Column Name="2" />
+ <Column Name="3" />
+ <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Right</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Left</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Center</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Default</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+</Table>
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Demonstration of simple table syntax.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Simple table without caption:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="3" ColumnCount="4">
+ <Column Name="0" />
+ <Column Name="1" />
+ <Column Name="2" />
+ <Column Name="3" />
+ <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Right</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Left</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Center</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Default</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+</Table>
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Simple table indented two spaces:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="3" ColumnCount="4">
+ <Column Name="0" />
+ <Column Name="1" />
+ <Column Name="2" />
+ <Column Name="3" />
+ <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Right</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Left</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Center</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Default</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:3" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+</Table>
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Demonstration of simple table syntax.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Multiline table with caption:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="2" ColumnCount="4">
+ <Column Name="0" SingleColumnWidth="75.0" />
+ <Column Name="1" SingleColumnWidth="68.75" />
+ <Column Name="2" SingleColumnWidth="81.25" />
+ <Column Name="3" SingleColumnWidth="168.75" />
+ <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Centered Header</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Left Aligned</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Right Aligned</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Default aligned</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>First</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>row</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12.0</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Example of a row that spans multiple lines.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Second</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>row</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>5.0</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s another one. Note the blank line between rows.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+</Table>
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s the caption. It may span multiple lines.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Multiline table without caption:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="2" ColumnCount="4">
+ <Column Name="0" SingleColumnWidth="75.0" />
+ <Column Name="1" SingleColumnWidth="68.75" />
+ <Column Name="2" SingleColumnWidth="81.25" />
+ <Column Name="3" SingleColumnWidth="168.75" />
+ <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Centered Header</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Left Aligned</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Right Aligned</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Default aligned</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>First</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>row</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12.0</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Example of a row that spans multiple lines.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Second</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>row</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>5.0</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s another one. Note the blank line between rows.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+</Table>
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Table without column headers:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="0" BodyRowCount="3" ColumnCount="4">
+ <Column Name="0" />
+ <Column Name="1" />
+ <Column Name="2" />
+ <Column Name="3" />
+ <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>123</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>1</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+</Table>
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Multiline table without column headers:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="0" BodyRowCount="2" ColumnCount="4">
+ <Column Name="0" SingleColumnWidth="75.0" />
+ <Column Name="1" SingleColumnWidth="68.75" />
+ <Column Name="2" SingleColumnWidth="81.25" />
+ <Column Name="3" SingleColumnWidth="168.75" />
+ <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>First</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>row</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>12.0</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Example of a row that spans multiple lines.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Second</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>row</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>5.0</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+ <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s another one. Note the blank line between rows.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Cell>
+</Table>
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
+</ParagraphStyleRange>
diff --git a/test/tables.jats b/test/tables.jats
new file mode 100644
index 000000000..46af61635
--- /dev/null
+++ b/test/tables.jats
@@ -0,0 +1,430 @@
+<p>
+ Simple table with caption:
+</p>
+<table-wrap>
+ <caption>
+ <p>
+ Demonstration of simple table syntax.
+ </p>
+ </caption>
+ <table>
+ <col align="right" />
+ <col align="left" />
+ <col align="center" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ Right
+ </th>
+ <th>
+ Left
+ </th>
+ <th>
+ Center
+ </th>
+ <th>
+ Default
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</table-wrap>
+<p>
+ Simple table without caption:
+</p>
+<table>
+ <col align="right" />
+ <col align="left" />
+ <col align="center" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ Right
+ </th>
+ <th>
+ Left
+ </th>
+ <th>
+ Center
+ </th>
+ <th>
+ Default
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ </tr>
+ </tbody>
+</table>
+<p>
+ Simple table indented two spaces:
+</p>
+<table-wrap>
+ <caption>
+ <p>
+ Demonstration of simple table syntax.
+ </p>
+ </caption>
+ <table>
+ <col align="right" />
+ <col align="left" />
+ <col align="center" />
+ <col align="left" />
+ <thead>
+ <tr>
+ <th>
+ Right
+ </th>
+ <th>
+ Left
+ </th>
+ <th>
+ Center
+ </th>
+ <th>
+ Default
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</table-wrap>
+<p>
+ Multiline table with caption:
+</p>
+<table-wrap>
+ <caption>
+ <p>
+ Here’s the caption. It may span multiple lines.
+ </p>
+ </caption>
+ <table>
+ <col width="15*" align="center" />
+ <col width="13*" align="left" />
+ <col width="16*" align="right" />
+ <col width="33*" align="left" />
+ <thead>
+ <tr>
+ <th>
+ Centered Header
+ </th>
+ <th>
+ Left Aligned
+ </th>
+ <th>
+ Right Aligned
+ </th>
+ <th>
+ Default aligned
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ First
+ </td>
+ <td>
+ row
+ </td>
+ <td>
+ 12.0
+ </td>
+ <td>
+ Example of a row that spans multiple lines.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Second
+ </td>
+ <td>
+ row
+ </td>
+ <td>
+ 5.0
+ </td>
+ <td>
+ Here’s another one. Note the blank line between rows.
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</table-wrap>
+<p>
+ Multiline table without caption:
+</p>
+<table>
+ <col width="15*" align="center" />
+ <col width="13*" align="left" />
+ <col width="16*" align="right" />
+ <col width="33*" align="left" />
+ <thead>
+ <tr>
+ <th>
+ Centered Header
+ </th>
+ <th>
+ Left Aligned
+ </th>
+ <th>
+ Right Aligned
+ </th>
+ <th>
+ Default aligned
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ First
+ </td>
+ <td>
+ row
+ </td>
+ <td>
+ 12.0
+ </td>
+ <td>
+ Example of a row that spans multiple lines.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Second
+ </td>
+ <td>
+ row
+ </td>
+ <td>
+ 5.0
+ </td>
+ <td>
+ Here’s another one. Note the blank line between rows.
+ </td>
+ </tr>
+ </tbody>
+</table>
+<p>
+ Table without column headers:
+</p>
+<table>
+ <col align="right" />
+ <col align="left" />
+ <col align="center" />
+ <col align="right" />
+ <tbody>
+ <tr>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ <td>
+ 12
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ <td>
+ 123
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ <td>
+ 1
+ </td>
+ </tr>
+ </tbody>
+</table>
+<p>
+ Multiline table without column headers:
+</p>
+<table>
+ <col width="15*" align="center" />
+ <col width="13*" align="left" />
+ <col width="16*" align="right" />
+ <col width="33*" align="left" />
+ <tbody>
+ <tr>
+ <td>
+ First
+ </td>
+ <td>
+ row
+ </td>
+ <td>
+ 12.0
+ </td>
+ <td>
+ Example of a row that spans multiple lines.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Second
+ </td>
+ <td>
+ row
+ </td>
+ <td>
+ 5.0
+ </td>
+ <td>
+ Here’s another one. Note the blank line between rows.
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/test/tables.latex b/test/tables.latex
new file mode 100644
index 000000000..759b35dfa
--- /dev/null
+++ b/test/tables.latex
@@ -0,0 +1,170 @@
+Simple table with caption:
+
+\begin{longtable}[]{@{}rlcl@{}}
+\caption{Demonstration of simple table syntax.}\tabularnewline
+\toprule
+Right & Left & Center & Default\tabularnewline
+\midrule
+\endfirsthead
+\toprule
+Right & Left & Center & Default\tabularnewline
+\midrule
+\endhead
+12 & 12 & 12 & 12\tabularnewline
+123 & 123 & 123 & 123\tabularnewline
+1 & 1 & 1 & 1\tabularnewline
+\bottomrule
+\end{longtable}
+
+Simple table without caption:
+
+\begin{longtable}[]{@{}rlcl@{}}
+\toprule
+Right & Left & Center & Default\tabularnewline
+\midrule
+\endhead
+12 & 12 & 12 & 12\tabularnewline
+123 & 123 & 123 & 123\tabularnewline
+1 & 1 & 1 & 1\tabularnewline
+\bottomrule
+\end{longtable}
+
+Simple table indented two spaces:
+
+\begin{longtable}[]{@{}rlcl@{}}
+\caption{Demonstration of simple table syntax.}\tabularnewline
+\toprule
+Right & Left & Center & Default\tabularnewline
+\midrule
+\endfirsthead
+\toprule
+Right & Left & Center & Default\tabularnewline
+\midrule
+\endhead
+12 & 12 & 12 & 12\tabularnewline
+123 & 123 & 123 & 123\tabularnewline
+1 & 1 & 1 & 1\tabularnewline
+\bottomrule
+\end{longtable}
+
+Multiline table with caption:
+
+\begin{longtable}[]{@{}clrl@{}}
+\caption{Here's the caption. It may span multiple lines.}\tabularnewline
+\toprule
+\begin{minipage}[b]{0.13\columnwidth}\centering
+Centered Header\strut
+\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright
+Left Aligned\strut
+\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft
+Right Aligned\strut
+\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright
+Default aligned\strut
+\end{minipage}\tabularnewline
+\midrule
+\endfirsthead
+\toprule
+\begin{minipage}[b]{0.13\columnwidth}\centering
+Centered Header\strut
+\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright
+Left Aligned\strut
+\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft
+Right Aligned\strut
+\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright
+Default aligned\strut
+\end{minipage}\tabularnewline
+\midrule
+\endhead
+\begin{minipage}[t]{0.13\columnwidth}\centering
+First\strut
+\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright
+row\strut
+\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft
+12.0\strut
+\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright
+Example of a row that spans multiple lines.\strut
+\end{minipage}\tabularnewline
+\begin{minipage}[t]{0.13\columnwidth}\centering
+Second\strut
+\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright
+row\strut
+\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft
+5.0\strut
+\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright
+Here's another one. Note the blank line between rows.\strut
+\end{minipage}\tabularnewline
+\bottomrule
+\end{longtable}
+
+Multiline table without caption:
+
+\begin{longtable}[]{@{}clrl@{}}
+\toprule
+\begin{minipage}[b]{0.13\columnwidth}\centering
+Centered Header\strut
+\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright
+Left Aligned\strut
+\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft
+Right Aligned\strut
+\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright
+Default aligned\strut
+\end{minipage}\tabularnewline
+\midrule
+\endhead
+\begin{minipage}[t]{0.13\columnwidth}\centering
+First\strut
+\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright
+row\strut
+\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft
+12.0\strut
+\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright
+Example of a row that spans multiple lines.\strut
+\end{minipage}\tabularnewline
+\begin{minipage}[t]{0.13\columnwidth}\centering
+Second\strut
+\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright
+row\strut
+\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft
+5.0\strut
+\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright
+Here's another one. Note the blank line between rows.\strut
+\end{minipage}\tabularnewline
+\bottomrule
+\end{longtable}
+
+Table without column headers:
+
+\begin{longtable}[]{@{}rlcr@{}}
+\toprule
+\endhead
+12 & 12 & 12 & 12\tabularnewline
+123 & 123 & 123 & 123\tabularnewline
+1 & 1 & 1 & 1\tabularnewline
+\bottomrule
+\end{longtable}
+
+Multiline table without column headers:
+
+\begin{longtable}[]{@{}clrl@{}}
+\toprule
+\endhead
+\begin{minipage}[t]{0.13\columnwidth}\centering
+First\strut
+\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright
+row\strut
+\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft
+12.0\strut
+\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright
+Example of a row that spans multiple lines.\strut
+\end{minipage}\tabularnewline
+\begin{minipage}[t]{0.13\columnwidth}\centering
+Second\strut
+\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright
+row\strut
+\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft
+5.0\strut
+\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright
+Here's another one. Note the blank line between rows.\strut
+\end{minipage}\tabularnewline
+\bottomrule
+\end{longtable}
diff --git a/test/tables.man b/test/tables.man
new file mode 100644
index 000000000..dd6a3cce9
--- /dev/null
+++ b/test/tables.man
@@ -0,0 +1,267 @@
+.PP
+Simple table with caption:
+.PP
+Demonstration of simple table syntax.
+.TS
+tab(@);
+r l c l.
+T{
+Right
+T}@T{
+Left
+T}@T{
+Center
+T}@T{
+Default
+T}
+_
+T{
+12
+T}@T{
+12
+T}@T{
+12
+T}@T{
+12
+T}
+T{
+123
+T}@T{
+123
+T}@T{
+123
+T}@T{
+123
+T}
+T{
+1
+T}@T{
+1
+T}@T{
+1
+T}@T{
+1
+T}
+.TE
+.PP
+Simple table without caption:
+.PP
+.TS
+tab(@);
+r l c l.
+T{
+Right
+T}@T{
+Left
+T}@T{
+Center
+T}@T{
+Default
+T}
+_
+T{
+12
+T}@T{
+12
+T}@T{
+12
+T}@T{
+12
+T}
+T{
+123
+T}@T{
+123
+T}@T{
+123
+T}@T{
+123
+T}
+T{
+1
+T}@T{
+1
+T}@T{
+1
+T}@T{
+1
+T}
+.TE
+.PP
+Simple table indented two spaces:
+.PP
+Demonstration of simple table syntax.
+.TS
+tab(@);
+r l c l.
+T{
+Right
+T}@T{
+Left
+T}@T{
+Center
+T}@T{
+Default
+T}
+_
+T{
+12
+T}@T{
+12
+T}@T{
+12
+T}@T{
+12
+T}
+T{
+123
+T}@T{
+123
+T}@T{
+123
+T}@T{
+123
+T}
+T{
+1
+T}@T{
+1
+T}@T{
+1
+T}@T{
+1
+T}
+.TE
+.PP
+Multiline table with caption:
+.PP
+Here's the caption. It may span multiple lines.
+.TS
+tab(@);
+cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
+T{
+Centered Header
+T}@T{
+Left Aligned
+T}@T{
+Right Aligned
+T}@T{
+Default aligned
+T}
+_
+T{
+First
+T}@T{
+row
+T}@T{
+12.0
+T}@T{
+Example of a row that spans multiple lines.
+T}
+T{
+Second
+T}@T{
+row
+T}@T{
+5.0
+T}@T{
+Here's another one.
+Note the blank line between rows.
+T}
+.TE
+.PP
+Multiline table without caption:
+.PP
+.TS
+tab(@);
+cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
+T{
+Centered Header
+T}@T{
+Left Aligned
+T}@T{
+Right Aligned
+T}@T{
+Default aligned
+T}
+_
+T{
+First
+T}@T{
+row
+T}@T{
+12.0
+T}@T{
+Example of a row that spans multiple lines.
+T}
+T{
+Second
+T}@T{
+row
+T}@T{
+5.0
+T}@T{
+Here's another one.
+Note the blank line between rows.
+T}
+.TE
+.PP
+Table without column headers:
+.PP
+.TS
+tab(@);
+r l c r.
+T{
+12
+T}@T{
+12
+T}@T{
+12
+T}@T{
+12
+T}
+T{
+123
+T}@T{
+123
+T}@T{
+123
+T}@T{
+123
+T}
+T{
+1
+T}@T{
+1
+T}@T{
+1
+T}@T{
+1
+T}
+.TE
+.PP
+Multiline table without column headers:
+.PP
+.TS
+tab(@);
+cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
+T{
+First
+T}@T{
+row
+T}@T{
+12.0
+T}@T{
+Example of a row that spans multiple lines.
+T}
+T{
+Second
+T}@T{
+row
+T}@T{
+5.0
+T}@T{
+Here's another one.
+Note the blank line between rows.
+T}
+.TE
diff --git a/test/tables.markdown b/test/tables.markdown
new file mode 100644
index 000000000..f5ee776fa
--- /dev/null
+++ b/test/tables.markdown
@@ -0,0 +1,76 @@
+Simple table with caption:
+
+ Right Left Center Default
+ ------- ------ -------- ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+ : Demonstration of simple table syntax.
+
+Simple table without caption:
+
+ Right Left Center Default
+ ------- ------ -------- ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+Simple table indented two spaces:
+
+ Right Left Center Default
+ ------- ------ -------- ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+ : Demonstration of simple table syntax.
+
+Multiline table with caption:
+
+ -------------------------------------------------------------
+ Centered Left Right Default aligned
+ Header Aligned Aligned
+ ----------- ---------- ------------ -------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here's another one. Note
+ the blank line between
+ rows.
+ -------------------------------------------------------------
+
+ : Here's the caption. It may span multiple lines.
+
+Multiline table without caption:
+
+ -------------------------------------------------------------
+ Centered Left Right Default aligned
+ Header Aligned Aligned
+ ----------- ---------- ------------ -------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here's another one. Note
+ the blank line between
+ rows.
+ -------------------------------------------------------------
+
+Table without column headers:
+
+ ----- ----- ----- -----
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+ ----- ----- ----- -----
+
+Multiline table without column headers:
+
+ ----------- ---------- ------------ -------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here's another one. Note
+ the blank line between
+ rows.
+ ----------- ---------- ------------ -------------------------
diff --git a/test/tables.mediawiki b/test/tables.mediawiki
new file mode 100644
index 000000000..ce7c17887
--- /dev/null
+++ b/test/tables.mediawiki
@@ -0,0 +1,146 @@
+Simple table with caption:
+
+{|
+|+ Demonstration of simple table syntax.
+!align="right"| Right
+! Left
+!align="center"| Center
+! Default
+|-
+|align="right"| 12
+| 12
+|align="center"| 12
+| 12
+|-
+|align="right"| 123
+| 123
+|align="center"| 123
+| 123
+|-
+|align="right"| 1
+| 1
+|align="center"| 1
+| 1
+|}
+
+Simple table without caption:
+
+{|
+!align="right"| Right
+! Left
+!align="center"| Center
+! Default
+|-
+|align="right"| 12
+| 12
+|align="center"| 12
+| 12
+|-
+|align="right"| 123
+| 123
+|align="center"| 123
+| 123
+|-
+|align="right"| 1
+| 1
+|align="center"| 1
+| 1
+|}
+
+Simple table indented two spaces:
+
+{|
+|+ Demonstration of simple table syntax.
+!align="right"| Right
+! Left
+!align="center"| Center
+! Default
+|-
+|align="right"| 12
+| 12
+|align="center"| 12
+| 12
+|-
+|align="right"| 123
+| 123
+|align="center"| 123
+| 123
+|-
+|align="right"| 1
+| 1
+|align="center"| 1
+| 1
+|}
+
+Multiline table with caption:
+
+{|
+|+ Here’s the caption. It may span multiple lines.
+!align="center" width="15%"| Centered Header
+!width="13%"| Left Aligned
+!align="right" width="16%"| Right Aligned
+!width="33%"| Default aligned
+|-
+|align="center"| First
+| row
+|align="right"| 12.0
+| Example of a row that spans multiple lines.
+|-
+|align="center"| Second
+| row
+|align="right"| 5.0
+| Here’s another one. Note the blank line between rows.
+|}
+
+Multiline table without caption:
+
+{|
+!align="center" width="15%"| Centered Header
+!width="13%"| Left Aligned
+!align="right" width="16%"| Right Aligned
+!width="33%"| Default aligned
+|-
+|align="center"| First
+| row
+|align="right"| 12.0
+| Example of a row that spans multiple lines.
+|-
+|align="center"| Second
+| row
+|align="right"| 5.0
+| Here’s another one. Note the blank line between rows.
+|}
+
+Table without column headers:
+
+{|
+|align="right"| 12
+| 12
+|align="center"| 12
+|align="right"| 12
+|-
+|align="right"| 123
+| 123
+|align="center"| 123
+|align="right"| 123
+|-
+|align="right"| 1
+| 1
+|align="center"| 1
+|align="right"| 1
+|}
+
+Multiline table without column headers:
+
+{|
+|align="center" width="15%"| First
+|width="13%"| row
+|align="right" width="16%"| 12.0
+|width="33%"| Example of a row that spans multiple lines.
+|-
+|align="center"| Second
+| row
+|align="right"| 5.0
+| Here’s another one. Note the blank line between rows.
+|}
+
diff --git a/test/tables.ms b/test/tables.ms
new file mode 100644
index 000000000..21b3bd4e2
--- /dev/null
+++ b/test/tables.ms
@@ -0,0 +1,267 @@
+.LP
+Simple table with caption:
+.PP
+Demonstration of simple table syntax.
+.TS
+delim(@@) tab( );
+r l c l.
+T{
+Right
+T} T{
+Left
+T} T{
+Center
+T} T{
+Default
+T}
+_
+T{
+12
+T} T{
+12
+T} T{
+12
+T} T{
+12
+T}
+T{
+123
+T} T{
+123
+T} T{
+123
+T} T{
+123
+T}
+T{
+1
+T} T{
+1
+T} T{
+1
+T} T{
+1
+T}
+.TE
+.LP
+Simple table without caption:
+.PP
+.TS
+delim(@@) tab( );
+r l c l.
+T{
+Right
+T} T{
+Left
+T} T{
+Center
+T} T{
+Default
+T}
+_
+T{
+12
+T} T{
+12
+T} T{
+12
+T} T{
+12
+T}
+T{
+123
+T} T{
+123
+T} T{
+123
+T} T{
+123
+T}
+T{
+1
+T} T{
+1
+T} T{
+1
+T} T{
+1
+T}
+.TE
+.LP
+Simple table indented two spaces:
+.PP
+Demonstration of simple table syntax.
+.TS
+delim(@@) tab( );
+r l c l.
+T{
+Right
+T} T{
+Left
+T} T{
+Center
+T} T{
+Default
+T}
+_
+T{
+12
+T} T{
+12
+T} T{
+12
+T} T{
+12
+T}
+T{
+123
+T} T{
+123
+T} T{
+123
+T} T{
+123
+T}
+T{
+1
+T} T{
+1
+T} T{
+1
+T} T{
+1
+T}
+.TE
+.LP
+Multiline table with caption:
+.PP
+Here's the caption. It may span multiple lines.
+.TS
+delim(@@) tab( );
+cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
+T{
+Centered Header
+T} T{
+Left Aligned
+T} T{
+Right Aligned
+T} T{
+Default aligned
+T}
+_
+T{
+First
+T} T{
+row
+T} T{
+12.0
+T} T{
+Example of a row that spans multiple lines.
+T}
+T{
+Second
+T} T{
+row
+T} T{
+5.0
+T} T{
+Here's another one.
+Note the blank line between rows.
+T}
+.TE
+.LP
+Multiline table without caption:
+.PP
+.TS
+delim(@@) tab( );
+cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
+T{
+Centered Header
+T} T{
+Left Aligned
+T} T{
+Right Aligned
+T} T{
+Default aligned
+T}
+_
+T{
+First
+T} T{
+row
+T} T{
+12.0
+T} T{
+Example of a row that spans multiple lines.
+T}
+T{
+Second
+T} T{
+row
+T} T{
+5.0
+T} T{
+Here's another one.
+Note the blank line between rows.
+T}
+.TE
+.LP
+Table without column headers:
+.PP
+.TS
+delim(@@) tab( );
+r l c r.
+T{
+12
+T} T{
+12
+T} T{
+12
+T} T{
+12
+T}
+T{
+123
+T} T{
+123
+T} T{
+123
+T} T{
+123
+T}
+T{
+1
+T} T{
+1
+T} T{
+1
+T} T{
+1
+T}
+.TE
+.LP
+Multiline table without column headers:
+.PP
+.TS
+delim(@@) tab( );
+cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
+T{
+First
+T} T{
+row
+T} T{
+12.0
+T} T{
+Example of a row that spans multiple lines.
+T}
+T{
+Second
+T} T{
+row
+T} T{
+5.0
+T} T{
+Here's another one.
+Note the blank line between rows.
+T}
+.TE
diff --git a/test/tables.muse b/test/tables.muse
new file mode 100644
index 000000000..fdf20be49
--- /dev/null
+++ b/test/tables.muse
@@ -0,0 +1,46 @@
+Simple table with caption:
+
+ Right || Left || Center || Default
+ 12 | 12 | 12 | 12
+ 123 | 123 | 123 | 123
+ 1 | 1 | 1 | 1
+ |+ Demonstration of simple table syntax. +|
+
+Simple table without caption:
+
+ Right || Left || Center || Default
+ 12 | 12 | 12 | 12
+ 123 | 123 | 123 | 123
+ 1 | 1 | 1 | 1
+
+Simple table indented two spaces:
+
+ Right || Left || Center || Default
+ 12 | 12 | 12 | 12
+ 123 | 123 | 123 | 123
+ 1 | 1 | 1 | 1
+ |+ Demonstration of simple table syntax. +|
+
+Multiline table with caption:
+
+ Centered Header || Left Aligned || Right Aligned || Default aligned
+ First | row | 12.0 | Example of a row that spans multiple lines.
+ Second | row | 5.0 | Here’s another one. Note the blank line between rows.
+ |+ Here’s the caption. It may span multiple lines. +|
+
+Multiline table without caption:
+
+ Centered Header || Left Aligned || Right Aligned || Default aligned
+ First | row | 12.0 | Example of a row that spans multiple lines.
+ Second | row | 5.0 | Here’s another one. Note the blank line between rows.
+
+Table without column headers:
+
+ 12 | 12 | 12 | 12
+ 123 | 123 | 123 | 123
+ 1 | 1 | 1 | 1
+
+Multiline table without column headers:
+
+ First | row | 12.0 | Example of a row that spans multiple lines.
+ Second | row | 5.0 | Here’s another one. Note the blank line between rows.
diff --git a/test/tables.native b/test/tables.native
new file mode 100644
index 000000000..a60f9b586
--- /dev/null
+++ b/test/tables.native
@@ -0,0 +1,114 @@
+[Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"]
+,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Simple",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+,Table [] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Simple",Space,Str "table",Space,Str "indented",Space,Str "two",Space,Str "spaces:"]
+,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
+ [[Plain [Str "Right"]]
+ ,[Plain [Str "Left"]]
+ ,[Plain [Str "Center"]]
+ ,[Plain [Str "Default"]]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"]
+,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",SoftBreak,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.3375]
+ [[Plain [Str "Centered",SoftBreak,Str "Header"]]
+ ,[Plain [Str "Left",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Right",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Default",Space,Str "aligned"]]]
+ [[[Plain [Str "First"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "12.0"]]
+ ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",Space,Str "spans",SoftBreak,Str "multiple",Space,Str "lines."]]]
+ ,[[Plain [Str "Second"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "5.0"]]
+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows."]]]]
+,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"]
+,Table [] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.3375]
+ [[Plain [Str "Centered",SoftBreak,Str "Header"]]
+ ,[Plain [Str "Left",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Right",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Default",Space,Str "aligned"]]]
+ [[[Plain [Str "First"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "12.0"]]
+ ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",Space,Str "spans",SoftBreak,Str "multiple",Space,Str "lines."]]]
+ ,[[Plain [Str "Second"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "5.0"]]
+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows."]]]]
+,Para [Str "Table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
+,Table [] [AlignRight,AlignLeft,AlignCenter,AlignRight] [0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]
+ ,[Plain [Str "12"]]]
+ ,[[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]
+ ,[Plain [Str "123"]]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "1"]]]]
+,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
+,Table [] [AlignCenter,AlignLeft,AlignRight,AlignDefault] [0.15,0.1375,0.1625,0.3375]
+ [[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "First"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "12.0"]]
+ ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",Space,Str "spans",SoftBreak,Str "multiple",Space,Str "lines."]]]
+ ,[[Plain [Str "Second"]]
+ ,[Plain [Str "row"]]
+ ,[Plain [Str "5.0"]]
+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows."]]]]]
diff --git a/test/tables.opendocument b/test/tables.opendocument
new file mode 100644
index 000000000..c331ecc43
--- /dev/null
+++ b/test/tables.opendocument
@@ -0,0 +1,397 @@
+<text:p text:style-name="Text_20_body">Simple table with caption:</text:p>
+<table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A" />
+ <table:table-column table:style-name="Table1.B" />
+ <table:table-column table:style-name="Table1.C" />
+ <table:table-column table:style-name="Table1.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P1">Right</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P2">Center</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P3">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P4">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P3">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P4">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P3">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P4">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ </table:table-row>
+</table:table>
+<text:p text:style-name="Table">Demonstration of simple table syntax.</text:p>
+<text:p text:style-name="First_20_paragraph">Simple table without
+caption:</text:p>
+<table:table table:name="Table2" table:style-name="Table2">
+ <table:table-column table:style-name="Table2.A" />
+ <table:table-column table:style-name="Table2.B" />
+ <table:table-column table:style-name="Table2.C" />
+ <table:table-column table:style-name="Table2.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P5">Right</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P6">Center</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P7">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P8">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P7">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P8">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P7">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P8">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ </table:table-row>
+</table:table>
+<text:p text:style-name="First_20_paragraph">Simple table indented two
+spaces:</text:p>
+<table:table table:name="Table3" table:style-name="Table3">
+ <table:table-column table:style-name="Table3.A" />
+ <table:table-column table:style-name="Table3.B" />
+ <table:table-column table:style-name="Table3.C" />
+ <table:table-column table:style-name="Table3.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P9">Right</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P10">Center</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P11">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P12">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P11">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P12">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P11">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="P12">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table3.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ </table:table-row>
+</table:table>
+<text:p text:style-name="Table">Demonstration of simple table syntax.</text:p>
+<text:p text:style-name="First_20_paragraph">Multiline table with
+caption:</text:p>
+<table:table table:name="Table4" table:style-name="Table4">
+ <table:table-column table:style-name="Table4.A" />
+ <table:table-column table:style-name="Table4.B" />
+ <table:table-column table:style-name="Table4.C" />
+ <table:table-column table:style-name="Table4.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P13">Centered Header</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left Aligned</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P14">Right Aligned</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default aligned</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P15">First</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P16">12.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Example of a row that spans
+ multiple lines.</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P15">Second</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="P16">5.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table4.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Here’s another one. Note the
+ blank line between rows.</text:p>
+ </table:table-cell>
+ </table:table-row>
+</table:table>
+<text:p text:style-name="Table">Here’s the caption. It may span multiple
+lines.</text:p>
+<text:p text:style-name="First_20_paragraph">Multiline table without
+caption:</text:p>
+<table:table table:name="Table5" table:style-name="Table5">
+ <table:table-column table:style-name="Table5.A" />
+ <table:table-column table:style-name="Table5.B" />
+ <table:table-column table:style-name="Table5.C" />
+ <table:table-column table:style-name="Table5.D" />
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P17">Centered Header</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Left Aligned</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P18">Right Aligned</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Heading">Default aligned</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-row>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P19">First</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P20">12.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Example of a row that spans
+ multiple lines.</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P19">Second</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="P20">5.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table5.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Here’s another one. Note the
+ blank line between rows.</text:p>
+ </table:table-cell>
+ </table:table-row>
+</table:table>
+<text:p text:style-name="First_20_paragraph">Table without column
+headers:</text:p>
+<table:table table:name="Table6" table:style-name="Table6">
+ <table:table-column table:style-name="Table6.A" />
+ <table:table-column table:style-name="Table6.B" />
+ <table:table-column table:style-name="Table6.C" />
+ <table:table-column table:style-name="Table6.D" />
+ <table:table-row>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P24">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P25">12</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P26">12</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P24">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P25">123</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P26">123</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P24">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P25">1</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table6.A1" office:value-type="string">
+ <text:p text:style-name="P26">1</text:p>
+ </table:table-cell>
+ </table:table-row>
+</table:table>
+<text:p text:style-name="First_20_paragraph">Multiline table without column
+headers:</text:p>
+<table:table table:name="Table7" table:style-name="Table7">
+ <table:table-column table:style-name="Table7.A" />
+ <table:table-column table:style-name="Table7.B" />
+ <table:table-column table:style-name="Table7.C" />
+ <table:table-column table:style-name="Table7.D" />
+ <table:table-row>
+ <table:table-cell table:style-name="Table7.A1" office:value-type="string">
+ <text:p text:style-name="P29">First</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table7.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table7.A1" office:value-type="string">
+ <text:p text:style-name="P30">12.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table7.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Example of a row that spans
+ multiple lines.</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table7.A1" office:value-type="string">
+ <text:p text:style-name="P29">Second</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table7.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">row</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table7.A1" office:value-type="string">
+ <text:p text:style-name="P30">5.0</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table7.A1" office:value-type="string">
+ <text:p text:style-name="Table_20_Contents">Here’s another one. Note the
+ blank line between rows.</text:p>
+ </table:table-cell>
+ </table:table-row>
+</table:table>
diff --git a/tests/tables.org b/test/tables.org
index 9eaf5e706..9eaf5e706 100644
--- a/tests/tables.org
+++ b/test/tables.org
diff --git a/test/tables.plain b/test/tables.plain
new file mode 100644
index 000000000..7013d0caa
--- /dev/null
+++ b/test/tables.plain
@@ -0,0 +1,76 @@
+Simple table with caption:
+
+ Right Left Center Default
+ ------- ------ -------- ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+ : Demonstration of simple table syntax.
+
+Simple table without caption:
+
+ Right Left Center Default
+ ------- ------ -------- ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+Simple table indented two spaces:
+
+ Right Left Center Default
+ ------- ------ -------- ---------
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+
+ : Demonstration of simple table syntax.
+
+Multiline table with caption:
+
+ -------------------------------------------------------------
+ Centered Left Right Default aligned
+ Header Aligned Aligned
+ ----------- ---------- ------------ -------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here’s another one. Note
+ the blank line between
+ rows.
+ -------------------------------------------------------------
+
+ : Here’s the caption. It may span multiple lines.
+
+Multiline table without caption:
+
+ -------------------------------------------------------------
+ Centered Left Right Default aligned
+ Header Aligned Aligned
+ ----------- ---------- ------------ -------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here’s another one. Note
+ the blank line between
+ rows.
+ -------------------------------------------------------------
+
+Table without column headers:
+
+ ----- ----- ----- -----
+ 12 12 12 12
+ 123 123 123 123
+ 1 1 1 1
+ ----- ----- ----- -----
+
+Multiline table without column headers:
+
+ ----------- ---------- ------------ -------------------------
+ First row 12.0 Example of a row that
+ spans multiple lines.
+
+ Second row 5.0 Here’s another one. Note
+ the blank line between
+ rows.
+ ----------- ---------- ------------ -------------------------
diff --git a/test/tables.rst b/test/tables.rst
new file mode 100644
index 000000000..e76c505aa
--- /dev/null
+++ b/test/tables.rst
@@ -0,0 +1,90 @@
+Simple table with caption:
+
+.. table:: Demonstration of simple table syntax.
+
+ +-------+------+--------+---------+
+ | Right | Left | Center | Default |
+ +=======+======+========+=========+
+ | 12 | 12 | 12 | 12 |
+ +-------+------+--------+---------+
+ | 123 | 123 | 123 | 123 |
+ +-------+------+--------+---------+
+ | 1 | 1 | 1 | 1 |
+ +-------+------+--------+---------+
+
+Simple table without caption:
+
++-------+------+--------+---------+
+| Right | Left | Center | Default |
++=======+======+========+=========+
+| 12 | 12 | 12 | 12 |
++-------+------+--------+---------+
+| 123 | 123 | 123 | 123 |
++-------+------+--------+---------+
+| 1 | 1 | 1 | 1 |
++-------+------+--------+---------+
+
+Simple table indented two spaces:
+
+.. table:: Demonstration of simple table syntax.
+
+ +-------+------+--------+---------+
+ | Right | Left | Center | Default |
+ +=======+======+========+=========+
+ | 12 | 12 | 12 | 12 |
+ +-------+------+--------+---------+
+ | 123 | 123 | 123 | 123 |
+ +-------+------+--------+---------+
+ | 1 | 1 | 1 | 1 |
+ +-------+------+--------+---------+
+
+Multiline table with caption:
+
+.. table:: Here’s the caption. It may span multiple lines.
+
+ +----------+---------+-----------+-------------------------+
+ | Centered | Left | Right | Default aligned |
+ | Header | Aligned | Aligned | |
+ +==========+=========+===========+=========================+
+ | First | row | 12.0 | Example of a row that |
+ | | | | spans multiple lines. |
+ +----------+---------+-----------+-------------------------+
+ | Second | row | 5.0 | Here’s another one. |
+ | | | | Note the blank line |
+ | | | | between rows. |
+ +----------+---------+-----------+-------------------------+
+
+Multiline table without caption:
+
++----------+---------+-----------+-------------------------+
+| Centered | Left | Right | Default aligned |
+| Header | Aligned | Aligned | |
++==========+=========+===========+=========================+
+| First | row | 12.0 | Example of a row that |
+| | | | spans multiple lines. |
++----------+---------+-----------+-------------------------+
+| Second | row | 5.0 | Here’s another one. |
+| | | | Note the blank line |
+| | | | between rows. |
++----------+---------+-----------+-------------------------+
+
+Table without column headers:
+
++-----+-----+-----+-----+
+| 12 | 12 | 12 | 12 |
++-----+-----+-----+-----+
+| 123 | 123 | 123 | 123 |
++-----+-----+-----+-----+
+| 1 | 1 | 1 | 1 |
++-----+-----+-----+-----+
+
+Multiline table without column headers:
+
++----------+---------+-----------+-------------------------+
+| First | row | 12.0 | Example of a row that |
+| | | | spans multiple lines. |
++----------+---------+-----------+-------------------------+
+| Second | row | 5.0 | Here’s another one. |
+| | | | Note the blank line |
+| | | | between rows. |
++----------+---------+-----------+-------------------------+
diff --git a/test/tables.rtf b/test/tables.rtf
new file mode 100644
index 000000000..57030b114
--- /dev/null
+++ b/test/tables.rtf
@@ -0,0 +1,360 @@
+{\pard \ql \f0 \sa180 \li0 \fi0 Simple table with caption:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx2160\clbrdrb\brdrs\cellx4320\clbrdrb\brdrs\cellx6480\clbrdrb\brdrs\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Center\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 Demonstration of simple table syntax.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Simple table without caption:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx2160\clbrdrb\brdrs\cellx4320\clbrdrb\brdrs\cellx6480\clbrdrb\brdrs\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Center\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Simple table indented two spaces:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx2160\clbrdrb\brdrs\cellx4320\clbrdrb\brdrs\cellx6480\clbrdrb\brdrs\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Center\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 Demonstration of simple table syntax.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiline table with caption:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6804
+\trkeep\intbl
+{
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Centered Header\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left Aligned\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right Aligned\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default aligned\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12.0\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Example of a row that spans multiple lines.\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 5.0\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Here\u8217's another one. Note the blank line between rows.\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's the caption. It may span multiple lines.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiline table without caption:\par}
+{
+\trowd \trgaph120
+\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6804
+\trkeep\intbl
+{
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Centered Header\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left Aligned\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right Aligned\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default aligned\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12.0\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Example of a row that spans multiple lines.\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 5.0\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Here\u8217's another one. Note the blank line between rows.\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Table without column headers:\par}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx2160\cellx4320\cellx6480\cellx8640
+\trkeep\intbl
+{
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiline table without column headers:\par}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12.0\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Example of a row that spans multiple lines.\par}
+\cell}
+}
+\intbl\row}
+{
+\trowd \trgaph120
+\cellx1296\cellx2484\cellx3888\cellx6804
+\trkeep\intbl
+{
+{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
+\cell}
+{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 5.0\par}
+\cell}
+{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Here\u8217's another one. Note the blank line between rows.\par}
+\cell}
+}
+\intbl\row}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+
diff --git a/test/tables.tei b/test/tables.tei
new file mode 100644
index 000000000..64438e520
--- /dev/null
+++ b/test/tables.tei
@@ -0,0 +1,171 @@
+<p>Simple table with caption:</p>
+<table>
+ <row role="label">
+ <cell><p>Right</p></cell>
+ <cell><p>Left</p></cell>
+ <cell><p>Center</p></cell>
+ <cell><p>Default</p></cell>
+ </row>
+ <row>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ </row>
+ <row>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ </row>
+ <row>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ </row>
+</table>
+<p>Simple table without caption:</p>
+<table>
+ <row role="label">
+ <cell><p>Right</p></cell>
+ <cell><p>Left</p></cell>
+ <cell><p>Center</p></cell>
+ <cell><p>Default</p></cell>
+ </row>
+ <row>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ </row>
+ <row>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ </row>
+ <row>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ </row>
+</table>
+<p>Simple table indented two spaces:</p>
+<table>
+ <row role="label">
+ <cell><p>Right</p></cell>
+ <cell><p>Left</p></cell>
+ <cell><p>Center</p></cell>
+ <cell><p>Default</p></cell>
+ </row>
+ <row>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ </row>
+ <row>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ </row>
+ <row>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ </row>
+</table>
+<p>Multiline table with caption:</p>
+<table>
+ <row role="label">
+ <cell><p>Centered Header</p></cell>
+ <cell><p>Left Aligned</p></cell>
+ <cell><p>Right Aligned</p></cell>
+ <cell><p>Default aligned</p></cell>
+ </row>
+ <row>
+ <cell><p>First</p></cell>
+ <cell><p>row</p></cell>
+ <cell><p>12.0</p></cell>
+ <cell><p>Example of a row that spans multiple lines.</p></cell>
+ </row>
+ <row>
+ <cell><p>Second</p></cell>
+ <cell><p>row</p></cell>
+ <cell><p>5.0</p></cell>
+ <cell><p>Here’s another one. Note the blank line between rows.</p></cell>
+ </row>
+</table>
+<p>Multiline table without caption:</p>
+<table>
+ <row role="label">
+ <cell><p>Centered Header</p></cell>
+ <cell><p>Left Aligned</p></cell>
+ <cell><p>Right Aligned</p></cell>
+ <cell><p>Default aligned</p></cell>
+ </row>
+ <row>
+ <cell><p>First</p></cell>
+ <cell><p>row</p></cell>
+ <cell><p>12.0</p></cell>
+ <cell><p>Example of a row that spans multiple lines.</p></cell>
+ </row>
+ <row>
+ <cell><p>Second</p></cell>
+ <cell><p>row</p></cell>
+ <cell><p>5.0</p></cell>
+ <cell><p>Here’s another one. Note the blank line between rows.</p></cell>
+ </row>
+</table>
+<p>Table without column headers:</p>
+<table>
+ <row role="label">
+ <cell></cell>
+ <cell></cell>
+ <cell></cell>
+ <cell></cell>
+ </row>
+ <row>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ <cell><p>12</p></cell>
+ </row>
+ <row>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ <cell><p>123</p></cell>
+ </row>
+ <row>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ <cell><p>1</p></cell>
+ </row>
+</table>
+<p>Multiline table without column headers:</p>
+<table>
+ <row role="label">
+ <cell></cell>
+ <cell></cell>
+ <cell></cell>
+ <cell></cell>
+ </row>
+ <row>
+ <cell><p>First</p></cell>
+ <cell><p>row</p></cell>
+ <cell><p>12.0</p></cell>
+ <cell><p>Example of a row that spans multiple lines.</p></cell>
+ </row>
+ <row>
+ <cell><p>Second</p></cell>
+ <cell><p>row</p></cell>
+ <cell><p>5.0</p></cell>
+ <cell><p>Here’s another one. Note the blank line between rows.</p></cell>
+ </row>
+</table>
diff --git a/tests/tables.texinfo b/test/tables.texinfo
index b82006f1a..b82006f1a 100644
--- a/tests/tables.texinfo
+++ b/test/tables.texinfo
diff --git a/tests/tables.textile b/test/tables.textile
index 6c6b234e6..6c6b234e6 100644
--- a/tests/tables.textile
+++ b/test/tables.textile
diff --git a/tests/tables.txt b/test/tables.txt
index d70492262..d70492262 100644
--- a/tests/tables.txt
+++ b/test/tables.txt
diff --git a/test/tables.zimwiki b/test/tables.zimwiki
new file mode 100644
index 000000000..2757055f6
--- /dev/null
+++ b/test/tables.zimwiki
@@ -0,0 +1,56 @@
+Simple table with caption:
+
+Demonstration of simple table syntax.
+|Right|Left |Center |Default|
+|----:|:----|:-----:|-------|
+| 12|12 | 12 |12 |
+| 123|123 | 123 |123 |
+| 1|1 | 1 |1 |
+
+Simple table without caption:
+
+|Right|Left |Center |Default|
+|----:|:----|:-----:|-------|
+| 12|12 | 12 |12 |
+| 123|123 | 123 |123 |
+| 1|1 | 1 |1 |
+
+Simple table indented two spaces:
+
+Demonstration of simple table syntax.
+|Right|Left |Center |Default|
+|----:|:----|:-----:|-------|
+| 12|12 | 12 |12 |
+| 123|123 | 123 |123 |
+| 1|1 | 1 |1 |
+
+Multiline table with caption:
+
+Here’s the caption. It may span multiple lines.
+|Centered Header|Left Aligned|Right Aligned|Default aligned |
+|:-------------:|:-----------|------------:|:------------------------------------------------------|
+| First |row | 12.0|Example of a row that spans multiple lines. |
+| Second |row | 5.0|Here’s another one. Note the blank line between rows. |
+
+Multiline table without caption:
+
+|Centered Header|Left Aligned|Right Aligned|Default aligned |
+|:-------------:|:-----------|------------:|:------------------------------------------------------|
+| First |row | 12.0|Example of a row that spans multiple lines. |
+| Second |row | 5.0|Here’s another one. Note the blank line between rows. |
+
+Table without column headers:
+
+| 12|12 | 12 | 12|
+|----:|:----|:-----:|----:|
+| 12|12 | 12 | 12|
+| 123|123 | 123 | 123|
+| 1|1 | 1 | 1|
+
+Multiline table without column headers:
+
+| First |row | 12.0|Example of a row that spans multiple lines. |
+|:--------:|:----|-----:|-----------------------------------------------------|
+| First |row | 12.0|Example of a row that spans multiple lines. |
+| Second |row | 5.0|Here’s another one. Note the blank line between rows.|
+
diff --git a/test/test-pandoc.hs b/test/test-pandoc.hs
new file mode 100644
index 000000000..4cf1a952d
--- /dev/null
+++ b/test/test-pandoc.hs
@@ -0,0 +1,83 @@
+{-# OPTIONS_GHC -Wall #-}
+
+module Main where
+
+import GHC.IO.Encoding
+import Test.Tasty
+import qualified Tests.Command
+import qualified Tests.Lua
+import qualified Tests.Old
+import qualified Tests.Readers.Creole
+import qualified Tests.Readers.Docx
+import qualified Tests.Readers.EPUB
+import qualified Tests.Readers.HTML
+import qualified Tests.Readers.JATS
+import qualified Tests.Readers.LaTeX
+import qualified Tests.Readers.Markdown
+import qualified Tests.Readers.Muse
+import qualified Tests.Readers.Odt
+import qualified Tests.Readers.Org
+import qualified Tests.Readers.RST
+import qualified Tests.Readers.Txt2Tags
+import qualified Tests.Shared
+import qualified Tests.Writers.AsciiDoc
+import qualified Tests.Writers.ConTeXt
+import qualified Tests.Writers.Docbook
+import qualified Tests.Writers.Docx
+import qualified Tests.Writers.FB2
+import qualified Tests.Writers.HTML
+import qualified Tests.Writers.JATS
+import qualified Tests.Writers.LaTeX
+import qualified Tests.Writers.Markdown
+import qualified Tests.Writers.Muse
+import qualified Tests.Writers.Native
+import qualified Tests.Writers.Org
+import qualified Tests.Writers.Plain
+import qualified Tests.Writers.Powerpoint
+import qualified Tests.Writers.RST
+import qualified Tests.Writers.TEI
+import Text.Pandoc.Shared (inDirectory)
+
+tests :: TestTree
+tests = testGroup "pandoc tests" [ Tests.Command.tests
+ , testGroup "Old" Tests.Old.tests
+ , testGroup "Shared" Tests.Shared.tests
+ , testGroup "Writers"
+ [ testGroup "Native" Tests.Writers.Native.tests
+ , testGroup "ConTeXt" Tests.Writers.ConTeXt.tests
+ , testGroup "LaTeX" Tests.Writers.LaTeX.tests
+ , testGroup "HTML" Tests.Writers.HTML.tests
+ , testGroup "JATS" Tests.Writers.JATS.tests
+ , testGroup "Docbook" Tests.Writers.Docbook.tests
+ , testGroup "Markdown" Tests.Writers.Markdown.tests
+ , testGroup "Org" Tests.Writers.Org.tests
+ , testGroup "Plain" Tests.Writers.Plain.tests
+ , testGroup "AsciiDoc" Tests.Writers.AsciiDoc.tests
+ , testGroup "Docx" Tests.Writers.Docx.tests
+ , testGroup "RST" Tests.Writers.RST.tests
+ , testGroup "TEI" Tests.Writers.TEI.tests
+ , testGroup "Muse" Tests.Writers.Muse.tests
+ , testGroup "FB2" Tests.Writers.FB2.tests
+ , testGroup "PowerPoint" Tests.Writers.Powerpoint.tests
+ ]
+ , testGroup "Readers"
+ [ testGroup "LaTeX" Tests.Readers.LaTeX.tests
+ , testGroup "Markdown" Tests.Readers.Markdown.tests
+ , testGroup "HTML" Tests.Readers.HTML.tests
+ , testGroup "JATS" Tests.Readers.JATS.tests
+ , testGroup "Org" Tests.Readers.Org.tests
+ , testGroup "RST" Tests.Readers.RST.tests
+ , testGroup "Docx" Tests.Readers.Docx.tests
+ , testGroup "Odt" Tests.Readers.Odt.tests
+ , testGroup "Txt2Tags" Tests.Readers.Txt2Tags.tests
+ , testGroup "EPUB" Tests.Readers.EPUB.tests
+ , testGroup "Muse" Tests.Readers.Muse.tests
+ , testGroup "Creole" Tests.Readers.Creole.tests
+ ]
+ , testGroup "Lua filters" Tests.Lua.tests
+ ]
+
+main :: IO ()
+main = do
+ setLocaleEncoding utf8
+ inDirectory "test" $ defaultMain tests
diff --git a/test/testsuite.native b/test/testsuite.native
new file mode 100644
index 000000000..0587bddb8
--- /dev/null
+++ b/test/testsuite.native
@@ -0,0 +1,409 @@
+Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
+[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",SoftBreak,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+,HorizontalRule
+,Header 1 ("headers",[],[]) [Str "Headers"]
+,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
+,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
+,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
+,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
+,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,HorizontalRule
+,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",SoftBreak,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",SoftBreak,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",SoftBreak,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",SoftBreak,Str "list",Space,Str "item."]
+,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",SoftBreak,Str "*",Space,Str "criminey."]
+,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
+,HorizontalRule
+,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
+,Para [Str "E-mail",Space,Str "style:"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",SoftBreak,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
+,BlockQuote
+ [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ ,Para [Str "A",Space,Str "list:"]
+ ,OrderedList (1,Decimal,Period)
+ [[Plain [Str "item",Space,Str "one"]]
+ ,[Plain [Str "item",Space,Str "two"]]]
+ ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ ,BlockQuote
+ [Para [Str "nested"]]
+ ,BlockQuote
+ [Para [Str "nested"]]]
+,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",SoftBreak,Str ">",Space,Str "1."]
+,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
+,HorizontalRule
+,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+,Para [Str "And:"]
+,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+,HorizontalRule
+,Header 1 ("lists",[],[]) [Str "Lists"]
+,Header 2 ("unordered",[],[]) [Str "Unordered"]
+,Para [Str "Asterisks",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "asterisk",Space,Str "1"]]
+ ,[Plain [Str "asterisk",Space,Str "2"]]
+ ,[Plain [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Asterisks",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "asterisk",Space,Str "1"]]
+ ,[Para [Str "asterisk",Space,Str "2"]]
+ ,[Para [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "Plus",Space,Str "1"]]
+ ,[Plain [Str "Plus",Space,Str "2"]]
+ ,[Plain [Str "Plus",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Plus",Space,Str "1"]]
+ ,[Para [Str "Plus",Space,Str "2"]]
+ ,[Para [Str "Plus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "Minus",Space,Str "1"]]
+ ,[Plain [Str "Minus",Space,Str "2"]]
+ ,[Plain [Str "Minus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Minus",Space,Str "1"]]
+ ,[Para [Str "Minus",Space,Str "2"]]
+ ,[Para [Str "Minus",Space,Str "3"]]]
+,Header 2 ("ordered",[],[]) [Str "Ordered"]
+,Para [Str "Tight:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second"]]
+ ,[Plain [Str "Third"]]]
+,Para [Str "and:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "One"]]
+ ,[Plain [Str "Two"]]
+ ,[Plain [Str "Three"]]]
+,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second"]]
+ ,[Para [Str "Third"]]]
+,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "One"]]
+ ,[Para [Str "Two"]]
+ ,[Para [Str "Three"]]]
+,Para [Str "Multiple",Space,Str "paragraphs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",SoftBreak,Str "back."]]
+ ,[Para [Str "Item",Space,Str "2."]]
+ ,[Para [Str "Item",Space,Str "3."]]]
+,Header 2 ("nested",[],[]) [Str "Nested"]
+,BulletList
+ [[Plain [Str "Tab"]
+ ,BulletList
+ [[Plain [Str "Tab"]
+ ,BulletList
+ [[Plain [Str "Tab"]]]]]]]
+,Para [Str "Here\8217s",Space,Str "another:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second:"]
+ ,BulletList
+ [[Plain [Str "Fee"]]
+ ,[Plain [Str "Fie"]]
+ ,[Plain [Str "Foe"]]]]
+ ,[Plain [Str "Third"]]]
+,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second:"]
+ ,BulletList
+ [[Plain [Str "Fee"]]
+ ,[Plain [Str "Fie"]]
+ ,[Plain [Str "Foe"]]]]
+ ,[Para [Str "Third"]]]
+,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "spaces"]
+ ,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
+,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
+,OrderedList (2,Decimal,TwoParens)
+ [[Plain [Str "begins",Space,Str "with",Space,Str "2"]]
+ ,[Para [Str "and",Space,Str "now",Space,Str "3"]
+ ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ ,OrderedList (4,LowerRoman,Period)
+ [[Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",SoftBreak,Str "starting",Space,Str "with",Space,Str "4"]]
+ ,[Plain [Str "more",Space,Str "items"]
+ ,OrderedList (1,UpperAlpha,TwoParens)
+ [[Plain [Str "a",Space,Str "subsublist"]]
+ ,[Plain [Str "a",Space,Str "subsublist"]]]]]]]
+,Para [Str "Nesting:"]
+,OrderedList (1,UpperAlpha,Period)
+ [[Plain [Str "Upper",Space,Str "Alpha"]
+ ,OrderedList (1,UpperRoman,Period)
+ [[Plain [Str "Upper",Space,Str "Roman."]
+ ,OrderedList (6,Decimal,TwoParens)
+ [[Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ ,OrderedList (3,LowerAlpha,OneParen)
+ [[Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
+,Para [Str "Autonumbering:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Autonumber."]]
+ ,[Plain [Str "More."]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Nested."]]]]]
+,Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
+,Para [Str "M.A.\160\&2007"]
+,Para [Str "B.",Space,Str "Williams"]
+,HorizontalRule
+,Header 1 ("definition-lists",[],[]) [Str "Definition",Space,Str "Lists"]
+,Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Plain [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Plain [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Plain [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Plain [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Plain [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Plain [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Loose:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Para [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
+,DefinitionList
+ [([Emph [Str "apple"]],
+ [[Para [Str "red",Space,Str "fruit"]
+ ,Para [Str "contains",Space,Str "seeds,",SoftBreak,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"]]])
+ ,([Emph [Str "orange"]],
+ [[Para [Str "orange",Space,Str "fruit"]
+ ,CodeBlock ("",[],[]) "{ orange code block }"
+ ,BlockQuote
+ [Para [Str "orange",Space,Str "block",Space,Str "quote"]]]])]
+,Para [Str "Multiple",Space,Str "definitions,",Space,Str "tight:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Plain [Str "red",Space,Str "fruit"]]
+ ,[Plain [Str "computer"]]])
+ ,([Str "orange"],
+ [[Plain [Str "orange",Space,Str "fruit"]]
+ ,[Plain [Str "bank"]]])]
+,Para [Str "Multiple",Space,Str "definitions,",Space,Str "loose:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]
+ ,[Para [Str "computer"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]]
+ ,[Para [Str "bank"]]])]
+,Para [Str "Blank",Space,Str "line",Space,Str "after",Space,Str "term,",Space,Str "indented",Space,Str "marker,",Space,Str "alternate",Space,Str "markers:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]
+ ,[Para [Str "computer"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]
+ ,OrderedList (1,Decimal,Period)
+ [[Plain [Str "sublist"]]
+ ,[Plain [Str "sublist"]]]]])]
+,Header 1 ("html-blocks",[],[]) [Str "HTML",Space,Str "Blocks"]
+,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
+,Div ("",[],[])
+ [Plain [Str "foo"]]
+,Para [Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
+,Div ("",[],[])
+ [Div ("",[],[])
+ [Div ("",[],[])
+ [Para [Str "foo"]]]
+ ,Div ("",[],[])
+ [Plain [Str "bar"]]]
+,Para [Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
+,RawBlock (Format "html") "<table>"
+,RawBlock (Format "html") "<tr>"
+,RawBlock (Format "html") "<td>"
+,Plain [Str "This",Space,Str "is",Space,Emph [Str "emphasized"]]
+,RawBlock (Format "html") "</td>"
+,RawBlock (Format "html") "<td>"
+,Plain [Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"]]
+,RawBlock (Format "html") "</td>"
+,RawBlock (Format "html") "</tr>"
+,RawBlock (Format "html") "</table>"
+,RawBlock (Format "html") "<script type=\"text/javascript\">document.write('This *should not* be interpreted as markdown');</script>"
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
+,Div ("",[],[])
+ [Para [Str "foo"]]
+,Para [Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
+,CodeBlock ("",[],[]) "<div>\n foo\n</div>"
+,Para [Str "As",Space,Str "should",Space,Str "this:"]
+,CodeBlock ("",[],[]) "<div>foo</div>"
+,Para [Str "Now,",Space,Str "nested:"]
+,Div ("",[],[])
+ [Div ("",[],[])
+ [Div ("",[],[])
+ [Plain [Str "foo"]]]]
+,Para [Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
+,RawBlock (Format "html") "<!-- Comment -->"
+,Para [Str "Multiline:"]
+,RawBlock (Format "html") "<!--\nBlah\nBlah\n-->"
+,RawBlock (Format "html") "<!--\n This is another comment.\n-->"
+,Para [Str "Code",Space,Str "block:"]
+,CodeBlock ("",[],[]) "<!-- Comment -->"
+,Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
+,RawBlock (Format "html") "<!-- foo -->"
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "<hr />"
+,Para [Str "Hr\8217s:"]
+,RawBlock (Format "html") "<hr>"
+,RawBlock (Format "html") "<hr />"
+,RawBlock (Format "html") "<hr />"
+,RawBlock (Format "html") "<hr>"
+,RawBlock (Format "html") "<hr />"
+,RawBlock (Format "html") "<hr />"
+,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\" />"
+,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\" />"
+,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\">"
+,HorizontalRule
+,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
+,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
+,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
+,Para [Str "An",Space,Emph [Link ("",[],[]) [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
+,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
+,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello\160there"],Str "."]
+,Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",Space,Str "H",Subscript [Str "many\160of\160them"],Str "O."]
+,Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",SoftBreak,Str "because",Space,Str "of",Space,Str "the",Space,Str "unescaped",Space,Str "spaces:",Space,Str "a^b",Space,Str "c^d,",Space,Str "a~b",Space,Str "c~d."]
+,HorizontalRule
+,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+,Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
+,Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
+,Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",SoftBreak,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine."]]
+,Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",SoftBreak,Str "70\8217s?"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code ("",[],[]) "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
+,Para [Str "Some",Space,Str "dashes:",Space,Str "one\8212two",Space,Str "\8212",Space,Str "three\8212four",Space,Str "\8212",Space,Str "five."]
+,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5\8211\&7,",Space,Str "255\8211\&66,",Space,Str "1987\8211\&1999."]
+,Para [Str "Ellipses\8230and\8230and\8230."]
+,HorizontalRule
+,Header 1 ("latex",[],[]) [Str "LaTeX"]
+,BulletList
+ [[Plain [RawInline (Format "tex") "\\cite[22-23]{smith.1899}"]]
+ ,[Plain [Math InlineMath "2+2=4"]]
+ ,[Plain [Math InlineMath "x \\in y"]]
+ ,[Plain [Math InlineMath "\\alpha \\wedge \\omega"]]
+ ,[Plain [Math InlineMath "223"]]
+ ,[Plain [Math InlineMath "p",Str "-Tree"]]
+ ,[Plain [Str "Here\8217s",Space,Str "some",Space,Str "display",Space,Str "math:",SoftBreak,Math DisplayMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"]]
+ ,[Plain [Str "Here\8217s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."]]]
+,Para [Str "These",Space,Str "shouldn\8217t",Space,Str "be",Space,Str "math:"]
+,BulletList
+ [[Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code ("",[],[]) "$e = mc^2$",Str "."]]
+ ,[Plain [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",SoftBreak,Str "(It",Space,Str "worked",Space,Str "if",Space,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized.)"]]
+ ,[Plain [Str "Shoes",Space,Str "($20)",Space,Str "and",Space,Str "socks",Space,Str "($5)."]]
+ ,[Plain [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+,RawBlock (Format "latex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"
+,HorizontalRule
+,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+,BulletList
+ [[Plain [Str "I",Space,Str "hat:",Space,Str "\206"]]
+ ,[Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
+ ,[Plain [Str "section:",Space,Str "\167"]]
+ ,[Plain [Str "set",Space,Str "membership:",Space,Str "\8712"]]
+ ,[Plain [Str "copyright:",Space,Str "\169"]]]
+,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
+,Para [Str "This",Space,Str "&",Space,Str "that."]
+,Para [Str "4",Space,Str "<",Space,Str "5."]
+,Para [Str "6",Space,Str ">",Space,Str "5."]
+,Para [Str "Backslash:",Space,Str "\\"]
+,Para [Str "Backtick:",Space,Str "`"]
+,Para [Str "Asterisk:",Space,Str "*"]
+,Para [Str "Underscore:",Space,Str "_"]
+,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+,Para [Str "Left",Space,Str "paren:",Space,Str "("]
+,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+,Para [Str "Greater-than:",Space,Str ">"]
+,Para [Str "Hash:",Space,Str "#"]
+,Para [Str "Period:",Space,Str "."]
+,Para [Str "Bang:",Space,Str "!"]
+,Para [Str "Plus:",Space,Str "+"]
+,Para [Str "Minus:",Space,Str "-"]
+,HorizontalRule
+,Header 1 ("links",[],[]) [Str "Links"]
+,Header 2 ("explicit",[],[]) [Str "Explicit"]
+,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
+,Para [Link ("",[],[]) [Str "with_underscore"] ("/url/with_underscore","")]
+,Para [Link ("",[],[]) [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
+,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
+,Header 2 ("reference",[],[]) [Str "Reference"]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
+,Para [Str "This",Space,Str "should",Space,Str "[not][]",Space,Str "be",Space,Str "a",Space,Str "link."]
+,CodeBlock ("",[],[]) "[not]: /url"
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
+,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
+,Para [Str "Here\8217s",Space,Str "a",Space,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link ("",[],[]) [Str "AT&T"] ("http://att.com/","AT&T"),Str "."]
+,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
+,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
+,BulletList
+ [[Plain [Str "In",Space,Str "a",Space,Str "list?"]]
+ ,[Plain [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+ ,[Plain [Str "It",Space,Str "should."]]]
+,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
+,BlockQuote
+ [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
+,CodeBlock ("",[],[]) "or here: <http://example.com/>"
+,HorizontalRule
+,Header 1 ("images",[],[]) [Str "Images"]
+,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+,Para [Image ("",[],[]) [Str "lalune"] ("lalune.jpg","fig:Voyage dans la Lune")]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
+,HorizontalRule
+,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",SoftBreak,Str "reference.",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document."]],Space,Str "and",Space,Str "another.",Note [Para [Str "Here\8217s",Space,Str "the",Space,Str "long",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",SoftBreak,Str "blocks."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",SoftBreak,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",SoftBreak,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block."]],SoftBreak,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",SoftBreak,Str "contains",Space,Str "a",Space,Str "space.[^my",Space,Str "note]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note.",Note [Para [Str "This",SoftBreak,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type.",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",SoftBreak,Link ("",[],[]) [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code ("",[],[]) "]",Space,Str "verbatim",Space,Str "characters,",SoftBreak,Str "as",Space,Str "well",Space,Str "as",Space,Str "[bracketed",Space,Str "text]."]]]
+,BlockQuote
+ [Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes.",Note [Para [Str "In",Space,Str "quote."]]]]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]]]]
+,Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented."]]
diff --git a/test/testsuite.txt b/test/testsuite.txt
new file mode 100644
index 000000000..9413cc81a
--- /dev/null
+++ b/test/testsuite.txt
@@ -0,0 +1,725 @@
+% Pandoc Test Suite
+% John MacFarlane; Anonymous
+% July 17, 2006
+
+This is a set of tests for pandoc. Most of them are adapted from
+John Gruber's markdown test suite.
+
+-----
+
+# Headers
+
+## Level 2 with an [embedded link](/url)
+
+### Level 3 with *emphasis*
+
+#### Level 4
+
+##### Level 5
+
+Level 1
+=======
+
+Level 2 with *emphasis*
+-----------------------
+
+### Level 3
+with no blank line
+
+Level 2
+-------
+with no blank line
+
+----------
+
+# Paragraphs
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.
+
+Here's one with a bullet.
+* criminey.
+
+There should be a hard line break
+here.
+
+---
+
+# Block Quotes
+
+E-mail style:
+
+> This is a block quote.
+> It is pretty short.
+
+> Code in a block quote:
+>
+> sub status {
+> print "working";
+> }
+>
+> A list:
+>
+> 1. item one
+> 2. item two
+>
+> Nested block quotes:
+>
+> > nested
+>
+>> nested
+>
+
+This should not be a block quote: 2
+> 1.
+
+And a following paragraph.
+
+* * * *
+
+# Code Blocks
+
+Code:
+
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+
+And:
+
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+
+___________
+
+# Lists
+
+## Unordered
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Asterisks loose:
+
+* asterisk 1
+
+* asterisk 2
+
+* asterisk 3
+
+Pluses tight:
+
++ Plus 1
++ Plus 2
++ Plus 3
+
+Pluses loose:
+
++ Plus 1
+
++ Plus 2
+
++ Plus 3
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+## Ordered
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+2. Item 2.
+
+3. Item 3.
+
+## Nested
+
+* Tab
+ * Tab
+ * Tab
+
+Here's another:
+
+1. First
+2. Second:
+ * Fee
+ * Fie
+ * Foe
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+
+ * Fee
+ * Fie
+ * Foe
+
+3. Third
+
+## Tabs and spaces
+
++ this is a list item
+ indented with tabs
+
++ this is a list item
+ indented with spaces
+
+ + this is an example list item
+ indented with tabs
+
+ + this is an example list item
+ indented with spaces
+
+## Fancy list markers
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+ iv. sublist with roman numerals,
+ starting with 4
+ v. more items
+ (A) a subsublist
+ (B) a subsublist
+
+Nesting:
+
+A. Upper Alpha
+ I. Upper Roman.
+ (6) Decimal start with 6
+ c) Lower alpha with paren
+
+Autonumbering:
+
+ #. Autonumber.
+ #. More.
+ #. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+ * * * * *
+
+# Definition Lists
+
+Tight using spaces:
+
+apple
+: red fruit
+
+orange
+: orange fruit
+
+banana
+: yellow fruit
+
+Tight using tabs:
+
+apple
+: red fruit
+
+orange
+: orange fruit
+
+banana
+: yellow fruit
+
+Loose:
+
+apple
+
+: red fruit
+
+orange
+
+: orange fruit
+
+banana
+
+: yellow fruit
+
+Multiple blocks with italics:
+
+*apple*
+
+: red fruit
+
+ contains seeds,
+ crisp, pleasant to taste
+
+*orange*
+
+: orange fruit
+
+ { orange code block }
+
+ > orange block quote
+
+Multiple definitions, tight:
+
+apple
+: red fruit
+: computer
+
+orange
+: orange fruit
+: bank
+
+Multiple definitions, loose:
+
+apple
+
+: red fruit
+
+: computer
+
+orange
+
+: orange fruit
+
+: bank
+
+Blank line after term, indented marker, alternate markers:
+
+apple
+
+ ~ red fruit
+
+ ~ computer
+
+orange
+
+ ~ orange fruit
+
+ 1. sublist
+ 2. sublist
+
+# HTML Blocks
+
+Simple block on one line:
+
+<div>foo</div>
+
+And nested without indentation:
+
+<div>
+<div>
+<div>
+foo
+</div>
+</div>
+<div>bar</div>
+</div>
+
+Interpreted markdown in a table:
+
+<table>
+<tr>
+<td>This is *emphasized*</td>
+<td>And this is **strong**</td>
+</tr>
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+Here's a simple block:
+
+<div>
+foo
+</div>
+
+This should be a code block, though:
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+ <div>foo</div>
+
+Now, nested:
+
+<div>
+ <div>
+ <div>
+ foo
+ </div>
+ </div>
+</div>
+
+This should just be an HTML comment:
+
+<!-- Comment -->
+
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+
+Code block:
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+
+Code:
+
+ <hr />
+
+Hr's:
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar">
+
+-----
+
+# Inline Markup
+
+This is *emphasized*, and so _is this_.
+
+This is **strong**, and so __is this__.
+
+An *[emphasized link](/url)*.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+___This is strong and em.___
+
+So is ___this___ word.
+
+This is code: `>`, `$`, `\`, `\$`, `<html>`.
+
+~~This is *strikeout*.~~
+
+Superscripts: a^bc^d a^*hello*^ a^hello\ there^.
+
+Subscripts: H~2~O, H~23~O, H~many\ of\ them~O.
+
+These should not be superscripts or subscripts,
+because of the unescaped spaces: a^b c^d, a~b c~d.
+
+-----
+
+# Smart quotes, ellipses, dashes
+
+"Hello," said the spider. "'Shelob' is my name."
+
+'A', 'B', and 'C' are letters.
+
+'Oak,' 'elm,' and 'beech' are names of trees.
+So is 'pine.'
+
+'He said, "I want to go."' Were you alive in the
+70's?
+
+Here is some quoted '`code`' and a "[quoted link][1]".
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses...and...and....
+
+-----
+
+# LaTeX
+
+- \cite[22-23]{smith.1899}
+- $2+2=4$
+- $x \in y$
+- $\alpha \wedge \omega$
+- $223$
+- $p$-Tree
+- Here's some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+- Here's one that has a line break in it: $\alpha + \omega \times
+x^2$.
+
+These shouldn't be math:
+
+- To get the famous equation, write `$e = mc^2$`.
+- $22,000 is a *lot* of money. So is $34,000.
+ (It worked if "lot" is emphasized.)
+- Shoes ($20) and socks ($5).
+- Escaped `$`: $73 *this should be emphasized* 23\$.
+
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+* * * * *
+
+# Special Characters
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&amp;T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: \[
+
+Right bracket: \]
+
+Left paren: \(
+
+Right paren: \)
+
+Greater-than: \>
+
+Hash: \#
+
+Period: \.
+
+Bang: \!
+
+Plus: \+
+
+Minus: \-
+
+- - - - - - - - - - - - -
+
+# Links
+
+## Explicit
+
+Just a [URL](/url/).
+
+[URL and title](/url/ "title").
+
+[URL and title](/url/ "title preceded by two spaces").
+
+[URL and title](/url/ "title preceded by a tab").
+
+[URL and title](/url/ "title with "quotes" in it")
+
+[URL and title](/url/ 'title with single quotes')
+
+[with\_underscore](/url/with_underscore)
+
+[Email link](mailto:nobody@nowhere.net)
+
+[Empty]().
+
+## Reference
+
+Foo [bar][a].
+
+[a]: /url/
+
+With [embedded [brackets]][b].
+
+[b] by itself should be a link.
+
+Indented [once][].
+
+Indented [twice][].
+
+Indented [thrice][].
+
+This should [not][] be a link.
+
+ [once]: /url
+ [twice]: /url
+
+ [thrice]: /url
+
+ [not]: /url
+
+[b]: /url/
+
+Foo [bar][].
+
+Foo [biz](/url/ "Title with "quote" inside").
+
+ [bar]: /url/ "Title with "quotes" inside"
+
+## With ampersands
+
+Here's a [link with an ampersand in the URL][1].
+
+Here's a link with an amersand in the link text: [AT&T][2].
+
+Here's an [inline link](/script?foo=1&bar=2).
+
+Here's an [inline link in pointy braces](</script?foo=1&bar=2>).
+
+[1]: http://example.com/?foo=1&bar=2
+[2]: http://att.com/ "AT&T"
+
+## Autolinks
+
+With an ampersand: <http://example.com/?foo=1&bar=2>
+
+* In a list?
+* <http://example.com/>
+* It should.
+
+An e-mail address: <nobody@nowhere.net>
+
+> Blockquoted: <http://example.com/>
+
+Auto-links should not occur here: `<http://example.com/>`
+
+ or here: <http://example.com/>
+
+----
+
+# Images
+
+From "Voyage dans la Lune" by Georges Melies (1902):
+
+![lalune][]
+
+ [lalune]: lalune.jpg "Voyage dans la Lune"
+
+Here is a movie ![movie](movie.jpg) icon.
+
+----
+
+# Footnotes
+
+Here is a footnote reference,[^1] and another.[^longnote]
+This should *not* be a footnote reference, because it
+contains a space.[^my note] Here is an inline note.^[This
+is *easier* to type. Inline notes may contain
+[links](http://google.com) and `]` verbatim characters,
+as well as [bracketed text].]
+
+> Notes can go in quotes.^[In quote.]
+
+1. And in list items.^[In list.]
+
+[^longnote]: Here's the long note. This one contains multiple
+blocks.
+
+ Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).
+
+ { <code> }
+
+ If you want, you can indent every line, but you can also be
+ lazy and just indent the first line of each block.
+
+This paragraph should not be part of the note, as it is not indented.
+
+ [^1]: Here is the footnote. It can go anywhere after the footnote
+ reference. It need not be placed at the end of the document.
diff --git a/test/textile-reader.native b/test/textile-reader.native
new file mode 100644
index 000000000..10bf2c857
--- /dev/null
+++ b/test/textile-reader.native
@@ -0,0 +1,180 @@
+Pandoc (Meta {unMeta = fromList []})
+[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc",Space,Str "Textile",Space,Str "Reader.",Space,Str "Part",Space,Str "of",Space,Str "it",Space,Str "comes",LineBreak,Str "from",Space,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+,HorizontalRule
+,Header 1 ("headers",[],[]) [Str "Headers"]
+,Header 2 ("level-2-with-an-embeded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embeded",Space,Str "link"] ("http://www.example.com","")]
+,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Strong [Str "emphasis"]]
+,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
+,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
+,Header 6 ("level-6",[],[]) [Str "Level",Space,Str "6"]
+,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+,Para [Str "Line",Space,Str "breaks",Space,Str "are",Space,Str "preserved",Space,Str "in",Space,Str "textile,",Space,Str "so",Space,Str "you",Space,Str "can",Space,Str "not",Space,Str "wrap",Space,Str "your",Space,Str "very",LineBreak,Str "long",Space,Str "paragraph",Space,Str "with",Space,Str "your",Space,Str "favourite",Space,Str "text",Space,Str "editor",Space,Str "and",Space,Str "have",Space,Str "it",Space,Str "rendered",LineBreak,Str "with",Space,Str "no",Space,Str "break."]
+,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet."]
+,BulletList
+ [[Plain [Str "criminey."]]]
+,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "paragraph",Space,Str "break",Space,Str "between",Space,Str "here"]
+,Para [Str "and",Space,Str "here."]
+,Para [Str "pandoc",Space,Str "converts",Space,Str "textile."]
+,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "famous",Space,Str "quote",Space,Str "from",Space,Str "somebody.",Space,Str "He",Space,Str "had",Space,Str "a",Space,Str "lot",Space,Str "of",Space,Str "things",Space,Str "to",LineBreak,Str "say,",Space,Str "so",Space,Str "the",Space,Str "text",Space,Str "is",Space,Str "really",Space,Str "really",Space,Str "long",Space,Str "and",Space,Str "spans",Space,Str "on",Space,Str "multiple",Space,Str "lines."]]
+,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
+,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) " ---- (should be four hyphens)\n\n sub status {\n print \"working\";\n }\n\n this code block is indented by one tab"
+,Para [Str "And:"]
+,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\n These should not be escaped: \\$ \\\\ \\> \\[ \\{"
+,CodeBlock ("",[],[]) "Code block with .bc\n continued\n @</\\"
+,CodeBlock ("",[],[]) "extended code block\n\n continued"
+,Para [Str "ended",Space,Str "by",Space,Str "paragraph"]
+,Para [Str "Inline",Space,Str "code:",Space,Code ("",[],[]) "<tt>",Str ",",Space,Code ("",[],[]) "@",Str "."]
+,Header 1 ("notextile",[],[]) [Str "Notextile"]
+,Para [Str "A",Space,Str "block",Space,Str "of",Space,Str "text",Space,Str "can",Space,Str "be",Space,Str "protected",Space,Str "with",Space,Str "notextile",Space,Str ":"]
+,Para [Str "\nNo *bold* and\n* no bullet\n"]
+,Para [Str "and",Space,Str "inlines",Space,Str "can",Space,Str "be",Space,Str "protected",Space,Str "with",Space,Str "double *equals (=)* markup."]
+,Header 1 ("lists",[],[]) [Str "Lists"]
+,Header 2 ("unordered",[],[]) [Str "Unordered"]
+,Para [Str "Asterisks",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "asterisk",Space,Str "1"]]
+ ,[Plain [Str "asterisk",Space,Str "2"]]
+ ,[Plain [Str "asterisk",Space,Str "3"]]]
+,Para [Str "With",Space,Str "line",Space,Str "breaks:"]
+,BulletList
+ [[Plain [Str "asterisk",Space,Str "1",LineBreak,Str "newline"]]
+ ,[Plain [Str "asterisk",Space,Str "2"]]]
+,Header 2 ("ordered",[],[]) [Str "Ordered"]
+,Para [Str "Tight:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second"]]
+ ,[Plain [Str "Third"]]]
+,Header 2 ("nested",[],[]) [Str "Nested"]
+,BulletList
+ [[Plain [Str "ui",Space,Str "1"]
+ ,BulletList
+ [[Plain [Str "ui",Space,Str "1.1"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "oi",Space,Str "1.1.1"]]
+ ,[Plain [Str "oi",Space,Str "1.1.2"]]]]
+ ,[Plain [Str "ui",Space,Str "1.2"]]]]
+ ,[Plain [Str "ui",Space,Str "2"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "oi",Space,Str "2.1"]
+ ,BulletList
+ [[Plain [Str "ui",Space,Str "2.1.1"]]
+ ,[Plain [Str "ui",Space,Str "2.1.2"]]]]]]]
+,Header 2 ("issue-1500",[],[]) [Str "Issue",Space,Str "#1500"]
+,BulletList
+ [[Plain [Str "one"]]
+ ,[Plain [Str "two",LineBreak,Str "->",Space,Str "and",Space,Str "more"]]]
+,Header 2 ("issue-1513",[],[]) [Str "Issue",Space,Str "#1513"]
+,Para [Str "List:"]
+,BulletList
+ [[Plain [Str "one"]]
+ ,[Plain [Str "two"]]]
+,Header 2 ("definition-list",[],[]) [Str "Definition",Space,Str "List"]
+,DefinitionList
+ [([Str "coffee"],
+ [[Plain [Str "Hot",Space,Str "and",Space,Str "black"]]])
+ ,([Str "tea"],
+ [[Plain [Str "Also",Space,Str "hot,",Space,Str "but",Space,Str "a",Space,Str "little",Space,Str "less",Space,Str "black"]]])
+ ,([Str "milk"],
+ [[Para [Str "Nourishing",Space,Str "beverage",Space,Str "for",Space,Str "baby",Space,Str "cows."]
+ ,Para [Str "Cold",Space,Str "drink",Space,Str "that",Space,Str "goes",Space,Str "great",Space,Str "with",Space,Str "cookies."]]])
+ ,([Str "beer"],
+ [[Plain [Str "fresh",Space,Str "and",Space,Str "bitter"]]])]
+,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
+,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str ".",LineBreak,Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str ".",LineBreak,Str "This",Space,Str "is",Space,Span ("",["underline"],[]) [Str "inserted"],Str ",",Space,Str "and",Space,Str "this",Space,Str "is",Space,Strikeout [Str "deleted"],Str ".",LineBreak,Str "Hyphenated-words-are-ok,",Space,Str "as",Space,Str "well",Space,Str "as",Space,Str "strange_underscore_notation.",LineBreak,Str "A",Space,Link ("",[],[]) [Strong [Str "strong",Space,Str "link"]] ("http://www.foobar.com",""),Str "."]
+,Para [Emph [Strong [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]],LineBreak,Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word",Space,Str "and",Space,Emph [Strong [Str "that",Space,Str "one"]],Str ".",LineBreak,Strikeout [Str "This",Space,Str "is",Space,Str "strikeout",Space,Str "and",Space,Strong [Str "strong"]]]
+,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Space,Superscript [Strong [Str "hello"]],Space,Str "a",Superscript [Str "hello",Space,Str "there"],Str ".",LineBreak,Str "Subscripts:",Space,Subscript [Str "here"],Space,Str "H",Space,Subscript [Str "2"],Str "O,",Space,Str "H",Space,Subscript [Str "23"],Str "O,",Space,Str "H",Space,Subscript [Str "many",Space,Str "of",Space,Str "them"],Str "O."]
+,Para [Str "Dashes",Space,Str ":",Space,Str "How",Space,Str "cool",Space,Str "\8212",Space,Str "automatic",Space,Str "dashes."]
+,Para [Str "Elipses",Space,Str ":",Space,Str "He",Space,Str "thought",Space,Str "and",Space,Str "thought",Space,Str "\8230",Space,Str "and",Space,Str "then",Space,Str "thought",Space,Str "some",Space,Str "more."]
+,Para [Str "Quotes",Space,Str "and",Space,Str "apostrophes",Space,Str ":",Space,Quoted DoubleQuote [Str "I\8217d",Space,Str "like",Space,Str "to",Space,Str "thank",Space,Str "you"],Space,Str "for",Space,Str "example."]
+,Header 1 ("links",[],[]) [Str "Links"]
+,Header 2 ("explicit",[],[]) [Str "Explicit"]
+,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "url"] ("http://www.url.com","")]
+,Para [Link ("",[],[]) [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
+,Para [Quoted DoubleQuote [Str "not",Space,Str "a",Space,Str "link"],Str ":",Space,Str "foo"]
+,Para [Str "Automatic",Space,Str "linking",Space,Str "to",Space,Link ("",[],[]) [Str "http://www.example.com"] ("http://www.example.com",""),Str "."]
+,Para [Link ("",[],[]) [Str "Example"] ("http://www.example.com/",""),Str ":",Space,Str "Example",Space,Str "of",Space,Str "a",Space,Str "link",Space,Str "followed",Space,Str "by",Space,Str "a",Space,Str "colon."]
+,Para [Str "A",Space,Str "link",Link ("",[],[]) [Str "with",Space,Str "brackets"] ("http://www.example.com",""),Str "and",Space,Str "no",Space,Str "spaces."]
+,Header 1 ("tables",[],[]) [Str "Tables"]
+,Para [Str "Textile",Space,Str "allows",Space,Str "tables",Space,Str "with",Space,Str "and",Space,Str "without",Space,Str "headers",Space,Str ":"]
+,Header 2 ("without-headers",[],[]) [Str "Without",Space,Str "headers"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "name"]]
+ ,[Plain [Str "age"]]
+ ,[Plain [Str "sex"]]]
+ ,[[Plain [Str "joan"]]
+ ,[Plain [Str "24"]]
+ ,[Plain [Str "f"]]]
+ ,[[Plain [Str "archie"]]
+ ,[Plain [Str "29"]]
+ ,[Plain [Str "m"]]]
+ ,[[Plain [Str "bella"]]
+ ,[Plain [Str "45"]]
+ ,[Plain [Str "f"]]]]
+,Para [Str "and",Space,Str "some",Space,Str "text",Space,Str "following",Space,Str "\8230"]
+,Header 2 ("with-headers",[],[]) [Str "With",Space,Str "headers"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "name"]]
+ ,[Plain [Str "age"]]
+ ,[Plain [Str "sex"]]]
+ [[[Plain [Str "joan"]]
+ ,[Plain [Str "24"]]
+ ,[Plain [Str "f"]]]
+ ,[[Plain [Str "archie"]]
+ ,[Plain [Str "29"]]
+ ,[Plain [Str "m"]]]
+ ,[[Plain [Str "bella"]]
+ ,[Plain [Str "45"]]
+ ,[Plain [Str "f"]]]]
+,Header 1 ("images",[],[]) [Str "Images"]
+,Para [Str "Textile",Space,Str "inline",Space,Str "image",Space,Str "syntax,",Space,Str "like",LineBreak,Str "here",Space,Image ("",[],[]) [Str "this is the alt text"] ("this_is_an_image.png","this is the alt text"),LineBreak,Str "and",Space,Str "here",Space,Image ("",[],[]) [Str ""] ("this_is_an_image.png",""),Str "."]
+,Header 1 ("attributes",[],[]) [Str "Attributes"]
+,Header 2 ("ident",["bar","foo"],[("style","color:red;"),("lang","en")]) [Str "HTML",Space,Str "and",Space,Str "CSS",Space,Str "attributes",Space,Str "are",Space,Str "parsed",Space,Str "in",Space,Str "headers."]
+,Header 2 ("centered",[],[("style","text-align:center;")]) [Str "Centered"]
+,Header 2 ("right",[],[("style","text-align:right;")]) [Str "Right"]
+,Header 2 ("justified",[],[("lang","en"),("style","color:blue;text-align:justify;")]) [Str "Justified"]
+,Para [Str "as",Space,Str "well",Space,Str "as",Space,Strong [Span ("",["foo"],[]) [Str "inline",Space,Str "attributes"]],Space,Str "of",Space,Span ("",[],[("style","color:red;")]) [Str "all",Space,Str "kind"]]
+,Para [Str "and",Space,Str "paragraph",Space,Str "attributes,",Space,Str "and",Space,Str "table",Space,Str "attributes."]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "name"]]
+ ,[Plain [Str "age"]]
+ ,[Plain [Str "sex"]]]
+ ,[[Plain [Str "joan"]]
+ ,[Plain [Str "24"]]
+ ,[Plain [Str "f"]]]]
+,Para [Emph [Str "(class#id)",Space,Str "emph"]]
+,Para [Emph [Str "(no",Space,Str "class#id)",Space,Str "emph"]]
+,Header 1 ("entities",[],[]) [Str "Entities"]
+,Para [Str "*",LineBreak,Str "&"]
+,Header 1 ("raw-html",[],[]) [Str "Raw",Space,Str "HTML"]
+,Para [Str "However,",Space,RawInline (Format "html") "<strong>",Space,Str "raw",Space,Str "HTML",Space,Str "inlines",Space,RawInline (Format "html") "</strong>",Space,Str "are",Space,Str "accepted,",Space,Str "as",Space,Str "well",Space,Str "as",Space,Str ":"]
+,RawBlock (Format "html") "<div class=\"foobar\">"
+,Para [Str "any",Space,Strong [Str "Raw",Space,Str "HTML",Space,Str "Block"],Space,Str "with",Space,Str "bold"]
+,RawBlock (Format "html") "</div>"
+,Para [Str "Html",Space,Str "blocks",Space,Str "can"]
+,RawBlock (Format "html") "<div>"
+,Para [Str "interrupt",Space,Str "paragraphs"]
+,RawBlock (Format "html") "</div>"
+,Para [Str "as",Space,Str "well."]
+,Para [Str "Can",Space,Str "you",Space,Str "prove",Space,Str "that",Space,Str "2",Space,Str "<",Space,Str "3",Space,Str "?"]
+,Header 1 ("acronyms-and-marks",[],[]) [Str "Acronyms",Space,Str "and",Space,Str "marks"]
+,Para [Str "PBS (Public Broadcasting System)"]
+,Para [Str "Hi\8482"]
+,Para [Str "Hi",Space,Str "\8482"]
+,Para [Str "\174",Space,Str "Hi\174"]
+,Para [Str "Hi\169\&2008",Space,Str "\169",Space,Str "2008"]
+,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
+,Para [Str "A",Space,Str "note.",Note [Para [Str "The",Space,Str "note",LineBreak,Str "is",Space,Str "here!"]],Space,Str "Another",Space,Str "note",Note [Para [Str "Other",Space,Str "note."]],Str "."]
+,Header 1 ("comment-blocks",[],[]) [Str "Comment",Space,Str "blocks"]
+,Para [Str "not",Space,Str "a",Space,Str "comment."]]
diff --git a/test/textile-reader.textile b/test/textile-reader.textile
new file mode 100644
index 000000000..cca0b83f7
--- /dev/null
+++ b/test/textile-reader.textile
@@ -0,0 +1,279 @@
+This is a set of tests for pandoc Textile Reader. Part of it comes
+from John Gruber's markdown test suite.
+
+-----
+
+h1. Headers
+
+h2. Level 2 with an "embeded link":http://www.example.com
+
+h3. Level 3 with *emphasis*
+
+h4. Level 4
+
+h5. Level 5
+
+h6. Level 6
+
+
+h1. Paragraphs
+
+Here's a regular paragraph.
+
+Line breaks are preserved in textile, so you can not wrap your very
+long paragraph with your favourite text editor and have it rendered
+with no break.
+
+
+Here's one with a bullet.
+
+* criminey.
+
+There should be a paragraph break between here
+
+and here.
+
+pandoc converts textile.
+
+h1. Block Quotes
+
+bq. This is a famous quote from somebody. He had a lot of things to
+say, so the text is really really long and spans on multiple lines.
+
+And a following paragraph.
+
+h1. Code Blocks
+
+Code:
+
+<pre>
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+</pre>
+
+And:
+
+<pre>
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+</pre>
+
+bc. Code block with .bc
+ continued
+ @</\
+
+bc.. extended code block
+
+ continued
+p. ended by paragraph
+
+Inline code: @<tt>@, <tt>@</tt>.
+
+h1. Notextile
+
+A block of text can be protected with notextile :
+
+<notextile>
+No *bold* and
+* no bullet
+</notextile>
+
+and inlines can be protected with ==double *equals (=)* markup==.
+
+h1. Lists
+
+h2. Unordered
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+With line breaks:
+
+* asterisk 1
+newline
+* asterisk 2
+
+h2. Ordered
+
+Tight:
+
+# First
+# Second
+# Third
+
+h2. Nested
+
+* ui 1
+** ui 1.1
+### oi 1.1.1
+### oi 1.1.2
+** ui 1.2
+* ui 2
+## oi 2.1
+*** ui 2.1.1
+*** ui 2.1.2
+
+h2. Issue #1500
+
+* one
+* two
+-> and more
+
+h2. Issue #1513
+
+List:
+* one
+* two
+
+h2. Definition List
+
+- coffee := Hot and black
+- tea := Also hot, but a little less black
+- milk :=
+Nourishing beverage for baby cows.
+
+Cold drink that goes great with cookies.=:
+- beer := fresh and bitter
+
+
+h1. Inline Markup
+
+This is _emphasized_, and so __is this__.
+This is *strong*, and so **is this**.
+This is +inserted+, and this is -deleted-.
+Hyphenated-words-are-ok, as well as strange_underscore_notation.
+A "*strong link*":http://www.foobar.com.
+
+_*This is strong and em.*_
+So is *_this_* word and __**that one**__.
+-This is strikeout and *strong*-
+
+Superscripts: a[^bc^]d a ^*hello*^ a[^hello there^].
+Subscripts: ~here~ H[ ~2~]O, H[ ~23~]O, H[ ~many of them~]O.
+
+Dashes : How cool -- automatic dashes.
+
+Elipses : He thought and thought ... and then thought some more.
+
+Quotes and apostrophes : "I'd like to thank you" for example.
+
+
+h1. Links
+
+h2. Explicit
+
+Just a "url":http://www.url.com
+
+"Email link":mailto:nobody@nowhere.net
+
+"not a link": foo
+
+Automatic linking to "$":http://www.example.com.
+
+"Example":http://www.example.com/: Example of a link followed by a colon.
+
+A link["with brackets":http://www.example.com]and no spaces.
+
+h1. Tables
+
+Textile allows tables with and without headers :
+
+h2. Without headers
+
+| name | age | sex |
+| joan | 24 | f |
+| archie | 29 | m |
+| bella | 45 | f |
+
+and some text following ...
+
+h2. With headers
+
+|_. name |_. age |_. sex |
+| joan | 24 | f |
+| archie | 29 | m |
+| bella | 45 | f |
+
+
+
+h1. Images
+
+Textile inline image syntax, like
+here !this_is_an_image.png(this is the alt text)!
+and here !this_is_an_image.png!.
+
+h1. Attributes
+
+h2[en]{color:red}(foo bar #ident). HTML and CSS attributes are parsed in headers.
+
+h2=. Centered
+
+h2>. Right
+
+h2<>{color:blue}[en]. Justified
+
+as well as *(foo)inline attributes* of %{color:red}all kind%
+
+p{color:green}. and paragraph attributes, and table attributes.
+
+table{foo:bar}.
+| name | age | sex |
+| joan | 24 | f |
+
+_(class#id) emph_
+
+_(no class#id) emph_
+
+h1. Entities
+
+&#42;
+&amp;
+
+h1. Raw HTML
+
+However, <strong> raw HTML inlines </strong> are accepted, as well as :
+
+<div class="foobar">
+ any *Raw HTML Block* with bold
+</div>
+
+Html blocks can <div>interrupt paragraphs</div> as well.
+
+Can you prove that 2 < 3 ?
+
+h1. Acronyms and marks
+
+PBS(Public Broadcasting System)
+
+Hi(tm)
+
+Hi (TM)
+
+(r) Hi(r)
+
+Hi(c)2008 (C) 2008
+
+h1. Footnotes
+
+A note.[1] Another note[2].
+
+fn1. The note
+is here!
+
+fn2. Other note.
+
+h1. Comment blocks
+
+###. my comment
+is here.
+
+not a comment.
diff --git a/test/tikiwiki-reader.native b/test/tikiwiki-reader.native
new file mode 100644
index 000000000..2ab053217
--- /dev/null
+++ b/test/tikiwiki-reader.native
@@ -0,0 +1,130 @@
+Pandoc (Meta {unMeta = fromList []})
+[Header 1 ("header",[],[]) [Str "header"]
+,Header 2 ("header-level-two",[],[]) [Str "header",Space,Str "level",Space,Str "two"]
+,Header 3 ("header-level-3",[],[]) [Str "header",Space,Str "level",Space,Str "3"]
+,Header 4 ("header-_level_-four",[],[]) [Str "header",Space,Str "_level_",Space,Str "four"]
+,Header 5 ("header-level-5",[],[]) [Str "header",Space,Str "level",Space,Str "5"]
+,Header 6 ("header-level-6",[],[]) [Str "header",Space,Str "level",Space,Str "6"]
+,Para [Str "!!!!!!!",Space,Str "not",Space,Str "a",Space,Str "header"]
+,Para [Str "--++",Space,Str "not",Space,Str "a",Space,Str "header"]
+,Header 1 ("emph-and-strong",[],[]) [Str "emph",Space,Str "and",Space,Str "strong"]
+,Para [Emph [Str "emph"],Space,Strong [Str "strong"]]
+,Para [Emph [Strong [Str "strong",Space,Str "and",Space,Str "emph",Space,Str "1"]]]
+,Para [Strong [Emph [Str "strong",Space,Str "and",Space,Str "emph",Space,Str "2"]]]
+,Para [Strong [Emph [Str "emph",Space,Str "inside"],Space,Str "strong"]]
+,Para [Strong [Str "strong",Space,Str "with",Space,Emph [Str "emph"]]]
+,Para [Emph [Strong [Str "strong",Space,Str "inside"],Space,Str "emph"]]
+,Header 1 ("horizontal-rule",[],[]) [Str "horizontal",Space,Str "rule"]
+,Para [Str "top"]
+,HorizontalRule
+,Para [Str "bottom"]
+,HorizontalRule
+,Header 1 ("nop",[],[]) [Str "nop"]
+,Para [Str "__not emph__"]
+,Header 1 ("entities",[],[]) [Str "entities"]
+,Para [Str "hi",Space,Str "&",Space,Str "low"]
+,Para [Str "hi",Space,Str "&",Space,Str "low"]
+,Para [Str "G\246del"]
+,Para [Str "\777\2730"]
+,Header 1 ("linebreaks",[],[]) [Str "linebreaks"]
+,Para [Str "hi",LineBreak,Str "there"]
+,Para [Str "hi",LineBreak,Str "there"]
+,Header 1 ("inline-code",[],[]) [Str "inline",Space,Str "code"]
+,Para [Code ("",[],[]) "*\8594*",Space,Code ("",[],[]) "typed",Space,Code ("",[],[]) ">>="]
+,Header 1 ("code-blocks",[],[]) [Str "code",Space,Str "blocks"]
+,CodeBlock ("",[],[]) "\ncase xs of\n (_:_) -> reverse xs\n [] -> ['*']\n"
+,CodeBlock ("",["haskell"],[("colors","haskell"),("ln","0")]) "\ncase xs of\n (_:_) -> reverse xs\n [] -> ['*']\n"
+,Header 1 ("external-links",[],[]) [Str "external",Space,Str "links"]
+,Para [Link ("",[],[]) [Emph [Str "Google"],Space,Str "search",Space,Str "engine"] ("http://google.com","")]
+,Para [Link ("",[],[]) [Str "http://pandoc.org"] ("http://pandoc.org","")]
+,Para [Link ("",[],[]) [Str "http://google.com"] ("http://google.com",""),Space,Link ("",[],[]) [Str "http://yahoo.com"] ("http://yahoo.com","")]
+,Para [Link ("",[],[]) [Str "email",Space,Str "me"] ("mailto:info@example.org","")]
+,Para [Str "http://google.com"]
+,Para [Str "info@example.org"]
+,Header 1 ("lists",[],[]) [Str "lists"]
+,BulletList
+ [[Plain [Str "Start",Space,Str "each",Space,Str "line",Space]]
+ ,[Plain [Str "with",Space,Str "an",Space,Str "asterisk",Space,Str "(*).",Space]
+ ,BulletList
+ [[Plain [Str "More",Space,Str "asterisks",Space,Str "gives",Space,Str "deeper",Space]
+ ,BulletList
+ [[Plain [Str "and",Space,Str "deeper",Space,Str "levels.",Space]]]]]]
+ ,[Plain [Str "Line",Space,Str "breaks",LineBreak,Str "don't",Space,Str "break",Space,Str "levels.",Space]]
+ ,[Plain [Str "Continuations",Space,Str "are",Space,Str "also",Space,Str "possible",Space]
+ ,BulletList
+ [[Plain [Str "and",Space,Str "do",Space,Str "not",Space,Str "break",Space,Str "the",Space,Str "list",Space,Str "flow",Space]]]]
+ ,[Plain [Str "Level",Space,Str "one",Space]]]
+,Para [Str "Any",Space,Str "other",Space,Str "start",Space,Str "ends",Space,Str "the",Space,Str "list."]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Start",Space,Str "each",Space,Str "line",Space]]
+ ,[Plain [Str "with",Space,Str "a",Space,Str "number",Space,Str "(1.).",Space]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "More",Space,Str "number",Space,Str "signs",Space,Str "gives",Space,Str "deeper",Space]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "and",Space,Str "deeper",Space]]
+ ,[Plain [Str "levels.",Space]]]]]]
+ ,[Plain [Str "Line",Space,Str "breaks",LineBreak,Str "don't",Space,Str "break",Space,Str "levels.",Space]]
+ ,[Plain [Str "Blank",Space,Str "lines",Space]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "end",Space,Str "the",Space,Str "list",Space,Str "and",Space,Str "start",Space,Str "another.",Space]]]
+,Para [Str "Any",Space,Str "other",Space,Str "start",Space,Str "also",Space,Str "ends",Space,Str "the",Space,Str "list."]
+,DefinitionList
+ [([Str "item",Space,Str "1"],
+ [[Plain [Str "definition",Space,Str "1",Space]]])
+ ,([Str "item",Space,Str "2"],
+ [[Plain [Str "definition",Space,Str "2-1",Space,Str "definition",Space,Str "2-2",Space]]])
+ ,([Str "item",Space,Emph [Str "3"]],
+ [[Plain [Str "definition",Space,Emph [Str "3"],Space]]])]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "one",Space]]
+ ,[Plain [Str "two",Space]
+ ,BulletList
+ [[Plain [Str "two",Space,Str "point",Space,Str "one",Space]]
+ ,[Plain [Str "two",Space,Str "point",Space,Str "two",Space]]]]
+ ,[Plain [Str "three",Space]]
+ ,[Plain [Str "four",Space]]
+ ,[Plain [Str "five",Space]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "five",Space,Str "sub",Space,Str "1",Space]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "five",Space,Str "sub",Space,Str "1",Space,Str "sub",Space,Str "1",Space]]]]
+ ,[Plain [Str "five",Space,Str "sub",Space,Str "2",Space]]]]]
+,Header 1 ("tables",[],[]) [Str "tables"]
+,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str ""]]
+ ,[Plain [Str ""]]]
+ [[[Plain [Str "Orange"]]
+ ,[Plain [Str "Apple"]]]
+ ,[[Plain [Str "Bread"]]
+ ,[Plain [Str "Pie"]]]
+ ,[[Plain [Str "Butter"]]
+ ,[Plain [Str "Ice",Space,Str "cream"]]]]
+,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str ""]]
+ ,[Plain [Str ""]]]
+ [[[Plain [Str "Orange"]]
+ ,[Plain [Str "Apple"]]]
+ ,[[Plain [Str "Bread"]]
+ ,[Plain [Str "Pie"]]]
+ ,[[Plain [Strong [Str "Butter"]]]
+ ,[Plain [Str "Ice",Space,Str "cream"]]]]
+,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str ""]]
+ ,[Plain [Str ""]]]
+ [[[Plain [Str "Orange"]]
+ ,[Plain [Str "Apple"]]]
+ ,[[Plain [Str "Bread",LineBreak,LineBreak,Str "and",Space,Str "cheese"]]
+ ,[Plain [Str "Pie",LineBreak,LineBreak,Strong [Str "apple"],Space,Str "and",Space,Emph [Str "carrot"],Space]]]]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str ""]]
+ ,[Plain [Str ""]]
+ ,[Plain [Str ""]]]
+ [[[Plain [Space,Str "Orange",Space]]
+ ,[Plain [Space,Str "Apple",Space]]
+ ,[Plain [Space,Str "more"]]]
+ ,[[Plain [Space,Str "Bread",Space]]
+ ,[Plain [Space,Str "Pie",Space]]
+ ,[Plain [Space,Str "more"]]]
+ ,[[Plain [Space,Str "Butter",Space]]
+ ,[Plain [Space,Str "Ice",Space,Str "cream",Space]]
+ ,[Plain [Space,Str "and",Space,Str "more",Space]]]]]
diff --git a/test/tikiwiki-reader.tikiwiki b/test/tikiwiki-reader.tikiwiki
new file mode 100644
index 000000000..d1971feb1
--- /dev/null
+++ b/test/tikiwiki-reader.tikiwiki
@@ -0,0 +1,148 @@
+! header
+
+!! header level two
+
+!!! header level 3
+
+!!!! header _level_ four
+
+!!!!! header level 5
+
+!!!!!! header level 6
+
+!!!!!!! not a header
+
+ --++ not a header
+
+! emph and strong
+
+''emph'' __strong__
+
+''__strong and emph 1__''
+
+__''strong and emph 2''__
+
+__''emph inside'' strong__
+
+__strong with ''emph''__
+
+''__strong inside__ emph''
+
+! horizontal rule
+
+top
+----
+bottom
+
+----
+
+! nop
+
+~np~__not emph__~/np~
+
+! entities
+
+hi & low
+
+hi &amp; low
+
+G&ouml;del
+
+&#777;&#xAAA;
+
+! linebreaks
+
+hi%%%there
+
+hi%%%
+there
+
+! inline code
+
+-+*→*+- -+typed+- -+>>=+-
+
+! code blocks
+
+{CODE()}
+case xs of
+ (_:_) -> reverse xs
+ [] -> ['*']
+{CODE}
+
+{CODE(colors="haskell" ln=0)}
+case xs of
+ (_:_) -> reverse xs
+ [] -> ['*']
+{CODE}
+
+! external links
+
+[http://google.com|''Google'' search engine]
+
+[http://pandoc.org]
+
+[http://google.com] [http://yahoo.com]
+
+[mailto:info@example.org|email me]
+
+http://google.com
+
+info@example.org
+
+! lists
+
+* Start each line
+* with an asterisk (*).
+** More asterisks gives deeper
+*** and deeper levels.
+* Line breaks%%%don't break levels.
+* Continuations
++ are also possible
+** and do not break the list flow
+* Level one
+Any other start ends the list.
+
+# Start each line
+# with a number (1.).
+## More number signs gives deeper
+### and deeper
+### levels.
+# Line breaks%%%don't break levels.
+# Blank lines
+
+# end the list and start another.
+Any other start also
+ends the list.
+
+;item 1: definition 1
+;item 2: definition 2-1
++ definition 2-2
+;item ''3'': definition ''3''
+
+# one
+# two
+** two point one
+** two point two
+# three
+# four
+# five
+## five sub 1
+### five sub 1 sub 1
+## five sub 2
+
+! tables
+
+||Orange|Apple
+Bread|Pie
+Butter|Ice cream||
+
+||Orange|Apple
+Bread|Pie
+__Butter__|Ice cream||
+
+||Orange|Apple
+Bread%%%%%%and cheese|Pie%%%%%%__apple__ and ''carrot'' ||
+
+|| Orange | Apple | more
+ Bread | Pie | more
+ Butter | Ice cream | and more ||
diff --git a/tests/twiki-reader.native b/test/twiki-reader.native
index 1447dcc3d..1447dcc3d 100644
--- a/tests/twiki-reader.native
+++ b/test/twiki-reader.native
diff --git a/tests/twiki-reader.twiki b/test/twiki-reader.twiki
index c2df10573..c2df10573 100644
--- a/tests/twiki-reader.twiki
+++ b/test/twiki-reader.twiki
diff --git a/test/txt2tags.native b/test/txt2tags.native
new file mode 100644
index 000000000..f5134b8a1
--- /dev/null
+++ b/test/txt2tags.native
@@ -0,0 +1,611 @@
+Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "author"]]),("date",MetaInlines [Str "date"]),("includeconf",MetaString "rules.conf"),("title",MetaInlines [Str "Txt2tags",Space,Str "Markup",Space,Str "Rules"])]})
+[Para [Str "This",Space,Str "document",Space,Str "describes",Space,Str "all",Space,Str "the",Space,Str "details",Space,Str "about",Space,Str "each",Space,Str "txt2tags",Space,Str "mark.",SoftBreak,Str "The",Space,Str "target",Space,Str "audience",Space,Str "are",Space,Strong [Str "experienced"],Space,Str "users.",Space,Str "You",Space,Str "may",Space,Str "find",Space,Str "it",SoftBreak,Str "useful",Space,Str "if",Space,Str "you",Space,Str "want",Space,Str "to",Space,Str "master",Space,Str "the",Space,Str "marks",Space,Str "or",Space,Str "solve",Space,Str "a",Space,Str "specific",Space,Str "problem",SoftBreak,Str "about",Space,Str "a",Space,Str "mark."]
+,Para [Str "If",Space,Str "you",Space,Str "are",Space,Str "new",Space,Str "to",Space,Str "txt2tags",Space,Str "or",Space,Str "just",Space,Str "want",Space,Str "to",Space,Str "know",Space,Str "which",Space,Str "are",Space,Str "the",SoftBreak,Str "available",Space,Str "marks,",Space,Str "please",Space,Str "read",Space,Str "the",Space,Link ("",[],[]) [Str "Markup",Space,Str "Demo"] ("MARKUPDEMO",""),Str "."]
+,Para [Str "Note",Space,Str "1:",Space,Str "This",Space,Str "document",Space,Str "is",Space,Str "generated",Space,Str "directly",Space,Str "from",Space,Str "the",Space,Str "txt2tags",SoftBreak,Str "test-suite.",Space,Str "All",Space,Str "the",Space,Str "rules",Space,Str "mentioned",Space,Str "here",Space,Str "are",Space,Str "100%",Space,Str "in",Space,Str "sync",Space,Str "with",Space,Str "the",SoftBreak,Str "current",Space,Str "program",Space,Str "code."]
+,Para [Str "Note",Space,Str "2:",Space,Str "A",Space,Str "good",Space,Str "practice",Space,Str "is",Space,Str "to",Space,Str "consult",Space,Link ("",[],[]) [Str "the",Space,Str "sources"] ("rules.t2t",""),Space,Str "when",SoftBreak,Str "reading,",Space,Str "to",Space,Str "see",Space,Str "how",Space,Str "the",Space,Str "texts",Space,Str "were",Space,Str "made."]
+,Para [Str "Table",Space,Str "of",Space,Str "Contents:"]
+,HorizontalRule
+,Header 1 ("paragraph",[],[]) [Str "Paragraph"]
+,Para [Str "A",Space,Str "paragraph",Space,Str "is",Space,Str "composed",Space,Str "by",Space,Str "one",Space,Str "or",Space,Str "more",Space,Str "lines.",SoftBreak,Str "A",Space,Str "blank",Space,Str "line",Space,Str "(or",Space,Str "a",Space,Str "table,",Space,Str "or",Space,Str "a",Space,Str "list)",Space,Str "ends",Space,Str "the",SoftBreak,Str "current",Space,Str "paragraph."]
+,Para [Str "Leading",Space,Str "and",Space,Str "trailing",Space,Str "spaces",Space,Str "are",Space,Str "ignored."]
+,Para [Str "A",Space,Str "comment",Space,Str "line",Space,Str "can",Space,Str "be",Space,Str "placed",Space,Str "inside",Space,Str "a",Space,Str "paragraph.",SoftBreak,Str "It",Space,Str "will",Space,Str "not",Space,Str "affect",Space,Str "it."]
+,Para [Str "The",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "file",Space,Str "(EOF)",Space,Str "closes",Space,Str "the",SoftBreak,Str "currently",Space,Str "open",Space,Str "paragraph."]
+,Header 1 ("comment",[],[]) [Str "Comment"]
+,Para [Str "%",Space,Str "not",Space,Str "on",Space,Str "the",Space,Str "line",Space,Str "beginning",Space,Str "(at",Space,Str "column",Space,Str "2)"]
+,Para [Str "some",Space,Str "text",Space,Str "%",Space,Str "half",Space,Str "line",Space,Str "comments",Space,Str "are",Space,Str "not",Space,Str "allowed"]
+,Header 1 ("line",[],[]) [Str "Line"]
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,HorizontalRule
+,Para [Strikeout [Str "-----"],SoftBreak,Strikeout [Str "-------",Space,Str "--------"]]
+,Para [Strikeout [Str "-------+--------"]]
+,Para [Str "(",Space,Strikeout [Str "----------------"],Space,Str ")"]
+,Header 1 ("inline",[],[]) [Str "Inline"]
+,Para [Str "i)",Space,Strong [Str "b"],Space,Emph [Str "i"],Space,Span ("",["underline"],[]) [Str "u"],Space,Strikeout [Str "s"],Space,Code ("",[],[]) "m",Space,Str "r",Space,RawInline (Format "html") "t",SoftBreak,Str "i)",Space,Strong [Str "bo"],Space,Emph [Str "it"],Space,Span ("",["underline"],[]) [Str "un"],Space,Strikeout [Str "st"],Space,Code ("",[],[]) "mo",Space,Str "ra",Space,RawInline (Format "html") "tg",SoftBreak,Str "i)",Space,Strong [Str "bold"],Space,Emph [Str "ital"],Space,Span ("",["underline"],[]) [Str "undr"],Space,Strikeout [Str "strk"],Space,Code ("",[],[]) "mono",Space,Str "raw",Space,RawInline (Format "html") "tggd",SoftBreak,Str "i)",Space,Strong [Str "bo",Space,Str "ld"],Space,Emph [Str "it",Space,Str "al"],Space,Span ("",["underline"],[]) [Str "un",Space,Str "dr"],Space,Strikeout [Str "st",Space,Str "rk"],Space,Code ("",[],[]) "mo no",Space,Str "r",Space,Str "aw",Space,RawInline (Format "html") "tg gd",SoftBreak,Str "i)",Space,Strong [Str "bo",Space,Str "*",Space,Str "ld"],Space,Emph [Str "it",Space,Str "/",Space,Str "al"],Space,Span ("",["underline"],[]) [Str "un",Space,Str "_",Space,Str "dr"],Space,Strikeout [Str "st",Space,Str "-",Space,Str "rk"],Space,Code ("",[],[]) "mo ` no",Space,Str "r",Space,Str "\"",Space,Str "aw",Space,RawInline (Format "html") "tg ' gd",SoftBreak,Str "i)",Space,Strong [Str "bo",Space,Str "**ld"],Space,Emph [Str "it",Space,Str "//al"],Space,Span ("",["underline"],[]) [Str "un",Space,Str "__dr"],Space,Strikeout [Str "st",Space,Str "--rk"],Space,Code ("",[],[]) "mo ``no",Space,Str "r",Space,Str "\"\"aw",Space,RawInline (Format "html") "tg ''gd",SoftBreak,Str "i)",Space,Strong [Str "bo",Space,Str "**",Space,Str "ld"],Space,Emph [Str "it",Space,Str "//",Space,Str "al"],Space,Span ("",["underline"],[]) [Str "un",Space,Str "__",Space,Str "dr"],Space,Strikeout [Str "st",Space,Str "--",Space,Str "rk"],Space,Code ("",[],[]) "mo `` no",Space,Str "r",Space,Str "\"\"",Space,Str "aw",Space,RawInline (Format "html") "tg '' gd",SoftBreak,Str "i)",Space,Strong [Str "**bold**"],Space,Emph [Str "//ital//"],Space,Span ("",["underline"],[]) [Str "__undr__"],Space,Strikeout [Str "--strk--"],Space,Code ("",[],[]) "``mono``",Space,Str "\"\"raw\"\"",Space,RawInline (Format "html") "''tggd''",SoftBreak,Str "i)",Space,Strong [Str "*bold*"],Space,Emph [Str "/ital/"],Space,Span ("",["underline"],[]) [Str "_undr_"],Space,Strikeout [Str "-strk-"],Space,Code ("",[],[]) "`mono`",Space,Str "\"raw\"",Space,RawInline (Format "html") "'tggd'"]
+,Para [Str "i)",Space,Strong [Str "*"],Space,Emph [Str "/"],Space,Span ("",["underline"],[]) [Str "_"],Space,Strikeout [Str "-"],Space,Code ("",[],[]) "`",Space,Str "\"",Space,RawInline (Format "html") "'",SoftBreak,Str "i)",Space,Strong [Str "**"],Space,Emph [Str "//"],Space,Span ("",["underline"],[]) [Str "__"],Space,Strikeout [Str "--"],Space,Code ("",[],[]) "``",Space,Str "\"\"",Space,RawInline (Format "html") "''",SoftBreak,Str "i)",Space,Strong [Str "***"],Space,Emph [Str "///"],Space,Span ("",["underline"],[]) [Str "___"],Space,Strikeout [Str "---"],Space,Code ("",[],[]) "```",Space,Str "\"\"\"",Space,RawInline (Format "html") "'''",SoftBreak,Str "i)",Space,Strong [Str "****"],Space,Emph [Str "////"],Space,Span ("",["underline"],[]) [Str "____"],Space,Strikeout [Str "----"],Space,Code ("",[],[]) "````",Space,Str "\"\"\"\"",Space,RawInline (Format "html") "''''",SoftBreak,Str "i)",Space,Strong [Str "*****"],Space,Emph [Str "/////"],Space,Span ("",["underline"],[]) [Str "_____"],Space,Strikeout [Str "-----"],Space,Code ("",[],[]) "`````",Space,Str "\"\"\"\"\"",Space,RawInline (Format "html") "'''''",SoftBreak,Str "i)",Space,Strong [Str "******"],Space,Emph [Str "//////"],Space,Span ("",["underline"],[]) [Str "______"],Space,Strikeout [Str "------"],Space,Code ("",[],[]) "``````",Space,Str "\"\"\"\"\"\"",Space,RawInline (Format "html") "''''''"]
+,Para [Str "i)",Space,Str "****",Space,Str "////",Space,Str "____",Space,Str "----",Space,Str "````",Space,Str "\"\"\"\"",Space,Str "''''",SoftBreak,Str "i)",Space,Str "**",Space,Str "**",Space,Str "//",Space,Str "//",Space,Str "__",Space,Str "__",Space,Str "--",Space,Str "--",Space,Str "``",Space,Str "``",Space,Str "\"\"",Space,Str "\"\"",Space,Str "''",Space,Str "''"]
+,Para [Str "i)",Space,Str "**",Space,Str "bold**",Space,Str "//",Space,Str "ital//",Space,Str "__",Space,Str "undr__",Space,Str "--",Space,Str "strk--",Space,Str "``",Space,Str "mono``",Space,Str "\"\"",Space,Str "raw\"\"",Space,Str "''",Space,Str "tggd''",SoftBreak,Str "i)",Space,Str "**bold",Space,Str "**",Space,Str "//ital",Space,Str "//",Space,Str "__undr",Space,Str "__",Space,Str "--strk",Space,Str "--",Space,Str "``mono",Space,Str "``",Space,Str "\"\"raw",Space,Str "\"\"",Space,Str "''tggd",Space,Str "''",SoftBreak,Str "i)",Space,Str "**",Space,Str "bold",Space,Str "**",Space,Str "//",Space,Str "ital",Space,Str "//",Space,Str "__",Space,Str "undr",Space,Str "__",Space,Str "--",Space,Str "strk",Space,Str "--",Space,Str "``",Space,Str "mono",Space,Str "``",Space,Str "\"\"",Space,Str "raw",Space,Str "\"\"",Space,Str "''",Space,Str "tggd",Space,Str "''"]
+,Header 1 ("link",[],[]) [Str "Link"]
+,Para [Link ("",[],[]) [Str "mailto:user@domain.com"] ("user@domain.com",""),SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com"] ("user@domain.com",""),Str ".",SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com"] ("user@domain.com",""),Str ".",Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "mailto:user@domain.com"] ("user@domain.com",""),Str ".",Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "label"] ("user@domain.com",""),SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla"] ("user@domain.com?subject=bla",""),SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla"] ("user@domain.com?subject=bla",""),Str ".",SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla"] ("user@domain.com?subject=bla",""),Str ",",SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla&cc=otheruser@domain.com"] ("user@domain.com?subject=bla&cc=otheruser@domain.com",""),SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla&cc=otheruser@domain.com"] ("user@domain.com?subject=bla&cc=otheruser@domain.com",""),Str ".",SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla&cc=otheruser@domain.com"] ("user@domain.com?subject=bla&cc=otheruser@domain.com",""),Str ",",SoftBreak,Link ("",[],[]) [Str "label"] ("user@domain.com?subject=bla&cc=otheruser@domain.com",""),Str ".",SoftBreak,Link ("",[],[]) [Str "label"] ("user@domain.com?subject=bla&cc=otheruser@domain.com.",""),Str ".",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com"] ("http://www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/"] ("http://www.domain.com/dir/",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir///"] ("http://www.domain.com/dir///",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com."] ("http://www.domain.com.",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com,"] ("http://www.domain.com,",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com."] ("http://www.domain.com.",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com,"] ("http://www.domain.com,",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/."] ("http://www.domain.com/dir/.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com."] ("http://www.domain.com.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/."] ("http://www.domain.com/dir/.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html."] ("http://www.domain.com/dir/index.html.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html,"] ("http://www.domain.com/dir/index.html,",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/#anchor"] ("http://www.domain.com/dir/#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html#anchor"] ("http://www.domain.com/dir/index.html#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html#anchor."] ("http://www.domain.com/dir/index.html#anchor.",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/#anchor."] ("http://www.domain.com/dir/#anchor.",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html#anchor."] ("http://www.domain.com/dir/index.html#anchor.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/#anchor."] ("http://www.domain.com/dir/#anchor.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html#anchor."] ("http://www.domain.com/dir/index.html#anchor.",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://domain.com?a=a@a.a&b=a+b+c."] ("http://domain.com?a=a@a.a&b=a+b+c.",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com?a=a@a.a&b=a+b+c,"] ("http://domain.com?a=a@a.a&b=a+b+c,",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com/bla.cgi?a=a@a.a&b=a+b+c."] ("http://domain.com/bla.cgi?a=a@a.a&b=a+b+c.",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com/bla.cgi?a=a@a.a&b=a+b+c@."] ("http://domain.com/bla.cgi?a=a@a.a&b=a+b+c@.",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com?a=a@a.a&b=a+b+c.#anchor"] ("http://domain.com?a=a@a.a&b=a+b+c.#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor"] ("http://domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com/bla.cgi?a=a@a.a&b=a+b+c@.#anchor"] ("http://domain.com/bla.cgi?a=a@a.a&b=a+b+c@.#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com/bla.html."] ("http://user:password@domain.com/bla.html.",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com/dir/."] ("http://user:password@domain.com/dir/.",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com."] ("http://user:password@domain.com.",""),SoftBreak,Link ("",[],[]) [Str "http://user:@domain.com."] ("http://user:@domain.com.",""),SoftBreak,Link ("",[],[]) [Str "http://user@domain.com."] ("http://user@domain.com.",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor"] ("http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c@#anchor"] ("http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c@#anchor",""),SoftBreak,Link ("",[],[]) [Str "label"] ("www.domain.com",""),SoftBreak,Str "[",Space,Str "label",Space,Link ("",[],[]) [Str "www.domain.com"] ("www.domain.com",""),Str "]",SoftBreak,Link ("",[],[]) [Str "label",Space] ("www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "anchor",Space] ("http://www.domain.com/dir/index.html#anchor.",""),SoftBreak,Link ("",[],[]) [Str "login",Space] ("http://user:password@domain.com/bla.html",""),SoftBreak,Link ("",[],[]) [Str "form",Space] ("http://www.domain.com/bla.cgi?a=a@a.a&b=a+b+c.",""),SoftBreak,Link ("",[],[]) [Str "form",Space,Str "&",Space,Str "anchor"] ("http://www.domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor",""),SoftBreak,Link ("",[],[]) [Str "login",Space,Str "&",Space,Str "form",Space] ("http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c.",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "up",Space] ("..",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "file",Space] ("bla.html",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "anchor",Space] ("#anchor",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "file/anchor"] ("bla.html#anchor",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "file/anchor"] ("bla.html#anchor.",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "img",Space] ("abc.gif",""),SoftBreak,Link ("",[],[]) [Str "www.fake.com"] ("www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm"] ("http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-"] ("http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-#anchor_"] ("http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-#anchor_",""),Str "-1%.",SoftBreak,Link ("",[],[]) [Str "http://foo._user-9:pass!#$%&*()+word@domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-#anchor_"] ("http://foo._user-9:pass!#$%&*()+word@domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-#anchor_",""),Str "-1%.",SoftBreak,Link ("",[],[]) [Str "http://L1.com"] ("http://L1.com",""),Space,Str "!",Space,Link ("",[],[]) [Str "mailto:L2@www.com"] ("L2@www.com",""),Space,Str "!",Space,Link ("",[],[]) [Str "L3"] ("www.com",""),Space,Str "!",Space,Link ("",[],[]) [Str "L4"] ("w@ww.com",""),Space,Str "!",Space,Link ("",[],[]) [Str "www.L5.com"] ("www.L5.com",""),SoftBreak,Link ("",[],[]) [Str "www.domain.com"] ("www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "www2.domain.com"] ("www2.domain.com",""),SoftBreak,Link ("",[],[]) [Str "ftp.domain.com"] ("ftp.domain.com",""),SoftBreak,Link ("",[],[]) [Str "WWW.DOMAIN.COM"] ("WWW.DOMAIN.COM",""),SoftBreak,Link ("",[],[]) [Str "FTP.DOMAIN.COM"] ("FTP.DOMAIN.COM",""),SoftBreak,Link ("",[],[]) [Str "label"] ("www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "label"] ("ftp.domain.com",""),SoftBreak,Link ("",[],[]) [Str "label"] ("WWW.DOMAIN.COM",""),SoftBreak,Link ("",[],[]) [Str "label"] ("FTP.DOMAIN.COM",""),SoftBreak,Str "[label",Space,Link ("",[],[]) [Str "www.domain.com"] ("www.domain.com",""),Space,Str "]",SoftBreak,Str "[label]",Space,Link ("",[],[]) [Str "www.domain.com"] ("www.domain.com",""),Str "]"]
+,Header 1 ("image",[],[]) [Str "Image"]
+,Para [Image ("",[],[]) [] ("img.png","")]
+,Para [Link ("",[],[]) [Image ("",[],[]) [] ("img.png","")] ("http://txt2tags.org","")]
+,Para [Image ("",[],[]) [] ("img.png",""),Space,Str "Image",Space,Str "at",Space,Str "the",Space,Str "line",Space,Str "beginning."]
+,Para [Str "Image",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Image ("",[],[]) [] ("img.png",""),Space,Str "of",Space,Str "the",Space,Str "line."]
+,Para [Str "Image",Space,Str "at",Space,Str "the",Space,Str "line",Space,Str "end.",Space,Image ("",[],[]) [] ("img.png","")]
+,Para [Image ("",[],[]) [] ("img.png",""),SoftBreak,Image ("",[],[]) [] ("img.png",""),SoftBreak,Image ("",[],[]) [] ("img.png","")]
+,Para [Image ("",[],[]) [] ("img.png",""),Image ("",[],[]) [] ("img.png","")]
+,Para [Str "Images",Space,Image ("",[],[]) [] ("img.png",""),Space,Str "mixed",Space,Image ("",[],[]) [] ("img.png",""),Space,Str "with",Space,Image ("",[],[]) [] ("img.png",""),Space,Str "text."]
+,Para [Str "Images",Space,Str "glued",Space,Str "together:",Space,Image ("",[],[]) [] ("img.png",""),Image ("",[],[]) [] ("img.png",""),Image ("",[],[]) [] ("img.png",""),Str "."]
+,Para [Str "[img.png",Space,Str "]"]
+,Para [Str "[",Space,Str "img.png]"]
+,Para [Str "[",Space,Str "img.png",Space,Str "]"]
+,Header 1 ("numtitle",[],[]) [Str "Numbered",Space,Str "Title"]
+,Header 1 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "1"]
+,Header 2 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "2"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 4 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "4"]
+,Header 5 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "5"]
+,Header 1 ("lab_el-1",[],[]) [Str "Title",Space,Str "Level",Space,Str "1"]
+,Header 2 ("lab_el-2",[],[]) [Str "Title",Space,Str "Level",Space,Str "2"]
+,Header 3 ("lab_el-3",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 4 ("lab_el-4",[],[]) [Str "Title",Space,Str "Level",Space,Str "4"]
+,Header 5 ("lab_el-5",[],[]) [Str "Title",Space,Str "Level",Space,Str "5"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("lab_el-9",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Para [Str "+Not",Space,Str "Title"]
+,Para [Str "++Not",Space,Str "Title+"]
+,Para [Str "+++Not",Space,Str "Title++++",SoftBreak,Str "++++++Not",Space,Str "Title",Space,Str "6++++++"]
+,Para [Str "+++++++Not",Space,Str "Title",Space,Str "7+++++++",SoftBreak,Str "+Not",Space,Str "Title+",Space,Str "[label1]",SoftBreak,Str "+Not",Space,Str "Title+[",Space,Str "label",Space,Str "]",SoftBreak,Str "+Not",Space,Str "Title+[la/bel]"]
+,Header 1 ("title",[],[]) [Str "Title"]
+,Header 1 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "1"]
+,Header 2 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "2"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 4 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "4"]
+,Header 5 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "5"]
+,Header 1 ("lab_el-1",[],[]) [Str "Title",Space,Str "Level",Space,Str "1"]
+,Header 2 ("lab_el-2",[],[]) [Str "Title",Space,Str "Level",Space,Str "2"]
+,Header 3 ("lab_el-3",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 4 ("lab_el-4",[],[]) [Str "Title",Space,Str "Level",Space,Str "4"]
+,Header 5 ("lab_el-5",[],[]) [Str "Title",Space,Str "Level",Space,Str "5"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Header 3 ("lab_el-9",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
+,Para [Str "=Not",Space,Str "Title"]
+,Para [Str "==Not",Space,Str "Title="]
+,Para [Str "===Not",Space,Str "Title====",SoftBreak,Str "======Not",Space,Str "Title",Space,Str "6======"]
+,Para [Str "=======Not",Space,Str "Title",Space,Str "7=======",SoftBreak,Str "=Not",Space,Str "Title=",Space,Str "[label1]",SoftBreak,Str "=Not",Space,Str "Title=[",Space,Str "label",Space,Str "]",SoftBreak,Str "=Not",Space,Str "Title=[la/bel]"]
+,Header 1 ("quote",[],[]) [Str "Quote"]
+,BlockQuote
+ [Para [Str "To",Space,Str "quote",Space,Str "a",Space,Str "paragraph,",Space,Str "just",Space,Str "prefix",Space,Str "it",Space,Str "by",Space,Str "a",Space,Str "TAB",SoftBreak,Str "character.",Space,Str "All",Space,Str "the",Space,Str "lines",Space,Str "of",Space,Str "the",Space,Str "paragraph",Space,Str "must",SoftBreak,Str "begin",Space,Str "with",Space,Str "a",Space,Str "TAB."]]
+,Para [Str "Any",Space,Str "non-tabbed",Space,Str "line",Space,Str "closes",Space,Str "the",Space,Str "quote",Space,Str "block."]
+,BlockQuote
+ [Para [Str "The",Space,Str "number",Space,Str "of",Space,Str "leading",Space,Str "TABs",Space,Str "identifies",Space,Str "the",Space,Str "quote",SoftBreak,Str "block",Space,Str "depth.",Space,Str "This",Space,Str "is",Space,Str "quote",Space,Str "level",Space,Str "1."]
+ ,BlockQuote
+ [Para [Str "With",Space,Str "two",Space,Str "TABs,",Space,Str "we",Space,Str "are",Space,Str "on",Space,Str "the",Space,Str "quote",SoftBreak,Str "level",Space,Str "2."]
+ ,BlockQuote
+ [Para [Str "The",Space,Str "more",Space,Str "TABs,",Space,Str "more",Space,Str "deep",Space,Str "is",SoftBreak,Str "the",Space,Str "quote",Space,Str "level."]
+ ,BlockQuote
+ [Para [Str "There",Space,Str "isn't",Space,Str "a",Space,Str "limit."]]]]]
+,BlockQuote
+ [BlockQuote
+ [BlockQuote
+ [BlockQuote
+ [Para [Str "This",Space,Str "quote",Space,Str "starts",Space,Str "at",SoftBreak,Str "level",Space,Str "4."]]
+ ,Para [Str "Then",Space,Str "its",Space,Str "depth",Space,Str "is",Space,Str "decreased."]]
+ ,Para [Str "Counting",Space,Str "down,",Space,Str "one",Space,Str "by",Space,Str "one."]]
+ ,Para [Str "Until",Space,Str "the",Space,Str "level",Space,Str "1."]]
+,BlockQuote
+ [BlockQuote
+ [BlockQuote
+ [Para [Str "Unlike",Space,Str "lists,",Space,Str "any",Space,Str "quote",Space,Str "block",Space,Str "is",SoftBreak,Str "independent,",Space,Str "not",Space,Str "part",Space,Str "of",Space,Str "a",Space,Str "tree."]]]
+ ,Para [Str "The",Space,Str "TAB",Space,Str "count",Space,Str "don't",Space,Str "need",Space,Str "to",Space,Str "be",Space,Str "incremental",SoftBreak,Str "by",Space,Str "one."]
+ ,BlockQuote
+ [BlockQuote
+ [BlockQuote
+ [Para [Str "The",Space,Str "nesting",Space,Str "don't",Space,Str "need",SoftBreak,Str "to",Space,Str "follow",Space,Str "any",Space,Str "rule."]]]
+ ,Para [Str "Quotes",Space,Str "can",Space,Str "be",Space,Str "opened",Space,Str "and",Space,Str "closed",SoftBreak,Str "in",Space,Str "any",Space,Str "way."]
+ ,BlockQuote
+ [BlockQuote
+ [BlockQuote
+ [Para [Str "You",Space,Str "choose."]]]]]]
+,BlockQuote
+ [Para [Str "Some",Space,Str "targets",Space,Str "(as",Space,Str "sgml)",Space,Str "don't",Space,Str "support",Space,Str "the",SoftBreak,Str "nesting",Space,Str "of",Space,Str "quotes.",Space,Str "There",Space,Str "is",Space,Str "only",Space,Str "one",Space,Str "quote",SoftBreak,Str "level."]
+ ,BlockQuote
+ [Para [Str "In",Space,Str "this",Space,Str "case,",Space,Str "no",Space,Str "matter",Space,Str "how",Space,Str "much",SoftBreak,Str "TABs",Space,Str "are",Space,Str "used",Space,Str "to",Space,Str "define",Space,Str "the",Space,Str "quote",SoftBreak,Str "block,",Space,Str "it",Space,Str "always",Space,Str "will",Space,Str "be",Space,Str "level",Space,Str "1."]]]
+,BlockQuote
+ [Para [Str "Spaces",Space,Str "AFTER",Space,Str "the",Space,Str "TAB",Space,Str "character",Space,Str "are",Space,Str "allowed.",SoftBreak,Str "But",Space,Str "be",Space,Str "careful,",Space,Str "it",Space,Str "can",Space,Str "be",Space,Str "confusing."]]
+,Para [Str "Spaces",Space,Str "BEFORE",Space,Str "the",Space,Str "TAB",Space,Str "character",SoftBreak,Str "invalidate",Space,Str "the",Space,Str "mark.",Space,Str "It's",Space,Str "not",Space,Str "quote."]
+,BlockQuote
+ [Para [Str "Paragraph",Space,Str "breaks",Space,Str "inside",Space,Str "a",Space,Str "quote",Space,Str "aren't",SoftBreak,Str "possible."]
+ ,Para [Str "This",Space,Str "sample",Space,Str "are",Space,Str "two",Space,Str "separated",Space,Str "quoted",SoftBreak,Str "paragraphs,",Space,Str "not",Space,Str "a",Space,Str "quote",Space,Str "block",Space,Str "with",SoftBreak,Str "two",Space,Str "paragraphs",Space,Str "inside."]]
+,BlockQuote
+ [Para [Str "The",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "file",Space,Str "(EOF)",Space,Str "closes",Space,Str "the",SoftBreak,Str "currently",Space,Str "open",Space,Str "quote",Space,Str "block."]]
+,Header 1 ("raw",[],[]) [Str "Raw"]
+,Para [Str "A raw line.\n"]
+,Para [Str " Another raw line, with leading spaces.\n"]
+,Para [Str "A raw area delimited\n by lines with marks.\n"]
+,Para [Str "Trailing spaces and TABs after the area marks\nare allowed, but not encouraged nor documented.\n"]
+,Para [Str "\"\"\"Not",Space,Str "a",Space,Str "raw",Space,Str "line,",Space,Str "need",Space,Str "one",Space,Str "space",Space,Str "after",Space,Str "mark."]
+,Para [Str "\"\"\"",SoftBreak,Str "Not",Space,Str "a",Space,Str "raw",Space,Str "area.",SoftBreak,Str "The",Space,Str "marks",Space,Str "must",Space,Str "be",Space,Str "at",Space,Str "the",Space,Str "line",Space,Str "beginning,",SoftBreak,Str "no",Space,Str "leading",Space,Str "spaces.",SoftBreak,Str "\"\"\""]
+,Para [Str "The end of the file (EOF) closes\nthe currently open raw area.\n"]
+,Header 1 ("verbatim",[],[]) [Str "Verbatim"]
+,CodeBlock ("",[],[]) "A verbatim line.\n"
+,CodeBlock ("",[],[]) " Another verbatim line, with leading spaces.\n"
+,CodeBlock ("",[],[]) "A verbatim area delimited\n by lines with marks.\n"
+,CodeBlock ("",[],[]) "Trailing spaces and TABs after the area marks\nare allowed, but not encouraged nor documented.\n"
+,Para [Str "```Not",Space,Str "a",Space,Str "verbatim",Space,Str "line,",Space,Str "need",Space,Str "one",Space,Str "space",Space,Str "after",Space,Str "mark."]
+,Para [Str "```",SoftBreak,Str "Not",Space,Str "a",Space,Str "verbatim",Space,Str "area.",SoftBreak,Str "The",Space,Str "marks",Space,Str "must",Space,Str "be",Space,Str "at",Space,Str "the",Space,Str "line",Space,Str "beginning,",SoftBreak,Str "no",Space,Str "leading",Space,Str "spaces.",SoftBreak,Str "```"]
+,CodeBlock ("",[],[]) "The end of the file (EOF) closes\nthe currently open verbatim area.\n"
+,Header 1 ("deflist",[],[]) [Str "Definition",Space,Str "List"]
+,DefinitionList
+ [([Str "Definition",Space,Str "list"],
+ [[Plain [Str "A",Space,Str "list",Space,Str "with",Space,Str "terms"]]])
+ ,([Str "Start",Space,Str "term",Space,Str "with",Space,Str "colon"],
+ [[Plain [Str "And",Space,Str "its",Space,Str "definition",Space,Str "follows"]]])]
+,Header 1 ("numlist",[],[]) [Str "Numbered",Space,Str "List"]
+,Para [Str "See",Space,Link ("",[],[]) [Str "List"] ("#list",""),Str ",",Space,Str "the",Space,Str "same",Space,Str "rules",Space,Str "apply."]
+,Header 1 ("list",[],[]) [Str "List"]
+,BulletList
+ [[Plain [Str "Use",Space,Str "the",Space,Str "hyphen",Space,Str "to",Space,Str "prefix",Space,Str "list",Space,Str "items."]]
+ ,[Plain [Str "There",Space,Str "must",Space,Str "be",Space,Str "one",Space,Str "space",Space,Str "after",Space,Str "the",Space,Str "hyphen."]]
+ ,[Plain [Str "The",Space,Str "list",Space,Str "is",Space,Str "closed",Space,Str "by",Space,Str "two",Space,Str "consecutive",Space,Str "blank",Space,Str "lines."]]]
+,BulletList
+ [[Plain [Str "The",Space,Str "list",Space,Str "can",Space,Str "be",Space,Str "indented",Space,Str "on",Space,Str "the",Space,Str "source",Space,Str "document."]]
+ ,[Plain [Str "You",Space,Str "can",Space,Str "use",Space,Str "any",Space,Str "number",Space,Str "of",Space,Str "spaces."]]
+ ,[Plain [Str "The",Space,Str "result",Space,Str "will",Space,Str "be",Space,Str "the",Space,Str "same."]]]
+,BulletList
+ [[Para [Str "Let",Space,Str "one",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "the",Space,Str "list",Space,Str "items."]]
+ ,[Para [Str "It",Space,Str "will",Space,Str "be",Space,Str "maintained",Space,Str "on",Space,Str "the",Space,Str "conversion."]]
+ ,[Para [Str "Some",Space,Str "targets",Space,Str "don't",Space,Str "support",Space,Str "this",Space,Str "behavior."]]
+ ,[Para [Str "This",Space,Str "one",Space,Str "was",Space,Str "separated",Space,Str "by",Space,Str "a",Space,Str "line",Space,Str "with",Space,Str "blanks.",SoftBreak,Str "You",Space,Str "can",Space,Str "also",Space,Str "put",Space,Str "a",Space,Str "blank",Space,Str "line",Space,Str "inside"]
+ ,Para [Str "the",Space,Str "item",Space,Str "contents",Space,Str "and",Space,Str "it",Space,Str "will",Space,Str "be",Space,Str "preserved."]]]
+,Para [Str "-This",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "list",Space,Str "(no",Space,Str "space)"]
+,Para [Str "-",Space,Str "This",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "list",Space,Str "(more",Space,Str "than",Space,Str "one",Space,Str "space)"]
+,Para [Str "-",Space,Str "This",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "list",Space,Str "(a",Space,Str "TAB",Space,Str "instead",Space,Str "the",Space,Str "space)"]
+,BulletList
+ [[BulletList
+ [[Plain [Str "This",Space,Str "is",Space,Str "a",Space,Str "list"]]]]
+ ,[OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "This",Space,Str "is",Space,Str "a",Space,Str "list"]]]]
+ ,[DefinitionList
+ [([Str "This",Space,Str "is",Space,Str "a",Space,Str "list"],
+ [[]])]]]
+,BulletList
+ [[Plain [Str "This",Space,Str "is",Space,Str "the",Space,Str "\"mother\"",Space,Str "list",Space,Str "first",Space,Str "item."]]
+ ,[Plain [Str "Here",Space,Str "is",Space,Str "the",Space,Str "second,",Space,Str "but",Space,Str "inside",Space,Str "this",Space,Str "item,"]
+ ,BulletList
+ [[Plain [Str "there",Space,Str "is",Space,Str "a",Space,Str "sublist,",Space,Str "with",Space,Str "its",Space,Str "own",Space,Str "items."]]
+ ,[Plain [Str "Note",Space,Str "that",Space,Str "the",Space,Str "items",Space,Str "of",Space,Str "the",Space,Str "same",Space,Str "sublist"]]
+ ,[Plain [Str "must",Space,Str "have",Space,Str "the",Space,Str "same",Space,Str "indentation."]
+ ,BulletList
+ [[Plain [Str "And",Space,Str "this",Space,Str "can",Space,Str "go",Space,Str "on,",Space,Str "opening",Space,Str "sublists."]
+ ,BulletList
+ [[Plain [Str "Just",Space,Str "add",Space,Str "leading",Space,Str "spaces",Space,Str "before",Space,Str "the"]]
+ ,[Plain [Str "hyphen",Space,Str "and",Space,Str "sublists",Space,Str "will",Space,Str "be",Space,Str "opened."]]
+ ,[Plain [Str "The",Space,Str "two",Space,Str "blank",Space,Str "lines",Space,Str "closes",Space,Str "them",Space,Str "all."]]]]]]]]]
+,BulletList
+ [[Plain [Str "When",Space,Str "nesting",Space,Str "lists,",Space,Str "the",Space,Str "additional",Space,Str "spaces",Space,Str "are",Space,Str "free."]]
+ ,[Plain [Str "You",Space,Str "can",Space,Str "add",Space,Str "just",Space,Str "one,"]
+ ,BulletList
+ [[Plain [Str "or",Space,Str "many."]
+ ,BulletList
+ [[Plain [Str "What",Space,Str "matters",Space,Str "is",Space,Str "to",Space,Str "put",Space,Str "more",Space,Str "than",Space,Str "the",Space,Str "previous."]]
+ ,[Plain [Str "But",Space,Str "remember",Space,Str "that",Space,Str "the",Space,Str "other",Space,Str "items",Space,Str "of",Space,Str "the",Space,Str "same",Space,Str "list"]]
+ ,[Plain [Str "must",Space,Str "use",Space,Str "the",Space,Str "same",Space,Str "indentation."]]]]]]]
+,BulletList
+ [[Plain [Str "There",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "depth",Space,Str "limit,"]
+ ,BulletList
+ [[Plain [Str "you",Space,Str "can",Space,Str "go",Space,Str "deeper",Space,Str "and",Space,Str "deeper."]
+ ,BulletList
+ [[Plain [Str "But",Space,Str "some",Space,Str "targets",Space,Str "may",Space,Str "have",Space,Str "restrictions."]
+ ,BulletList
+ [[Plain [Str "The",Space,Str "LaTeX",Space,Str "maximum",Space,Str "is",Space,Str "here,",Space,Str "4",Space,Str "levels."]]]]]]]]]
+,BulletList
+ [[Plain [Str "Reverse",Space,Str "nesting",Space,Str "doesn't",Space,Str "work."]]
+ ,[Plain [Str "Because",Space,Str "a",Space,Str "sublist",Space,Str "*must*",Space,Str "have",Space,Str "a",Space,Str "mother",Space,Str "list."]]
+ ,[Plain [Str "It's",Space,Str "the",Space,Str "list",Space,Str "concept,",Space,Str "not",Space,Str "a",Space,Str "txt2tags",Space,Str "limitation."]]
+ ,[Plain [Str "All",Space,Str "this",Space,Str "sublists",Space,Str "will",Space,Str "be",Space,Str "bumped",Space,Str "to",Space,Str "mother",Space,Str "lists."]]
+ ,[Plain [Str "At",Space,Str "level",Space,Str "1,",Space,Str "like",Space,Str "this",Space,Str "one."]]]
+,BulletList
+ [[Plain [Str "Level",Space,Str "1"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "2"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "3"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "4"]]]]
+ ,[Plain [Str "Level",Space,Str "3",Space,Str "--",Space,Str "(closed",Space,Str "Level",Space,Str "4)"]]]]
+ ,[Plain [Str "Level",Space,Str "2",Space,Str "--",Space,Str "(closed",Space,Str "Level",Space,Str "3)"]]]]
+ ,[Plain [Str "Level",Space,Str "1",Space,Str "--",Space,Str "(closed",Space,Str "Level",Space,Str "2)"]]]
+,BulletList
+ [[Plain [Str "Level",Space,Str "1"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "2"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "3"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "4"]]]]]]]]
+ ,[Plain [Str "Level",Space,Str "1",Space,Str "--",Space,Str "(closed",Space,Str "Level",Space,Str "4,",Space,Str "Level",Space,Str "3",Space,Str "and",Space,Str "Level",Space,Str "2)"]]]
+,BulletList
+ [[Para [Str "Level",Space,Str "1"]
+ ,BulletList
+ [[Para [Str "Level",Space,Str "2",Space,Str "--",Space,Str "blank",Space,Str "BEFORE",Space,Str "and",Space,Str "AFTER",Space,Str "(in)"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "3"]]]]]]]
+,BulletList
+ [[Plain [Str "Level",Space,Str "4"]]]
+,BulletList
+ [[Para [Str "Level",Space,Str "3"]]
+ ,[Para [Str "Level",Space,Str "2",Space,Str "--",Space,Str "blank",Space,Str "BEFORE",Space,Str "and",Space,Str "AFTER",Space,Str "(out)"]]
+ ,[Para [Str "Level",Space,Str "1"]
+ ,BulletList
+ [[Para [Str "Level",Space,Str "2",Space,Str "--",Space,Str "blank",Space,Str "BEFORE",Space,Str "(spaces)",Space,Str "and",Space,Str "AFTER",Space,Str "(TAB)"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "3"]]]]]]]
+,BulletList
+ [[Plain [Str "Level",Space,Str "1"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "2"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "3"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "4"]]
+ ,[Plain [Str "Level",Space,Str "3.5",Space,Str "???"]]]]
+ ,[Plain [Str "Level",Space,Str "3"]]
+ ,[Plain [Str "Level",Space,Str "2.5",Space,Str "???"]]]]
+ ,[Plain [Str "Level",Space,Str "2"]]
+ ,[Plain [Str "Level",Space,Str "1.5",Space,Str "???"]]]]
+ ,[Plain [Str "Level",Space,Str "1"]]]
+,BulletList
+ [[Plain [Str "This",Space,Str "list",Space,Str "is",Space,Str "closed",Space,Str "by",Space,Str "a",Space,Str "line",Space,Str "with",Space,Str "spaces",Space,Str "and",Space,Str "other",Space,Str "with",Space,Str "TABs"]]]
+,BulletList
+ [[Plain [Str "This",Space,Str "list",Space,Str "is",Space,Str "NOT",Space,Str "closed",Space,Str "by",Space,Str "two",Space,Str "comment",Space,Str "lines"]]]
+,BulletList
+ [[Plain [Str "This",Space,Str "list",Space,Str "is",Space,Str "closed",Space,Str "by",Space,Str "a",Space,Str "line",Space,Str "with",Space,Str "spaces",Space,Str "and",Space,Str "TAB,"]]
+ ,[Plain [Str "then",Space,Str "a",Space,Str "comment",Space,Str "line,",Space,Str "then",Space,Str "an",Space,Str "empty",Space,Str "line."]]]
+,BulletList
+ [[Plain [Str "Level",Space,Str "1"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "2"]
+ ,BulletList
+ [[Plain [Str "Level",Space,Str "3"]]]
+ ,Plain [Str "-",SoftBreak,Str "Level",Space,Str "2"]]]
+ ,Plain [Str "-",SoftBreak,Str "Level",Space,Str "1"]]]
+,Para [Str "-"]
+,BulletList
+ [[Plain [Str "Empty",Space,Str "item",Space,Str "with",Space,Str "trailing",Space,Str "spaces."]]]
+,Para [Str "-"]
+,BulletList
+ [[Plain [Str "Empty",Space,Str "item",Space,Str "with",Space,Str "trailing",Space,Str "TAB."]]]
+,Para [Str "-"]
+,BulletList
+ [[Plain [Str "If",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "file",Space,Str "(EOF)",Space,Str "is",Space,Str "hit,"]
+ ,BulletList
+ [[Plain [Str "all",Space,Str "the",Space,Str "currently",Space,Str "opened",Space,Str "list",Space,Str "are",Space,Str "closed,"]
+ ,BulletList
+ [[Plain [Str "just",Space,Str "like",Space,Str "when",Space,Str "using",Space,Str "the",Space,Str "two",Space,Str "blank",Space,Str "lines."]]]]]]]
+,Header 1 ("table",[],[]) [Str "Table"]
+,Table [] [AlignRight] [0.0]
+ [[]]
+ [[[Plain [Str "Cell",Space,Str "1"]]]]
+,Table [] [AlignCenter,AlignCenter,AlignRight] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "Cell",Space,Str "1"]]
+ ,[Plain [Str "Cell",Space,Str "2"]]
+ ,[Plain [Str "Cell",Space,Str "3"]]]]
+,Table [] [AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "Cell",Space,Str "1"]]
+ ,[Plain [Str "Cell",Space,Str "2"]]
+ ,[Plain [Str "Cell",Space,Str "3"]]]]
+,Para [Str "||",Space,Str "Cell",Space,Str "1",Space,Str "|",Space,Str "Cell",Space,Str "2",Space,Str "|",Space,Str "Cell",Space,Str "3",Space,Str "|"]
+,Table [] [AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "Cell",Space,Str "1"]]
+ ,[Plain [Str "Cell",Space,Str "2"]]
+ ,[Plain [Str "Cell",Space,Str "3"]]]]
+,Table [] [AlignDefault,AlignCenter,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "Heading"]]
+ ,[Plain [Str "Heading"]]
+ ,[Plain [Str "Heading"]]]
+ [[[Plain [Str "<-"]]
+ ,[Plain [Str "--"]]
+ ,[Plain [Str "->"]]]
+ ,[[Plain [Str "--"]]
+ ,[Plain [Str "--"]]
+ ,[Plain [Str "--"]]]
+ ,[[Plain [Str "->"]]
+ ,[Plain [Str "--"]]
+ ,[Plain [Str "<-"]]]]
+,Table [] [AlignDefault,AlignDefault,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0]
+ [[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3+4"]]
+ ,[]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]
+ ,[Plain [Str "4"]]]
+ ,[[Plain [Str "1+2+3"]]
+ ,[Plain [Str "4"]]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "2+3"]]
+ ,[Plain [Str "4"]]
+ ,[]]
+ ,[[Plain [Str "1+2+3+4"]]
+ ,[]
+ ,[]
+ ,[]]]
+,Table [] [AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "0"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[]
+ ,[Plain [Str "7"]]]
+ ,[[Plain [Str "8"]]
+ ,[]
+ ,[Plain [Str "A"]]
+ ,[Plain [Str "B"]]]
+ ,[[]
+ ,[Plain [Str "D"]]
+ ,[Plain [Str "E"]]
+ ,[Plain [Str "F"]]]]
+,Table [] [AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "1"]]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]
+ ,[Plain [Str "4"]]
+ ,[]]
+ ,[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]
+ ,[Plain [Str "4"]]
+ ,[Plain [Str "5"]]]]
+,Table [] [AlignDefault,AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "Jan"]]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "Fev"]]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "Mar"]]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "Apr"]]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "May"]]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "20%"]]
+ ,[Plain [Str "40%"]]
+ ,[Plain [Str "60%"]]
+ ,[Plain [Str "80%"]]
+ ,[Plain [Str "100%"]]]]
+,Table [] [AlignCenter,AlignDefault,AlignDefault,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[]
+ ,[]
+ ,[Plain [Str "/"]]
+ ,[]
+ ,[]]
+ ,[[]
+ ,[Plain [Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/"]]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[Plain [Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/"]]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ ,[[]
+ ,[Plain [Str "o"]]
+ ,[]
+ ,[Plain [Str "o"]]
+ ,[]]
+ ,[[]
+ ,[]
+ ,[Plain [Str "."]]
+ ,[]
+ ,[]]
+ ,[[]
+ ,[Plain [Str "=",Space,Str "=",Space,Str "=",Space,Str "="]]
+ ,[]
+ ,[]
+ ,[]]]
+,Table [] [AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "01"]]
+ ,[Plain [Str "02"]]
+ ,[]
+ ,[]
+ ,[Plain [Str "05"]]
+ ,[]
+ ,[Plain [Str "07"]]
+ ,[]]
+ ,[[]
+ ,[]
+ ,[Plain [Str "11"]]
+ ,[]
+ ,[Plain [Str "13"]]
+ ,[]
+ ,[]
+ ,[Plain [Str "16"]]]
+ ,[[Plain [Str "17"]]
+ ,[]
+ ,[Plain [Str "19"]]
+ ,[Plain [Str "20"]]
+ ,[]
+ ,[]
+ ,[Plain [Str "23"]]
+ ,[]]
+ ,[[Plain [Str "25"]]
+ ,[Plain [Str "26"]]
+ ,[]
+ ,[]
+ ,[Plain [Str "29"]]
+ ,[Plain [Str "30"]]
+ ,[]
+ ,[Plain [Str "32"]]]
+ ,[[]
+ ,[]
+ ,[Plain [Str "35"]]
+ ,[]
+ ,[Plain [Str "37"]]
+ ,[]
+ ,[Plain [Str "39"]]
+ ,[Plain [Str "40"]]]]
+,Table [] [AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "0"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]
+ ,[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]
+ ,[Plain [Str "7"]]
+ ,[Plain [Str "8"]]
+ ,[Plain [Str "9"]]
+ ,[Plain [Str "A"]]
+ ,[Plain [Str "B"]]
+ ,[Plain [Str "C"]]
+ ,[Plain [Str "D"]]
+ ,[Plain [Str "E"]]
+ ,[Plain [Str "F"]]
+ ,[Plain [Str "0"]]
+ ,[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]
+ ,[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]
+ ,[Plain [Str "7"]]
+ ,[Plain [Str "8"]]
+ ,[Plain [Str "9"]]
+ ,[Plain [Str "A"]]
+ ,[Plain [Str "B"]]
+ ,[Plain [Str "C"]]
+ ,[Plain [Str "D"]]
+ ,[Plain [Str "E"]]
+ ,[Plain [Str "F"]]]]
+,Table [] [AlignCenter] [0.0]
+ [[]]
+ [[[]]
+ ,[[]]
+ ,[[]]]
+,Para [Str "|this|is|not|a|table|"]
+,Para [Str "|this|",Space,Str "is|",Space,Str "not|",Space,Str "a|",Space,Str "table|"]
+,Para [Str "|this",Space,Str "|is",Space,Str "|not",Space,Str "|a",Space,Str "|table",Space,Str "|"]
+,Para [Str "|",Space,Str "this\t|",Space,Str "is\t|",Space,Str "not\t|",Space,Str "a\t|",Space,Str "table\t|"]
+,HorizontalRule
+,Para [Str "The",Space,Str "End."]]
diff --git a/tests/txt2tags.t2t b/test/txt2tags.t2t
index d374b7a85..d374b7a85 100644
--- a/tests/txt2tags.t2t
+++ b/test/txt2tags.t2t
diff --git a/test/vimwiki-reader.native b/test/vimwiki-reader.native
new file mode 100644
index 000000000..8c9bff3f6
--- /dev/null
+++ b/test/vimwiki-reader.native
@@ -0,0 +1,309 @@
+Pandoc (Meta {unMeta = fromList [("date",MetaInlines [Str "2017-05-01"]),("title",MetaInlines [Str "title"])]})
+[Header 1 ("implemented",[],[]) [Emph [Span ("implemented",[],[]) [],Strong [Str "implemented"]]]
+,Header 1 ("header",[],[]) [Str "header"]
+,Header 2 ("header level two",[],[]) [Str "header",Space,Str "level",Space,Str "two"]
+,Header 3 ("header level 3",[],[]) [Str "header",Space,Code ("",[],[]) "level",Space,Str "3"]
+,Header 4 ("header level four",[],[]) [Str "header",Space,Strikeout [Str "level"],Space,Str "four"]
+,Header 5 ("header level 5",[],[]) [Str "header",Space,Emph [Span ("level",[],[]) [],Strong [Str "level"],Space,Str "5"]]
+,Header 6 ("header level 6",[],[]) [Str "header",Space,Str "level",Space,Str "6"]
+,Para [Str "=======",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "========"]
+,Para [Str "hi==",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "=="]
+,Para [Str "===",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "=="]
+,Para [Str "===",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "===-"]
+,Para [Str "not",Space,Str "a",Space,Str "header:"]
+,Para [Str "=n="]
+,Para [Str "===",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "===="]
+,Header 2 ("centred header",["justcenter"],[]) [Str "centred",Space,Str "header"]
+,Header 2 ("header with some == in between",[],[]) [Str "header",Space,Str "with",Space,Str "some",Space,Code ("",[],[]) "==",Space,Str "in",Space,Str "between"]
+,Header 2 ("header with some == in between",[],[]) [Str "header",Space,Str "with",Space,Str "some",Space,Str "==",Space,Str "in",Space,Str "between"]
+,Header 2 ("header with some ==in between",[],[]) [Str "header",Space,Str "with",Space,Str "some",Space,Str "==in",Space,Str "between"]
+,Header 2 ("emph strong and strikeout",[],[]) [Str "emph",Space,Str "strong",Space,Str "and",Space,Str "strikeout"]
+,Para [Emph [Str "emph"],Space,Span ("strong",[],[]) [],Strong [Str "strong"]]
+,Para [Span ("strong and emph",[],[]) [],Strong [Emph [Str "strong",Space,Str "and",Space,Str "emph"]]]
+,Para [Emph [Span ("emph and strong",[],[]) [],Strong [Str "emph",Space,Str "and",Space,Str "strong"]]]
+,Para [Span ("emph inside strong",[],[]) [],Strong [Emph [Str "emph",Space,Str "inside"],Space,Str "strong"]]
+,Para [Span ("strong with emph",[],[]) [],Strong [Str "strong",Space,Str "with",Space,Emph [Str "emph"]]]
+,Para [Emph [Span ("strong inside",[],[]) [],Strong [Str "strong",Space,Str "inside"],Space,Str "emph"]]
+,Para [Emph [Strikeout [Str "strikeout"],Space,Str "inside",Space,Str "emph"]]
+,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "struck",Space,Str "out"],Space,Str "with",Space,Str "emph"]]
+,Para [Str "*not",SoftBreak,Str "strong*"]
+,Para [Str "just",Space,Str "two",Space,Str "stars:",Space,Str "**"]
+,Para [Str "just",Space,Str "two",Space,Str "underscores:",Space,Str "__"]
+,Para [Str "just",Space,Str "four",Space,Str "~s:",Space,Str "~~~~"]
+,Para [Str "_not",SoftBreak,Str "emph_"]
+,Para [Str "~~not",SoftBreak,Str "strikeout~~"]
+,Header 2 ("horizontal rule",[],[]) [Str "horizontal",Space,Str "rule"]
+,Para [Str "top"]
+,HorizontalRule
+,Para [Str "middle"]
+,HorizontalRule
+,Para [Str "not",Space,Str "a",Space,Str "rule-----"]
+,Para [Str "not",Space,Str "a",Space,Str "rule",Space,Str "(trailing",Space,Str "spaces):",SoftBreak,Str "-----"]
+,Para [Str "not",Space,Str "a",Space,Str "rule",Space,Str "(leading",Space,Str "spaces):",SoftBreak,Str "----"]
+,Header 2 ("comments",[],[]) [Str "comments"]
+,Para [Str "this",SoftBreak,Str "is",Space,Str "%%",Space,Str "not",Space,Str "secret"]
+,Header 2 ("inline code",[],[]) [Str "inline",Space,Str "code"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Code ("",[],[]) "inline code",Str "."]
+,Para [Str "Just",Space,Str "two",Space,Str "backticks:",Space,Str "``"]
+,Header 2 ("preformatted text",[],[]) [Str "preformatted",Space,Str "text"]
+,CodeBlock ("",[],[]) " Tyger! Tyger! burning bright\n In the forests of the night,\n What immortal hand or eye\n Could frame thy fearful symmetry?\n In what distant deeps or skies\n Burnt the fire of thine eyes?\n On what wings dare he aspire?\n What the hand dare sieze the fire?"
+,Header 3 ("preformatted text with attributes",[],[]) [Str "preformatted",Space,Str "text",Space,Str "with",Space,Str "attributes"]
+,CodeBlock ("",[],[("class","python"),("style","color:blue")]) " for i in range(1, 5):\n print(i)"
+,Header 2 ("block quotes",[],[]) [Str "block",Space,Str "quotes"]
+,BlockQuote
+ [Plain [Str "(indentation",Space,Str "4",Space,Str "spaces)",Space,Str "This",Space,Str "would",Space,Str "be",Space,Str "a",Space,Str "blockquote",Space,Str "in",Space,Str "Vimwiki.",Space,Str "It",Space,Str "is",Space,Str "not",Space,Span ("highlighted",[],[]) [],Strong [Str "highlighted"],Space,Str "in",Space,Str "Vim",Space,Str "but",SoftBreak,Str "(indentation",Space,Str "1",Space,Str "space",Space,Str "followed",Space,Str "by",Space,Str "1",Space,Str "tab",Space,Str "of",Space,Str "width",Space,Str "4)",Space,Str "could",Space,Str "be",Space,Str "styled",Space,Str "by",Space,Str "CSS",Space,Str "in",Space,Str "HTML.",Space,Str "Blockquotes",Space,Str "are",Space,Str "usually",Space,Str "used",Space,Str "to",Space,Str "quote",Space,Str "a",SoftBreak,Str "(indentation",Space,Str "1",Space,Str "tab",Space,Str "of",Space,Str "width",Space,Str "4)",Space,Str "long",Space,Str "piece",Space,Str "of",Space,Str "text",Space,Str "from",Space,Str "another",Space,Str "source.",Space,Strikeout [Str "blah",Space,Str "blah"],Space,Span ("-blockquote",[],[]) [Str ""],Span ("blockquote",["tag"],[]) [Str "blockquote"]]]
+,Header 2 ("external links",[],[]) [Str "external",Space,Str "links"]
+,Para [Link ("",[],[]) [Emph [Str "Google"],Space,Str "search",Space,Str "engine"] ("http://google.com","")]
+,Para [Link ("",[],[]) [Str "http://pandoc.org"] ("http://pandoc.org","")]
+,Para [Link ("",[],[]) [Str "ftp://vim.org"] ("ftp://vim.org","")]
+,Para [Link ("",[],[]) [Str "http://google.com"] ("http://google.com","")]
+,Para [Link ("",[],[]) [Str "email",Space,Str "me"] ("mailto:info@example.org","")]
+,Para [Link ("",[],[]) [Str "mailto:hello@bye.com"] ("mailto:hello@bye.com","")]
+,Header 2 ("internal links",[],[]) [Str "internal",Space,Str "links"]
+,Para [Link ("",[],[]) [Str "This is a link"] ("This is a link.html","")]
+,Para [Link ("",[],[]) [Str "Description",Space,Str "of",Space,Str "the",Space,Str "link"] ("This is a link source.html","")]
+,Para [Link ("",[],[]) [Str "projects/Important Project 1"] ("projects/Important Project 1.html",""),SoftBreak,Link ("",[],[]) [Str "../index"] ("../index.html",""),SoftBreak,Link ("",[],[]) [Str "Other",Space,Str "files"] ("a subdirectory/","")]
+,Para [Link ("",[],[]) [Str "try",Space,Str "me",Space,Str "to",Space,Str "test",Space,Str "tag",Space,Str "anchors"] ("#tag-one","")]
+,Para [Link ("",[],[]) [Str "try",Space,Str "me",Space,Str "to",Space,Str "test",Space,Str "header",Space,Str "anchors"] ("#block quotes","")]
+,Para [Link ("",[],[]) [Str "try",Space,Str "me",Space,Str "to",Space,Str "test",Space,Str "strong",Space,Str "anchors"] ("#strong","")]
+,Para [Link ("",[],[]) [Str "Tasks",Space,Str "for",Space,Str "tomorrow"] ("Todo List.html#Tomorrow","")]
+,Para [Link ("",[],[]) [Str "diary:2017-05-01"] ("diary/2017-05-01.html","")]
+,Para [Link ("",[],[]) [Str "Important",Space,Str "Data"] ("file:../assets/data.csv","")]
+,Header 3 ("links with thumbnails",[],[]) [Str "links",Space,Str "with",Space,Str "thumbnails"]
+,Para [Link ("",[],[]) [Image ("",[],[]) [Str ""] ("./movie.jpg","")] ("http://www.google.com","")]
+,Header 2 ("images",[],[]) [Str "images"]
+,Para [Image ("",[],[]) [Str ""] ("file:./lalune.jpg","")]
+,Para [Image ("",[],[]) [Str "Vimwiki"] ("http://vimwiki.googlecode.com/hg/images/vimwiki_logo.png",""),SoftBreak,Image ("",[],[]) [Str ""] ("file:./movie.jpg","")]
+,Header 3 ("image with attributes",[],[]) [Str "image",Space,Str "with",Space,Str "attributes"]
+,Para [Image ("",[],[("style","width:150px;height:120px;")]) [Emph [Str "cool",Space,Str "stuff"]] ("lalune.jpg","")]
+,Para [Image ("",[],[("style","font-color:red")]) [Span ("Non-existing",[],[]) [],Strong [Str "Non-existing"],Space,Str "image"] ("nonexist.jpg","")]
+,Para [Image ("",[],[("style","width:150px;height:120px;")]) [Emph [Str "cool",Space,Str "stuff"]] ("lalune.jpg","")]
+,Header 2 ("lists",[],[]) [Str "lists"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "ordered",Space,Str "list",Space,Str "item",Space,Str "1,",Space,Str "and",Space,Str "here",Space,Str "is",Space,Str "some",Space,Str "math",Space,Str "belonging",Space,Str "to",Space,Str "list",Space,Str "item",Space,Str "1"]
+ ,Para [Math DisplayMath "a^2 + b^2 = c^2"]
+ ,Plain [Str "and",Space,Str "some",Space,Str "preformatted",Space,Str "and",Space,Str "tables",Space,Str "belonging",Space,Str "to",Space,Str "item",Space,Str "1",Space,Str "as",Space,Str "well"]
+ ,CodeBlock ("",[],[]) "I'm part of item 1."
+ ,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "this",Space,Str "table"]]
+ ,[Plain [Str "is"]]]
+ ,[[Plain [Str "also",Space,Str "a",Space,Str "part"]]
+ ,[Plain [Str "of",Space,Str "item",Space,Str "1"]]]]
+ ,Plain [Str "and",Space,Str "some",Space,Str "more",Space,Str "text",Space,Str "belonging",Space,Str "to",Space,Str "item",Space,Str "1."]]
+ ,[Plain [Str "ordered",Space,Str "list",Space,Str "item",Space,Str "2"]]]
+,BulletList
+ [[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "2"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "the",Space,Str "#",Space,Str "become",Space,Str "numbers",Space,Str "when",Space,Str "converted",Space,Str "to",Space,Str "HTML"]]]
+,BulletList
+ [[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "2"]]]
+,BulletList
+ [[Plain [Str "Item",Space,Str "1"]]
+ ,[Plain [Str "Item",Space,Str "2"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Sub",Space,Str "item",Space,Str "1",Space,Str "(indentation",Space,Str "4",Space,Str "spaces)",SoftBreak,Str "Sub",Space,Str "item",Space,Str "1",Space,Str "continued",Space,Str "line.",SoftBreak,Str "Sub",Space,Str "item",Space,Str "1",Space,Str "next",Space,Str "continued",Space,Str "line."]]
+ ,[Plain [Str "Sub",Space,Str "item",Space,Str "2,",Space,Str "as",Space,Str "an",Space,Str "ordered",Space,Str "list",Space,Str "item",Space,Str "even",Space,Str "though",Space,Str "the",Space,Str "identifier",Space,Str "is",Space,Code ("",[],[]) "*",Space,Str "(indentation",Space,Str "2",Space,Str "spaces",Space,Str "followed",Space,Str "by",Space,Str "one",Space,Str "tab",Space,Str "of",Space,Str "width",Space,Str "4)"]]
+ ,[Plain [Str "etc.",SoftBreak,Str "Continuation",Space,Str "of",Space,Str "Item",Space,Str "2",SoftBreak,Str "Next",Space,Str "continuation",Space,Str "of",Space,Str "Item",Space,Str "2"]]]]]
+,Para [Str "But",Space,Str "this",Space,Str "is",Space,Str "a",Space,Str "new",Space,Str "paragraph."]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "1"]
+ ,BulletList
+ [[Plain [Code ("",[],[]) "1.1"]]]]
+ ,[Plain [Str "2"]
+ ,BulletList
+ [[Plain [Str "2.1"]]]]]
+,BulletList
+ [[Plain [Str "3"]]]
+,Header 3 ("ordered lists with non-# identifiers",[],[]) [Str "ordered",Space,Str "lists",Space,Str "with",Space,Str "non-#",Space,Str "identifiers"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,BulletList
+ [[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "2"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "sub",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "more",Space,Str "..."]
+ ,BulletList
+ [[Plain [Str "and",Space,Str "more",Space,Str "..."]]
+ ,[Plain [Str "..."]]]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "sub",Space,Str "item",Space,Str "3"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "sub",Space,Str "sub",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "sub",Space,Str "sub",Space,Str "item",Space,Str "2"]]]]
+ ,[Plain [Str "etc."]]]]
+ ,[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,Header 2 ("todo lists",[],[]) [Str "todo",Space,Str "lists"]
+,BulletList
+ [[Plain [Span ("",["done0"],[]) [],Str "task",Space,Str "1"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Span ("",["done1"],[]) [],Str "5"]]]]
+ ,[Plain [Span ("",["done2"],[]) [],Str "3"]]
+ ,[Plain [Str "[]",Space,Str "not",Space,Str "a",Space,Str "todo",Space,Str "item"]]
+ ,[Plain [Str "[",Space,Str "]not",Space,Str "a",Space,Str "todo",Space,Str "item"]]
+ ,[Plain [Str "[r]",Space,Str "not",Space,Str "a",Space,Str "todo",Space,Str "item"]]
+ ,[Plain [Str "[",Space,Str "]",Space,Str "not",Space,Str "a",Space,Str "todo",Space,Str "item"]]
+ ,[Plain [Span ("",["done2"],[]) [],Str "a",Space,Str "tab",Space,Str "in",Space,Str "the",Space,Str "todo",Space,Str "list",Space,Str "marker",Space,Code ("",[],[]) "[ ]"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Span ("",["done3"],[]) [],Str "4",SoftBreak,Str "5"]]
+ ,[Plain [Span ("",["done4"],[]) []]
+ ,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "a"]]
+ ,[Plain [Str "b"]]]]]]]
+ ,[Plain [Span ("",["done4"],[]) [],Str "task",Space,Str "2"]]]
+,Header 2 ("math",[],[]) [Str "math"]
+,Para [Math InlineMath " \\sum_i a_i^2 = 1 "]
+,Para [Math DisplayMath "\\sum_i a_i^2\n=\n1"]
+,Para [Math DisplayMath "\\begin{aligned}\n\\sum_i a_i^2 &= 1 + 1 \\\\\n&= 2.\n\\end{aligned}"]
+,Para [Str "edge",Space,Str "case",Space,Str "(the",Space,Code ("",[],[]) "c^2 + ",Space,Str "after",Space,Str "the",Space,Str "multline",Space,Str "tag",Space,Str "is",Space,Str "in",Space,Str "the",Space,Str "equation):"]
+,Para [Math DisplayMath "\\begin{gathered}\nc^2 + \na^2 + b^2\n\\end{gathered}"]
+,Para [Str "edge",Space,Str "case",Space,Str "(the",Space,Str "tag",Space,Str "is",Space,Code ("",[],[]) "hello%bye",Str ")"]
+,Para [Math DisplayMath "\\begin{hello%bye}\n\\int_a^b f(x) dx\n\\end{hello%bye}"]
+,Para [Str "Just",Space,Str "two",Space,Str "dollar",Space,Str "signs:",Space,Str "$$"]
+,Para [Str "[not",Space,Str "math]",Space,Str "You",Space,Str "have",Space,Str "$1",SoftBreak,Str "and",Space,Str "I",Space,Str "have",Space,Str "$1."]
+,Header 2 ("tags",[],[]) [Str "tags"]
+,Para [Span ("-tag-one",[],[]) [Str ""],Span ("tag-one",["tag"],[]) [Str "tag-one"],Space,Span ("-tag-two",[],[]) [Str ""],Span ("tag-two",["tag"],[]) [Str "tag-two"]]
+,Header 2 ("tables",[],[]) [Str "tables"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "Year"]]
+ ,[Plain [Str "Temperature",Space,Str "(low)"]]
+ ,[Plain [Str "Temperature",Space,Str "(high)"]]]
+ [[[Plain [Str "1900"]]
+ ,[Plain [Str "-10"]]
+ ,[Plain [Str "25"]]]
+ ,[[Plain [Str "1910"]]
+ ,[Plain [Str "-15"]]
+ ,[Plain [Str "30"]]]
+ ,[[Plain [Str "1920"]]
+ ,[Plain [Str "-10"]]
+ ,[Plain [Str "32"]]]
+ ,[[Plain [Str "1930"]]
+ ,[Plain [Emph [Str "N/A"]]]
+ ,[Plain [Emph [Str "N/A"]]]]
+ ,[[Plain [Str "1940"]]
+ ,[Plain [Str "-2"]]
+ ,[Plain [Str "40"]]]]
+,Header 3 ("centered headerless tables",[],[]) [Str "centered",Space,Str "headerless",Space,Str "tables"]
+,Div ("",["center"],[])
+ [Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "a"]]
+ ,[Plain [Str "b"]]]
+ ,[[Plain [Str "c"]]
+ ,[Plain [Str "d"]]]]]
+,Header 2 ("paragraphs",[],[]) [Str "paragraphs"]
+,Para [Str "This",Space,Str "is",Space,Str "first",Space,Str "paragraph",SoftBreak,Str "with",Space,Str "two",Space,Str "lines."]
+,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "second",Space,Str "paragraph",Space,Str "with",SoftBreak,Str "two",Space,Str "lines",Space,Str "after",Space,Str "many",Space,Str "blank",Space,Str "lines."]
+,Header 2 ("definition list",[],[]) [Str "definition",Space,Str "list"]
+,DefinitionList
+ [([Str "Term",Space,Str "1"],
+ [[Plain [Str "Definition",Space,Str "1"]]])
+ ,([Str "Term",Space,Str "2"],
+ [[Plain [Str "Definition",Space,Str "2"]]
+ ,[Plain [Str "Definition",Space,Str "3"]]])
+ ,([Str "Term",Space,Str "::",Space,Span ("separated",[],[]) [],Strong [Str "separated"],Space,Str "by",Space,Str "::",Space,Emph [Str "double",Space,Str "colons"]],
+ [[Plain [Str "Def1"]]
+ ,[Plain [Str "Def2"]]])
+ ,([Str "Term",Space,Str "with",Space,Str "lots",Space,Str "of",Space,Str "trailing",Space,Str "colons:::::::"],
+ [[Plain [Str "Definition"]]])
+ ,([Str "::",Space,Str "This",Space,Str "is",Space,Str "::",Space,Str "A",Space,Str "term",Space,Str "(rather",Space,Str "than",Space,Str "a",Space,Str "definition)"],
+ [[Plain [Str "and",Space,Str "this",Space,Str "is",Space,Str "a",Space,Str "definition"]]])
+ ,([Str "Term",Space,Str "Without",Space,Str "definitions"],
+ [[]])
+ ,([Str "Part",Space,Str "::",Space,Str "of",Space,Str "::",Space,Str "dt"],
+ [[Plain [Str "part",Space,Str "of",Space,Str "::dd"]]])]
+,DefinitionList
+ [([],
+ [[Plain [Str "Definition",Space,Str "1",Space,Str "without",Space,Str "a",Space,Str "term"]]
+ ,[Plain [Str "Definition",Space,Str "2",Space,Str "without",Space,Str "a",Space,Str "term"]]])]
+,DefinitionList
+ [([Str "T1"],
+ [[Plain [Str "D1"]]])]
+,Para [Str "new",Space,Str "paragraph"]
+,DefinitionList
+ [([Str "T1"],
+ [[Plain [Str "D1"]]])]
+,Para [Str "Not::Definition"]
+,Para [Str "Not",Space,Str "::Definition"]
+,Para [Str "::Not",Space,Str "definition"]
+,BlockQuote
+ [Plain [Str "::",Space,Str "blockquote"]]
+,BlockQuote
+ [Plain [Str "block",Space,Str "::",Space,Str "quote"]]
+,Header 2 ("metadata placeholders",[],[]) [Str "metadata",Space,Str "placeholders"]
+,Para [Str "%this",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "placeholder"]
+,Para [Str "placeholders",SoftBreak,Str "serves",Space,Str "as",Space,Str "space",Space,Str "/",Space,Str "softbreak",Space,Str "in",Space,Str "paragraphs"]
+,Header 2 ("sup, sub",[],[]) [Str "sup,",Space,Str "sub"]
+,Para [Str "super",Superscript [Str "script"]]
+,Para [Str "sub",Subscript [Str "script"]]
+,Header 2 ("the todo mark",[],[]) [Str "the",Space,Str "todo",Space,Str "mark"]
+,Para [Span ("",["todo"],[]) [Str "TODO:"]]
+,Header 1 ("not implemented yet",[],[]) [Emph [Span ("not implemented yet",[],[]) [],Strong [Str "not",Space,Str "implemented",Space,Str "yet"]]]
+,Header 2 ("tables with spans",[],[]) [Str "tables",Space,Str "with",Space,Str "spans"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "a"]]
+ ,[Plain [Str "b"]]
+ ,[Plain [Str "c"]]
+ ,[Plain [Str "d"]]]
+ ,[[Plain [Str "\\/"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str ">"]]
+ ,[Plain [Str "f"]]]
+ ,[[Plain [Str "\\/"]]
+ ,[Plain [Str "\\/"]]
+ ,[Plain [Str ">"]]
+ ,[Plain [Str "g"]]]
+ ,[[Plain [Str "h"]]
+ ,[Plain [Str ">"]]
+ ,[Plain [Str ">"]]
+ ,[Plain [Str ">"]]]]
+,Header 2 ("tables with multiple lines of headers",[],[]) [Str "tables",Space,Str "with",Space,Str "multiple",Space,Str "lines",Space,Str "of",Space,Str "headers"]
+,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "a"]]
+ ,[Plain [Str "b"]]]
+ ,[[Plain [Str "c"]]
+ ,[Plain [Str "d"]]]
+ ,[[Plain [Str "---"]]
+ ,[Plain [Str "---"]]]]
+,Header 2 ("some other placeholders",[],[]) [Str "some",Space,Str "other",Space,Str "placeholders"]
+,Para [Code ("",[],[]) "template",Space,Str "placeholder",Space,Str "is",Space,Str "ignored."]
+,Para [Code ("",[],[]) "nohtml",Space,Str "placeholder",Space,Str "is",Space,Str "ignored."]]
diff --git a/test/vimwiki-reader.wiki b/test/vimwiki-reader.wiki
new file mode 100644
index 000000000..63d39b146
--- /dev/null
+++ b/test/vimwiki-reader.wiki
@@ -0,0 +1,424 @@
+= _*implemented*_ =
+= header =
+
+== header level two ==
+
+=== header `level` 3 ===
+
+==== header ~~level~~ four ====
+
+===== header _*level* 5_ =====
+
+====== header level 6 ======
+
+======= not a header ========
+
+hi== not a header ==
+
+=== not a header ==
+
+=== not a header ===-
+
+not a header:
+
+=n=
+
+=== not a header ====
+
+ == centred header ==
+
+== header with some `==` in between ==
+== header with some == in between ==
+== header with some ==in between ==
+
+== emph strong and strikeout ==
+
+_emph_ *strong*
+
+*_strong and emph_*
+
+_*emph and strong*_
+
+*_emph inside_ strong*
+
+*strong with _emph_*
+
+_*strong inside* emph_
+
+_~~strikeout~~ inside emph_
+
+~~This is _struck out_ with emph~~
+
+*not
+strong*
+
+just two stars: **
+
+just two underscores: __
+
+just four ~s: ~~~~
+
+_not
+%%comment
+emph_
+
+~~not
+ %%comment
+ %%comment
+strikeout~~
+
+== horizontal rule ==
+
+top
+----
+middle
+
+-------
+
+not a rule-----
+
+not a rule (trailing spaces):
+-----
+
+not a rule (leading spaces):
+ ----
+
+== comments ==
+
+%% you can't see me.
+
+this
+%% secret
+is %% not secret
+
+== inline code ==
+
+Here is some `inline code`.
+
+Just two backticks: ``
+
+== preformatted text ==
+
+{{{
+ Tyger! Tyger! burning bright
+ In the forests of the night,
+ What immortal hand or eye
+ Could frame thy fearful symmetry?
+ In what distant deeps or skies
+ Burnt the fire of thine eyes?
+ On what wings dare he aspire?
+ What the hand dare sieze the fire?
+}}}
+
+=== preformatted text with attributes ===
+
+ {{{class="python" style="color:blue"
+ for i in range(1, 5):
+ print(i)
+ }}}
+
+== block quotes ==
+
+ (indentation 4 spaces) This would be a blockquote in Vimwiki. It is not *highlighted* in Vim but
+ (indentation 1 space followed by 1 tab of width 4) could be styled by CSS in HTML. Blockquotes are usually used to quote a
+ (indentation 1 tab of width 4) long piece of text from another source. ~~blah blah~~ :blockquote:
+
+== external links ==
+
+[[http://google.com|_Google_ search engine]]
+
+http://pandoc.org
+
+ftp://vim.org
+
+[[http://google.com]]
+
+[[mailto:info@example.org|email me]]
+
+mailto:hello@bye.com
+
+== internal links ==
+
+[[This is a link]]
+
+[[This is a link source|Description of the link]]
+
+[[projects/Important Project 1]]
+
+[[../index]]
+
+[[a subdirectory/|Other files]]
+
+[[#tag-one|try me to test tag anchors]]
+
+[[#block quotes|try me to test header anchors]]
+
+[[#strong|try me to test strong anchors]]
+
+[[Todo List#Tomorrow|Tasks for tomorrow]]
+
+[[diary:2017-05-01]]
+
+[[file:../assets/data.csv|Important Data]]
+
+=== links with thumbnails ===
+[[http://www.google.com|{{./movie.jpg}}]]
+
+== images ==
+
+{{file:./lalune.jpg}}
+
+{{http://vimwiki.googlecode.com/hg/images/vimwiki_logo.png|Vimwiki}}
+
+{{local:./movie.jpg}}
+
+
+=== image with attributes ===
+{{lalune.jpg|_cool stuff_|style="width:150px;height:120px;"}}
+
+{{nonexist.jpg|*Non-existing* image|class="center flow blabla" style="font-color:red"}}
+
+{{lalune.jpg|_cool stuff_|style="width:150px;height:120px;"|anything in this segment is ignored}}
+
+
+== lists ==
+
+
+# ordered list item 1, and here is some math belonging to list item 1
+ {{$
+ a^2 + b^2 = c^2
+ }}$
+ and some preformatted and tables belonging to item 1 as well
+{{{
+I'm part of item 1.
+}}}
+| this table | is |
+| also a part | of item 1 |
+ and some more text belonging to item 1.
+# ordered list item 2
+
+
+* Bulleted list item 1
+* Bulleted list item 2
+
+
+# Bulleted list item 1
+# the # become numbers when converted to HTML
+
+- Bulleted list item 1
+- Bulleted list item 2
+
+* Item 1
+* Item 2
+ # Sub item 1 (indentation 4 spaces)
+ Sub item 1 continued line.
+%%comments
+ Sub item 1 next continued line.
+ * Sub item 2, as an ordered list item even though the identifier is `*` (indentation 2 spaces followed by one tab of width 4)
+ * etc.
+ Continuation of Item 2
+ Next continuation of Item 2
+But this is a new paragraph.
+
+# 1
+ * `1.1`
+ * 2
+ * 2.1
+ * 3
+
+=== ordered lists with non-# identifiers ===
+1. Numbered list item 1
+2. Numbered list item 2
+3. Numbered list item 3
+
+4. Numbered list item 1
+5. Numbered list item 2
+6. Numbered list item 3
+
+1) Numbered list item 1
+2) Numbered list item 2
+3) Numbered list item 3
+
+a) Numbered list item 1
+b) Numbered list item 2
+c) Numbered list item 3
+
+A) Numbered list item 1
+B) Numbered list item 2
+C) Numbered list item 3
+
+i) Numbered list item 1
+ii) Numbered list item 2
+iii) Numbered list item 3
+
+I) Numbered list item 1
+II) Numbered list item 2
+III) Numbered list item 3
+
+- Bulleted list item 1
+- Bulleted list item 2
+ a) Numbered list sub item 1
+ b) more ...
+ * and more ...
+ * ...
+ c) Numbered list sub item 3
+ 1. Numbered list sub sub item 1
+ 2. Numbered list sub sub item 2
+ d) etc.
+- Bulleted list item 3
+
+== todo lists ==
+* [ ] task 1
+ 1. [.] 5
+* [o] 3
+* [] not a todo item
+* [ ]not a todo item
+* [r] not a todo item
+* [ ] not a todo item
+* [o] a tab in the todo list marker `[ ]`
+ III) [O] 4
+ 5
+ i) [X]
+| a | b |
+* [X] task 2
+
+== math ==
+
+$ \sum_i a_i^2 = 1 $
+
+{{$
+\sum_i a_i^2
+=
+1
+}}$
+
+{{$%align%
+\sum_i a_i^2 &= 1 + 1 \\
+&= 2.
+}}$
+
+edge case (the `c^2 + ` after the multline tag is in the equation):
+{{$%multline%c^2 +
+a^2 + b^2
+}}$
+
+edge case (the tag is `hello%bye`)
+{{$%hello%bye%
+\int_a^b f(x) dx
+}}$
+
+Just two dollar signs: $$
+
+[not math] You have $1
+and I have $1.
+
+== tags ==
+
+:tag-one:tag-two:
+
+== tables ==
+
+| Year | Temperature (low) | Temperature (high) |
+|------|-------------------|--------------------|
+| 1900 | -10 | 25 |
+| 1910 | -15 | 30 |
+| 1920 | -10 | 32 |
+| 1930 | _N/A_ | _N/A_ |
+| 1940 | -2 | 40 |
+
+
+=== centered headerless tables ===
+ | a | b |
+ | c | d |
+
+
+== paragraphs ==
+
+This is first paragraph
+with two lines.
+
+
+
+
+
+
+
+
+This is a second paragraph with
+two lines after many blank lines.
+
+== definition list ==
+
+Term 1:: Definition 1
+Term 2::
+:: Definition 2
+ :: Definition 3
+Term :: *separated* by :: _double colons_ :: Def1
+:: Def2
+Term with lots of trailing colons::::::::: Definition
+:: This is :: A term (rather than a definition) :: and this is a definition
+Term Without definitions ::
+::
+Part :: of :: dt :: part of ::dd
+
+:: Definition 1 without a term
+:: Definition 2 without a term
+
+T1 :: D1
+new paragraph
+T1 :: D1
+
+Not::Definition
+
+Not ::Definition
+
+::Not definition
+
+ :: blockquote
+
+ block :: quote
+
+== metadata placeholders ==
+%title title
+%date 2017-05-01
+
+%title second title is ignored
+%date second date is ignored
+
+%this is not a placeholder
+
+placeholders
+%title another title
+%date 2017-04-23
+serves as space / softbreak in paragraphs
+
+
+== sup, sub ==
+
+super^script^
+
+sub,,script,,
+
+== the todo mark ==
+TODO:
+
+= _*not implemented yet*_ =
+== tables with spans ==
+| a | b | c | d |
+| \/ | e | > | f |
+| \/ | \/ | > | g |
+| h | > | > | > |
+
+== tables with multiple lines of headers ==
+| a | b |
+| c | d |
+|---|---|
+
+== some other placeholders ==
+`template` placeholder is ignored.
+%template template
+
+`nohtml` placeholder is ignored.
+%nohtml
+
+
diff --git a/test/writer.asciidoc b/test/writer.asciidoc
new file mode 100644
index 000000000..4dca188e4
--- /dev/null
+++ b/test/writer.asciidoc
@@ -0,0 +1,658 @@
+Pandoc Test Suite
+=================
+John MacFarlane; Anonymous
+July 17, 2006
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
+markdown test suite.
+
+'''''
+
+Headers
+-------
+
+Level 2 with an link:/url[embedded link]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Level 3 with _emphasis_
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Level 4
++++++++
+
+Level 5
+
+Level 1
+-------
+
+Level 2 with _emphasis_
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Level 3
+^^^^^^^
+
+with no blank line
+
+Level 2
+~~~~~~~
+
+with no blank line
+
+'''''
+
+Paragraphs
+----------
+
+Here’s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here’s one with a bullet. * criminey.
+
+There should be a hard line break +
+here.
+
+'''''
+
+Block Quotes
+------------
+
+E-mail style:
+
+__________________________________________
+This is a block quote. It is pretty short.
+__________________________________________
+
+______________________
+--
+Code in a block quote:
+
+....
+sub status {
+ print "working";
+}
+....
+
+A list:
+
+1. item one
+2. item two
+
+Nested block quotes:
+
+______
+nested
+______
+
+______
+nested
+______
+
+--
+______________________
+
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+'''''
+
+Code Blocks
+-----------
+
+Code:
+
+....
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+....
+
+And:
+
+....
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+....
+
+'''''
+
+Lists
+-----
+
+Unordered
+~~~~~~~~~
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Asterisks loose:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Pluses tight:
+
+* Plus 1
+* Plus 2
+* Plus 3
+
+Pluses loose:
+
+* Plus 1
+* Plus 2
+* Plus 3
+
+Minuses tight:
+
+* Minus 1
+* Minus 2
+* Minus 3
+
+Minuses loose:
+
+* Minus 1
+* Minus 2
+* Minus 3
+
+Ordered
+~~~~~~~
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+2. Second
+3. Third
+
+and using spaces:
+
+1. One
+2. Two
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
++
+Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
+2. Item 2.
+3. Item 3.
+
+Nested
+~~~~~~
+
+* Tab
+** Tab
+*** Tab
+
+Here’s another:
+
+1. First
+2. Second:
+* Fee
+* Fie
+* Foe
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+2. Second:
+* Fee
+* Fie
+* Foe
+3. Third
+
+Tabs and spaces
+~~~~~~~~~~~~~~~
+
+* this is a list item indented with tabs
+* this is a list item indented with spaces
+** this is an example list item indented with tabs
+** this is an example list item indented with spaces
+
+Fancy list markers
+~~~~~~~~~~~~~~~~~~
+
+1. begins with 2
+2. and now 3
++
+with a continuation
+a. sublist with roman numerals, starting with 4
+b. more items
+A. a subsublist
+B. a subsublist
+
+Nesting:
+
+A. Upper Alpha
+A. Upper Roman.
+1. Decimal start with 6
+a. Lower alpha with paren
+
+Autonumbering:
+
+1. Autonumber.
+2. More.
+1. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+'''''
+
+Definition Lists
+----------------
+
+Tight using spaces:
+
+apple::
+ red fruit
+orange::
+ orange fruit
+banana::
+ yellow fruit
+
+Tight using tabs:
+
+apple::
+ red fruit
+orange::
+ orange fruit
+banana::
+ yellow fruit
+
+Loose:
+
+apple::
+ red fruit
+orange::
+ orange fruit
+banana::
+ yellow fruit
+
+Multiple blocks with italics:
+
+_apple_::
+ red fruit
+ +
+ contains seeds, crisp, pleasant to taste
+_orange_::
+ orange fruit
+ +
+....
+{ orange code block }
+....
+ +
+ __________________
+ orange block quote
+ __________________
+
+Multiple definitions, tight:
+
+apple::
+ red fruit
+ +
+ computer
+orange::
+ orange fruit
+ +
+ bank
+
+Multiple definitions, loose:
+
+apple::
+ red fruit
+ +
+ computer
+orange::
+ orange fruit
+ +
+ bank
+
+Blank line after term, indented marker, alternate markers:
+
+apple::
+ red fruit
+ +
+ computer
+orange::
+ orange fruit
+ +
+ 1. sublist
+ 2. sublist
+
+HTML Blocks
+-----------
+
+Simple block on one line:
+
+foo
+
+And nested without indentation:
+
+foo
+
+bar
+
+Interpreted markdown in a table:
+
+This is _emphasized_
+
+And this is *strong*
+
+Here’s a simple block:
+
+foo
+
+This should be a code block, though:
+
+....
+<div>
+ foo
+</div>
+....
+
+As should this:
+
+....
+<div>foo</div>
+....
+
+Now, nested:
+
+foo
+
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+....
+<!-- Comment -->
+....
+
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+....
+<hr />
+....
+
+Hr’s:
+
+'''''
+
+Inline Markup
+-------------
+
+This is _emphasized_, and so _is this_.
+
+This is *strong*, and so *is this*.
+
+An _link:/url[emphasized link]_.
+
+*_This is strong and em._*
+
+So is *_this_* word.
+
+*_This is strong and em._*
+
+So is *_this_* word.
+
+This is code: `>`, `$`, `\`, `\$`, `<html>`.
+
+[line-through]*This is _strikeout_.*
+
+Superscripts: a^bc^d a^_hello_^ a^hello there^.
+
+Subscripts: H~2~O, H~23~O, H~many of them~O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a~b c~d.
+
+'''''
+
+Smart quotes, ellipses, dashes
+------------------------------
+
+``Hello,'' said the spider. ```Shelob' is my name.''
+
+`A', `B', and `C' are letters.
+
+`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
+
+`He said, ``I want to go.''' Were you alive in the 70’s?
+
+Here is some quoted ``code`' and a ``http://example.com/?foo=1&bar=2[quoted
+link]''.
+
+Some dashes: one—two — three—four — five.
+
+Dashes between numbers: 5–7, 255–66, 1987–1999.
+
+Ellipses…and…and….
+
+'''''
+
+LaTeX
+-----
+
+*
+* latexmath:[$2+2=4$]
+* latexmath:[$x \in y$]
+* latexmath:[$\alpha \wedge \omega$]
+* latexmath:[$223$]
+* latexmath:[$p$]-Tree
+* Here’s some display math:
+latexmath:[\[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\]]
+* Here’s one that has a line break in it:
+latexmath:[$\alpha + \omega \times x^2$].
+
+These shouldn’t be math:
+
+* To get the famous equation, write `$e = mc^2$`.
+* $22,000 is a _lot_ of money. So is $34,000. (It worked if ``lot'' is
+emphasized.)
+* Shoes ($20) and socks ($5).
+* Escaped `$`: $73 _this should be emphasized_ 23$.
+
+Here’s a LaTeX table:
+
+'''''
+
+Special Characters
+------------------
+
+Here is some unicode:
+
+* I hat: Î
+* o umlaut: ö
+* section: §
+* set membership: ∈
+* copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: \{
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+'''''
+
+Links
+-----
+
+Explicit
+~~~~~~~~
+
+Just a link:/url/[URL].
+
+link:/url/[URL and title].
+
+link:/url/[URL and title].
+
+link:/url/[URL and title].
+
+link:/url/[URL and title]
+
+link:/url/[URL and title]
+
+link:/url/with_underscore[with_underscore]
+
+mailto:nobody@nowhere.net[Email link]
+
+link:[Empty].
+
+Reference
+~~~~~~~~~
+
+Foo link:/url/[bar].
+
+With link:/url/[embedded [brackets]].
+
+link:/url/[b] by itself should be a link.
+
+Indented link:/url[once].
+
+Indented link:/url[twice].
+
+Indented link:/url[thrice].
+
+This should [not][] be a link.
+
+....
+[not]: /url
+....
+
+Foo link:/url/[bar].
+
+Foo link:/url/[biz].
+
+With ampersands
+~~~~~~~~~~~~~~~
+
+Here’s a http://example.com/?foo=1&bar=2[link with an ampersand in the URL].
+
+Here’s a link with an amersand in the link text: http://att.com/[AT&T].
+
+Here’s an link:/script?foo=1&bar=2[inline link].
+
+Here’s an link:/script?foo=1&bar=2[inline link in pointy braces].
+
+Autolinks
+~~~~~~~~~
+
+With an ampersand: http://example.com/?foo=1&bar=2
+
+* In a list?
+* http://example.com/
+* It should.
+
+An e-mail address: nobody@nowhere.net
+
+________________________________
+Blockquoted: http://example.com/
+________________________________
+
+Auto-links should not occur here: `<http://example.com/>`
+
+....
+or here: <http://example.com/>
+....
+
+'''''
+
+Images
+------
+
+From ``Voyage dans la Lune'' by Georges Melies (1902):
+
+image:lalune.jpg[lalune,title="Voyage dans la Lune"]
+
+Here is a movie image:movie.jpg[movie] icon.
+
+'''''
+
+Footnotes
+---------
+
+Here is a footnote reference,footnote:[Here is the footnote. It can go
+anywhere after the footnote reference. It need not be placed at the end of the
+document.] and another.[multiblock footnote omitted] This should _not_ be a
+footnote reference, because it contains a space.[^my note] Here is an inline
+note.footnote:[This is _easier_ to type. Inline notes may contain
+http://google.com[links] and `]` verbatim characters, as well as [bracketed
+text].]
+
+___________________________________________
+Notes can go in quotes.footnote:[In quote.]
+___________________________________________
+
+1. And in list items.footnote:[In list.]
+
+This paragraph should not be part of the note, as it is not indented.
diff --git a/test/writer.context b/test/writer.context
new file mode 100644
index 000000000..0cbbc7df4
--- /dev/null
+++ b/test/writer.context
@@ -0,0 +1,901 @@
+% Enable hyperlinks
+\setupinteraction
+ [state=start,
+ title={Pandoc Test Suite},
+ author={John MacFarlane; Anonymous},
+ style=,
+ color=,
+ contrastcolor=]
+
+% make chapter, section bookmarks visible when opening document
+\placebookmarks[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][chapter, section]
+\setupinteractionscreen[option=bookmark]
+\setuptagging[state=start]
+
+
+% use microtypography
+\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
+\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
+\setupalign[hz,hanging]
+\setupitaliccorrection[global, always]
+
+\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
+
+\definefallbackfamily[mainface][rm][DejaVu Serif][preset=range:greek, force=yes]
+\definefontfamily[mainface][rm][Latin Modern Roman]
+\definefontfamily[mainface][mm][Latin Modern Math]
+\definefontfamily[mainface][ss][Latin Modern Sans]
+\definefontfamily[mainface][tt][Latin Modern Typewriter][features=none]
+\setupbodyfont[mainface]
+
+\setupwhitespace[medium]
+
+\setuphead[chapter] [style=\tfd,header=empty]
+\setuphead[section] [style=\tfc]
+\setuphead[subsection] [style=\tfb]
+\setuphead[subsubsection] [style=\bf]
+\setuphead[subsubsubsection] [style=\sc]
+\setuphead[subsubsubsubsection][style=\it]
+
+\setuphead[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][number=no]
+
+\definedescription
+ [description]
+ [headstyle=bold, style=normal, location=hanging, width=broad, margin=1cm, alternative=hanging]
+
+\setupitemize[autointro] % prevent orphan list intro
+\setupitemize[indentnext=no]
+
+\setupfloat[figure][default={here,nonumber}]
+\setupfloat[table][default={here,nonumber}]
+
+\setupthinrules[width=15em] % width of horizontal rules
+
+\setupxtable[frame=off]
+\setupxtable[head][topframe=on,bottomframe=on]
+\setupxtable[body][]
+\setupxtable[foot][bottomframe=on]
+
+
+\starttext
+\startalignment[middle]
+ {\tfd Pandoc Test Suite}
+ \smallskip
+ {\tfa John MacFarlane\crlf Anonymous}
+ \smallskip
+ {\tfa July 17, 2006}
+ \bigskip
+\stopalignment
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber's
+markdown test suite.
+
+\thinrule
+
+\section[title={Headers},reference={headers}]
+
+\subsection[title={Level 2 with an \useURL[url1][/url][][embedded
+link]\from[url1]},reference={level-2-with-an-embedded-link}]
+
+\subsubsection[title={Level 3 with
+{\em emphasis}},reference={level-3-with-emphasis}]
+
+\subsubsubsection[title={Level 4},reference={level-4}]
+
+\subsubsubsubsection[title={Level 5},reference={level-5}]
+
+\section[title={Level 1},reference={level-1}]
+
+\subsection[title={Level 2 with
+{\em emphasis}},reference={level-2-with-emphasis}]
+
+\subsubsection[title={Level 3},reference={level-3}]
+
+with no blank line
+
+\subsection[title={Level 2},reference={level-2}]
+
+with no blank line
+
+\thinrule
+
+\section[title={Paragraphs},reference={paragraphs}]
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break\crlf
+here.
+
+\thinrule
+
+\section[title={Block Quotes},reference={block-quotes}]
+
+E-mail style:
+
+\startblockquote
+This is a block quote. It is pretty short.
+\stopblockquote
+
+\startblockquote
+Code in a block quote:
+
+\starttyping
+sub status {
+ print "working";
+}
+\stoptyping
+
+A list:
+
+\startitemize[n,packed][stopper=.]
+\item
+ item one
+\item
+ item two
+\stopitemize
+
+Nested block quotes:
+
+\startblockquote
+nested
+\stopblockquote
+
+\startblockquote
+nested
+\stopblockquote
+\stopblockquote
+
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+\thinrule
+
+\section[title={Code Blocks},reference={code-blocks}]
+
+Code:
+
+\starttyping
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+\stoptyping
+
+And:
+
+\starttyping
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+\stoptyping
+
+\thinrule
+
+\section[title={Lists},reference={lists}]
+
+\subsection[title={Unordered},reference={unordered}]
+
+Asterisks tight:
+
+\startitemize[packed]
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\stopitemize
+
+Asterisks loose:
+
+\startitemize
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\stopitemize
+
+Pluses tight:
+
+\startitemize[packed]
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\stopitemize
+
+Pluses loose:
+
+\startitemize
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\stopitemize
+
+Minuses tight:
+
+\startitemize[packed]
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\stopitemize
+
+Minuses loose:
+
+\startitemize
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\stopitemize
+
+\subsection[title={Ordered},reference={ordered}]
+
+Tight:
+
+\startitemize[n,packed][stopper=.]
+\item
+ First
+\item
+ Second
+\item
+ Third
+\stopitemize
+
+and:
+
+\startitemize[n,packed][stopper=.]
+\item
+ One
+\item
+ Two
+\item
+ Three
+\stopitemize
+
+Loose using tabs:
+
+\startitemize[n][stopper=.]
+\item
+ First
+\item
+ Second
+\item
+ Third
+\stopitemize
+
+and using spaces:
+
+\startitemize[n][stopper=.]
+\item
+ One
+\item
+ Two
+\item
+ Three
+\stopitemize
+
+Multiple paragraphs:
+
+\startitemize[n][stopper=.]
+\item
+ Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
+\item
+ Item 2.
+\item
+ Item 3.
+\stopitemize
+
+\subsection[title={Nested},reference={nested}]
+
+\startitemize[packed]
+\item
+ Tab
+ \startitemize[packed]
+ \item
+ Tab
+ \startitemize[packed]
+ \item
+ Tab
+ \stopitemize
+ \stopitemize
+\stopitemize
+
+Here's another:
+
+\startitemize[n,packed][stopper=.]
+\item
+ First
+\item
+ Second:
+ \startitemize[packed]
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \stopitemize
+\item
+ Third
+\stopitemize
+
+Same thing but with paragraphs:
+
+\startitemize[n][stopper=.]
+\item
+ First
+\item
+ Second:
+
+ \startitemize[packed]
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \stopitemize
+\item
+ Third
+\stopitemize
+
+\subsection[title={Tabs and spaces},reference={tabs-and-spaces}]
+
+\startitemize
+\item
+ this is a list item indented with tabs
+\item
+ this is a list item indented with spaces
+
+ \startitemize
+ \item
+ this is an example list item indented with tabs
+ \item
+ this is an example list item indented with spaces
+ \stopitemize
+\stopitemize
+
+\subsection[title={Fancy list markers},reference={fancy-list-markers}]
+
+\startitemize[n][start=2,left=(,stopper=),width=2.0em]
+\item
+ begins with 2
+\item
+ and now 3
+
+ with a continuation
+
+ \startitemize[r,packed][start=4,stopper=.,width=2.0em]
+ \item
+ sublist with roman numerals, starting with 4
+ \item
+ more items
+ \startitemize[A,packed][left=(,stopper=),width=2.0em]
+ \item
+ a subsublist
+ \item
+ a subsublist
+ \stopitemize
+ \stopitemize
+\stopitemize
+
+Nesting:
+
+\startitemize[A,packed][stopper=.]
+\item
+ Upper Alpha
+ \startitemize[R,packed][stopper=.]
+ \item
+ Upper Roman.
+ \startitemize[n,packed][start=6,left=(,stopper=),width=2.0em]
+ \item
+ Decimal start with 6
+ \startitemize[a,packed][start=3,stopper=)]
+ \item
+ Lower alpha with paren
+ \stopitemize
+ \stopitemize
+ \stopitemize
+\stopitemize
+
+Autonumbering:
+
+\startitemize[n,packed]
+\item
+ Autonumber.
+\item
+ More.
+ \startitemize[a,packed]
+ \item
+ Nested.
+ \stopitemize
+\stopitemize
+
+Should not be a list item:
+
+M.A.~2007
+
+B. Williams
+
+\thinrule
+
+\section[title={Definition Lists},reference={definition-lists}]
+
+Tight using spaces:
+
+\startdescription{apple}
+ red fruit
+\stopdescription
+
+\startdescription{orange}
+ orange fruit
+\stopdescription
+
+\startdescription{banana}
+ yellow fruit
+\stopdescription
+
+Tight using tabs:
+
+\startdescription{apple}
+ red fruit
+\stopdescription
+
+\startdescription{orange}
+ orange fruit
+\stopdescription
+
+\startdescription{banana}
+ yellow fruit
+\stopdescription
+
+Loose:
+
+\startdescription{apple}
+ red fruit
+\stopdescription
+
+\startdescription{orange}
+ orange fruit
+\stopdescription
+
+\startdescription{banana}
+ yellow fruit
+\stopdescription
+
+Multiple blocks with italics:
+
+\startdescription{{\em apple}}
+ red fruit
+
+ contains seeds, crisp, pleasant to taste
+\stopdescription
+
+\startdescription{{\em orange}}
+ orange fruit
+
+\starttyping
+{ orange code block }
+\stoptyping
+
+ \startblockquote
+ orange block quote
+ \stopblockquote
+\stopdescription
+
+Multiple definitions, tight:
+
+\startdescription{apple}
+ red fruit
+
+ computer
+\stopdescription
+
+\startdescription{orange}
+ orange fruit
+
+ bank
+\stopdescription
+
+Multiple definitions, loose:
+
+\startdescription{apple}
+ red fruit
+
+ computer
+\stopdescription
+
+\startdescription{orange}
+ orange fruit
+
+ bank
+\stopdescription
+
+Blank line after term, indented marker, alternate markers:
+
+\startdescription{apple}
+ red fruit
+
+ computer
+\stopdescription
+
+\startdescription{orange}
+ orange fruit
+
+ \startitemize[n,packed][stopper=.]
+ \item
+ sublist
+ \item
+ sublist
+ \stopitemize
+\stopdescription
+
+\section[title={HTML Blocks},reference={html-blocks}]
+
+Simple block on one line:
+
+foo
+
+And nested without indentation:
+
+foo
+
+bar
+
+Interpreted markdown in a table:
+
+This is {\em emphasized}
+And this is {\bf strong}
+Here's a simple block:
+
+foo
+
+This should be a code block, though:
+
+\starttyping
+<div>
+ foo
+</div>
+\stoptyping
+
+As should this:
+
+\starttyping
+<div>foo</div>
+\stoptyping
+
+Now, nested:
+
+foo
+
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+\starttyping
+<!-- Comment -->
+\stoptyping
+
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+\starttyping
+<hr />
+\stoptyping
+
+Hr's:
+
+\thinrule
+
+\section[title={Inline Markup},reference={inline-markup}]
+
+This is {\em emphasized}, and so {\em is this}.
+
+This is {\bf strong}, and so {\bf is this}.
+
+An {\em \useURL[url2][/url][][emphasized link]\from[url2]}.
+
+{\bf {\em This is strong and em.}}
+
+So is {\bf {\em this}} word.
+
+{\bf {\em This is strong and em.}}
+
+So is {\bf {\em this}} word.
+
+This is code: \type{>}, \type{$}, \type{\}, \type{\$}, \type{<html>}.
+
+\overstrikes{This is {\em strikeout}.}
+
+Superscripts: a\high{bc}d a\high{{\em hello}} a\high{hello~there}.
+
+Subscripts: H\low{2}O, H\low{23}O, H\low{many~of~them}O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a\lettertilde{}b c\lettertilde{}d.
+
+\thinrule
+
+\section[title={Smart quotes, ellipses,
+dashes},reference={smart-quotes-ellipses-dashes}]
+
+\quotation{Hello,} said the spider. \quotation{\quote{Shelob} is my name.}
+
+\quote{A}, \quote{B}, and \quote{C} are letters.
+
+\quote{Oak,} \quote{elm,} and \quote{beech} are names of trees. So is
+\quote{pine.}
+
+\quote{He said, \quotation{I want to go.}} Were you alive in the 70's?
+
+Here is some quoted \quote{\type{code}} and a
+\quotation{\useURL[url3][http://example.com/?foo=1&bar=2][][quoted
+link]\from[url3]}.
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses\ldots{}and\ldots{}and\ldots{}.
+
+\thinrule
+
+\section[title={LaTeX},reference={latex}]
+
+\startitemize[packed]
+\item
+ \cite[22-23]{smith.1899}
+\item
+ $2+2=4$
+\item
+ $x \in y$
+\item
+ $\alpha \wedge \omega$
+\item
+ $223$
+\item
+ $p$-Tree
+\item
+ Here's some display math:
+ \startformula \frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h} \stopformula
+\item
+ Here's one that has a line break in it: $\alpha + \omega \times x^2$.
+\stopitemize
+
+These shouldn't be math:
+
+\startitemize[packed]
+\item
+ To get the famous equation, write \type{$e = mc^2$}.
+\item
+ \$22,000 is a {\em lot} of money. So is \$34,000. (It worked if
+ \quotation{lot} is emphasized.)
+\item
+ Shoes (\$20) and socks (\$5).
+\item
+ Escaped \type{$}: \$73 {\em this should be emphasized} 23\$.
+\stopitemize
+
+Here's a LaTeX table:
+
+\thinrule
+
+\section[title={Special Characters},reference={special-characters}]
+
+Here is some unicode:
+
+\startitemize[packed]
+\item
+ I hat: Î
+\item
+ o umlaut: ö
+\item
+ section: §
+\item
+ set membership: ∈
+\item
+ copyright: ©
+\stopitemize
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \letterbackslash{}
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: {[}
+
+Right bracket: {]}
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: \#
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+\thinrule
+
+\section[title={Links},reference={links}]
+
+\subsection[title={Explicit},reference={explicit}]
+
+Just a \useURL[url4][/url/][][URL]\from[url4].
+
+\useURL[url5][/url/][][URL and title]\from[url5].
+
+\useURL[url6][/url/][][URL and title]\from[url6].
+
+\useURL[url7][/url/][][URL and title]\from[url7].
+
+\useURL[url8][/url/][][URL and title]\from[url8]
+
+\useURL[url9][/url/][][URL and title]\from[url9]
+
+\useURL[url10][/url/with_underscore][][with_underscore]\from[url10]
+
+\useURL[url11][mailto:nobody@nowhere.net][][Email link]\from[url11]
+
+\useURL[url12][][][Empty]\from[url12].
+
+\subsection[title={Reference},reference={reference}]
+
+Foo \useURL[url13][/url/][][bar]\from[url13].
+
+With \useURL[url14][/url/][][embedded {[}brackets{]}]\from[url14].
+
+\useURL[url15][/url/][][b]\from[url15] by itself should be a link.
+
+Indented \useURL[url16][/url][][once]\from[url16].
+
+Indented \useURL[url17][/url][][twice]\from[url17].
+
+Indented \useURL[url18][/url][][thrice]\from[url18].
+
+This should {[}not{]}{[}{]} be a link.
+
+\starttyping
+[not]: /url
+\stoptyping
+
+Foo \useURL[url19][/url/][][bar]\from[url19].
+
+Foo \useURL[url20][/url/][][biz]\from[url20].
+
+\subsection[title={With ampersands},reference={with-ampersands}]
+
+Here's a \useURL[url21][http://example.com/?foo=1&bar=2][][link with an
+ampersand in the URL]\from[url21].
+
+Here's a link with an amersand in the link text:
+\useURL[url22][http://att.com/][][AT&T]\from[url22].
+
+Here's an \useURL[url23][/script?foo=1&bar=2][][inline link]\from[url23].
+
+Here's an \useURL[url24][/script?foo=1&bar=2][][inline link in pointy
+braces]\from[url24].
+
+\subsection[title={Autolinks},reference={autolinks}]
+
+With an ampersand: \useURL[url25][http://example.com/?foo=1&bar=2]\from[url25]
+
+\startitemize[packed]
+\item
+ In a list?
+\item
+ \useURL[url26][http://example.com/]\from[url26]
+\item
+ It should.
+\stopitemize
+
+An e-mail address:
+\useURL[url27][mailto:nobody@nowhere.net][][nobody@nowhere.net]\from[url27]
+
+\startblockquote
+Blockquoted: \useURL[url28][http://example.com/]\from[url28]
+\stopblockquote
+
+Auto-links should not occur here: \type{<http://example.com/>}
+
+\starttyping
+or here: <http://example.com/>
+\stoptyping
+
+\thinrule
+
+\section[title={Images},reference={images}]
+
+From \quotation{Voyage dans la Lune} by Georges Melies (1902):
+
+\placefigure{lalune}{\externalfigure[lalune.jpg]}
+
+Here is a movie {\externalfigure[movie.jpg]} icon.
+
+\thinrule
+
+\section[title={Footnotes},reference={footnotes}]
+
+Here is a footnote reference,\footnote{Here is the footnote. It can go
+ anywhere after the footnote reference. It need not be placed at the end of
+ the document.} and another.\startbuffer Here's the long note. This one
+ contains multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the footnote (as
+ with list items).
+
+\starttyping
+ { <code> }
+\stoptyping
+
+ If you want, you can indent every line, but you can also be lazy and just
+ indent the first line of each block.\stopbuffer\footnote{\getbuffer} This
+should {\em not} be a footnote reference, because it contains a space.{[}^my
+note{]} Here is an inline note.\footnote{This is {\em easier} to type. Inline
+ notes may contain \useURL[url29][http://google.com][][links]\from[url29] and
+ \type{]} verbatim characters, as well as {[}bracketed text{]}.}
+
+\startblockquote
+Notes can go in quotes.\footnote{In quote.}
+\stopblockquote
+
+\startitemize[n,packed][stopper=.]
+\item
+ And in list items.\footnote{In list.}
+\stopitemize
+
+This paragraph should not be part of the note, as it is not indented.
+
+\stoptext
diff --git a/test/writer.custom b/test/writer.custom
new file mode 100644
index 000000000..b32d777de
--- /dev/null
+++ b/test/writer.custom
@@ -0,0 +1,783 @@
+<p>This is a set of tests for pandoc. Most of them are adapted from
+John Gruber’s markdown test suite.</p>
+
+<hr/>
+
+<h1 id="headers">Headers</h1>
+
+<h2 id="level-2-with-an-embedded-link">Level 2 with an <a href='/url' title=''>embedded link</a></h2>
+
+<h3 id="level-3-with-emphasis">Level 3 with <em>emphasis</em></h3>
+
+<h4 id="level-4">Level 4</h4>
+
+<h5 id="level-5">Level 5</h5>
+
+<h1 id="level-1">Level 1</h1>
+
+<h2 id="level-2-with-emphasis">Level 2 with <em>emphasis</em></h2>
+
+<h3 id="level-3">Level 3</h3>
+
+<p>with no blank line</p>
+
+<h2 id="level-2">Level 2</h2>
+
+<p>with no blank line</p>
+
+<hr/>
+
+<h1 id="paragraphs">Paragraphs</h1>
+
+<p>Here’s a regular paragraph.</p>
+
+<p>In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.</p>
+
+<p>Here’s one with a bullet.
+* criminey.</p>
+
+<p>There should be a hard line break<br/>here.</p>
+
+<hr/>
+
+<h1 id="block-quotes">Block Quotes</h1>
+
+<p>E-mail style:</p>
+
+<blockquote>
+<p>This is a block quote.
+It is pretty short.</p>
+</blockquote>
+
+<blockquote>
+<p>Code in a block quote:</p>
+
+<pre><code>sub status {
+ print &quot;working&quot;;
+}</code></pre>
+
+<p>A list:</p>
+
+<ol>
+<li>item one</li>
+<li>item two</li>
+</ol>
+
+<p>Nested block quotes:</p>
+
+<blockquote>
+<p>nested</p>
+</blockquote>
+
+<blockquote>
+<p>nested</p>
+</blockquote>
+</blockquote>
+
+<p>This should not be a block quote: 2
+&gt; 1.</p>
+
+<p>And a following paragraph.</p>
+
+<hr/>
+
+<h1 id="code-blocks">Code Blocks</h1>
+
+<p>Code:</p>
+
+<pre><code>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</code></pre>
+
+<p>And:</p>
+
+<pre><code> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</code></pre>
+
+<hr/>
+
+<h1 id="lists">Lists</h1>
+
+<h2 id="unordered">Unordered</h2>
+
+<p>Asterisks tight:</p>
+
+<ul>
+<li>asterisk 1</li>
+<li>asterisk 2</li>
+<li>asterisk 3</li>
+</ul>
+
+<p>Asterisks loose:</p>
+
+<ul>
+<li><p>asterisk 1</p></li>
+<li><p>asterisk 2</p></li>
+<li><p>asterisk 3</p></li>
+</ul>
+
+<p>Pluses tight:</p>
+
+<ul>
+<li>Plus 1</li>
+<li>Plus 2</li>
+<li>Plus 3</li>
+</ul>
+
+<p>Pluses loose:</p>
+
+<ul>
+<li><p>Plus 1</p></li>
+<li><p>Plus 2</p></li>
+<li><p>Plus 3</p></li>
+</ul>
+
+<p>Minuses tight:</p>
+
+<ul>
+<li>Minus 1</li>
+<li>Minus 2</li>
+<li>Minus 3</li>
+</ul>
+
+<p>Minuses loose:</p>
+
+<ul>
+<li><p>Minus 1</p></li>
+<li><p>Minus 2</p></li>
+<li><p>Minus 3</p></li>
+</ul>
+
+<h2 id="ordered">Ordered</h2>
+
+<p>Tight:</p>
+
+<ol>
+<li>First</li>
+<li>Second</li>
+<li>Third</li>
+</ol>
+
+<p>and:</p>
+
+<ol>
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ol>
+
+<p>Loose using tabs:</p>
+
+<ol>
+<li><p>First</p></li>
+<li><p>Second</p></li>
+<li><p>Third</p></li>
+</ol>
+
+<p>and using spaces:</p>
+
+<ol>
+<li><p>One</p></li>
+<li><p>Two</p></li>
+<li><p>Three</p></li>
+</ol>
+
+<p>Multiple paragraphs:</p>
+
+<ol>
+<li><p>Item 1, graf one.</p>
+
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s
+back.</p></li>
+<li><p>Item 2.</p></li>
+<li><p>Item 3.</p></li>
+</ol>
+
+<h2 id="nested">Nested</h2>
+
+<ul>
+<li>Tab
+
+<ul>
+<li>Tab
+
+<ul>
+<li>Tab</li>
+</ul></li>
+</ul></li>
+</ul>
+
+<p>Here’s another:</p>
+
+<ol>
+<li>First</li>
+<li>Second:
+
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li>Third</li>
+</ol>
+
+<p>Same thing but with paragraphs:</p>
+
+<ol>
+<li><p>First</p></li>
+<li><p>Second:</p>
+
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li><p>Third</p></li>
+</ol>
+
+<h2 id="tabs-and-spaces">Tabs and spaces</h2>
+
+<ul>
+<li><p>this is a list item
+indented with tabs</p></li>
+<li><p>this is a list item
+indented with spaces</p>
+
+<ul>
+<li><p>this is an example list item
+indented with tabs</p></li>
+<li><p>this is an example list item
+indented with spaces</p></li>
+</ul></li>
+</ul>
+
+<h2 id="fancy-list-markers">Fancy list markers</h2>
+
+<ol>
+<li>begins with 2</li>
+<li><p>and now 3</p>
+
+<p>with a continuation</p>
+
+<ol>
+<li>sublist with roman numerals,
+starting with 4</li>
+<li>more items
+
+<ol>
+<li>a subsublist</li>
+<li>a subsublist</li>
+</ol></li>
+</ol></li>
+</ol>
+
+<p>Nesting:</p>
+
+<ol>
+<li>Upper Alpha
+
+<ol>
+<li>Upper Roman.
+
+<ol>
+<li>Decimal start with 6
+
+<ol>
+<li>Lower alpha with paren</li>
+</ol></li>
+</ol></li>
+</ol></li>
+</ol>
+
+<p>Autonumbering:</p>
+
+<ol>
+<li>Autonumber.</li>
+<li>More.
+
+<ol>
+<li>Nested.</li>
+</ol></li>
+</ol>
+
+<p>Should not be a list item:</p>
+
+<p>M.A. 2007</p>
+
+<p>B. Williams</p>
+
+<hr/>
+
+<h1 id="definition-lists">Definition Lists</h1>
+
+<p>Tight using spaces:</p>
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dt>banana</dt>
+<dd>yellow fruit</dd>
+</dl>
+
+<p>Tight using tabs:</p>
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dt>banana</dt>
+<dd>yellow fruit</dd>
+</dl>
+
+<p>Loose:</p>
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p></dd>
+<dt>banana</dt>
+<dd><p>yellow fruit</p></dd>
+</dl>
+
+<p>Multiple blocks with italics:</p>
+
+<dl>
+<dt><em>apple</em></dt>
+<dd><p>red fruit</p>
+
+<p>contains seeds,
+crisp, pleasant to taste</p></dd>
+<dt><em>orange</em></dt>
+<dd><p>orange fruit</p>
+
+<pre><code>{ orange code block }</code></pre>
+
+<blockquote>
+<p>orange block quote</p>
+</blockquote></dd>
+</dl>
+
+<p>Multiple definitions, tight:</p>
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dd>computer</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dd>bank</dd>
+</dl>
+
+<p>Multiple definitions, loose:</p>
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dd><p>computer</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p></dd>
+<dd><p>bank</p></dd>
+</dl>
+
+<p>Blank line after term, indented marker, alternate markers:</p>
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dd><p>computer</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+
+<ol>
+<li>sublist</li>
+<li>sublist</li>
+</ol></dd>
+</dl>
+
+<h1 id="html-blocks">HTML Blocks</h1>
+
+<p>Simple block on one line:</p>
+
+<div>
+foo</div>
+
+<p>And nested without indentation:</p>
+
+<div>
+<div>
+<div>
+<p>foo</p></div></div>
+
+<div>
+bar</div></div>
+
+<p>Interpreted markdown in a table:</p>
+
+<table>
+
+<tr>
+
+<td>
+
+This is <em>emphasized</em>
+
+</td>
+
+<td>
+
+And this is <strong>strong</strong>
+
+</td>
+
+</tr>
+
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+<p>Here’s a simple block:</p>
+
+<div>
+<p>foo</p></div>
+
+<p>This should be a code block, though:</p>
+
+<pre><code>&lt;div&gt;
+ foo
+&lt;/div&gt;</code></pre>
+
+<p>As should this:</p>
+
+<pre><code>&lt;div&gt;foo&lt;/div&gt;</code></pre>
+
+<p>Now, nested:</p>
+
+<div>
+<div>
+<div>
+foo</div></div></div>
+
+<p>This should just be an HTML comment:</p>
+
+<!-- Comment -->
+
+<p>Multiline:</p>
+
+<!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+
+<p>Code block:</p>
+
+<pre><code>&lt;!-- Comment --&gt;</code></pre>
+
+<p>Just plain comment, with trailing spaces on the line:</p>
+
+<!-- foo -->
+
+<p>Code:</p>
+
+<pre><code>&lt;hr /&gt;</code></pre>
+
+<p>Hr’s:</p>
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar">
+
+<hr/>
+
+<h1 id="inline-markup">Inline Markup</h1>
+
+<p>This is <em>emphasized</em>, and so <em>is this</em>.</p>
+
+<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
+
+<p>An <em><a href='/url' title=''>emphasized link</a></em>.</p>
+
+<p><strong><em>This is strong and em.</em></strong></p>
+
+<p>So is <strong><em>this</em></strong> word.</p>
+
+<p><strong><em>This is strong and em.</em></strong></p>
+
+<p>So is <strong><em>this</em></strong> word.</p>
+
+<p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p>
+
+<p><del>This is <em>strikeout</em>.</del></p>
+
+<p>Superscripts: a<sup>bc</sup>d a<sup><em>hello</em></sup> a<sup>hello there</sup>.</p>
+
+<p>Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.</p>
+
+<p>These should not be superscripts or subscripts,
+because of the unescaped spaces: a^b c^d, a~b c~d.</p>
+
+<hr/>
+
+<h1 id="smart-quotes-ellipses-dashes">Smart quotes, ellipses, dashes</h1>
+
+<p> said the spider. </p>
+
+<p>, , and are letters.</p>
+
+<p> and are names of trees.
+So is </p>
+
+<p> Were you alive in the
+70’s?</p>
+
+<p>Here is some quoted and a .</p>
+
+<p>Some dashes: one—two — three—four — five.</p>
+
+<p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p>
+
+<p>Ellipses…and…and….</p>
+
+<hr/>
+
+<h1 id="latex">LaTeX</h1>
+
+<ul>
+<li></li>
+<li>\(2+2=4\)</li>
+<li>\(x \in y\)</li>
+<li>\(\alpha \wedge \omega\)</li>
+<li>\(223\)</li>
+<li>\(p\)-Tree</li>
+<li>Here’s some display math:
+\[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\]</li>
+<li>Here’s one that has a line break in it: \(\alpha + \omega \times x^2\).</li>
+</ul>
+
+<p>These shouldn’t be math:</p>
+
+<ul>
+<li>To get the famous equation, write <code>$e = mc^2$</code>.</li>
+<li>$22,000 is a <em>lot</em> of money. So is $34,000.
+(It worked if is emphasized.)</li>
+<li>Shoes ($20) and socks ($5).</li>
+<li>Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.</li>
+</ul>
+
+<p>Here’s a LaTeX table:</p>
+
+
+
+<hr/>
+
+<h1 id="special-characters">Special Characters</h1>
+
+<p>Here is some unicode:</p>
+
+<ul>
+<li>I hat: Î</li>
+<li>o umlaut: ö</li>
+<li>section: §</li>
+<li>set membership: ∈</li>
+<li>copyright: ©</li>
+</ul>
+
+<p>AT&amp;T has an ampersand in their name.</p>
+
+<p>AT&amp;T is another way to write it.</p>
+
+<p>This &amp; that.</p>
+
+<p>4 &lt; 5.</p>
+
+<p>6 &gt; 5.</p>
+
+<p>Backslash: \</p>
+
+<p>Backtick: `</p>
+
+<p>Asterisk: *</p>
+
+<p>Underscore: _</p>
+
+<p>Left brace: {</p>
+
+<p>Right brace: }</p>
+
+<p>Left bracket: [</p>
+
+<p>Right bracket: ]</p>
+
+<p>Left paren: (</p>
+
+<p>Right paren: )</p>
+
+<p>Greater-than: &gt;</p>
+
+<p>Hash: #</p>
+
+<p>Period: .</p>
+
+<p>Bang: !</p>
+
+<p>Plus: +</p>
+
+<p>Minus: -</p>
+
+<hr/>
+
+<h1 id="links">Links</h1>
+
+<h2 id="explicit">Explicit</h2>
+
+<p>Just a <a href='/url/' title=''>URL</a>.</p>
+
+<p><a href='/url/' title='title'>URL and title</a>.</p>
+
+<p><a href='/url/' title='title preceded by two spaces'>URL and title</a>.</p>
+
+<p><a href='/url/' title='title preceded by a tab'>URL and title</a>.</p>
+
+<p><a href='/url/' title='title with &quot;quotes&quot; in it'>URL and title</a></p>
+
+<p><a href='/url/' title='title with single quotes'>URL and title</a></p>
+
+<p><a href='/url/with_underscore' title=''>with_underscore</a></p>
+
+<p><a href='mailto:nobody@nowhere.net' title=''>Email link</a></p>
+
+<p><a href='' title=''>Empty</a>.</p>
+
+<h2 id="reference">Reference</h2>
+
+<p>Foo <a href='/url/' title=''>bar</a>.</p>
+
+<p>With <a href='/url/' title=''>embedded [brackets]</a>.</p>
+
+<p><a href='/url/' title=''>b</a> by itself should be a link.</p>
+
+<p>Indented <a href='/url' title=''>once</a>.</p>
+
+<p>Indented <a href='/url' title=''>twice</a>.</p>
+
+<p>Indented <a href='/url' title=''>thrice</a>.</p>
+
+<p>This should [not][] be a link.</p>
+
+<pre><code>[not]: /url</code></pre>
+
+<p>Foo <a href='/url/' title='Title with &quot;quotes&quot; inside'>bar</a>.</p>
+
+<p>Foo <a href='/url/' title='Title with &quot;quote&quot; inside'>biz</a>.</p>
+
+<h2 id="with-ampersands">With ampersands</h2>
+
+<p>Here’s a <a href='http://example.com/?foo=1&amp;bar=2' title=''>link with an ampersand in the URL</a>.</p>
+
+<p>Here’s a link with an amersand in the link text: <a href='http://att.com/' title='AT&amp;T'>AT&amp;T</a>.</p>
+
+<p>Here’s an <a href='/script?foo=1&amp;bar=2' title=''>inline link</a>.</p>
+
+<p>Here’s an <a href='/script?foo=1&amp;bar=2' title=''>inline link in pointy braces</a>.</p>
+
+<h2 id="autolinks">Autolinks</h2>
+
+<p>With an ampersand: <a href='http://example.com/?foo=1&amp;bar=2' title=''>http://example.com/?foo=1&amp;bar=2</a></p>
+
+<ul>
+<li>In a list?</li>
+<li><a href='http://example.com/' title=''>http://example.com/</a></li>
+<li>It should.</li>
+</ul>
+
+<p>An e-mail address: <a href='mailto:nobody@nowhere.net' title=''>nobody@nowhere.net</a></p>
+
+<blockquote>
+<p>Blockquoted: <a href='http://example.com/' title=''>http://example.com/</a></p>
+</blockquote>
+
+<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p>
+
+<pre><code>or here: &lt;http://example.com/&gt;</code></pre>
+
+<hr/>
+
+<h1 id="images">Images</h1>
+
+<p>From by Georges Melies (1902):</p>
+
+<div class="figure">
+<img src="lalune.jpg" title="fig:Voyage dans la Lune"/>
+<p class="caption">lalune</p>
+</div>
+
+<p>Here is a movie <img src='movie.jpg' title=''/> icon.</p>
+
+<hr/>
+
+<h1 id="footnotes">Footnotes</h1>
+
+<p>Here is a footnote reference,<a id="fnref1" href="#fn1"><sup>1</sup></a> and another.<a id="fnref2" href="#fn2"><sup>2</sup></a>
+This should <em>not</em> be a footnote reference, because it
+contains a space.[^my note] Here is an inline note.<a id="fnref3" href="#fn3"><sup>3</sup></a></p>
+
+<blockquote>
+<p>Notes can go in quotes.<a id="fnref4" href="#fn4"><sup>4</sup></a></p>
+</blockquote>
+
+<ol>
+<li>And in list items.<a id="fnref5" href="#fn5"><sup>5</sup></a></li>
+</ol>
+
+<p>This paragraph should not be part of the note, as it is not indented.</p>
+<ol class="footnotes">
+<li id="fn1"><p>Here is the footnote. It can go anywhere after the footnote
+reference. It need not be placed at the end of the document. <a href="#fnref1">&#8617;</a></p></li>
+<li id="fn2"><p>Here’s the long note. This one contains multiple
+blocks.</p>
+
+<p>Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).</p>
+
+<pre><code> { &lt;code&gt; }</code></pre>
+
+<p>If you want, you can indent every line, but you can also be
+lazy and just indent the first line of each block. <a href="#fnref2">&#8617;</a></p></li>
+<li id="fn3"><p>This
+is <em>easier</em> to type. Inline notes may contain
+<a href='http://google.com' title=''>links</a> and <code>]</code> verbatim characters,
+as well as [bracketed text]. <a href="#fnref3">&#8617;</a></p></li>
+<li id="fn4"><p>In quote. <a href="#fnref4">&#8617;</a></p></li>
+<li id="fn5"><p>In list. <a href="#fnref5">&#8617;</a></p></li>
+</ol>
+
diff --git a/test/writer.docbook4 b/test/writer.docbook4
new file mode 100644
index 000000000..163255974
--- /dev/null
+++ b/test/writer.docbook4
@@ -0,0 +1,1416 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<article>
+ <articleinfo>
+ <title>Pandoc Test Suite</title>
+ <authorgroup>
+ <author>
+ <firstname>John</firstname>
+ <surname>MacFarlane</surname>
+ </author>
+ <author>
+ <firstname></firstname>
+ <surname>Anonymous</surname>
+ </author>
+ </authorgroup>
+ <date>July 17, 2006</date>
+ </articleinfo>
+<para>
+ This is a set of tests for pandoc. Most of them are adapted from John
+ Gruber’s markdown test suite.
+</para>
+<sect1 id="headers">
+ <title>Headers</title>
+ <sect2 id="level-2-with-an-embedded-link">
+ <title>Level 2 with an <ulink url="/url">embedded link</ulink></title>
+ <sect3 id="level-3-with-emphasis">
+ <title>Level 3 with <emphasis>emphasis</emphasis></title>
+ <sect4 id="level-4">
+ <title>Level 4</title>
+ <sect5 id="level-5">
+ <title>Level 5</title>
+ <para>
+ </para>
+ </sect5>
+ </sect4>
+ </sect3>
+ </sect2>
+</sect1>
+<sect1 id="level-1">
+ <title>Level 1</title>
+ <sect2 id="level-2-with-emphasis">
+ <title>Level 2 with <emphasis>emphasis</emphasis></title>
+ <sect3 id="level-3">
+ <title>Level 3</title>
+ <para>
+ with no blank line
+ </para>
+ </sect3>
+ </sect2>
+ <sect2 id="level-2">
+ <title>Level 2</title>
+ <para>
+ with no blank line
+ </para>
+ </sect2>
+</sect1>
+<sect1 id="paragraphs">
+ <title>Paragraphs</title>
+ <para>
+ Here’s a regular paragraph.
+ </para>
+ <para>
+ In Markdown 1.0.0 and earlier. Version 8. This line turns into a list
+ item. Because a hard-wrapped line in the middle of a paragraph looked like
+ a list item.
+ </para>
+ <para>
+ Here’s one with a bullet. * criminey.
+ </para>
+<literallayout>There should be a hard line break
+here.</literallayout>
+</sect1>
+<sect1 id="block-quotes">
+ <title>Block Quotes</title>
+ <para>
+ E-mail style:
+ </para>
+ <blockquote>
+ <para>
+ This is a block quote. It is pretty short.
+ </para>
+ </blockquote>
+ <blockquote>
+ <para>
+ Code in a block quote:
+ </para>
+ <programlisting>
+sub status {
+ print &quot;working&quot;;
+}
+</programlisting>
+ <para>
+ A list:
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ item one
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ item two
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Nested block quotes:
+ </para>
+ <blockquote>
+ <para>
+ nested
+ </para>
+ </blockquote>
+ <blockquote>
+ <para>
+ nested
+ </para>
+ </blockquote>
+ </blockquote>
+ <para>
+ This should not be a block quote: 2 &gt; 1.
+ </para>
+ <para>
+ And a following paragraph.
+ </para>
+</sect1>
+<sect1 id="code-blocks">
+ <title>Code Blocks</title>
+ <para>
+ Code:
+ </para>
+ <programlisting>
+---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab
+</programlisting>
+ <para>
+ And:
+ </para>
+ <programlisting>
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{
+</programlisting>
+</sect1>
+<sect1 id="lists">
+ <title>Lists</title>
+ <sect2 id="unordered">
+ <title>Unordered</title>
+ <para>
+ Asterisks tight:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ asterisk 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Asterisks loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ asterisk 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Pluses tight:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Plus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Pluses loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Plus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Minuses tight:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Minus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Minuses loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Minus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+ <sect2 id="ordered">
+ <title>Ordered</title>
+ <para>
+ Tight:
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ and:
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ One
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Two
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Three
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Loose using tabs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ and using spaces:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ One
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Two
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Three
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Multiple paragraphs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ Item 1, graf one.
+ </para>
+ <para>
+ Item 1. graf two. The quick brown fox jumped over the lazy dog’s
+ back.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Item 2.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Item 3.
+ </para>
+ </listitem>
+ </orderedlist>
+ </sect2>
+ <sect2 id="nested">
+ <title>Nested</title>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Tab
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Tab
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Tab
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Here’s another:
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Fee
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fie
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Foe
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Same thing but with paragraphs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Fee
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fie
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Foe
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ </sect2>
+ <sect2 id="tabs-and-spaces">
+ <title>Tabs and spaces</title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ this is a list item indented with tabs
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ this is a list item indented with spaces
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ this is an example list item indented with tabs
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ this is an example list item indented with spaces
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+ <sect2 id="fancy-list-markers">
+ <title>Fancy list markers</title>
+ <orderedlist numeration="arabic">
+ <listitem override="2">
+ <para>
+ begins with 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ and now 3
+ </para>
+ <para>
+ with a continuation
+ </para>
+ <orderedlist numeration="lowerroman" spacing="compact">
+ <listitem override="4">
+ <para>
+ sublist with roman numerals, starting with 4
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ more items
+ </para>
+ <orderedlist numeration="upperalpha" spacing="compact">
+ <listitem>
+ <para>
+ a subsublist
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a subsublist
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Nesting:
+ </para>
+ <orderedlist numeration="upperalpha" spacing="compact">
+ <listitem>
+ <para>
+ Upper Alpha
+ </para>
+ <orderedlist numeration="upperroman" spacing="compact">
+ <listitem>
+ <para>
+ Upper Roman.
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem override="6">
+ <para>
+ Decimal start with 6
+ </para>
+ <orderedlist numeration="loweralpha" spacing="compact">
+ <listitem override="3">
+ <para>
+ Lower alpha with paren
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Autonumbering:
+ </para>
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Autonumber.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ More.
+ </para>
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Nested.
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Should not be a list item:
+ </para>
+ <para>
+ M.A. 2007
+ </para>
+ <para>
+ B. Williams
+ </para>
+ </sect2>
+</sect1>
+<sect1 id="definition-lists">
+ <title>Definition Lists</title>
+ <para>
+ Tight using spaces:
+ </para>
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Tight using tabs:
+ </para>
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Loose:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Multiple blocks with italics:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <emphasis>apple</emphasis>
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ contains seeds, crisp, pleasant to taste
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <emphasis>orange</emphasis>
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <programlisting>
+{ orange code block }
+</programlisting>
+ <blockquote>
+ <para>
+ orange block quote
+ </para>
+ </blockquote>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Multiple definitions, tight:
+ </para>
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ computer
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <para>
+ bank
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Multiple definitions, loose:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ computer
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <para>
+ bank
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Blank line after term, indented marker, alternate markers:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ computer
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ sublist
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ sublist
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+</sect1>
+<sect1 id="html-blocks">
+ <title>HTML Blocks</title>
+ <para>
+ Simple block on one line:
+ </para>
+ <para>
+ foo
+ </para>
+ <para>
+ And nested without indentation:
+ </para>
+ <para>
+ foo
+ </para>
+ <para>
+ bar
+ </para>
+ <para>
+ Interpreted markdown in a table:
+ </para>
+ <table>
+ <tr>
+ <td>
+ This is <emphasis>emphasized</emphasis>
+ </td>
+ <td>
+ And this is <emphasis role="strong">strong</emphasis>
+ </td>
+ </tr>
+ </table>
+ <script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+ <para>
+ Here’s a simple block:
+ </para>
+ <para>
+ foo
+ </para>
+ <para>
+ This should be a code block, though:
+ </para>
+ <programlisting>
+&lt;div&gt;
+ foo
+&lt;/div&gt;
+</programlisting>
+ <para>
+ As should this:
+ </para>
+ <programlisting>
+&lt;div&gt;foo&lt;/div&gt;
+</programlisting>
+ <para>
+ Now, nested:
+ </para>
+ <para>
+ foo
+ </para>
+ <para>
+ This should just be an HTML comment:
+ </para>
+ <!-- Comment -->
+ <para>
+ Multiline:
+ </para>
+ <!--
+ Blah
+ Blah
+ -->
+ <!--
+ This is another comment.
+ -->
+ <para>
+ Code block:
+ </para>
+ <programlisting>
+&lt;!-- Comment --&gt;
+</programlisting>
+ <para>
+ Just plain comment, with trailing spaces on the line:
+ </para>
+ <!-- foo -->
+ <para>
+ Code:
+ </para>
+ <programlisting>
+&lt;hr /&gt;
+</programlisting>
+ <para>
+ Hr’s:
+ </para>
+ <hr>
+ <hr />
+ <hr />
+ <hr>
+ <hr />
+ <hr />
+ <hr class="foo" id="bar" />
+ <hr class="foo" id="bar" />
+ <hr class="foo" id="bar">
+</sect1>
+<sect1 id="inline-markup">
+ <title>Inline Markup</title>
+ <para>
+ This is <emphasis>emphasized</emphasis>, and so <emphasis>is
+ this</emphasis>.
+ </para>
+ <para>
+ This is <emphasis role="strong">strong</emphasis>, and so
+ <emphasis role="strong">is this</emphasis>.
+ </para>
+ <para>
+ An <emphasis><ulink url="/url">emphasized link</ulink></emphasis>.
+ </para>
+ <para>
+ <emphasis role="strong"><emphasis>This is strong and
+ em.</emphasis></emphasis>
+ </para>
+ <para>
+ So is <emphasis role="strong"><emphasis>this</emphasis></emphasis> word.
+ </para>
+ <para>
+ <emphasis role="strong"><emphasis>This is strong and
+ em.</emphasis></emphasis>
+ </para>
+ <para>
+ So is <emphasis role="strong"><emphasis>this</emphasis></emphasis> word.
+ </para>
+ <para>
+ This is code: <literal>&gt;</literal>, <literal>$</literal>,
+ <literal>\</literal>, <literal>\$</literal>,
+ <literal>&lt;html&gt;</literal>.
+ </para>
+ <para>
+ <emphasis role="strikethrough">This is
+ <emphasis>strikeout</emphasis>.</emphasis>
+ </para>
+ <para>
+ Superscripts: a<superscript>bc</superscript>d
+ a<superscript><emphasis>hello</emphasis></superscript>
+ a<superscript>hello there</superscript>.
+ </para>
+ <para>
+ Subscripts: H<subscript>2</subscript>O, H<subscript>23</subscript>O,
+ H<subscript>many of them</subscript>O.
+ </para>
+ <para>
+ These should not be superscripts or subscripts, because of the unescaped
+ spaces: a^b c^d, a~b c~d.
+ </para>
+</sect1>
+<sect1 id="smart-quotes-ellipses-dashes">
+ <title>Smart quotes, ellipses, dashes</title>
+ <para>
+ <quote>Hello,</quote> said the spider. <quote><quote>Shelob</quote> is my
+ name.</quote>
+ </para>
+ <para>
+ <quote>A</quote>, <quote>B</quote>, and <quote>C</quote> are letters.
+ </para>
+ <para>
+ <quote>Oak,</quote> <quote>elm,</quote> and <quote>beech</quote> are names
+ of trees. So is <quote>pine.</quote>
+ </para>
+ <para>
+ <quote>He said, <quote>I want to go.</quote></quote> Were you alive in the
+ 70’s?
+ </para>
+ <para>
+ Here is some quoted <quote><literal>code</literal></quote> and a
+ <quote><ulink url="http://example.com/?foo=1&amp;bar=2">quoted
+ link</ulink></quote>.
+ </para>
+ <para>
+ Some dashes: one—two — three—four — five.
+ </para>
+ <para>
+ Dashes between numbers: 5–7, 255–66, 1987–1999.
+ </para>
+ <para>
+ Ellipses…and…and….
+ </para>
+</sect1>
+<sect1 id="latex">
+ <title>LaTeX</title>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 2 + 2 = 4
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>x</emphasis> ∈ <emphasis>y</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>α</emphasis> ∧ <emphasis>ω</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 223
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>p</emphasis>-Tree
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Here’s some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Here’s one that has a line break in it:
+ <emphasis>α</emphasis> + <emphasis>ω</emphasis> × <emphasis>x</emphasis><superscript>2</superscript>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ These shouldn’t be math:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ To get the famous equation, write <literal>$e = mc^2$</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It
+ worked if <quote>lot</quote> is emphasized.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Shoes ($20) and socks ($5).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Escaped <literal>$</literal>: $73 <emphasis>this should be
+ emphasized</emphasis> 23$.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Here’s a LaTeX table:
+ </para>
+</sect1>
+<sect1 id="special-characters">
+ <title>Special Characters</title>
+ <para>
+ Here is some unicode:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ I hat: Î
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ o umlaut: ö
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ section: §
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ set membership: ∈
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ copyright: ©
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ AT&amp;T has an ampersand in their name.
+ </para>
+ <para>
+ AT&amp;T is another way to write it.
+ </para>
+ <para>
+ This &amp; that.
+ </para>
+ <para>
+ 4 &lt; 5.
+ </para>
+ <para>
+ 6 &gt; 5.
+ </para>
+ <para>
+ Backslash: \
+ </para>
+ <para>
+ Backtick: `
+ </para>
+ <para>
+ Asterisk: *
+ </para>
+ <para>
+ Underscore: _
+ </para>
+ <para>
+ Left brace: {
+ </para>
+ <para>
+ Right brace: }
+ </para>
+ <para>
+ Left bracket: [
+ </para>
+ <para>
+ Right bracket: ]
+ </para>
+ <para>
+ Left paren: (
+ </para>
+ <para>
+ Right paren: )
+ </para>
+ <para>
+ Greater-than: &gt;
+ </para>
+ <para>
+ Hash: #
+ </para>
+ <para>
+ Period: .
+ </para>
+ <para>
+ Bang: !
+ </para>
+ <para>
+ Plus: +
+ </para>
+ <para>
+ Minus: -
+ </para>
+</sect1>
+<sect1 id="links">
+ <title>Links</title>
+ <sect2 id="explicit">
+ <title>Explicit</title>
+ <para>
+ Just a <ulink url="/url/">URL</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>
+ </para>
+ <para>
+ <ulink url="/url/">URL and title</ulink>
+ </para>
+ <para>
+ <ulink url="/url/with_underscore">with_underscore</ulink>
+ </para>
+ <para>
+ Email link (<email>nobody@nowhere.net</email>)
+ </para>
+ <para>
+ <ulink url="">Empty</ulink>.
+ </para>
+ </sect2>
+ <sect2 id="reference">
+ <title>Reference</title>
+ <para>
+ Foo <ulink url="/url/">bar</ulink>.
+ </para>
+ <para>
+ With <ulink url="/url/">embedded [brackets]</ulink>.
+ </para>
+ <para>
+ <ulink url="/url/">b</ulink> by itself should be a link.
+ </para>
+ <para>
+ Indented <ulink url="/url">once</ulink>.
+ </para>
+ <para>
+ Indented <ulink url="/url">twice</ulink>.
+ </para>
+ <para>
+ Indented <ulink url="/url">thrice</ulink>.
+ </para>
+ <para>
+ This should [not][] be a link.
+ </para>
+ <programlisting>
+[not]: /url
+</programlisting>
+ <para>
+ Foo <ulink url="/url/">bar</ulink>.
+ </para>
+ <para>
+ Foo <ulink url="/url/">biz</ulink>.
+ </para>
+ </sect2>
+ <sect2 id="with-ampersands">
+ <title>With ampersands</title>
+ <para>
+ Here’s a <ulink url="http://example.com/?foo=1&amp;bar=2">link with an
+ ampersand in the URL</ulink>.
+ </para>
+ <para>
+ Here’s a link with an amersand in the link text:
+ <ulink url="http://att.com/">AT&amp;T</ulink>.
+ </para>
+ <para>
+ Here’s an <ulink url="/script?foo=1&amp;bar=2">inline link</ulink>.
+ </para>
+ <para>
+ Here’s an <ulink url="/script?foo=1&amp;bar=2">inline link in pointy
+ braces</ulink>.
+ </para>
+ </sect2>
+ <sect2 id="autolinks">
+ <title>Autolinks</title>
+ <para>
+ With an ampersand:
+ <ulink url="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</ulink>
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ In a list?
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="http://example.com/">http://example.com/</ulink>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ It should.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ An e-mail address: <email>nobody@nowhere.net</email>
+ </para>
+ <blockquote>
+ <para>
+ Blockquoted:
+ <ulink url="http://example.com/">http://example.com/</ulink>
+ </para>
+ </blockquote>
+ <para>
+ Auto-links should not occur here:
+ <literal>&lt;http://example.com/&gt;</literal>
+ </para>
+ <programlisting>
+or here: &lt;http://example.com/&gt;
+</programlisting>
+ </sect2>
+</sect1>
+<sect1 id="images">
+ <title>Images</title>
+ <para>
+ From <quote>Voyage dans la Lune</quote> by Georges Melies (1902):
+ </para>
+ <figure>
+ <title>lalune</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="lalune.jpg" />
+ </imageobject>
+ <textobject><phrase>lalune</phrase></textobject>
+ </mediaobject>
+ </figure>
+ <para>
+ Here is a movie <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="movie.jpg" />
+ </imageobject>
+ </inlinemediaobject> icon.
+ </para>
+</sect1>
+<sect1 id="footnotes">
+ <title>Footnotes</title>
+ <para>
+ Here is a footnote reference,<footnote>
+ <para>
+ Here is the footnote. It can go anywhere after the footnote reference.
+ It need not be placed at the end of the document.
+ </para>
+ </footnote> and another.<footnote>
+ <para>
+ Here’s the long note. This one contains multiple blocks.
+ </para>
+ <para>
+ Subsequent blocks are indented to show that they belong to the
+ footnote (as with list items).
+ </para>
+ <programlisting>
+ { &lt;code&gt; }
+</programlisting>
+ <para>
+ If you want, you can indent every line, but you can also be lazy and
+ just indent the first line of each block.
+ </para>
+ </footnote> This should <emphasis>not</emphasis> be a footnote reference,
+ because it contains a space.[^my note] Here is an inline note.<footnote>
+ <para>
+ This is <emphasis>easier</emphasis> to type. Inline notes may contain
+ <ulink url="http://google.com">links</ulink> and <literal>]</literal>
+ verbatim characters, as well as [bracketed text].
+ </para>
+ </footnote>
+ </para>
+ <blockquote>
+ <para>
+ Notes can go in quotes.<footnote>
+ <para>
+ In quote.
+ </para>
+ </footnote>
+ </para>
+ </blockquote>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ And in list items.<footnote>
+ <para>
+ In list.
+ </para>
+ </footnote>
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ This paragraph should not be part of the note, as it is not indented.
+ </para>
+</sect1>
+</article>
diff --git a/test/writer.docbook5 b/test/writer.docbook5
new file mode 100644
index 000000000..992cd8b63
--- /dev/null
+++ b/test/writer.docbook5
@@ -0,0 +1,1391 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE article>
+<article
+ xmlns="http://docbook.org/ns/docbook" version="5.0"
+ xmlns:xlink="http://www.w3.org/1999/xlink" >
+ <info>
+ <title>Pandoc Test Suite</title>
+ <authorgroup>
+ <author>
+ <firstname>John</firstname>
+ <surname>MacFarlane</surname>
+ </author>
+ <author>
+ <firstname></firstname>
+ <surname>Anonymous</surname>
+ </author>
+ </authorgroup>
+ <date>July 17, 2006</date>
+ </info>
+<para>
+ This is a set of tests for pandoc. Most of them are adapted from John
+ Gruber’s markdown test suite.
+</para>
+<section xml:id="headers">
+ <title>Headers</title>
+ <section xml:id="level-2-with-an-embedded-link">
+ <title>Level 2 with an <link xlink:href="/url">embedded
+ link</link></title>
+ <section xml:id="level-3-with-emphasis">
+ <title>Level 3 with <emphasis>emphasis</emphasis></title>
+ <section xml:id="level-4">
+ <title>Level 4</title>
+ <section xml:id="level-5">
+ <title>Level 5</title>
+ <para>
+ </para>
+ </section>
+ </section>
+ </section>
+ </section>
+</section>
+<section xml:id="level-1">
+ <title>Level 1</title>
+ <section xml:id="level-2-with-emphasis">
+ <title>Level 2 with <emphasis>emphasis</emphasis></title>
+ <section xml:id="level-3">
+ <title>Level 3</title>
+ <para>
+ with no blank line
+ </para>
+ </section>
+ </section>
+ <section xml:id="level-2">
+ <title>Level 2</title>
+ <para>
+ with no blank line
+ </para>
+ </section>
+</section>
+<section xml:id="paragraphs">
+ <title>Paragraphs</title>
+ <para>
+ Here’s a regular paragraph.
+ </para>
+ <para>
+ In Markdown 1.0.0 and earlier. Version 8. This line turns into a list
+ item. Because a hard-wrapped line in the middle of a paragraph looked like
+ a list item.
+ </para>
+ <para>
+ Here’s one with a bullet. * criminey.
+ </para>
+<literallayout>There should be a hard line break
+here.</literallayout>
+</section>
+<section xml:id="block-quotes">
+ <title>Block Quotes</title>
+ <para>
+ E-mail style:
+ </para>
+ <blockquote>
+ <para>
+ This is a block quote. It is pretty short.
+ </para>
+ </blockquote>
+ <blockquote>
+ <para>
+ Code in a block quote:
+ </para>
+ <programlisting>
+sub status {
+ print &quot;working&quot;;
+}
+</programlisting>
+ <para>
+ A list:
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ item one
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ item two
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Nested block quotes:
+ </para>
+ <blockquote>
+ <para>
+ nested
+ </para>
+ </blockquote>
+ <blockquote>
+ <para>
+ nested
+ </para>
+ </blockquote>
+ </blockquote>
+ <para>
+ This should not be a block quote: 2 &gt; 1.
+ </para>
+ <para>
+ And a following paragraph.
+ </para>
+</section>
+<section xml:id="code-blocks">
+ <title>Code Blocks</title>
+ <para>
+ Code:
+ </para>
+ <programlisting>
+---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab
+</programlisting>
+ <para>
+ And:
+ </para>
+ <programlisting>
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{
+</programlisting>
+</section>
+<section xml:id="lists">
+ <title>Lists</title>
+ <section xml:id="unordered">
+ <title>Unordered</title>
+ <para>
+ Asterisks tight:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ asterisk 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Asterisks loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ asterisk 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ asterisk 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Pluses tight:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Plus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Pluses loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Plus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Minuses tight:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Minus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Minuses loose:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Minus 1
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Minus 3
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section xml:id="ordered">
+ <title>Ordered</title>
+ <para>
+ Tight:
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ and:
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ One
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Two
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Three
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Loose using tabs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ and using spaces:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ One
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Two
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Three
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Multiple paragraphs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ Item 1, graf one.
+ </para>
+ <para>
+ Item 1. graf two. The quick brown fox jumped over the lazy dog’s
+ back.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Item 2.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Item 3.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+ <section xml:id="nested">
+ <title>Nested</title>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Tab
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Tab
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Tab
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Here’s another:
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Fee
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fie
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Foe
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Same thing but with paragraphs:
+ </para>
+ <orderedlist numeration="arabic">
+ <listitem>
+ <para>
+ First
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Second:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Fee
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fie
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Foe
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ Third
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+ <section xml:id="tabs-and-spaces">
+ <title>Tabs and spaces</title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ this is a list item indented with tabs
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ this is a list item indented with spaces
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ this is an example list item indented with tabs
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ this is an example list item indented with spaces
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section xml:id="fancy-list-markers">
+ <title>Fancy list markers</title>
+ <orderedlist numeration="arabic">
+ <listitem override="2">
+ <para>
+ begins with 2
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ and now 3
+ </para>
+ <para>
+ with a continuation
+ </para>
+ <orderedlist numeration="lowerroman" spacing="compact">
+ <listitem override="4">
+ <para>
+ sublist with roman numerals, starting with 4
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ more items
+ </para>
+ <orderedlist numeration="upperalpha" spacing="compact">
+ <listitem>
+ <para>
+ a subsublist
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a subsublist
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Nesting:
+ </para>
+ <orderedlist numeration="upperalpha" spacing="compact">
+ <listitem>
+ <para>
+ Upper Alpha
+ </para>
+ <orderedlist numeration="upperroman" spacing="compact">
+ <listitem>
+ <para>
+ Upper Roman.
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem override="6">
+ <para>
+ Decimal start with 6
+ </para>
+ <orderedlist numeration="loweralpha" spacing="compact">
+ <listitem override="3">
+ <para>
+ Lower alpha with paren
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Autonumbering:
+ </para>
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Autonumber.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ More.
+ </para>
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Nested.
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+ <para>
+ Should not be a list item:
+ </para>
+ <para>
+ M.A. 2007
+ </para>
+ <para>
+ B. Williams
+ </para>
+ </section>
+</section>
+<section xml:id="definition-lists">
+ <title>Definition Lists</title>
+ <para>
+ Tight using spaces:
+ </para>
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Tight using tabs:
+ </para>
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Loose:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ banana
+ </term>
+ <listitem>
+ <para>
+ yellow fruit
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Multiple blocks with italics:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <emphasis>apple</emphasis>
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ contains seeds, crisp, pleasant to taste
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <emphasis>orange</emphasis>
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <programlisting>
+{ orange code block }
+</programlisting>
+ <blockquote>
+ <para>
+ orange block quote
+ </para>
+ </blockquote>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Multiple definitions, tight:
+ </para>
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ computer
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <para>
+ bank
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Multiple definitions, loose:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ computer
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <para>
+ bank
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Blank line after term, indented marker, alternate markers:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ apple
+ </term>
+ <listitem>
+ <para>
+ red fruit
+ </para>
+ <para>
+ computer
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ orange
+ </term>
+ <listitem>
+ <para>
+ orange fruit
+ </para>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ sublist
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ sublist
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+</section>
+<section xml:id="html-blocks">
+ <title>HTML Blocks</title>
+ <para>
+ Simple block on one line:
+ </para>
+ <para>
+ foo
+ </para>
+ <para>
+ And nested without indentation:
+ </para>
+ <para>
+ foo
+ </para>
+ <para>
+ bar
+ </para>
+ <para>
+ Interpreted markdown in a table:
+ </para>
+ This is <emphasis>emphasized</emphasis>
+ And this is <emphasis role="strong">strong</emphasis>
+ <para>
+ Here’s a simple block:
+ </para>
+ <para>
+ foo
+ </para>
+ <para>
+ This should be a code block, though:
+ </para>
+ <programlisting>
+&lt;div&gt;
+ foo
+&lt;/div&gt;
+</programlisting>
+ <para>
+ As should this:
+ </para>
+ <programlisting>
+&lt;div&gt;foo&lt;/div&gt;
+</programlisting>
+ <para>
+ Now, nested:
+ </para>
+ <para>
+ foo
+ </para>
+ <para>
+ This should just be an HTML comment:
+ </para>
+ <para>
+ Multiline:
+ </para>
+ <para>
+ Code block:
+ </para>
+ <programlisting>
+&lt;!-- Comment --&gt;
+</programlisting>
+ <para>
+ Just plain comment, with trailing spaces on the line:
+ </para>
+ <para>
+ Code:
+ </para>
+ <programlisting>
+&lt;hr /&gt;
+</programlisting>
+ <para>
+ Hr’s:
+ </para>
+</section>
+<section xml:id="inline-markup">
+ <title>Inline Markup</title>
+ <para>
+ This is <emphasis>emphasized</emphasis>, and so <emphasis>is
+ this</emphasis>.
+ </para>
+ <para>
+ This is <emphasis role="strong">strong</emphasis>, and so
+ <emphasis role="strong">is this</emphasis>.
+ </para>
+ <para>
+ An <emphasis><link xlink:href="/url">emphasized link</link></emphasis>.
+ </para>
+ <para>
+ <emphasis role="strong"><emphasis>This is strong and
+ em.</emphasis></emphasis>
+ </para>
+ <para>
+ So is <emphasis role="strong"><emphasis>this</emphasis></emphasis> word.
+ </para>
+ <para>
+ <emphasis role="strong"><emphasis>This is strong and
+ em.</emphasis></emphasis>
+ </para>
+ <para>
+ So is <emphasis role="strong"><emphasis>this</emphasis></emphasis> word.
+ </para>
+ <para>
+ This is code: <literal>&gt;</literal>, <literal>$</literal>,
+ <literal>\</literal>, <literal>\$</literal>,
+ <literal>&lt;html&gt;</literal>.
+ </para>
+ <para>
+ <emphasis role="strikethrough">This is
+ <emphasis>strikeout</emphasis>.</emphasis>
+ </para>
+ <para>
+ Superscripts: a<superscript>bc</superscript>d
+ a<superscript><emphasis>hello</emphasis></superscript>
+ a<superscript>hello there</superscript>.
+ </para>
+ <para>
+ Subscripts: H<subscript>2</subscript>O, H<subscript>23</subscript>O,
+ H<subscript>many of them</subscript>O.
+ </para>
+ <para>
+ These should not be superscripts or subscripts, because of the unescaped
+ spaces: a^b c^d, a~b c~d.
+ </para>
+</section>
+<section xml:id="smart-quotes-ellipses-dashes">
+ <title>Smart quotes, ellipses, dashes</title>
+ <para>
+ <quote>Hello,</quote> said the spider. <quote><quote>Shelob</quote> is my
+ name.</quote>
+ </para>
+ <para>
+ <quote>A</quote>, <quote>B</quote>, and <quote>C</quote> are letters.
+ </para>
+ <para>
+ <quote>Oak,</quote> <quote>elm,</quote> and <quote>beech</quote> are names
+ of trees. So is <quote>pine.</quote>
+ </para>
+ <para>
+ <quote>He said, <quote>I want to go.</quote></quote> Were you alive in the
+ 70’s?
+ </para>
+ <para>
+ Here is some quoted <quote><literal>code</literal></quote> and a
+ <quote><link xlink:href="http://example.com/?foo=1&amp;bar=2">quoted
+ link</link></quote>.
+ </para>
+ <para>
+ Some dashes: one—two — three—four — five.
+ </para>
+ <para>
+ Dashes between numbers: 5–7, 255–66, 1987–1999.
+ </para>
+ <para>
+ Ellipses…and…and….
+ </para>
+</section>
+<section xml:id="latex">
+ <title>LaTeX</title>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 2 + 2 = 4
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>x</emphasis> ∈ <emphasis>y</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>α</emphasis> ∧ <emphasis>ω</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 223
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>p</emphasis>-Tree
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Here’s some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Here’s one that has a line break in it:
+ <emphasis>α</emphasis> + <emphasis>ω</emphasis> × <emphasis>x</emphasis><superscript>2</superscript>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ These shouldn’t be math:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ To get the famous equation, write <literal>$e = mc^2$</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It
+ worked if <quote>lot</quote> is emphasized.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Shoes ($20) and socks ($5).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Escaped <literal>$</literal>: $73 <emphasis>this should be
+ emphasized</emphasis> 23$.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Here’s a LaTeX table:
+ </para>
+</section>
+<section xml:id="special-characters">
+ <title>Special Characters</title>
+ <para>
+ Here is some unicode:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ I hat: Î
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ o umlaut: ö
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ section: §
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ set membership: ∈
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ copyright: ©
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ AT&amp;T has an ampersand in their name.
+ </para>
+ <para>
+ AT&amp;T is another way to write it.
+ </para>
+ <para>
+ This &amp; that.
+ </para>
+ <para>
+ 4 &lt; 5.
+ </para>
+ <para>
+ 6 &gt; 5.
+ </para>
+ <para>
+ Backslash: \
+ </para>
+ <para>
+ Backtick: `
+ </para>
+ <para>
+ Asterisk: *
+ </para>
+ <para>
+ Underscore: _
+ </para>
+ <para>
+ Left brace: {
+ </para>
+ <para>
+ Right brace: }
+ </para>
+ <para>
+ Left bracket: [
+ </para>
+ <para>
+ Right bracket: ]
+ </para>
+ <para>
+ Left paren: (
+ </para>
+ <para>
+ Right paren: )
+ </para>
+ <para>
+ Greater-than: &gt;
+ </para>
+ <para>
+ Hash: #
+ </para>
+ <para>
+ Period: .
+ </para>
+ <para>
+ Bang: !
+ </para>
+ <para>
+ Plus: +
+ </para>
+ <para>
+ Minus: -
+ </para>
+</section>
+<section xml:id="links">
+ <title>Links</title>
+ <section xml:id="explicit">
+ <title>Explicit</title>
+ <para>
+ Just a <link xlink:href="/url/">URL</link>.
+ </para>
+ <para>
+ <link xlink:href="/url/">URL and title</link>.
+ </para>
+ <para>
+ <link xlink:href="/url/">URL and title</link>.
+ </para>
+ <para>
+ <link xlink:href="/url/">URL and title</link>.
+ </para>
+ <para>
+ <link xlink:href="/url/">URL and title</link>
+ </para>
+ <para>
+ <link xlink:href="/url/">URL and title</link>
+ </para>
+ <para>
+ <link xlink:href="/url/with_underscore">with_underscore</link>
+ </para>
+ <para>
+ Email link (<email>nobody@nowhere.net</email>)
+ </para>
+ <para>
+ <link xlink:href="">Empty</link>.
+ </para>
+ </section>
+ <section xml:id="reference">
+ <title>Reference</title>
+ <para>
+ Foo <link xlink:href="/url/">bar</link>.
+ </para>
+ <para>
+ With <link xlink:href="/url/">embedded [brackets]</link>.
+ </para>
+ <para>
+ <link xlink:href="/url/">b</link> by itself should be a link.
+ </para>
+ <para>
+ Indented <link xlink:href="/url">once</link>.
+ </para>
+ <para>
+ Indented <link xlink:href="/url">twice</link>.
+ </para>
+ <para>
+ Indented <link xlink:href="/url">thrice</link>.
+ </para>
+ <para>
+ This should [not][] be a link.
+ </para>
+ <programlisting>
+[not]: /url
+</programlisting>
+ <para>
+ Foo <link xlink:href="/url/">bar</link>.
+ </para>
+ <para>
+ Foo <link xlink:href="/url/">biz</link>.
+ </para>
+ </section>
+ <section xml:id="with-ampersands">
+ <title>With ampersands</title>
+ <para>
+ Here’s a <link xlink:href="http://example.com/?foo=1&amp;bar=2">link
+ with an ampersand in the URL</link>.
+ </para>
+ <para>
+ Here’s a link with an amersand in the link text:
+ <link xlink:href="http://att.com/">AT&amp;T</link>.
+ </para>
+ <para>
+ Here’s an <link xlink:href="/script?foo=1&amp;bar=2">inline link</link>.
+ </para>
+ <para>
+ Here’s an <link xlink:href="/script?foo=1&amp;bar=2">inline link in
+ pointy braces</link>.
+ </para>
+ </section>
+ <section xml:id="autolinks">
+ <title>Autolinks</title>
+ <para>
+ With an ampersand:
+ <link xlink:href="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</link>
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ In a list?
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <link xlink:href="http://example.com/">http://example.com/</link>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ It should.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ An e-mail address: <email>nobody@nowhere.net</email>
+ </para>
+ <blockquote>
+ <para>
+ Blockquoted:
+ <link xlink:href="http://example.com/">http://example.com/</link>
+ </para>
+ </blockquote>
+ <para>
+ Auto-links should not occur here:
+ <literal>&lt;http://example.com/&gt;</literal>
+ </para>
+ <programlisting>
+or here: &lt;http://example.com/&gt;
+</programlisting>
+ </section>
+</section>
+<section xml:id="images">
+ <title>Images</title>
+ <para>
+ From <quote>Voyage dans la Lune</quote> by Georges Melies (1902):
+ </para>
+ <figure>
+ <title>lalune</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="lalune.jpg" />
+ </imageobject>
+ <textobject><phrase>lalune</phrase></textobject>
+ </mediaobject>
+ </figure>
+ <para>
+ Here is a movie <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="movie.jpg" />
+ </imageobject>
+ </inlinemediaobject> icon.
+ </para>
+</section>
+<section xml:id="footnotes">
+ <title>Footnotes</title>
+ <para>
+ Here is a footnote reference,<footnote>
+ <para>
+ Here is the footnote. It can go anywhere after the footnote reference.
+ It need not be placed at the end of the document.
+ </para>
+ </footnote> and another.<footnote>
+ <para>
+ Here’s the long note. This one contains multiple blocks.
+ </para>
+ <para>
+ Subsequent blocks are indented to show that they belong to the
+ footnote (as with list items).
+ </para>
+ <programlisting>
+ { &lt;code&gt; }
+</programlisting>
+ <para>
+ If you want, you can indent every line, but you can also be lazy and
+ just indent the first line of each block.
+ </para>
+ </footnote> This should <emphasis>not</emphasis> be a footnote reference,
+ because it contains a space.[^my note] Here is an inline note.<footnote>
+ <para>
+ This is <emphasis>easier</emphasis> to type. Inline notes may contain
+ <link xlink:href="http://google.com">links</link> and
+ <literal>]</literal> verbatim characters, as well as [bracketed text].
+ </para>
+ </footnote>
+ </para>
+ <blockquote>
+ <para>
+ Notes can go in quotes.<footnote>
+ <para>
+ In quote.
+ </para>
+ </footnote>
+ </para>
+ </blockquote>
+ <orderedlist numeration="arabic" spacing="compact">
+ <listitem>
+ <para>
+ And in list items.<footnote>
+ <para>
+ In list.
+ </para>
+ </footnote>
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ This paragraph should not be part of the note, as it is not indented.
+ </para>
+</section>
+</article>
diff --git a/test/writer.dokuwiki b/test/writer.dokuwiki
new file mode 100644
index 000000000..4ba1b7054
--- /dev/null
+++ b/test/writer.dokuwiki
@@ -0,0 +1,638 @@
+This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.
+
+
+----
+
+====== Headers ======
+
+===== Level 2 with an embedded link =====
+
+==== Level 3 with emphasis ====
+
+=== Level 4 ===
+
+== Level 5 ==
+
+====== Level 1 ======
+
+===== Level 2 with emphasis =====
+
+==== Level 3 ====
+
+with no blank line
+
+===== Level 2 =====
+
+with no blank line
+
+
+----
+
+====== Paragraphs ======
+
+Here’s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
+
+Here’s one with a bullet. * criminey.
+
+There should be a hard line break\\
+here.
+
+
+----
+
+====== Block Quotes ======
+
+E-mail style:
+
+> This is a block quote. It is pretty short.
+
+<HTML><blockquote>
+Code in a block quote:
+
+<code>
+sub status {
+ print "working";
+}
+</code>
+A list:
+
+ - item one
+ - item two
+
+Nested block quotes:
+
+> nested
+
+> nested
+</blockquote></HTML>
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+
+----
+
+====== Code Blocks ======
+
+Code:
+
+<code>
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+</code>
+And:
+
+<code>
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+</code>
+
+----
+
+====== Lists ======
+
+===== Unordered =====
+
+Asterisks tight:
+
+ * asterisk 1
+ * asterisk 2
+ * asterisk 3
+
+Asterisks loose:
+
+ * asterisk 1
+ * asterisk 2
+ * asterisk 3
+
+Pluses tight:
+
+ * Plus 1
+ * Plus 2
+ * Plus 3
+
+Pluses loose:
+
+ * Plus 1
+ * Plus 2
+ * Plus 3
+
+Minuses tight:
+
+ * Minus 1
+ * Minus 2
+ * Minus 3
+
+Minuses loose:
+
+ * Minus 1
+ * Minus 2
+ * Minus 3
+
+===== Ordered =====
+
+Tight:
+
+ - First
+ - Second
+ - Third
+
+and:
+
+ - One
+ - Two
+ - Three
+
+Loose using tabs:
+
+ - First
+ - Second
+ - Third
+
+and using spaces:
+
+ - One
+ - Two
+ - Three
+
+Multiple paragraphs:
+
+<HTML><ol style="list-style-type: decimal;"></HTML>
+<HTML><li></HTML><HTML><p></HTML>Item 1, graf one.<HTML></p></HTML>
+<HTML><p></HTML>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.<HTML></p></HTML><HTML></li></HTML>
+<HTML><li></HTML><HTML><p></HTML>Item 2.<HTML></p></HTML><HTML></li></HTML>
+<HTML><li></HTML><HTML><p></HTML>Item 3.<HTML></p></HTML><HTML></li></HTML><HTML></ol></HTML>
+
+===== Nested =====
+
+ * Tab
+ * Tab
+ * Tab
+
+Here’s another:
+
+ - First
+ - Second:
+ * Fee
+ * Fie
+ * Foe
+ - Third
+
+Same thing but with paragraphs:
+
+ - First
+ - Second:
+ * Fee
+ * Fie
+ * Foe
+ - Third
+
+===== Tabs and spaces =====
+
+ * this is a list item indented with tabs
+ * this is a list item indented with spaces
+ * this is an example list item indented with tabs
+ * this is an example list item indented with spaces
+
+===== Fancy list markers =====
+
+<HTML><ol start="2" style="list-style-type: decimal;"></HTML>
+<HTML><li></HTML>begins with 2<HTML></li></HTML>
+<HTML><li></HTML><HTML><p></HTML>and now 3<HTML></p></HTML>
+<HTML><p></HTML>with a continuation<HTML></p></HTML>
+<HTML><ol start="4" style="list-style-type: lower-roman;"></HTML>
+<HTML><li></HTML>sublist with roman numerals, starting with 4<HTML></li></HTML>
+<HTML><li></HTML>more items
+<HTML><ol style="list-style-type: upper-alpha;"></HTML>
+<HTML><li></HTML>a subsublist<HTML></li></HTML>
+<HTML><li></HTML>a subsublist<HTML></li></HTML><HTML></ol></HTML>
+<HTML></li></HTML><HTML></ol></HTML>
+<HTML></li></HTML><HTML></ol></HTML>
+
+Nesting:
+
+<HTML><ol style="list-style-type: upper-alpha;"></HTML>
+<HTML><li></HTML>Upper Alpha
+<HTML><ol style="list-style-type: upper-roman;"></HTML>
+<HTML><li></HTML>Upper Roman.
+<HTML><ol start="6" style="list-style-type: decimal;"></HTML>
+<HTML><li></HTML>Decimal start with 6
+<HTML><ol start="3" style="list-style-type: lower-alpha;"></HTML>
+<HTML><li></HTML>Lower alpha with paren<HTML></li></HTML><HTML></ol></HTML>
+<HTML></li></HTML><HTML></ol></HTML>
+<HTML></li></HTML><HTML></ol></HTML>
+<HTML></li></HTML><HTML></ol></HTML>
+
+Autonumbering:
+
+ - Autonumber.
+ - More.
+ - Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+
+----
+
+====== Definition Lists ======
+
+Tight using spaces:
+
+ * **apple** red fruit
+ * **orange** orange fruit
+ * **banana** yellow fruit
+
+Tight using tabs:
+
+ * **apple** red fruit
+ * **orange** orange fruit
+ * **banana** yellow fruit
+
+Loose:
+
+ * **apple** red fruit
+ * **orange** orange fruit
+ * **banana** yellow fruit
+
+Multiple blocks with italics:
+
+<HTML><dl></HTML>
+<HTML><dt></HTML>//apple//<HTML></dt></HTML>
+<HTML><dd></HTML><HTML><p></HTML>red fruit<HTML></p></HTML>
+<HTML><p></HTML>contains seeds, crisp, pleasant to taste<HTML></p></HTML><HTML></dd></HTML>
+<HTML><dt></HTML>//orange//<HTML></dt></HTML>
+<HTML><dd></HTML><HTML><p></HTML>orange fruit<HTML></p></HTML>
+<code>
+{ orange code block }
+</code>
+> <HTML><p></HTML>orange block quote<HTML></p></HTML>
+<HTML></dd></HTML><HTML></dl></HTML>
+
+Multiple definitions, tight:
+
+ * **apple** red fruitcomputer
+ * **orange** orange fruitbank
+
+Multiple definitions, loose:
+
+ * **apple** red fruitcomputer
+ * **orange** orange fruitbank
+
+Blank line after term, indented marker, alternate markers:
+
+ * **apple** red fruitcomputer
+ * **orange** orange fruit
+ - sublist
+ - sublist
+
+====== HTML Blocks ======
+
+Simple block on one line:
+
+foo
+
+And nested without indentation:
+
+foo
+
+
+
+bar
+
+
+Interpreted markdown in a table:
+
+<HTML>
+<table>
+<tr>
+<td>
+</HTML>
+This is //emphasized//
+<HTML>
+</td>
+<td>
+</HTML>
+And this is **strong**
+<HTML>
+</td>
+</tr>
+</table>
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+</HTML>
+Here’s a simple block:
+
+foo
+
+
+This should be a code block, though:
+
+<code>
+<div>
+ foo
+</div>
+</code>
+As should this:
+
+<code>
+<div>foo</div>
+</code>
+Now, nested:
+
+foo
+
+
+
+This should just be an HTML comment:
+
+<HTML>
+<!-- Comment -->
+</HTML>
+Multiline:
+
+<HTML>
+<!--
+Blah
+Blah
+-->
+<!--
+ This is another comment.
+-->
+</HTML>
+Code block:
+
+<code>
+<!-- Comment -->
+</code>
+Just plain comment, with trailing spaces on the line:
+
+<HTML>
+<!-- foo -->
+</HTML>
+Code:
+
+<code>
+<hr />
+</code>
+Hr’s:
+
+<HTML>
+<hr>
+<hr />
+<hr />
+<hr>
+<hr />
+<hr />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar">
+</HTML>
+
+----
+
+====== Inline Markup ======
+
+This is //emphasized//, and so //is this//.
+
+This is **strong**, and so **is this**.
+
+An //[[url|emphasized link]]//.
+
+**//This is strong and em.//**
+
+So is **//this//** word.
+
+**//This is strong and em.//**
+
+So is **//this//** word.
+
+This is code: ''%%>%%'', ''%%$%%'', ''%%\%%'', ''%%\$%%'', ''%%<html>%%''.
+
+<del>This is //strikeout//.</del>
+
+Superscripts: a<sup>bc</sup>d a<sup>//hello//</sup> a<sup>hello there</sup>.
+
+Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.
+
+These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
+
+
+----
+
+====== Smart quotes, ellipses, dashes ======
+
+“Hello,” said the spider. “‘Shelob’ is my name.”
+
+‘A’, ‘B’, and ‘C’ are letters.
+
+‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
+
+‘He said, “I want to go.”’ Were you alive in the 70’s?
+
+Here is some quoted ‘''%%code%%''’ and a “[[http://example.com/?foo=1&bar=2|quoted link]]”.
+
+Some dashes: one—two — three—four — five.
+
+Dashes between numbers: 5–7, 255–66, 1987–1999.
+
+Ellipses…and…and….
+
+
+----
+
+====== LaTeX ======
+
+ *
+ * $2+2=4$
+ * $x \in y$
+ * $\alpha \wedge \omega$
+ * $223$
+ * $p$-Tree
+ * Here’s some display math: $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+ * Here’s one that has a line break in it: $\alpha + \omega \times x^2$.
+
+These shouldn’t be math:
+
+ * To get the famous equation, write ''%%$e = mc^2$%%''.
+ * $22,000 is a //lot// of money. So is $34,000. (It worked if “lot” is emphasized.)
+ * Shoes ($20) and socks ($5).
+ * Escaped ''%%$%%'': $73 //this should be emphasized// 23$.
+
+Here’s a LaTeX table:
+
+
+
+----
+
+====== Special Characters ======
+
+Here is some unicode:
+
+ * I hat: Î
+ * o umlaut: ö
+ * section: §
+ * set membership: ∈
+ * copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+
+----
+
+====== Links ======
+
+===== Explicit =====
+
+Just a [[url/|URL]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]]
+
+[[url/|URL and title]]
+
+[[url/with_underscore|with_underscore]]
+
+[[mailto:nobody@nowhere.net|Email link]]
+
+[[|Empty]].
+
+===== Reference =====
+
+Foo [[url/|bar]].
+
+With [[url/|embedded [brackets]]].
+
+[[url/|b]] by itself should be a link.
+
+Indented [[url|once]].
+
+Indented [[url|twice]].
+
+Indented [[url|thrice]].
+
+This should [not][] be a link.
+
+<code>
+[not]: /url
+</code>
+Foo [[url/|bar]].
+
+Foo [[url/|biz]].
+
+===== With ampersands =====
+
+Here’s a [[http://example.com/?foo=1&bar=2|link with an ampersand in the URL]].
+
+Here’s a link with an amersand in the link text: [[http://att.com/|AT&T]].
+
+Here’s an [[script?foo=1&bar=2|inline link]].
+
+Here’s an [[script?foo=1&bar=2|inline link in pointy braces]].
+
+===== Autolinks =====
+
+With an ampersand: http://example.com/?foo=1&bar=2
+
+ * In a list?
+ * http://example.com/
+ * It should.
+
+An e-mail address: <nobody@nowhere.net>
+
+> Blockquoted: http://example.com/
+
+Auto-links should not occur here: ''%%<http://example.com/>%%''
+
+<code>
+or here: <http://example.com/>
+</code>
+
+----
+
+====== Images ======
+
+From “Voyage dans la Lune” by Georges Melies (1902):
+
+{{:lalune.jpg|Voyage dans la Lune lalune}}
+
+Here is a movie {{:movie.jpg|movie}} icon.
+
+
+----
+
+====== Footnotes ======
+
+Here is a footnote reference,((Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
+)) and another.((Here’s the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the footnote (as with list items).
+
+<code>
+ { <code> }
+</code>
+If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
+)) This should //not// be a footnote reference, because it contains a space.[^my note] Here is an inline note.((This is //easier// to type. Inline notes may contain [[http://google.com|links]] and ''%%]%%'' verbatim characters, as well as [bracketed text].
+))
+
+> Notes can go in quotes.((In quote.
+> ))
+
+ - And in list items.((In list.))
+
+This paragraph should not be part of the note, as it is not indented.
diff --git a/test/writer.fb2 b/test/writer.fb2
new file mode 100644
index 000000000..20f566334
--- /dev/null
+++ b/test/writer.fb2
@@ -0,0 +1,1015 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink">
+<description>
+<title-info>
+<genre>unrecognised</genre>
+<book-title>Pandoc Test Suite</book-title>
+<author>
+<first-name>John</first-name>
+<last-name>MacFarlane</last-name>
+</author>
+<author>
+<nickname>Anonymous</nickname>
+</author>
+<date>July 17, 2006</date>
+</title-info>
+<document-info>
+<program-used>pandoc</program-used>
+</document-info>
+</description>
+<body>
+<title>
+<p>Pandoc Test Suite</p>
+</title>
+<section>
+<p>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Headers</p>
+</title>
+<section>
+<title>
+<p>Level 2 with an embedded link &lt;/url&gt;</p>
+</title>
+<section>
+<title>
+<p>Level 3 with emphasis</p>
+</title>
+<section>
+<title>
+<p>Level 4</p>
+</title>
+<section>
+<title>
+<p>Level 5</p>
+</title>
+</section>
+</section>
+</section>
+</section>
+</section>
+<section>
+<title>
+<p>Level 1</p>
+</title>
+<section>
+<title>
+<p>Level 2 with emphasis</p>
+</title>
+<section>
+<title>
+<p>Level 3</p>
+</title>
+<p>with no blank line</p>
+</section>
+</section>
+<section>
+<title>
+<p>Level 2</p>
+</title>
+<p>with no blank line</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+</section>
+<section>
+<title>
+<p>Paragraphs</p>
+</title>
+<p>Here’s a regular paragraph.</p>
+<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p>
+<p>Here’s one with a bullet. * criminey.</p>
+<p>There should be a hard line break<empty-line />here.</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Block Quotes</p>
+</title>
+<p>E-mail style:</p>
+<cite>
+<p>This is a block quote. It is pretty short.</p>
+</cite>
+<cite>
+<p>Code in a block quote:</p>
+<empty-line />
+<p>
+<code>sub status {</code>
+</p>
+<p>
+<code> print &quot;working&quot;;</code>
+</p>
+<p>
+<code>}</code>
+</p>
+<empty-line />
+<p>A list:</p>
+<p>1. item one</p>
+<p>2. item two</p>
+<p>Nested block quotes:</p>
+<cite>
+<p>nested</p>
+</cite>
+<cite>
+<p>nested</p>
+</cite>
+</cite>
+<p>This should not be a block quote: 2 &gt; 1.</p>
+<p>And a following paragraph.</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Code Blocks</p>
+</title>
+<p>Code:</p>
+<empty-line />
+<p>
+<code>---- (should be four hyphens)</code>
+</p>
+<p>
+<code>
+</code>
+</p>
+<p>
+<code>sub status {</code>
+</p>
+<p>
+<code> print &quot;working&quot;;</code>
+</p>
+<p>
+<code>}</code>
+</p>
+<p>
+<code>
+</code>
+</p>
+<p>
+<code>this code block is indented by one tab</code>
+</p>
+<empty-line />
+<p>And:</p>
+<empty-line />
+<p>
+<code> this code block is indented by two tabs</code>
+</p>
+<p>
+<code>
+</code>
+</p>
+<p>
+<code>These should not be escaped: \$ \\ \&gt; \[ \{</code>
+</p>
+<empty-line />
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Lists</p>
+</title>
+<section>
+<title>
+<p>Unordered</p>
+</title>
+<p>Asterisks tight:</p>
+<p>• asterisk 1</p>
+<p>• asterisk 2</p>
+<p>• asterisk 3</p>
+<p>Asterisks loose:</p>
+<p>• asterisk 1</p>
+<empty-line />
+<p>• asterisk 2</p>
+<empty-line />
+<p>• asterisk 3</p>
+<empty-line />
+<p>Pluses tight:</p>
+<p>• Plus 1</p>
+<p>• Plus 2</p>
+<p>• Plus 3</p>
+<p>Pluses loose:</p>
+<p>• Plus 1</p>
+<empty-line />
+<p>• Plus 2</p>
+<empty-line />
+<p>• Plus 3</p>
+<empty-line />
+<p>Minuses tight:</p>
+<p>• Minus 1</p>
+<p>• Minus 2</p>
+<p>• Minus 3</p>
+<p>Minuses loose:</p>
+<p>• Minus 1</p>
+<empty-line />
+<p>• Minus 2</p>
+<empty-line />
+<p>• Minus 3</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Ordered</p>
+</title>
+<p>Tight:</p>
+<p>1. First</p>
+<p>2. Second</p>
+<p>3. Third</p>
+<p>and:</p>
+<p>1. One</p>
+<p>2. Two</p>
+<p>3. Three</p>
+<p>Loose using tabs:</p>
+<p>1. First</p>
+<empty-line />
+<p>2. Second</p>
+<empty-line />
+<p>3. Third</p>
+<empty-line />
+<p>and using spaces:</p>
+<p>1. One</p>
+<empty-line />
+<p>2. Two</p>
+<empty-line />
+<p>3. Three</p>
+<empty-line />
+<p>Multiple paragraphs:</p>
+<p>1. Item 1, graf one.</p>
+<empty-line />
+<p>   Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.</p>
+<empty-line />
+<p>2. Item 2.</p>
+<empty-line />
+<p>3. Item 3.</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Nested</p>
+</title>
+<p>• Tab</p>
+<p>• • Tab</p>
+<p>• • • Tab</p>
+<p>Here’s another:</p>
+<p>1. First</p>
+<p>2. Second:</p>
+<p>2. • Fee</p>
+<p>2. • Fie</p>
+<p>2. • Foe</p>
+<p>3. Third</p>
+<p>Same thing but with paragraphs:</p>
+<p>1. First</p>
+<empty-line />
+<p>2. Second:</p>
+<empty-line />
+<p>2. • Fee</p>
+<p>2. • Fie</p>
+<p>2. • Foe</p>
+<p>3. Third</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Tabs and spaces</p>
+</title>
+<p>• this is a list item indented with tabs</p>
+<empty-line />
+<p>• this is a list item indented with spaces</p>
+<empty-line />
+<p>• • this is an example list item indented with tabs</p>
+<empty-line />
+<p>• • this is an example list item indented with spaces</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Fancy list markers</p>
+</title>
+<p>(2) begins with 2</p>
+<p>(3) and now 3</p>
+<empty-line />
+<p>    with a continuation</p>
+<empty-line />
+<p>(3) iv. sublist with roman numerals, starting with 4</p>
+<p>(3) v. more items</p>
+<p>(3) v. (A) a subsublist</p>
+<p>(3) v. (B) a subsublist</p>
+<p>Nesting:</p>
+<p>A. Upper Alpha</p>
+<p>A. I. Upper Roman.</p>
+<p>A. I. (6) Decimal start with 6</p>
+<p>A. I. (6) c) Lower alpha with paren</p>
+<p>Autonumbering:</p>
+<p>1. Autonumber.</p>
+<p>2. More.</p>
+<p>2. 1. Nested.</p>
+<p>Should not be a list item:</p>
+<p>M.A. 2007</p>
+<p>B. Williams</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+</section>
+<section>
+<title>
+<p>Definition Lists</p>
+</title>
+<p>Tight using spaces:</p>
+<p>
+<strong>apple</strong>
+</p>
+<p>    red fruit</p>
+<p>
+<strong>orange</strong>
+</p>
+<p>    orange fruit</p>
+<p>
+<strong>banana</strong>
+</p>
+<p>    yellow fruit</p>
+<p>Tight using tabs:</p>
+<p>
+<strong>apple</strong>
+</p>
+<p>    red fruit</p>
+<p>
+<strong>orange</strong>
+</p>
+<p>    orange fruit</p>
+<p>
+<strong>banana</strong>
+</p>
+<p>    yellow fruit</p>
+<p>Loose:</p>
+<p>
+<strong>apple</strong>
+</p>
+<p>    red fruit</p>
+<empty-line />
+<p>
+<strong>orange</strong>
+</p>
+<p>    orange fruit</p>
+<empty-line />
+<p>
+<strong>banana</strong>
+</p>
+<p>    yellow fruit</p>
+<empty-line />
+<p>Multiple blocks with italics:</p>
+<p>
+<strong>
+<emphasis>apple</emphasis>
+</strong>
+</p>
+<p>    red fruit</p>
+<empty-line />
+<p>    contains seeds, crisp, pleasant to taste</p>
+<empty-line />
+<p>
+<strong>
+<emphasis>orange</emphasis>
+</strong>
+</p>
+<p>    orange fruit</p>
+<empty-line />
+<empty-line />
+<p>
+<code>    { orange code block }</code>
+</p>
+<empty-line />
+<cite>
+<p>    orange block quote</p>
+</cite>
+<p>Multiple definitions, tight:</p>
+<p>
+<strong>apple</strong>
+</p>
+<p>    red fruit</p>
+<p>    computer</p>
+<p>
+<strong>orange</strong>
+</p>
+<p>    orange fruit</p>
+<p>    bank</p>
+<p>Multiple definitions, loose:</p>
+<p>
+<strong>apple</strong>
+</p>
+<p>    red fruit</p>
+<empty-line />
+<p>    computer</p>
+<empty-line />
+<p>
+<strong>orange</strong>
+</p>
+<p>    orange fruit</p>
+<empty-line />
+<p>    bank</p>
+<empty-line />
+<p>Blank line after term, indented marker, alternate markers:</p>
+<p>
+<strong>apple</strong>
+</p>
+<p>    red fruit</p>
+<empty-line />
+<p>    computer</p>
+<empty-line />
+<p>
+<strong>orange</strong>
+</p>
+<p>    orange fruit</p>
+<empty-line />
+<p>1. sublist</p>
+<p>2. sublist</p>
+</section>
+<section>
+<title>
+<p>HTML Blocks</p>
+</title>
+<p>Simple block on one line:</p>foo<p>And nested without indentation:</p>
+<p>foo</p>bar<p>Interpreted markdown in a table:</p>This is <emphasis>emphasized</emphasis>And this is <strong>strong</strong>
+<p>Here’s a simple block:</p>
+<p>foo</p>
+<p>This should be a code block, though:</p>
+<empty-line />
+<p>
+<code>&lt;div&gt;</code>
+</p>
+<p>
+<code> foo</code>
+</p>
+<p>
+<code>&lt;/div&gt;</code>
+</p>
+<empty-line />
+<p>As should this:</p>
+<empty-line />
+<p>
+<code>&lt;div&gt;foo&lt;/div&gt;</code>
+</p>
+<empty-line />
+<p>Now, nested:</p>foo<p>This should just be an HTML comment:</p>
+<p>Multiline:</p>
+<p>Code block:</p>
+<empty-line />
+<p>
+<code>&lt;!-- Comment --&gt;</code>
+</p>
+<empty-line />
+<p>Just plain comment, with trailing spaces on the line:</p>
+<p>Code:</p>
+<empty-line />
+<p>
+<code>&lt;hr /&gt;</code>
+</p>
+<empty-line />
+<p>Hr’s:</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Inline Markup</p>
+</title>
+<p>This is <emphasis>emphasized</emphasis>, and so <emphasis>is this</emphasis>.</p>
+<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
+<p>An <emphasis>emphasized link<a l:href="#l1" type="note">
+<sup>[1]</sup>
+</a>
+</emphasis>.</p>
+<p>
+<strong>
+<emphasis>This is strong and em.</emphasis>
+</strong>
+</p>
+<p>So is <strong>
+<emphasis>this</emphasis>
+</strong> word.</p>
+<p>
+<strong>
+<emphasis>This is strong and em.</emphasis>
+</strong>
+</p>
+<p>So is <strong>
+<emphasis>this</emphasis>
+</strong> word.</p>
+<p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p>
+<p>
+<strikethrough>This is <emphasis>strikeout</emphasis>.</strikethrough>
+</p>
+<p>Superscripts: a<sup>bc</sup>d a<sup>
+<emphasis>hello</emphasis>
+</sup> a<sup>hello there</sup>.</p>
+<p>Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.</p>
+<p>These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Smart quotes, ellipses, dashes</p>
+</title>
+<p>“Hello,” said the spider. “‘Shelob’ is my name.”</p>
+<p>‘A’, ‘B’, and ‘C’ are letters.</p>
+<p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’</p>
+<p>‘He said, “I want to go.”’ Were you alive in the 70’s?</p>
+<p>Here is some quoted ‘<code>code</code>’ and a “quoted link<a l:href="#l2" type="note">
+<sup>[2]</sup>
+</a>”.</p>
+<p>Some dashes: one—two — three—four — five.</p>
+<p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p>
+<p>Ellipses…and…and….</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>LaTeX</p>
+</title>
+<p>• </p>
+<p>• <code>2+2=4</code>
+</p>
+<p>• <code>x \in y</code>
+</p>
+<p>• <code>\alpha \wedge \omega</code>
+</p>
+<p>• <code>223</code>
+</p>
+<p>• <code>p</code>-Tree</p>
+<p>• Here’s some display math: <code>\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</code>
+</p>
+<p>• Here’s one that has a line break in it: <code>\alpha + \omega \times x^2</code>.</p>
+<p>These shouldn’t be math:</p>
+<p>• To get the famous equation, write <code>$e = mc^2$</code>.</p>
+<p>• $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It worked if “lot” is emphasized.)</p>
+<p>• Shoes ($20) and socks ($5).</p>
+<p>• Escaped <code>$</code>: $73 <emphasis>this should be emphasized</emphasis> 23$.</p>
+<p>Here’s a LaTeX table:</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Special Characters</p>
+</title>
+<p>Here is some unicode:</p>
+<p>• I hat: Î</p>
+<p>• o umlaut: ö</p>
+<p>• section: §</p>
+<p>• set membership: ∈</p>
+<p>• copyright: ©</p>
+<p>AT&amp;T has an ampersand in their name.</p>
+<p>AT&amp;T is another way to write it.</p>
+<p>This &amp; that.</p>
+<p>4 &lt; 5.</p>
+<p>6 &gt; 5.</p>
+<p>Backslash: \</p>
+<p>Backtick: `</p>
+<p>Asterisk: *</p>
+<p>Underscore: _</p>
+<p>Left brace: {</p>
+<p>Right brace: }</p>
+<p>Left bracket: [</p>
+<p>Right bracket: ]</p>
+<p>Left paren: (</p>
+<p>Right paren: )</p>
+<p>Greater-than: &gt;</p>
+<p>Hash: #</p>
+<p>Period: .</p>
+<p>Bang: !</p>
+<p>Plus: +</p>
+<p>Minus: -</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Links</p>
+</title>
+<section>
+<title>
+<p>Explicit</p>
+</title>
+<p>Just a URL<a l:href="#l3" type="note">
+<sup>[3]</sup>
+</a>.</p>
+<p>URL and title<a l:href="#l4" type="note">
+<sup>[4]</sup>
+</a>.</p>
+<p>URL and title<a l:href="#l5" type="note">
+<sup>[5]</sup>
+</a>.</p>
+<p>URL and title<a l:href="#l6" type="note">
+<sup>[6]</sup>
+</a>.</p>
+<p>URL and title<a l:href="#l7" type="note">
+<sup>[7]</sup>
+</a>
+</p>
+<p>URL and title<a l:href="#l8" type="note">
+<sup>[8]</sup>
+</a>
+</p>
+<p>with_underscore<a l:href="#l9" type="note">
+<sup>[9]</sup>
+</a>
+</p>
+<p>Email link<a l:href="#l10" type="note">
+<sup>[10]</sup>
+</a>
+</p>
+<p>Empty<a l:href="#l11" type="note">
+<sup>[11]</sup>
+</a>.</p>
+</section>
+<section>
+<title>
+<p>Reference</p>
+</title>
+<p>Foo bar<a l:href="#l12" type="note">
+<sup>[12]</sup>
+</a>.</p>
+<p>With embedded [brackets]<a l:href="#l13" type="note">
+<sup>[13]</sup>
+</a>.</p>
+<p>b<a l:href="#l14" type="note">
+<sup>[14]</sup>
+</a> by itself should be a link.</p>
+<p>Indented once<a l:href="#l15" type="note">
+<sup>[15]</sup>
+</a>.</p>
+<p>Indented twice<a l:href="#l16" type="note">
+<sup>[16]</sup>
+</a>.</p>
+<p>Indented thrice<a l:href="#l17" type="note">
+<sup>[17]</sup>
+</a>.</p>
+<p>This should [not][] be a link.</p>
+<empty-line />
+<p>
+<code>[not]: /url</code>
+</p>
+<empty-line />
+<p>Foo bar<a l:href="#l18" type="note">
+<sup>[18]</sup>
+</a>.</p>
+<p>Foo biz<a l:href="#l19" type="note">
+<sup>[19]</sup>
+</a>.</p>
+</section>
+<section>
+<title>
+<p>With ampersands</p>
+</title>
+<p>Here’s a link with an ampersand in the URL<a l:href="#l20" type="note">
+<sup>[20]</sup>
+</a>.</p>
+<p>Here’s a link with an amersand in the link text: AT&amp;T<a l:href="#l21" type="note">
+<sup>[21]</sup>
+</a>.</p>
+<p>Here’s an inline link<a l:href="#l22" type="note">
+<sup>[22]</sup>
+</a>.</p>
+<p>Here’s an inline link in pointy braces<a l:href="#l23" type="note">
+<sup>[23]</sup>
+</a>.</p>
+</section>
+<section>
+<title>
+<p>Autolinks</p>
+</title>
+<p>With an ampersand: http://example.com/?foo=1&amp;bar=2<a l:href="#l24" type="note">
+<sup>[24]</sup>
+</a>
+</p>
+<p>• In a list?</p>
+<p>• http://example.com/<a l:href="#l25" type="note">
+<sup>[25]</sup>
+</a>
+</p>
+<p>• It should.</p>
+<p>An e-mail address: nobody@nowhere.net<a l:href="#l26" type="note">
+<sup>[26]</sup>
+</a>
+</p>
+<cite>
+<p>Blockquoted: http://example.com/<a l:href="#l27" type="note">
+<sup>[27]</sup>
+</a>
+</p>
+</cite>
+<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code>
+</p>
+<empty-line />
+<p>
+<code>or here: &lt;http://example.com/&gt;</code>
+</p>
+<empty-line />
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+</section>
+<section>
+<title>
+<p>Images</p>
+</title>
+<p>From “Voyage dans la Lune” by Georges Melies (1902):</p>
+<image l:href="#image1" l:type="imageType" alt="lalune" title="Voyage dans la Lune" />
+<p>Here is a movie <image l:href="#image2" l:type="inlineImageType" alt="movie" /> icon.</p>
+<empty-line />
+<p>——————————</p>
+<empty-line />
+</section>
+<section>
+<title>
+<p>Footnotes</p>
+</title>
+<p>Here is a footnote reference,<a l:href="#n28" type="note">
+<sup>[28]</sup>
+</a> and another.<a l:href="#n29" type="note">
+<sup>[29]</sup>
+</a> This should <emphasis>not</emphasis> be a footnote reference, because it contains a space.[^my note] Here is an inline note.<a l:href="#n30" type="note">
+<sup>[30]</sup>
+</a>
+</p>
+<cite>
+<p>Notes can go in quotes.<a l:href="#n31" type="note">
+<sup>[31]</sup>
+</a>
+</p>
+</cite>
+<p>1. And in list items.<a l:href="#n32" type="note">
+<sup>[32]</sup>
+</a>
+</p>
+<p>This paragraph should not be part of the note, as it is not indented.</p>
+</section>
+</body>
+<body name="notes">
+<section id="l1">
+<title>
+<p>1</p>
+</title>
+<p>
+<code>/url</code>
+</p>
+</section>
+<section id="l2">
+<title>
+<p>2</p>
+</title>
+<p>
+<code>http://example.com/?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l3">
+<title>
+<p>3</p>
+</title>
+<p>
+<code>/url/</code>
+</p>
+</section>
+<section id="l4">
+<title>
+<p>4</p>
+</title>
+<p>title: <code>/url/</code>
+</p>
+</section>
+<section id="l5">
+<title>
+<p>5</p>
+</title>
+<p>title preceded by two spaces: <code>/url/</code>
+</p>
+</section>
+<section id="l6">
+<title>
+<p>6</p>
+</title>
+<p>title preceded by a tab: <code>/url/</code>
+</p>
+</section>
+<section id="l7">
+<title>
+<p>7</p>
+</title>
+<p>title with &quot;quotes&quot; in it: <code>/url/</code>
+</p>
+</section>
+<section id="l8">
+<title>
+<p>8</p>
+</title>
+<p>title with single quotes: <code>/url/</code>
+</p>
+</section>
+<section id="l9">
+<title>
+<p>9</p>
+</title>
+<p>
+<code>/url/with_underscore</code>
+</p>
+</section>
+<section id="l10">
+<title>
+<p>10</p>
+</title>
+<p>
+<code>mailto:nobody@nowhere.net</code>
+</p>
+</section>
+<section id="l11">
+<title>
+<p>11</p>
+</title>
+<p>
+<code>
+</code>
+</p>
+</section>
+<section id="l12">
+<title>
+<p>12</p>
+</title>
+<p>
+<code>/url/</code>
+</p>
+</section>
+<section id="l13">
+<title>
+<p>13</p>
+</title>
+<p>
+<code>/url/</code>
+</p>
+</section>
+<section id="l14">
+<title>
+<p>14</p>
+</title>
+<p>
+<code>/url/</code>
+</p>
+</section>
+<section id="l15">
+<title>
+<p>15</p>
+</title>
+<p>
+<code>/url</code>
+</p>
+</section>
+<section id="l16">
+<title>
+<p>16</p>
+</title>
+<p>
+<code>/url</code>
+</p>
+</section>
+<section id="l17">
+<title>
+<p>17</p>
+</title>
+<p>
+<code>/url</code>
+</p>
+</section>
+<section id="l18">
+<title>
+<p>18</p>
+</title>
+<p>Title with &quot;quotes&quot; inside: <code>/url/</code>
+</p>
+</section>
+<section id="l19">
+<title>
+<p>19</p>
+</title>
+<p>Title with &quot;quote&quot; inside: <code>/url/</code>
+</p>
+</section>
+<section id="l20">
+<title>
+<p>20</p>
+</title>
+<p>
+<code>http://example.com/?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l21">
+<title>
+<p>21</p>
+</title>
+<p>AT&amp;T: <code>http://att.com/</code>
+</p>
+</section>
+<section id="l22">
+<title>
+<p>22</p>
+</title>
+<p>
+<code>/script?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l23">
+<title>
+<p>23</p>
+</title>
+<p>
+<code>/script?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l24">
+<title>
+<p>24</p>
+</title>
+<p>
+<code>http://example.com/?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l25">
+<title>
+<p>25</p>
+</title>
+<p>
+<code>http://example.com/</code>
+</p>
+</section>
+<section id="l26">
+<title>
+<p>26</p>
+</title>
+<p>
+<code>mailto:nobody@nowhere.net</code>
+</p>
+</section>
+<section id="l27">
+<title>
+<p>27</p>
+</title>
+<p>
+<code>http://example.com/</code>
+</p>
+</section>
+<section id="n28">
+<title>
+<p>28</p>
+</title>
+<p>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</p>
+</section>
+<section id="n29">
+<title>
+<p>29</p>
+</title>
+<p>Here’s the long note. This one contains multiple blocks.</p>
+<p>Subsequent blocks are indented to show that they belong to the footnote (as with list items).</p>
+<empty-line />
+<p>
+<code> { &lt;code&gt; }</code>
+</p>
+<empty-line />
+<p>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</p>
+</section>
+<section id="n30">
+<title>
+<p>30</p>
+</title>
+<p>This is <emphasis>easier</emphasis> to type. Inline notes may contain links<a l:href="#l30" type="note">
+<sup>[30]</sup>
+</a> and <code>]</code> verbatim characters, as well as [bracketed text].</p>
+</section>
+<section id="n31">
+<title>
+<p>31</p>
+</title>
+<p>In quote.</p>
+</section>
+<section id="n32">
+<title>
+<p>32</p>
+</title>
+<p>In list.</p>
+</section>
+</body>
+</FictionBook>
diff --git a/test/writer.haddock b/test/writer.haddock
new file mode 100644
index 000000000..7f783abd1
--- /dev/null
+++ b/test/writer.haddock
@@ -0,0 +1,656 @@
+This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
+markdown test suite.
+
+______________________________________________________________________________
+
+= Headers
+#headers#
+
+== Level 2 with an </url embedded link>
+#level-2-with-an-embedded-link#
+
+=== Level 3 with /emphasis/
+#level-3-with-emphasis#
+
+==== Level 4
+#level-4#
+
+===== Level 5
+#level-5#
+
+= Level 1
+#level-1#
+
+== Level 2 with /emphasis/
+#level-2-with-emphasis#
+
+=== Level 3
+#level-3#
+
+with no blank line
+
+== Level 2
+#level-2#
+
+with no blank line
+
+______________________________________________________________________________
+
+= Paragraphs
+#paragraphs#
+
+Here’s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here’s one with a bullet. * criminey.
+
+There should be a hard line break
+here.
+
+______________________________________________________________________________
+
+= Block Quotes
+#block-quotes#
+
+E-mail style:
+
+This is a block quote. It is pretty short.
+
+Code in a block quote:
+
+> sub status {
+> print "working";
+> }
+
+A list:
+
+1. item one
+2. item two
+
+Nested block quotes:
+
+nested
+
+nested
+
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+______________________________________________________________________________
+
+= Code Blocks
+#code-blocks#
+
+Code:
+
+> ---- (should be four hyphens)
+>
+> sub status {
+> print "working";
+> }
+>
+> this code block is indented by one tab
+
+And:
+
+> this code block is indented by two tabs
+>
+> These should not be escaped: \$ \\ \> \[ \{
+
+______________________________________________________________________________
+
+= Lists
+#lists#
+
+== Unordered
+#unordered#
+
+Asterisks tight:
+
+- asterisk 1
+- asterisk 2
+- asterisk 3
+
+Asterisks loose:
+
+- asterisk 1
+
+- asterisk 2
+
+- asterisk 3
+
+Pluses tight:
+
+- Plus 1
+- Plus 2
+- Plus 3
+
+Pluses loose:
+
+- Plus 1
+
+- Plus 2
+
+- Plus 3
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+== Ordered
+#ordered#
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
+
+2. Item 2.
+
+3. Item 3.
+
+== Nested
+#nested#
+
+- Tab
+ - Tab
+ - Tab
+
+Here’s another:
+
+1. First
+2. Second:
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+== Tabs and spaces
+#tabs-and-spaces#
+
+- this is a list item indented with tabs
+
+- this is a list item indented with spaces
+
+ - this is an example list item indented with tabs
+
+ - this is an example list item indented with spaces
+
+== Fancy list markers
+#fancy-list-markers#
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+ 4. sublist with roman numerals, starting with 4
+ 5. more items
+ (1) a subsublist
+ (2) a subsublist
+
+Nesting:
+
+1. Upper Alpha
+ 1. Upper Roman.
+ (6) Decimal start with 6
+ 3) Lower alpha with paren
+
+Autonumbering:
+
+1. Autonumber.
+2. More.
+ 1. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+______________________________________________________________________________
+
+= Definition Lists
+#definition-lists#
+
+Tight using spaces:
+
+[apple]
+ red fruit
+[orange]
+ orange fruit
+[banana]
+ yellow fruit
+
+Tight using tabs:
+
+[apple]
+ red fruit
+[orange]
+ orange fruit
+[banana]
+ yellow fruit
+
+Loose:
+
+[apple]
+ red fruit
+
+[orange]
+ orange fruit
+
+[banana]
+ yellow fruit
+
+Multiple blocks with italics:
+
+[/apple/]
+ red fruit
+
+ contains seeds, crisp, pleasant to taste
+
+[/orange/]
+ orange fruit
+
+ > { orange code block }
+
+ orange block quote
+
+Multiple definitions, tight:
+
+[apple]
+ red fruit
+ computer
+[orange]
+ orange fruit
+ bank
+
+Multiple definitions, loose:
+
+[apple]
+ red fruit
+
+ computer
+
+[orange]
+ orange fruit
+
+ bank
+
+Blank line after term, indented marker, alternate markers:
+
+[apple]
+ red fruit
+
+ computer
+
+[orange]
+ orange fruit
+
+ 1. sublist
+ 2. sublist
+
+= HTML Blocks
+#html-blocks#
+
+Simple block on one line:
+
+foo
+
+And nested without indentation:
+
+foo
+
+bar
+
+Interpreted markdown in a table:
+
+This is /emphasized/
+And this is __strong__
+Here’s a simple block:
+
+foo
+
+This should be a code block, though:
+
+> <div>
+> foo
+> </div>
+
+As should this:
+
+> <div>foo</div>
+
+Now, nested:
+
+foo
+
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+> <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+> <hr />
+
+Hr’s:
+
+______________________________________________________________________________
+
+= Inline Markup
+#inline-markup#
+
+This is /emphasized/, and so /is this/.
+
+This is __strong__, and so __is this__.
+
+An /</url emphasized link>/.
+
+__/This is strong and em./__
+
+So is __/this/__ word.
+
+__/This is strong and em./__
+
+So is __/this/__ word.
+
+This is code: @>@, @$@, @\\@, @\\$@, @\<html>@.
+
+~~This is /strikeout/.~~
+
+Superscripts: abcd a/hello/ ahello there.
+
+Subscripts: H2O, H23O, Hmany of themO.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a~b c~d.
+
+______________________________________________________________________________
+
+= Smart quotes, ellipses, dashes
+#smart-quotes-ellipses-dashes#
+
+“Hello,” said the spider. “‘Shelob’ is my name.”
+
+‘A’, ‘B’, and ‘C’ are letters.
+
+‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
+
+‘He said, “I want to go.”’ Were you alive in the 70’s?
+
+Here is some quoted ‘@code@’ and a
+“<http://example.com/?foo=1&bar=2 quoted link>”.
+
+Some dashes: one—two — three—four — five.
+
+Dashes between numbers: 5–7, 255–66, 1987–1999.
+
+Ellipses…and…and….
+
+______________________________________________________________________________
+
+= LaTeX
+#latex#
+
+-
+- 2 + 2 = 4
+- /x/ ∈ /y/
+- /α/ ∧ /ω/
+- 223
+- /p/-Tree
+- Here’s some display math:
+ $$\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}$$
+- Here’s one that has a line break in it: /α/ + /ω/ × /x/2.
+
+These shouldn’t be math:
+
+- To get the famous equation, write @$e = mc^2$@.
+- $22,000 is a /lot/ of money. So is $34,000. (It worked if “lot” is
+ emphasized.)
+- Shoes ($20) and socks ($5).
+- Escaped @$@: $73 /this should be emphasized/ 23$.
+
+Here’s a LaTeX table:
+
+______________________________________________________________________________
+
+= Special Characters
+#special-characters#
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 \< 5.
+
+6 > 5.
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+______________________________________________________________________________
+
+= Links
+#links#
+
+== Explicit
+#explicit#
+
+Just a </url/ URL>.
+
+</url/ URL and title>.
+
+</url/ URL and title>.
+
+</url/ URL and title>.
+
+</url/ URL and title>
+
+</url/ URL and title>
+
+</url/with_underscore with_underscore>
+
+<mailto:nobody@nowhere.net Email link>
+
+< Empty>.
+
+== Reference
+#reference#
+
+Foo </url/ bar>.
+
+With </url/ embedded [brackets]>.
+
+</url/ b> by itself should be a link.
+
+Indented </url once>.
+
+Indented </url twice>.
+
+Indented </url thrice>.
+
+This should [not][] be a link.
+
+> [not]: /url
+
+Foo </url/ bar>.
+
+Foo </url/ biz>.
+
+== With ampersands
+#with-ampersands#
+
+Here’s a <http://example.com/?foo=1&bar=2 link with an ampersand in the URL>.
+
+Here’s a link with an amersand in the link text: <http://att.com/ AT&T>.
+
+Here’s an </script?foo=1&bar=2 inline link>.
+
+Here’s an </script?foo=1&bar=2 inline link in pointy braces>.
+
+== Autolinks
+#autolinks#
+
+With an ampersand: <http://example.com/?foo=1&bar=2>
+
+- In a list?
+- <http://example.com/>
+- It should.
+
+An e-mail address: <mailto:nobody@nowhere.net nobody\@nowhere.net>
+
+Blockquoted: <http://example.com/>
+
+Auto-links should not occur here: @\<http:\/\/example.com\/>@
+
+> or here: <http://example.com/>
+
+______________________________________________________________________________
+
+= Images
+#images#
+
+From “Voyage dans la Lune” by Georges Melies (1902):
+
+<<lalune.jpg lalune>>
+
+Here is a movie <<movie.jpg movie>> icon.
+
+______________________________________________________________________________
+
+= Footnotes
+#footnotes#
+
+Here is a footnote reference,<#notes [1]> and another.<#notes [2]> This should
+/not/ be a footnote reference, because it contains a space.[^my note] Here is
+an inline note.<#notes [3]>
+
+Notes can go in quotes.<#notes [4]>
+
+1. And in list items.<#notes [5]>
+
+This paragraph should not be part of the note, as it is not indented.
+
+#notes#
+
+1. Here is the footnote. It can go anywhere after the footnote reference. It
+ need not be placed at the end of the document.
+
+2. Here’s the long note. This one contains multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the footnote
+ (as with list items).
+
+ > { <code> }
+
+ If you want, you can indent every line, but you can also be lazy and just
+ indent the first line of each block.
+
+3. This is /easier/ to type. Inline notes may contain
+ <http://google.com links> and @]@ verbatim characters, as well as
+ [bracketed text].
+
+4. In quote.
+
+5. In list.
diff --git a/test/writer.html4 b/test/writer.html4
new file mode 100644
index 000000000..dc889f07a
--- /dev/null
+++ b/test/writer.html4
@@ -0,0 +1,549 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <meta name="generator" content="pandoc" />
+ <meta name="author" content="John MacFarlane" />
+ <meta name="author" content="Anonymous" />
+ <meta name="date" content="2006-07-17" />
+ <title>Pandoc Test Suite</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+ </style>
+</head>
+<body>
+<div id="header">
+<h1 class="title">Pandoc Test Suite</h1>
+<h2 class="author">John MacFarlane</h2>
+<h2 class="author">Anonymous</h2>
+<h3 class="date">July 17, 2006</h3>
+</div>
+<p>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</p>
+<hr />
+<h1 id="headers">Headers</h1>
+<h2 id="level-2-with-an-embedded-link">Level 2 with an <a href="/url">embedded link</a></h2>
+<h3 id="level-3-with-emphasis">Level 3 with <em>emphasis</em></h3>
+<h4 id="level-4">Level 4</h4>
+<h5 id="level-5">Level 5</h5>
+<h1 id="level-1">Level 1</h1>
+<h2 id="level-2-with-emphasis">Level 2 with <em>emphasis</em></h2>
+<h3 id="level-3">Level 3</h3>
+<p>with no blank line</p>
+<h2 id="level-2">Level 2</h2>
+<p>with no blank line</p>
+<hr />
+<h1 id="paragraphs">Paragraphs</h1>
+<p>Here’s a regular paragraph.</p>
+<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p>
+<p>Here’s one with a bullet. * criminey.</p>
+<p>There should be a hard line break<br />
+here.</p>
+<hr />
+<h1 id="block-quotes">Block Quotes</h1>
+<p>E-mail style:</p>
+<blockquote>
+<p>This is a block quote. It is pretty short.</p>
+</blockquote>
+<blockquote>
+<p>Code in a block quote:</p>
+<pre><code>sub status {
+ print &quot;working&quot;;
+}</code></pre>
+<p>A list:</p>
+<ol style="list-style-type: decimal">
+<li>item one</li>
+<li>item two</li>
+</ol>
+<p>Nested block quotes:</p>
+<blockquote>
+<p>nested</p>
+</blockquote>
+<blockquote>
+<p>nested</p>
+</blockquote>
+</blockquote>
+<p>This should not be a block quote: 2 &gt; 1.</p>
+<p>And a following paragraph.</p>
+<hr />
+<h1 id="code-blocks">Code Blocks</h1>
+<p>Code:</p>
+<pre><code>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</code></pre>
+<p>And:</p>
+<pre><code> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</code></pre>
+<hr />
+<h1 id="lists">Lists</h1>
+<h2 id="unordered">Unordered</h2>
+<p>Asterisks tight:</p>
+<ul>
+<li>asterisk 1</li>
+<li>asterisk 2</li>
+<li>asterisk 3</li>
+</ul>
+<p>Asterisks loose:</p>
+<ul>
+<li><p>asterisk 1</p></li>
+<li><p>asterisk 2</p></li>
+<li><p>asterisk 3</p></li>
+</ul>
+<p>Pluses tight:</p>
+<ul>
+<li>Plus 1</li>
+<li>Plus 2</li>
+<li>Plus 3</li>
+</ul>
+<p>Pluses loose:</p>
+<ul>
+<li><p>Plus 1</p></li>
+<li><p>Plus 2</p></li>
+<li><p>Plus 3</p></li>
+</ul>
+<p>Minuses tight:</p>
+<ul>
+<li>Minus 1</li>
+<li>Minus 2</li>
+<li>Minus 3</li>
+</ul>
+<p>Minuses loose:</p>
+<ul>
+<li><p>Minus 1</p></li>
+<li><p>Minus 2</p></li>
+<li><p>Minus 3</p></li>
+</ul>
+<h2 id="ordered">Ordered</h2>
+<p>Tight:</p>
+<ol style="list-style-type: decimal">
+<li>First</li>
+<li>Second</li>
+<li>Third</li>
+</ol>
+<p>and:</p>
+<ol style="list-style-type: decimal">
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ol>
+<p>Loose using tabs:</p>
+<ol style="list-style-type: decimal">
+<li><p>First</p></li>
+<li><p>Second</p></li>
+<li><p>Third</p></li>
+</ol>
+<p>and using spaces:</p>
+<ol style="list-style-type: decimal">
+<li><p>One</p></li>
+<li><p>Two</p></li>
+<li><p>Three</p></li>
+</ol>
+<p>Multiple paragraphs:</p>
+<ol style="list-style-type: decimal">
+<li><p>Item 1, graf one.</p>
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.</p></li>
+<li><p>Item 2.</p></li>
+<li><p>Item 3.</p></li>
+</ol>
+<h2 id="nested">Nested</h2>
+<ul>
+<li>Tab
+<ul>
+<li>Tab
+<ul>
+<li>Tab</li>
+</ul></li>
+</ul></li>
+</ul>
+<p>Here’s another:</p>
+<ol style="list-style-type: decimal">
+<li>First</li>
+<li>Second:
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li>Third</li>
+</ol>
+<p>Same thing but with paragraphs:</p>
+<ol style="list-style-type: decimal">
+<li><p>First</p></li>
+<li><p>Second:</p>
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li><p>Third</p></li>
+</ol>
+<h2 id="tabs-and-spaces">Tabs and spaces</h2>
+<ul>
+<li><p>this is a list item indented with tabs</p></li>
+<li><p>this is a list item indented with spaces</p>
+<ul>
+<li><p>this is an example list item indented with tabs</p></li>
+<li><p>this is an example list item indented with spaces</p></li>
+</ul></li>
+</ul>
+<h2 id="fancy-list-markers">Fancy list markers</h2>
+<ol start="2" style="list-style-type: decimal">
+<li>begins with 2</li>
+<li><p>and now 3</p>
+<p>with a continuation</p>
+<ol start="4" style="list-style-type: lower-roman">
+<li>sublist with roman numerals, starting with 4</li>
+<li>more items
+<ol style="list-style-type: upper-alpha">
+<li>a subsublist</li>
+<li>a subsublist</li>
+</ol></li>
+</ol></li>
+</ol>
+<p>Nesting:</p>
+<ol style="list-style-type: upper-alpha">
+<li>Upper Alpha
+<ol style="list-style-type: upper-roman">
+<li>Upper Roman.
+<ol start="6" style="list-style-type: decimal">
+<li>Decimal start with 6
+<ol start="3" style="list-style-type: lower-alpha">
+<li>Lower alpha with paren</li>
+</ol></li>
+</ol></li>
+</ol></li>
+</ol>
+<p>Autonumbering:</p>
+<ol>
+<li>Autonumber.</li>
+<li>More.
+<ol>
+<li>Nested.</li>
+</ol></li>
+</ol>
+<p>Should not be a list item:</p>
+<p>M.A. 2007</p>
+<p>B. Williams</p>
+<hr />
+<h1 id="definition-lists">Definition Lists</h1>
+<p>Tight using spaces:</p>
+<dl>
+<dt>apple</dt>
+<dd>red fruit
+</dd>
+<dt>orange</dt>
+<dd>orange fruit
+</dd>
+<dt>banana</dt>
+<dd>yellow fruit
+</dd>
+</dl>
+<p>Tight using tabs:</p>
+<dl>
+<dt>apple</dt>
+<dd>red fruit
+</dd>
+<dt>orange</dt>
+<dd>orange fruit
+</dd>
+<dt>banana</dt>
+<dd>yellow fruit
+</dd>
+</dl>
+<p>Loose:</p>
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p>
+</dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+</dd>
+<dt>banana</dt>
+<dd><p>yellow fruit</p>
+</dd>
+</dl>
+<p>Multiple blocks with italics:</p>
+<dl>
+<dt><em>apple</em></dt>
+<dd><p>red fruit</p>
+<p>contains seeds, crisp, pleasant to taste</p>
+</dd>
+<dt><em>orange</em></dt>
+<dd><p>orange fruit</p>
+<pre><code>{ orange code block }</code></pre>
+<blockquote>
+<p>orange block quote</p>
+</blockquote>
+</dd>
+</dl>
+<p>Multiple definitions, tight:</p>
+<dl>
+<dt>apple</dt>
+<dd>red fruit
+</dd>
+<dd>computer
+</dd>
+<dt>orange</dt>
+<dd>orange fruit
+</dd>
+<dd>bank
+</dd>
+</dl>
+<p>Multiple definitions, loose:</p>
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p>
+</dd>
+<dd><p>computer</p>
+</dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+</dd>
+<dd><p>bank</p>
+</dd>
+</dl>
+<p>Blank line after term, indented marker, alternate markers:</p>
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p>
+</dd>
+<dd><p>computer</p>
+</dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+<ol style="list-style-type: decimal">
+<li>sublist</li>
+<li>sublist</li>
+</ol>
+</dd>
+</dl>
+<h1 id="html-blocks">HTML Blocks</h1>
+<p>Simple block on one line:</p>
+<div>
+foo
+</div>
+<p>And nested without indentation:</p>
+<div>
+<div>
+<div>
+<p>foo</p>
+</div>
+</div>
+<div>
+bar
+</div>
+</div>
+<p>Interpreted markdown in a table:</p>
+<table>
+<tr>
+<td>
+This is <em>emphasized</em>
+</td>
+<td>
+And this is <strong>strong</strong>
+</td>
+</tr>
+</table>
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+<p>Here’s a simple block:</p>
+<div>
+<p>foo</p>
+</div>
+<p>This should be a code block, though:</p>
+<pre><code>&lt;div&gt;
+ foo
+&lt;/div&gt;</code></pre>
+<p>As should this:</p>
+<pre><code>&lt;div&gt;foo&lt;/div&gt;</code></pre>
+<p>Now, nested:</p>
+<div>
+<div>
+<div>
+foo
+</div>
+</div>
+</div>
+<p>This should just be an HTML comment:</p>
+<!-- Comment -->
+<p>Multiline:</p>
+<!--
+Blah
+Blah
+-->
+<!--
+ This is another comment.
+-->
+<p>Code block:</p>
+<pre><code>&lt;!-- Comment --&gt;</code></pre>
+<p>Just plain comment, with trailing spaces on the line:</p>
+<!-- foo -->
+<p>Code:</p>
+<pre><code>&lt;hr /&gt;</code></pre>
+<p>Hr’s:</p>
+<hr>
+<hr />
+<hr />
+<hr>
+<hr />
+<hr />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar">
+<hr />
+<h1 id="inline-markup">Inline Markup</h1>
+<p>This is <em>emphasized</em>, and so <em>is this</em>.</p>
+<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
+<p>An <em><a href="/url">emphasized link</a></em>.</p>
+<p><strong><em>This is strong and em.</em></strong></p>
+<p>So is <strong><em>this</em></strong> word.</p>
+<p><strong><em>This is strong and em.</em></strong></p>
+<p>So is <strong><em>this</em></strong> word.</p>
+<p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p>
+<p><del>This is <em>strikeout</em>.</del></p>
+<p>Superscripts: a<sup>bc</sup>d a<sup><em>hello</em></sup> a<sup>hello there</sup>.</p>
+<p>Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.</p>
+<p>These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</p>
+<hr />
+<h1 id="smart-quotes-ellipses-dashes">Smart quotes, ellipses, dashes</h1>
+<p>“Hello,” said the spider. “‘Shelob’ is my name.”</p>
+<p>‘A’, ‘B’, and ‘C’ are letters.</p>
+<p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’</p>
+<p>‘He said, “I want to go.”’ Were you alive in the 70’s?</p>
+<p>Here is some quoted ‘<code>code</code>’ and a “<a href="http://example.com/?foo=1&amp;bar=2">quoted link</a>”.</p>
+<p>Some dashes: one—two — three—four — five.</p>
+<p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p>
+<p>Ellipses…and…and….</p>
+<hr />
+<h1 id="latex">LaTeX</h1>
+<ul>
+<li></li>
+<li><span class="math inline">2 + 2 = 4</span></li>
+<li><span class="math inline"><em>x</em> ∈ <em>y</em></span></li>
+<li><span class="math inline"><em>α</em> ∧ <em>ω</em></span></li>
+<li><span class="math inline">223</span></li>
+<li><span class="math inline"><em>p</em></span>-Tree</li>
+<li>Here’s some display math: <br /><span class="math display">$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</span><br /></li>
+<li>Here’s one that has a line break in it: <span class="math inline"><em>α</em> + <em>ω</em> × <em>x</em><sup>2</sup></span>.</li>
+</ul>
+<p>These shouldn’t be math:</p>
+<ul>
+<li>To get the famous equation, write <code>$e = mc^2$</code>.</li>
+<li>$22,000 is a <em>lot</em> of money. So is $34,000. (It worked if “lot” is emphasized.)</li>
+<li>Shoes ($20) and socks ($5).</li>
+<li>Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.</li>
+</ul>
+<p>Here’s a LaTeX table:</p>
+
+<hr />
+<h1 id="special-characters">Special Characters</h1>
+<p>Here is some unicode:</p>
+<ul>
+<li>I hat: Î</li>
+<li>o umlaut: ö</li>
+<li>section: §</li>
+<li>set membership: ∈</li>
+<li>copyright: ©</li>
+</ul>
+<p>AT&amp;T has an ampersand in their name.</p>
+<p>AT&amp;T is another way to write it.</p>
+<p>This &amp; that.</p>
+<p>4 &lt; 5.</p>
+<p>6 &gt; 5.</p>
+<p>Backslash: \</p>
+<p>Backtick: `</p>
+<p>Asterisk: *</p>
+<p>Underscore: _</p>
+<p>Left brace: {</p>
+<p>Right brace: }</p>
+<p>Left bracket: [</p>
+<p>Right bracket: ]</p>
+<p>Left paren: (</p>
+<p>Right paren: )</p>
+<p>Greater-than: &gt;</p>
+<p>Hash: #</p>
+<p>Period: .</p>
+<p>Bang: !</p>
+<p>Plus: +</p>
+<p>Minus: -</p>
+<hr />
+<h1 id="links">Links</h1>
+<h2 id="explicit">Explicit</h2>
+<p>Just a <a href="/url/">URL</a>.</p>
+<p><a href="/url/" title="title">URL and title</a>.</p>
+<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
+<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
+<p><a href="/url/" title="title with &quot;quotes&quot; in it">URL and title</a></p>
+<p><a href="/url/" title="title with single quotes">URL and title</a></p>
+<p><a href="/url/with_underscore">with_underscore</a></p>
+<p><a href="mailto:nobody@nowhere.net">Email link</a></p>
+<p><a href="">Empty</a>.</p>
+<h2 id="reference">Reference</h2>
+<p>Foo <a href="/url/">bar</a>.</p>
+<p>With <a href="/url/">embedded [brackets]</a>.</p>
+<p><a href="/url/">b</a> by itself should be a link.</p>
+<p>Indented <a href="/url">once</a>.</p>
+<p>Indented <a href="/url">twice</a>.</p>
+<p>Indented <a href="/url">thrice</a>.</p>
+<p>This should [not][] be a link.</p>
+<pre><code>[not]: /url</code></pre>
+<p>Foo <a href="/url/" title="Title with &quot;quotes&quot; inside">bar</a>.</p>
+<p>Foo <a href="/url/" title="Title with &quot;quote&quot; inside">biz</a>.</p>
+<h2 id="with-ampersands">With ampersands</h2>
+<p>Here’s a <a href="http://example.com/?foo=1&amp;bar=2">link with an ampersand in the URL</a>.</p>
+<p>Here’s a link with an amersand in the link text: <a href="http://att.com/" title="AT&amp;T">AT&amp;T</a>.</p>
+<p>Here’s an <a href="/script?foo=1&amp;bar=2">inline link</a>.</p>
+<p>Here’s an <a href="/script?foo=1&amp;bar=2">inline link in pointy braces</a>.</p>
+<h2 id="autolinks">Autolinks</h2>
+<p>With an ampersand: <a href="http://example.com/?foo=1&amp;bar=2" class="uri">http://example.com/?foo=1&amp;bar=2</a></p>
+<ul>
+<li>In a list?</li>
+<li><a href="http://example.com/" class="uri">http://example.com/</a></li>
+<li>It should.</li>
+</ul>
+<p>An e-mail address: <a href="mailto:nobody@nowhere.net">nobody@nowhere.net</a></p>
+<blockquote>
+<p>Blockquoted: <a href="http://example.com/" class="uri">http://example.com/</a></p>
+</blockquote>
+<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p>
+<pre><code>or here: &lt;http://example.com/&gt;</code></pre>
+<hr />
+<h1 id="images">Images</h1>
+<p>From “Voyage dans la Lune” by Georges Melies (1902):</p>
+<div class="figure">
+<img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune" />
+<p class="caption">lalune</p>
+</div>
+<p>Here is a movie <img src="movie.jpg" alt="movie" /> icon.</p>
+<hr />
+<h1 id="footnotes">Footnotes</h1>
+<p>Here is a footnote reference,<a href="#fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a> and another.<a href="#fn2" class="footnote-ref" id="fnref2"><sup>2</sup></a> This should <em>not</em> be a footnote reference, because it contains a space.[^my note] Here is an inline note.<a href="#fn3" class="footnote-ref" id="fnref3"><sup>3</sup></a></p>
+<blockquote>
+<p>Notes can go in quotes.<a href="#fn4" class="footnote-ref" id="fnref4"><sup>4</sup></a></p>
+</blockquote>
+<ol style="list-style-type: decimal">
+<li>And in list items.<a href="#fn5" class="footnote-ref" id="fnref5"><sup>5</sup></a></li>
+</ol>
+<p>This paragraph should not be part of the note, as it is not indented.</p>
+<div class="footnotes">
+<hr />
+<ol>
+<li id="fn1"><p>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.<a href="#fnref1" class="footnote-back">↩</a></p></li>
+<li id="fn2"><p>Here’s the long note. This one contains multiple blocks.</p>
+<p>Subsequent blocks are indented to show that they belong to the footnote (as with list items).</p>
+<pre><code> { &lt;code&gt; }</code></pre>
+<p>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.<a href="#fnref2" class="footnote-back">↩</a></p></li>
+<li id="fn3"><p>This is <em>easier</em> to type. Inline notes may contain <a href="http://google.com">links</a> and <code>]</code> verbatim characters, as well as [bracketed text].<a href="#fnref3" class="footnote-back">↩</a></p></li>
+<li id="fn4"><p>In quote.<a href="#fnref4" class="footnote-back">↩</a></p></li>
+<li id="fn5"><p>In list.<a href="#fnref5" class="footnote-back">↩</a></p></li>
+</ol>
+</div>
+</body>
+</html>
diff --git a/test/writer.html5 b/test/writer.html5
new file mode 100644
index 000000000..53fcb84e2
--- /dev/null
+++ b/test/writer.html5
@@ -0,0 +1,551 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
+<head>
+ <meta charset="utf-8" />
+ <meta name="generator" content="pandoc" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+ <meta name="author" content="John MacFarlane" />
+ <meta name="author" content="Anonymous" />
+ <meta name="dcterms.date" content="2006-07-17" />
+ <title>Pandoc Test Suite</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+ </style>
+ <!--[if lt IE 9]>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
+ <![endif]-->
+</head>
+<body>
+<header>
+<h1 class="title">Pandoc Test Suite</h1>
+<p class="author">John MacFarlane</p>
+<p class="author">Anonymous</p>
+<p class="date">July 17, 2006</p>
+</header>
+<p>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</p>
+<hr />
+<h1 id="headers">Headers</h1>
+<h2 id="level-2-with-an-embedded-link">Level 2 with an <a href="/url">embedded link</a></h2>
+<h3 id="level-3-with-emphasis">Level 3 with <em>emphasis</em></h3>
+<h4 id="level-4">Level 4</h4>
+<h5 id="level-5">Level 5</h5>
+<h1 id="level-1">Level 1</h1>
+<h2 id="level-2-with-emphasis">Level 2 with <em>emphasis</em></h2>
+<h3 id="level-3">Level 3</h3>
+<p>with no blank line</p>
+<h2 id="level-2">Level 2</h2>
+<p>with no blank line</p>
+<hr />
+<h1 id="paragraphs">Paragraphs</h1>
+<p>Here’s a regular paragraph.</p>
+<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p>
+<p>Here’s one with a bullet. * criminey.</p>
+<p>There should be a hard line break<br />
+here.</p>
+<hr />
+<h1 id="block-quotes">Block Quotes</h1>
+<p>E-mail style:</p>
+<blockquote>
+<p>This is a block quote. It is pretty short.</p>
+</blockquote>
+<blockquote>
+<p>Code in a block quote:</p>
+<pre><code>sub status {
+ print &quot;working&quot;;
+}</code></pre>
+<p>A list:</p>
+<ol type="1">
+<li>item one</li>
+<li>item two</li>
+</ol>
+<p>Nested block quotes:</p>
+<blockquote>
+<p>nested</p>
+</blockquote>
+<blockquote>
+<p>nested</p>
+</blockquote>
+</blockquote>
+<p>This should not be a block quote: 2 &gt; 1.</p>
+<p>And a following paragraph.</p>
+<hr />
+<h1 id="code-blocks">Code Blocks</h1>
+<p>Code:</p>
+<pre><code>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</code></pre>
+<p>And:</p>
+<pre><code> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</code></pre>
+<hr />
+<h1 id="lists">Lists</h1>
+<h2 id="unordered">Unordered</h2>
+<p>Asterisks tight:</p>
+<ul>
+<li>asterisk 1</li>
+<li>asterisk 2</li>
+<li>asterisk 3</li>
+</ul>
+<p>Asterisks loose:</p>
+<ul>
+<li><p>asterisk 1</p></li>
+<li><p>asterisk 2</p></li>
+<li><p>asterisk 3</p></li>
+</ul>
+<p>Pluses tight:</p>
+<ul>
+<li>Plus 1</li>
+<li>Plus 2</li>
+<li>Plus 3</li>
+</ul>
+<p>Pluses loose:</p>
+<ul>
+<li><p>Plus 1</p></li>
+<li><p>Plus 2</p></li>
+<li><p>Plus 3</p></li>
+</ul>
+<p>Minuses tight:</p>
+<ul>
+<li>Minus 1</li>
+<li>Minus 2</li>
+<li>Minus 3</li>
+</ul>
+<p>Minuses loose:</p>
+<ul>
+<li><p>Minus 1</p></li>
+<li><p>Minus 2</p></li>
+<li><p>Minus 3</p></li>
+</ul>
+<h2 id="ordered">Ordered</h2>
+<p>Tight:</p>
+<ol type="1">
+<li>First</li>
+<li>Second</li>
+<li>Third</li>
+</ol>
+<p>and:</p>
+<ol type="1">
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ol>
+<p>Loose using tabs:</p>
+<ol type="1">
+<li><p>First</p></li>
+<li><p>Second</p></li>
+<li><p>Third</p></li>
+</ol>
+<p>and using spaces:</p>
+<ol type="1">
+<li><p>One</p></li>
+<li><p>Two</p></li>
+<li><p>Three</p></li>
+</ol>
+<p>Multiple paragraphs:</p>
+<ol type="1">
+<li><p>Item 1, graf one.</p>
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.</p></li>
+<li><p>Item 2.</p></li>
+<li><p>Item 3.</p></li>
+</ol>
+<h2 id="nested">Nested</h2>
+<ul>
+<li>Tab
+<ul>
+<li>Tab
+<ul>
+<li>Tab</li>
+</ul></li>
+</ul></li>
+</ul>
+<p>Here’s another:</p>
+<ol type="1">
+<li>First</li>
+<li>Second:
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li>Third</li>
+</ol>
+<p>Same thing but with paragraphs:</p>
+<ol type="1">
+<li><p>First</p></li>
+<li><p>Second:</p>
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li><p>Third</p></li>
+</ol>
+<h2 id="tabs-and-spaces">Tabs and spaces</h2>
+<ul>
+<li><p>this is a list item indented with tabs</p></li>
+<li><p>this is a list item indented with spaces</p>
+<ul>
+<li><p>this is an example list item indented with tabs</p></li>
+<li><p>this is an example list item indented with spaces</p></li>
+</ul></li>
+</ul>
+<h2 id="fancy-list-markers">Fancy list markers</h2>
+<ol start="2" type="1">
+<li>begins with 2</li>
+<li><p>and now 3</p>
+<p>with a continuation</p>
+<ol start="4" type="i">
+<li>sublist with roman numerals, starting with 4</li>
+<li>more items
+<ol type="A">
+<li>a subsublist</li>
+<li>a subsublist</li>
+</ol></li>
+</ol></li>
+</ol>
+<p>Nesting:</p>
+<ol type="A">
+<li>Upper Alpha
+<ol type="I">
+<li>Upper Roman.
+<ol start="6" type="1">
+<li>Decimal start with 6
+<ol start="3" type="a">
+<li>Lower alpha with paren</li>
+</ol></li>
+</ol></li>
+</ol></li>
+</ol>
+<p>Autonumbering:</p>
+<ol>
+<li>Autonumber.</li>
+<li>More.
+<ol>
+<li>Nested.</li>
+</ol></li>
+</ol>
+<p>Should not be a list item:</p>
+<p>M.A. 2007</p>
+<p>B. Williams</p>
+<hr />
+<h1 id="definition-lists">Definition Lists</h1>
+<p>Tight using spaces:</p>
+<dl>
+<dt>apple</dt>
+<dd>red fruit
+</dd>
+<dt>orange</dt>
+<dd>orange fruit
+</dd>
+<dt>banana</dt>
+<dd>yellow fruit
+</dd>
+</dl>
+<p>Tight using tabs:</p>
+<dl>
+<dt>apple</dt>
+<dd>red fruit
+</dd>
+<dt>orange</dt>
+<dd>orange fruit
+</dd>
+<dt>banana</dt>
+<dd>yellow fruit
+</dd>
+</dl>
+<p>Loose:</p>
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p>
+</dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+</dd>
+<dt>banana</dt>
+<dd><p>yellow fruit</p>
+</dd>
+</dl>
+<p>Multiple blocks with italics:</p>
+<dl>
+<dt><em>apple</em></dt>
+<dd><p>red fruit</p>
+<p>contains seeds, crisp, pleasant to taste</p>
+</dd>
+<dt><em>orange</em></dt>
+<dd><p>orange fruit</p>
+<pre><code>{ orange code block }</code></pre>
+<blockquote>
+<p>orange block quote</p>
+</blockquote>
+</dd>
+</dl>
+<p>Multiple definitions, tight:</p>
+<dl>
+<dt>apple</dt>
+<dd>red fruit
+</dd>
+<dd>computer
+</dd>
+<dt>orange</dt>
+<dd>orange fruit
+</dd>
+<dd>bank
+</dd>
+</dl>
+<p>Multiple definitions, loose:</p>
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p>
+</dd>
+<dd><p>computer</p>
+</dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+</dd>
+<dd><p>bank</p>
+</dd>
+</dl>
+<p>Blank line after term, indented marker, alternate markers:</p>
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p>
+</dd>
+<dd><p>computer</p>
+</dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+<ol type="1">
+<li>sublist</li>
+<li>sublist</li>
+</ol>
+</dd>
+</dl>
+<h1 id="html-blocks">HTML Blocks</h1>
+<p>Simple block on one line:</p>
+<div>
+foo
+</div>
+<p>And nested without indentation:</p>
+<div>
+<div>
+<div>
+<p>foo</p>
+</div>
+</div>
+<div>
+bar
+</div>
+</div>
+<p>Interpreted markdown in a table:</p>
+<table>
+<tr>
+<td>
+This is <em>emphasized</em>
+</td>
+<td>
+And this is <strong>strong</strong>
+</td>
+</tr>
+</table>
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+<p>Here’s a simple block:</p>
+<div>
+<p>foo</p>
+</div>
+<p>This should be a code block, though:</p>
+<pre><code>&lt;div&gt;
+ foo
+&lt;/div&gt;</code></pre>
+<p>As should this:</p>
+<pre><code>&lt;div&gt;foo&lt;/div&gt;</code></pre>
+<p>Now, nested:</p>
+<div>
+<div>
+<div>
+foo
+</div>
+</div>
+</div>
+<p>This should just be an HTML comment:</p>
+<!-- Comment -->
+<p>Multiline:</p>
+<!--
+Blah
+Blah
+-->
+<!--
+ This is another comment.
+-->
+<p>Code block:</p>
+<pre><code>&lt;!-- Comment --&gt;</code></pre>
+<p>Just plain comment, with trailing spaces on the line:</p>
+<!-- foo -->
+<p>Code:</p>
+<pre><code>&lt;hr /&gt;</code></pre>
+<p>Hr’s:</p>
+<hr>
+<hr />
+<hr />
+<hr>
+<hr />
+<hr />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar">
+<hr />
+<h1 id="inline-markup">Inline Markup</h1>
+<p>This is <em>emphasized</em>, and so <em>is this</em>.</p>
+<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
+<p>An <em><a href="/url">emphasized link</a></em>.</p>
+<p><strong><em>This is strong and em.</em></strong></p>
+<p>So is <strong><em>this</em></strong> word.</p>
+<p><strong><em>This is strong and em.</em></strong></p>
+<p>So is <strong><em>this</em></strong> word.</p>
+<p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p>
+<p><del>This is <em>strikeout</em>.</del></p>
+<p>Superscripts: a<sup>bc</sup>d a<sup><em>hello</em></sup> a<sup>hello there</sup>.</p>
+<p>Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.</p>
+<p>These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</p>
+<hr />
+<h1 id="smart-quotes-ellipses-dashes">Smart quotes, ellipses, dashes</h1>
+<p>“Hello,” said the spider. “‘Shelob’ is my name.”</p>
+<p>‘A’, ‘B’, and ‘C’ are letters.</p>
+<p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’</p>
+<p>‘He said, “I want to go.”’ Were you alive in the 70’s?</p>
+<p>Here is some quoted ‘<code>code</code>’ and a “<a href="http://example.com/?foo=1&amp;bar=2">quoted link</a>”.</p>
+<p>Some dashes: one—two — three—four — five.</p>
+<p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p>
+<p>Ellipses…and…and….</p>
+<hr />
+<h1 id="latex">LaTeX</h1>
+<ul>
+<li></li>
+<li><span class="math inline">2 + 2 = 4</span></li>
+<li><span class="math inline"><em>x</em> ∈ <em>y</em></span></li>
+<li><span class="math inline"><em>α</em> ∧ <em>ω</em></span></li>
+<li><span class="math inline">223</span></li>
+<li><span class="math inline"><em>p</em></span>-Tree</li>
+<li>Here’s some display math: <br /><span class="math display">$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</span><br /></li>
+<li>Here’s one that has a line break in it: <span class="math inline"><em>α</em> + <em>ω</em> × <em>x</em><sup>2</sup></span>.</li>
+</ul>
+<p>These shouldn’t be math:</p>
+<ul>
+<li>To get the famous equation, write <code>$e = mc^2$</code>.</li>
+<li>$22,000 is a <em>lot</em> of money. So is $34,000. (It worked if “lot” is emphasized.)</li>
+<li>Shoes ($20) and socks ($5).</li>
+<li>Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.</li>
+</ul>
+<p>Here’s a LaTeX table:</p>
+
+<hr />
+<h1 id="special-characters">Special Characters</h1>
+<p>Here is some unicode:</p>
+<ul>
+<li>I hat: Î</li>
+<li>o umlaut: ö</li>
+<li>section: §</li>
+<li>set membership: ∈</li>
+<li>copyright: ©</li>
+</ul>
+<p>AT&amp;T has an ampersand in their name.</p>
+<p>AT&amp;T is another way to write it.</p>
+<p>This &amp; that.</p>
+<p>4 &lt; 5.</p>
+<p>6 &gt; 5.</p>
+<p>Backslash: \</p>
+<p>Backtick: `</p>
+<p>Asterisk: *</p>
+<p>Underscore: _</p>
+<p>Left brace: {</p>
+<p>Right brace: }</p>
+<p>Left bracket: [</p>
+<p>Right bracket: ]</p>
+<p>Left paren: (</p>
+<p>Right paren: )</p>
+<p>Greater-than: &gt;</p>
+<p>Hash: #</p>
+<p>Period: .</p>
+<p>Bang: !</p>
+<p>Plus: +</p>
+<p>Minus: -</p>
+<hr />
+<h1 id="links">Links</h1>
+<h2 id="explicit">Explicit</h2>
+<p>Just a <a href="/url/">URL</a>.</p>
+<p><a href="/url/" title="title">URL and title</a>.</p>
+<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
+<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
+<p><a href="/url/" title="title with &quot;quotes&quot; in it">URL and title</a></p>
+<p><a href="/url/" title="title with single quotes">URL and title</a></p>
+<p><a href="/url/with_underscore">with_underscore</a></p>
+<p><a href="mailto:nobody@nowhere.net">Email link</a></p>
+<p><a href="">Empty</a>.</p>
+<h2 id="reference">Reference</h2>
+<p>Foo <a href="/url/">bar</a>.</p>
+<p>With <a href="/url/">embedded [brackets]</a>.</p>
+<p><a href="/url/">b</a> by itself should be a link.</p>
+<p>Indented <a href="/url">once</a>.</p>
+<p>Indented <a href="/url">twice</a>.</p>
+<p>Indented <a href="/url">thrice</a>.</p>
+<p>This should [not][] be a link.</p>
+<pre><code>[not]: /url</code></pre>
+<p>Foo <a href="/url/" title="Title with &quot;quotes&quot; inside">bar</a>.</p>
+<p>Foo <a href="/url/" title="Title with &quot;quote&quot; inside">biz</a>.</p>
+<h2 id="with-ampersands">With ampersands</h2>
+<p>Here’s a <a href="http://example.com/?foo=1&amp;bar=2">link with an ampersand in the URL</a>.</p>
+<p>Here’s a link with an amersand in the link text: <a href="http://att.com/" title="AT&amp;T">AT&amp;T</a>.</p>
+<p>Here’s an <a href="/script?foo=1&amp;bar=2">inline link</a>.</p>
+<p>Here’s an <a href="/script?foo=1&amp;bar=2">inline link in pointy braces</a>.</p>
+<h2 id="autolinks">Autolinks</h2>
+<p>With an ampersand: <a href="http://example.com/?foo=1&amp;bar=2" class="uri">http://example.com/?foo=1&amp;bar=2</a></p>
+<ul>
+<li>In a list?</li>
+<li><a href="http://example.com/" class="uri">http://example.com/</a></li>
+<li>It should.</li>
+</ul>
+<p>An e-mail address: <a href="mailto:nobody@nowhere.net">nobody@nowhere.net</a></p>
+<blockquote>
+<p>Blockquoted: <a href="http://example.com/" class="uri">http://example.com/</a></p>
+</blockquote>
+<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p>
+<pre><code>or here: &lt;http://example.com/&gt;</code></pre>
+<hr />
+<h1 id="images">Images</h1>
+<p>From “Voyage dans la Lune” by Georges Melies (1902):</p>
+<figure>
+<img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune" /><figcaption>lalune</figcaption>
+</figure>
+<p>Here is a movie <img src="movie.jpg" alt="movie" /> icon.</p>
+<hr />
+<h1 id="footnotes">Footnotes</h1>
+<p>Here is a footnote reference,<a href="#fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a> and another.<a href="#fn2" class="footnote-ref" id="fnref2"><sup>2</sup></a> This should <em>not</em> be a footnote reference, because it contains a space.[^my note] Here is an inline note.<a href="#fn3" class="footnote-ref" id="fnref3"><sup>3</sup></a></p>
+<blockquote>
+<p>Notes can go in quotes.<a href="#fn4" class="footnote-ref" id="fnref4"><sup>4</sup></a></p>
+</blockquote>
+<ol type="1">
+<li>And in list items.<a href="#fn5" class="footnote-ref" id="fnref5"><sup>5</sup></a></li>
+</ol>
+<p>This paragraph should not be part of the note, as it is not indented.</p>
+<section class="footnotes">
+<hr />
+<ol>
+<li id="fn1"><p>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.<a href="#fnref1" class="footnote-back">↩</a></p></li>
+<li id="fn2"><p>Here’s the long note. This one contains multiple blocks.</p>
+<p>Subsequent blocks are indented to show that they belong to the footnote (as with list items).</p>
+<pre><code> { &lt;code&gt; }</code></pre>
+<p>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.<a href="#fnref2" class="footnote-back">↩</a></p></li>
+<li id="fn3"><p>This is <em>easier</em> to type. Inline notes may contain <a href="http://google.com">links</a> and <code>]</code> verbatim characters, as well as [bracketed text].<a href="#fnref3" class="footnote-back">↩</a></p></li>
+<li id="fn4"><p>In quote.<a href="#fnref4" class="footnote-back">↩</a></p></li>
+<li id="fn5"><p>In list.<a href="#fnref5" class="footnote-back">↩</a></p></li>
+</ol>
+</section>
+</body>
+</html>
diff --git a/test/writer.icml b/test/writer.icml
new file mode 100644
index 000000000..6e070e264
--- /dev/null
+++ b/test/writer.icml
@@ -0,0 +1,3275 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<?aid style="50" type="snippet" readerVersion="6.0" featureSet="513" product="8.0(370)" ?>
+<?aid SnippetType="InCopyInterchange"?>
+<Document DOMVersion="8.0" Self="pandoc_doc">
+ <RootCharacterStyleGroup Self="pandoc_character_styles">
+ <CharacterStyle Self="$ID/NormalCharacterStyle" Name="Default" />
+ <CharacterStyle Self="CharacterStyle/" Name="">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Bold" Name="Bold" FontStyle="Bold">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Bold Italic" Name="Bold Italic" FontStyle="Bold Italic">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Code" Name="Code">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ <AppliedFont type="string">Courier New</AppliedFont>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Italic" Name="Italic" FontStyle="Italic">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Italic Link" Name="Italic Link" FontStyle="Italic">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Italic Strikeout" Name="Italic Strikeout" FontStyle="Italic" StrikeThru="true">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Italic Superscript" Name="Italic Superscript" FontStyle="Italic" Position="Superscript">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Link" Name="Link">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Strikeout" Name="Strikeout" StrikeThru="true">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Subscript" Name="Subscript" Position="Subscript">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ <CharacterStyle Self="CharacterStyle/Superscript" Name="Superscript" Position="Superscript">
+ <Properties>
+ <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
+ </Properties>
+ </CharacterStyle>
+ </RootCharacterStyleGroup>
+ <RootParagraphStyleGroup Self="pandoc_paragraph_styles">
+ <ParagraphStyle Self="$ID/NormalParagraphStyle" Name="$ID/NormalParagraphStyle"
+ SpaceBefore="6" SpaceAfter="6"> <!-- paragraph spacing -->
+ <Properties>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string"></Leader>
+ <Position type="unit">10</Position> <!-- first tab stop -->
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/" Name="" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; Blockquote &gt; Paragraph" Name="Blockquote &gt; Blockquote &gt; Paragraph" LeftIndent="30">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; CodeBlock" Name="Blockquote &gt; CodeBlock" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <AppliedFont type="string">Courier New</AppliedFont>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; NumList" Name="Blockquote &gt; NumList" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; NumList &gt; first" Name="Blockquote &gt; NumList &gt; first" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; Paragraph" Name="Blockquote &gt; Paragraph" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/BulList" Name="BulList" BulletsAndNumberingListType="BulletList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">10</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/BulList &gt; BulList &gt; BulList &gt; first" Name="BulList &gt; BulList &gt; BulList &gt; first" BulletsAndNumberingListType="BulletList" LeftIndent="20">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">30</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/BulList &gt; BulList &gt; Paragraph" Name="BulList &gt; BulList &gt; Paragraph" BulletsAndNumberingListType="BulletList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">20</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/BulList &gt; BulList &gt; first" Name="BulList &gt; BulList &gt; first" BulletsAndNumberingListType="BulletList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">20</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/BulList &gt; BulList &gt; first &gt; Paragraph" Name="BulList &gt; BulList &gt; first &gt; Paragraph" BulletsAndNumberingListType="BulletList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">20</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/BulList &gt; Paragraph" Name="BulList &gt; Paragraph" BulletsAndNumberingListType="BulletList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">10</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/BulList &gt; first" Name="BulList &gt; first" BulletsAndNumberingListType="BulletList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">10</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/BulList &gt; first &gt; Paragraph" Name="BulList &gt; first &gt; Paragraph" BulletsAndNumberingListType="BulletList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">10</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Caption" Name="Caption" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/CodeBlock" Name="CodeBlock" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <AppliedFont type="string">Courier New</AppliedFont>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/DefListDef" Name="DefListDef" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; Blockquote &gt; Paragraph" Name="DefListDef &gt; Blockquote &gt; Paragraph" LeftIndent="30">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; CodeBlock" Name="DefListDef &gt; CodeBlock" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <AppliedFont type="string">Courier New</AppliedFont>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; NumList" Name="DefListDef &gt; NumList" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; NumList &gt; first" Name="DefListDef &gt; NumList &gt; first" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; Paragraph" Name="DefListDef &gt; Paragraph" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/DefListTerm" Name="DefListTerm" LeftIndent="0" BulletsAndNumberingListType="BulletList" FontStyle="Bold">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Figure" Name="Figure" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Footnote &gt; CodeBlock" Name="Footnote &gt; CodeBlock" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <AppliedFont type="string">Courier New</AppliedFont>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Footnote &gt; Paragraph" Name="Footnote &gt; Paragraph" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Header1" Name="Header1" LeftIndent="0" PointSize="36">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Header2" Name="Header2" LeftIndent="0" PointSize="30">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Header3" Name="Header3" LeftIndent="0" PointSize="24">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Header4" Name="Header4" LeftIndent="0" PointSize="18">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Header5" Name="Header5" LeftIndent="0" PointSize="14">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList" Name="NumList" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; BulList" Name="NumList &gt; BulList" BulletsAndNumberingListType="BulletList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">20</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; BulList &gt; first" Name="NumList &gt; BulList &gt; first" BulletsAndNumberingListType="BulletList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <TabList type="list">
+ <ListItem type="record">
+ <Alignment type="enumeration">LeftAlign</Alignment>
+ <AlignmentCharacter type="string">.</AlignmentCharacter>
+ <Leader type="string" />
+ <Position type="unit">20</Position>
+ </ListItem>
+ </TabList>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-3 &gt; lowerAlpha" Name="NumList &gt; NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-3 &gt; lowerAlpha" NumberingExpression="^#.^t" NumberingLevel="4" BulletsAndNumberingListType="NumberedList" LeftIndent="30">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <NumberingFormat type="string">a, b, c, d...</NumberingFormat>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-6" Name="NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-6" NumberingExpression="^#.^t" NumberingLevel="3" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; first &gt; upperAlpha" Name="NumList &gt; NumList &gt; NumList &gt; first &gt; upperAlpha" NumberingExpression="^#.^t" NumberingLevel="3" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <NumberingFormat type="string">A, B, C, D...</NumberingFormat>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; upperAlpha" Name="NumList &gt; NumList &gt; NumList &gt; upperAlpha" NumberingExpression="^#.^t" NumberingLevel="3" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <NumberingFormat type="string">A, B, C, D...</NumberingFormat>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; beginsWith-4 &gt; lowerRoman" Name="NumList &gt; NumList &gt; beginsWith-4 &gt; lowerRoman" NumberingExpression="^#.^t" NumberingLevel="2" BulletsAndNumberingListType="NumberedList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <NumberingFormat type="string">i, ii, iii, iv...</NumberingFormat>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; first" Name="NumList &gt; NumList &gt; first" NumberingExpression="^#.^t" NumberingLevel="2" BulletsAndNumberingListType="NumberedList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; first &gt; beginsWith-4 &gt; lowerRoman" Name="NumList &gt; NumList &gt; first &gt; beginsWith-4 &gt; lowerRoman" NumberingExpression="^#.^t" NumberingLevel="2" BulletsAndNumberingListType="NumberedList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <NumberingFormat type="string">i, ii, iii, iv...</NumberingFormat>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; first &gt; upperRoman" Name="NumList &gt; NumList &gt; first &gt; upperRoman" NumberingExpression="^#.^t" NumberingLevel="2" BulletsAndNumberingListType="NumberedList" LeftIndent="10">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <NumberingFormat type="string">I, II, III, IV...</NumberingFormat>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; Paragraph" Name="NumList &gt; Paragraph" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; beginsWith-2 &gt; Paragraph" Name="NumList &gt; beginsWith-2 &gt; Paragraph" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; first" Name="NumList &gt; first" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; first &gt; Paragraph" Name="NumList &gt; first &gt; Paragraph" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; first &gt; beginsWith-2" Name="NumList &gt; first &gt; beginsWith-2" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; first &gt; upperAlpha" Name="NumList &gt; first &gt; upperAlpha" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ <NumberingFormat type="string">A, B, C, D...</NumberingFormat>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/NumList &gt; subParagraph &gt; Paragraph" Name="NumList &gt; subParagraph &gt; Paragraph" NumberingExpression="^#.^t" NumberingLevel="1" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ <ParagraphStyle Self="ParagraphStyle/Paragraph" Name="Paragraph" LeftIndent="0">
+ <Properties>
+ <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
+ </Properties>
+ </ParagraphStyle>
+ </RootParagraphStyleGroup>
+ <RootTableStyleGroup Self="pandoc_table_styles">
+ <TableStyle Self="TableStyle/Table" Name="Table" />
+ </RootTableStyleGroup>
+ <RootCellStyleGroup Self="pandoc_cell_styles">
+ <CellStyle Self="CellStyle/Cell" AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]" Name="Cell" />
+ </RootCellStyleGroup>
+ <Story Self="pandoc_story"
+ TrackChanges="false"
+ StoryTitle=""
+ AppliedTOCStyle="n"
+ AppliedNamedGrid="n" >
+ <StoryPreference OpticalMarginAlignment="true" OpticalMarginSize="12" />
+
+<!-- body needs to be non-indented, otherwise code blocks are indented too far -->
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Headers</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Level 2 with an </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-1" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>embedded link</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header3">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Level 3 with </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>emphasis</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header4">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Level 4</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header5">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Level 5</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Level 1</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Level 2 with </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>emphasis</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header3">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Level 3</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>with no blank line</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Level 2</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>with no blank line</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Paragraphs</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s a regular paragraph.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s one with a bullet. * criminey.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>There should be a hard line break</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>&#x2028;</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>here.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Block Quotes</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>E-mail style:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This is a block quote. It is pretty short.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Code in a block quote:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>sub status {
+ print &quot;working&quot;;
+}</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>A list:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; NumList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>item one</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>item two</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Nested block quotes:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>nested</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>nested</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This should not be a block quote: 2 &gt; 1.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>And a following paragraph.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Code Blocks</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Code:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>And:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Lists</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Unordered</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Asterisks tight:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>asterisk 1</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>asterisk 2</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>asterisk 3</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Asterisks loose:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>asterisk 1</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>asterisk 2</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>asterisk 3</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Pluses tight:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Plus 1</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Plus 2</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Plus 3</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Pluses loose:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Plus 1</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Plus 2</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Plus 3</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minuses tight:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minus 1</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minus 2</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minus 3</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minuses loose:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minus 1</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minus 2</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minus 3</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Ordered</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Tight:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>First</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Second</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Third</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>and:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>One</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Two</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Three</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Loose using tabs:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>First</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Second</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Third</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>and using spaces:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>One</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Two</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Three</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Multiple paragraphs:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Item 1, graf one.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; subParagraph &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Item 2.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Item 3.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Nested</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Tab</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Tab</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; BulList &gt; BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Tab</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s another:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>First</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Second:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Fee</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Fie</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Foe</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Third</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Same thing but with paragraphs:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>First</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Second:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Fee</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Fie</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Foe</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Third</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Tabs and spaces</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>this is a list item indented with tabs</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>this is a list item indented with spaces</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; BulList &gt; first &gt; Paragraph" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>this is an example list item indented with tabs</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; BulList &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>this is an example list item indented with spaces</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Fancy list markers</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange NumberingStartAt="2" AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; beginsWith-2" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>begins with 2</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; beginsWith-2 &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>and now 3</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; subParagraph &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>with a continuation</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange NumberingStartAt="4" AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; first &gt; beginsWith-4 &gt; lowerRoman" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>sublist with roman numerals, starting with 4</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; beginsWith-4 &gt; lowerRoman">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>more items</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; first &gt; upperAlpha" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>a subsublist</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; upperAlpha">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>a subsublist</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Nesting:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; upperAlpha" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Upper Alpha</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; first &gt; upperRoman" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Upper Roman.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange NumberingStartAt="6" AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-6" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Decimal start with 6</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange NumberingStartAt="3" AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-3 &gt; lowerAlpha" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Lower alpha with paren</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Autonumbering:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Autonumber.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>More.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Nested.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Should not be a list item:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>M.A. 2007</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>B. Williams</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Definition Lists</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Tight using spaces:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>apple</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>red fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>banana</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>yellow fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Tight using tabs:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>apple</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>red fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>banana</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>yellow fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Loose:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>apple</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>red fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>banana</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>yellow fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Multiple blocks with italics:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>apple</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>red fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>contains seeds, crisp, pleasant to taste</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>orange</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>{ orange code block }</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange block quote</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Multiple definitions, tight:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>apple</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>red fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>computer</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>bank</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Multiple definitions, loose:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>apple</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>red fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>computer</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>bank</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Blank line after term, indented marker, alternate markers:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>apple</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>red fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>computer</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>orange fruit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; NumList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>sublist</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; NumList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>sublist</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>HTML Blocks</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Simple block on one line:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>foo</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>And nested without indentation:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>foo</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>bar</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Interpreted markdown in a table:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>emphasized</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>And this is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold">
+ <Content>strong</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s a simple block:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>foo</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This should be a code block, though:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>&lt;div&gt;
+ foo
+&lt;/div&gt;</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>As should this:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>&lt;div&gt;foo&lt;/div&gt;</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Now, nested:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>foo</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This should just be an HTML comment:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Multiline:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Code block:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>&lt;!-- Comment --&gt;</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Just plain comment, with trailing spaces on the line:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Code:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>&lt;hr /&gt;</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Hr’s:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Inline Markup</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>emphasized</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>, and so </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>is this</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold">
+ <Content>strong</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>, and so </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold">
+ <Content>is this</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>An </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-2" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic Link">
+ <Content>emphasized link</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold Italic">
+ <Content>This is strong and em.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>So is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold Italic">
+ <Content>this</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> word.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold Italic">
+ <Content>This is strong and em.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>So is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold Italic">
+ <Content>this</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> word.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This is code: </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>&gt;</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>, </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>$</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>, </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>\</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>, </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>\$</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>, </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>&lt;html&gt;</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Strikeout">
+ <Content>This is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic Strikeout">
+ <Content>strikeout</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Strikeout">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Superscripts: a</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Superscript">
+ <Content>bc</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>d a</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic Superscript">
+ <Content>hello</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> a</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Superscript">
+ <Content>hello there</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Subscripts: H</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Subscript">
+ <Content>2</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>O, H</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Subscript">
+ <Content>23</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>O, H</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Subscript">
+ <Content>many of them</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>O.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Smart quotes, ellipses, dashes</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>“</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Hello,</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>”</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> said the spider. </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>“</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Shelob</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> is my name.</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>”</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>A</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>, </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>B</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>, and </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>C</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> are letters.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Oak,</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>elm,</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> and </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>beech</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> are names of trees. So is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>pine.</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>He said, </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>“</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>I want to go.</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>”</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> Were you alive in the 70’s?</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here is some quoted </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>‘</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>code</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>’</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> and a </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>“</Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-3" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>quoted link</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>”</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Some dashes: one—two — three—four — five.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Dashes between numbers: 5–7, 255–66, 1987–1999.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Ellipses…and…and….</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>LaTeX</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>2</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>+</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>2</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>=</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>4</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>x</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>∈</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>y</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>α</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>∧</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>ω</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>223</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>p</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>-Tree</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s some display math: </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s one that has a line break in it: </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>α</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>+</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>ω</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>×</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>x</Content>
+ </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Superscript">
+ <Content>2</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>These shouldn’t be math:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>To get the famous equation, write </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>$e = mc^2$</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>$22,000 is a </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>lot</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> of money. So is $34,000. (It worked if </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>“</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>lot</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>”</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> is emphasized.)</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Shoes ($20) and socks ($5).</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Escaped </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>$</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>: $73 </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>this should be emphasized</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> 23$.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s a LaTeX table:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Special Characters</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here is some unicode:</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>I hat: Î</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>o umlaut: ö</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>section: §</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>set membership: ∈</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>copyright: ©</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>AT&amp;T has an ampersand in their name.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>AT&amp;T is another way to write it.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This &amp; that.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>4 &lt; 5.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>6 &gt; 5.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Backslash: \</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Backtick: `</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Asterisk: *</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Underscore: _</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Left brace: {</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Right brace: }</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Left bracket: [</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Right bracket: ]</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Left paren: (</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Right paren: )</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Greater-than: &gt;</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Hash: #</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Period: .</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Bang: !</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Plus: +</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Minus: -</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Links</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Explicit</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Just a </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-4" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>URL</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-5" Name="title" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>URL and title</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-6" Name="title preceded by two spaces" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>URL and title</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-7" Name="title preceded by a tab" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>URL and title</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-8" Name="title with &quot;quotes&quot; in it" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>URL and title</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-9" Name="title with single quotes" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>URL and title</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-10" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>with_underscore</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-11" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>Email link</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-12" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>Empty</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Reference</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Foo </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-13" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>bar</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>With </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-14" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>embedded [brackets]</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <HyperlinkTextSource Self="htss-15" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>b</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> by itself should be a link.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Indented </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-16" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>once</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Indented </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-17" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>twice</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Indented </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-18" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>thrice</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This should [not][] be a link.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>[not]: /url</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Foo </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-19" Name="Title with &quot;quotes&quot; inside" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>bar</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Foo </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-20" Name="Title with &quot;quote&quot; inside" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>biz</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>With ampersands</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s a </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-21" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>link with an ampersand in the URL</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s a link with an amersand in the link text: </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-22" Name="AT&amp;T" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>AT&amp;T</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s an </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-23" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>inline link</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s an </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-24" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>inline link in pointy braces</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Autolinks</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>With an ampersand: </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-25" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>http://example.com/?foo=1&amp;bar=2</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>In a list?</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <HyperlinkTextSource Self="htss-26" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>http://example.com/</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>It should.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>An e-mail address: </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-27" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>nobody@nowhere.net</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Blockquoted: </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-28" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>http://example.com/</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Auto-links should not occur here: </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>&lt;http://example.com/&gt;</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>or here: &lt;http://example.com/&gt;</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Images</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>From </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>“</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Voyage dans la Lune</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>”</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> by Georges Melies (1902):</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Figure">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 75 -75">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-75 -75" LeftDirection="-75 -75" RightDirection="-75 -75" />
+ <PathPointType Anchor="-75 75" LeftDirection="-75 75" RightDirection="-75 75" />
+ <PathPointType Anchor="75 75" LeftDirection="75 75" RightDirection="75 75" />
+ <PathPointType Anchor="75 -75" LeftDirection="75 -75" RightDirection="75 -75" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -75 -75">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:lalune.jpg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Caption">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>lalune</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here is a movie </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 10 -11">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-10 -11" LeftDirection="-10 -11" RightDirection="-10 -11" />
+ <PathPointType Anchor="-10 11" LeftDirection="-10 11" RightDirection="-10 11" />
+ <PathPointType Anchor="10 11" LeftDirection="10 11" RightDirection="10 11" />
+ <PathPointType Anchor="10 -11" LeftDirection="10 -11" RightDirection="10 -11" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -10 -11">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:movie.jpg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> icon.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Footnotes</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here is a footnote reference,</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
+ <Footnote>
+ <ParagraphStyleRange>
+ <CharacterStyleRange>
+ <Content><?ACE 4?></Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Footnote>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> and another.</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
+ <Footnote>
+ <ParagraphStyleRange>
+ <CharacterStyleRange>
+ <Content><?ACE 4?></Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Here’s the long note. This one contains multiple blocks.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ <Br />
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Subsequent blocks are indented to show that they belong to the footnote (as with list items).</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ <Br />
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; CodeBlock">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> { &lt;code&gt; }</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ <Br />
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Footnote>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> This should </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>not</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> be a footnote reference, because it contains a space.[^my note] Here is an inline note.</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
+ <Footnote>
+ <ParagraphStyleRange>
+ <CharacterStyleRange>
+ <Content><?ACE 4?></Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This is </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
+ <Content>easier</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> to type. Inline notes may contain </Content>
+ </CharacterStyleRange>
+ <HyperlinkTextSource Self="htss-29" Name="" Hidden="false">
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
+ <Content>links</Content>
+ </CharacterStyleRange>
+ </HyperlinkTextSource>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> and </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
+ <Content>]</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> verbatim characters, as well as [bracketed text].</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Footnote>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>Notes can go in quotes.</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
+ <Footnote>
+ <ParagraphStyleRange>
+ <CharacterStyleRange>
+ <Content><?ACE 4?></Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>In quote.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Footnote>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>And in list items.</Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
+ <Footnote>
+ <ParagraphStyleRange>
+ <CharacterStyleRange>
+ <Content><?ACE 4?></Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content> </Content>
+ </CharacterStyleRange>
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>In list.</Content>
+ </CharacterStyleRange>
+ </ParagraphStyleRange>
+ </Footnote>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+<Br />
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Content>This paragraph should not be part of the note, as it is not indented.</Content>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+
+ </Story>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//google.com" Name="link" DestinationURL="http://google.com" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-29" Name="http://google.com" Source="htss-29" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/http%3a//google.com</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/" Name="link" DestinationURL="http://example.com/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-28" Name="http://example.com/" Source="htss-28" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/mailto%3anobody@nowhere.net" Name="link" DestinationURL="mailto:nobody@nowhere.net" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-27" Name="mailto:nobody@nowhere.net" Source="htss-27" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/mailto%3anobody@nowhere.net</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/" Name="link" DestinationURL="http://example.com/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-26" Name="http://example.com/" Source="htss-26" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-25" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-25" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//script?foo=1&amp;bar=2" Name="link" DestinationURL="/script?foo=1&amp;bar=2" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-24" Name="/script?foo=1&amp;bar=2" Source="htss-24" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//script?foo=1&amp;bar=2</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//script?foo=1&amp;bar=2" Name="link" DestinationURL="/script?foo=1&amp;bar=2" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-23" Name="/script?foo=1&amp;bar=2" Source="htss-23" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//script?foo=1&amp;bar=2</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//att.com/" Name="link" DestinationURL="http://att.com/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-22" Name="http://att.com/" Source="htss-22" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/http%3a//att.com/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-21" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-21" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-20" Name="/url/" Source="htss-20" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-19" Name="/url/" Source="htss-19" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-18" Name="/url" Source="htss-18" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-17" Name="/url" Source="htss-17" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-16" Name="/url" Source="htss-16" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-15" Name="/url/" Source="htss-15" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-14" Name="/url/" Source="htss-14" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-13" Name="/url/" Source="htss-13" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/" Name="link" DestinationURL="" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-12" Name="" Source="htss-12" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/mailto%3anobody@nowhere.net" Name="link" DestinationURL="mailto:nobody@nowhere.net" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-11" Name="mailto:nobody@nowhere.net" Source="htss-11" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/mailto%3anobody@nowhere.net</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/with_underscore" Name="link" DestinationURL="/url/with_underscore" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-10" Name="/url/with_underscore" Source="htss-10" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/with_underscore</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-9" Name="/url/" Source="htss-9" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-8" Name="/url/" Source="htss-8" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-7" Name="/url/" Source="htss-7" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-6" Name="/url/" Source="htss-6" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-5" Name="/url/" Source="htss-5" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-4" Name="/url/" Source="htss-4" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url/</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-3" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-3" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-2" Name="/url" Source="htss-2" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url</Destination>
+ </Properties>
+ </Hyperlink>
+ <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
+ <Hyperlink Self="uf-1" Name="/url" Source="htss-1" Visible="true" DestinationUniqueKey="1">
+ <Properties>
+ <BorderColor type="enumeration">Black</BorderColor>
+ <Destination type="object">HyperlinkURLDestination//url</Destination>
+ </Properties>
+ </Hyperlink>
+</Document>
diff --git a/test/writer.jats b/test/writer.jats
new file mode 100644
index 000000000..507e9f672
--- /dev/null
+++ b/test/writer.jats
@@ -0,0 +1,1448 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD v1.0 20120330//EN"
+ "JATS-journalpublishing1.dtd">
+<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.0" article-type="other">
+<front>
+<journal-meta>
+<journal-title-group>
+</journal-title-group>
+<publisher>
+<publisher-name></publisher-name>
+</publisher>
+</journal-meta>
+<article-meta>
+<title-group>
+<article-title>Pandoc Test Suite</article-title>
+</title-group>
+<contrib-group>
+<contrib contrib-type="author">
+<name>
+<string-name>John MacFarlane</string-name>
+</name>
+</contrib>
+<contrib contrib-type="author">
+<name>
+<string-name>Anonymous</string-name>
+</name>
+</contrib>
+</contrib-group>
+<pub-date pub-type="epub">
+<string-date>July 17, 2006</string-date>
+</pub-date>
+</article-meta>
+</front>
+<body>
+<p>
+ This is a set of tests for pandoc. Most of them are adapted from John
+ Gruber’s markdown test suite.
+</p>
+<sec id="headers">
+ <title>Headers</title>
+ <sec id="level-2-with-an-embedded-link">
+ <title>Level 2 with an
+ <ext-link ext-link-type="uri" xlink:href="/url">embedded
+ link</ext-link></title>
+ <sec id="level-3-with-emphasis">
+ <title>Level 3 with <italic>emphasis</italic></title>
+ <sec id="level-4">
+ <title>Level 4</title>
+ <sec id="level-5">
+ <title>Level 5</title>
+ </sec>
+ </sec>
+ </sec>
+ </sec>
+</sec>
+<sec id="level-1">
+ <title>Level 1</title>
+ <sec id="level-2-with-emphasis">
+ <title>Level 2 with <italic>emphasis</italic></title>
+ <sec id="level-3">
+ <title>Level 3</title>
+ <p>
+ with no blank line
+ </p>
+ </sec>
+ </sec>
+ <sec id="level-2">
+ <title>Level 2</title>
+ <p>
+ with no blank line
+ </p>
+ </sec>
+</sec>
+<sec id="paragraphs">
+ <title>Paragraphs</title>
+ <p>
+ Here’s a regular paragraph.
+ </p>
+ <p>
+ In Markdown 1.0.0 and earlier. Version 8. This line turns into a list
+ item. Because a hard-wrapped line in the middle of a paragraph looked like
+ a list item.
+ </p>
+ <p>
+ Here’s one with a bullet. * criminey.
+ </p>
+ <p>
+ There should be a hard line break<break />here.
+ </p>
+</sec>
+<sec id="block-quotes">
+ <title>Block Quotes</title>
+ <p>
+ E-mail style:
+ </p>
+ <disp-quote>
+ <p>
+ This is a block quote. It is pretty short.
+ </p>
+ </disp-quote>
+ <disp-quote>
+ <p>
+ Code in a block quote:
+ </p>
+ <preformat>sub status {
+ print &quot;working&quot;;
+}</preformat>
+ <p>
+ A list:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ item one
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ item two
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Nested block quotes:
+ </p>
+ <disp-quote>
+ <p>
+ nested
+ </p>
+ </disp-quote>
+ <disp-quote>
+ <p>
+ nested
+ </p>
+ </disp-quote>
+ </disp-quote>
+ <p>
+ This should not be a block quote: 2 &gt; 1.
+ </p>
+ <p>
+ And a following paragraph.
+ </p>
+</sec>
+<sec id="code-blocks">
+ <title>Code Blocks</title>
+ <p>
+ Code:
+ </p>
+ <preformat>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</preformat>
+ <p>
+ And:
+ </p>
+ <preformat> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
+</sec>
+<sec id="lists">
+ <title>Lists</title>
+ <sec id="unordered">
+ <title>Unordered</title>
+ <p>
+ Asterisks tight:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ asterisk 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ asterisk 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ asterisk 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Asterisks loose:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ asterisk 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ asterisk 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ asterisk 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Pluses tight:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Plus 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Plus 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Plus 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Pluses loose:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Plus 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Plus 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Plus 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Minuses tight:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Minus 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Minus 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Minus 3
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Minuses loose:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Minus 1
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Minus 2
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Minus 3
+ </p>
+ </list-item>
+ </list>
+ </sec>
+ <sec id="ordered">
+ <title>Ordered</title>
+ <p>
+ Tight:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ First
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Second
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Third
+ </p>
+ </list-item>
+ </list>
+ <p>
+ and:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ One
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Two
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Three
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Loose using tabs:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ First
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Second
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Third
+ </p>
+ </list-item>
+ </list>
+ <p>
+ and using spaces:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ One
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Two
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Three
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Multiple paragraphs:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ Item 1, graf one.
+ </p>
+ <p>
+ Item 1. graf two. The quick brown fox jumped over the lazy dog’s
+ back.
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Item 2.
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Item 3.
+ </p>
+ </list-item>
+ </list>
+ </sec>
+ <sec id="nested">
+ <title>Nested</title>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Tab
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Tab
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Tab
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ <p>
+ Here’s another:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ First
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Second:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Fee
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Fie
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Foe
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ <list-item>
+ <p>
+ Third
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Same thing but with paragraphs:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ First
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Second:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ Fee
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Fie
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Foe
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ <list-item>
+ <p>
+ Third
+ </p>
+ </list-item>
+ </list>
+ </sec>
+ <sec id="tabs-and-spaces">
+ <title>Tabs and spaces</title>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ this is a list item indented with tabs
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ this is a list item indented with spaces
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ this is an example list item indented with tabs
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ this is an example list item indented with spaces
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ </sec>
+ <sec id="fancy-list-markers">
+ <title>Fancy list markers</title>
+ <list list-type="order">
+ <list-item>
+ <label>
+ (2)
+ </label>
+ <p>
+ begins with 2
+ </p>
+ </list-item>
+ <list-item>
+ <label>
+ (3)
+ </label>
+ <p>
+ and now 3
+ </p>
+ <p>
+ with a continuation
+ </p>
+ <list list-type="roman-lower">
+ <list-item>
+ <label>
+ iv.
+ </label>
+ <p>
+ sublist with roman numerals, starting with 4
+ </p>
+ </list-item>
+ <list-item>
+ <label>
+ v.
+ </label>
+ <p>
+ more items
+ </p>
+ <list list-type="alpha-upper">
+ <list-item>
+ <label>
+ (A)
+ </label>
+ <p>
+ a subsublist
+ </p>
+ </list-item>
+ <list-item>
+ <label>
+ (B)
+ </label>
+ <p>
+ a subsublist
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ <p>
+ Nesting:
+ </p>
+ <list list-type="alpha-upper">
+ <list-item>
+ <p>
+ Upper Alpha
+ </p>
+ <list list-type="roman-upper">
+ <list-item>
+ <p>
+ Upper Roman.
+ </p>
+ <list list-type="order">
+ <list-item>
+ <label>
+ (6)
+ </label>
+ <p>
+ Decimal start with 6
+ </p>
+ <list list-type="alpha-lower">
+ <list-item>
+ <label>
+ c)
+ </label>
+ <p>
+ Lower alpha with paren
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ <p>
+ Autonumbering:
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ Autonumber.
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ More.
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ Nested.
+ </p>
+ </list-item>
+ </list>
+ </list-item>
+ </list>
+ <p>
+ Should not be a list item:
+ </p>
+ <p>
+ M.A. 2007
+ </p>
+ <p>
+ B. Williams
+ </p>
+ </sec>
+</sec>
+<sec id="definition-lists">
+ <title>Definition Lists</title>
+ <p>
+ Tight using spaces:
+ </p>
+ <def-list>
+ <def-item>
+ <term>
+ apple
+ </term>
+ <def>
+ <p>
+ red fruit
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ orange
+ </term>
+ <def>
+ <p>
+ orange fruit
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ banana
+ </term>
+ <def>
+ <p>
+ yellow fruit
+ </p>
+ </def>
+ </def-item>
+ </def-list>
+ <p>
+ Tight using tabs:
+ </p>
+ <def-list>
+ <def-item>
+ <term>
+ apple
+ </term>
+ <def>
+ <p>
+ red fruit
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ orange
+ </term>
+ <def>
+ <p>
+ orange fruit
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ banana
+ </term>
+ <def>
+ <p>
+ yellow fruit
+ </p>
+ </def>
+ </def-item>
+ </def-list>
+ <p>
+ Loose:
+ </p>
+ <def-list>
+ <def-item>
+ <term>
+ apple
+ </term>
+ <def>
+ <p>
+ red fruit
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ orange
+ </term>
+ <def>
+ <p>
+ orange fruit
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ banana
+ </term>
+ <def>
+ <p>
+ yellow fruit
+ </p>
+ </def>
+ </def-item>
+ </def-list>
+ <p>
+ Multiple blocks with italics:
+ </p>
+ <def-list>
+ <def-item>
+ <term>
+ <italic>apple</italic>
+ </term>
+ <def>
+ <p>
+ red fruit
+ </p>
+ <p>
+ contains seeds, crisp, pleasant to taste
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ <italic>orange</italic>
+ </term>
+ <def>
+ <p>
+ orange fruit
+ </p>
+ <preformat>{ orange code block }</preformat>
+ <disp-quote>
+ <p>
+ orange block quote
+ </p>
+ </disp-quote>
+ </def>
+ </def-item>
+ </def-list>
+ <p>
+ Multiple definitions, tight:
+ </p>
+ <def-list>
+ <def-item>
+ <term>
+ apple
+ </term>
+ <def>
+ <p>
+ red fruit
+ </p>
+ <p>
+ computer
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ orange
+ </term>
+ <def>
+ <p>
+ orange fruit
+ </p>
+ <p>
+ bank
+ </p>
+ </def>
+ </def-item>
+ </def-list>
+ <p>
+ Multiple definitions, loose:
+ </p>
+ <def-list>
+ <def-item>
+ <term>
+ apple
+ </term>
+ <def>
+ <p>
+ red fruit
+ </p>
+ <p>
+ computer
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ orange
+ </term>
+ <def>
+ <p>
+ orange fruit
+ </p>
+ <p>
+ bank
+ </p>
+ </def>
+ </def-item>
+ </def-list>
+ <p>
+ Blank line after term, indented marker, alternate markers:
+ </p>
+ <def-list>
+ <def-item>
+ <term>
+ apple
+ </term>
+ <def>
+ <p>
+ red fruit
+ </p>
+ <p>
+ computer
+ </p>
+ </def>
+ </def-item>
+ <def-item>
+ <term>
+ orange
+ </term>
+ <def>
+ <p>
+ orange fruit
+ </p>
+ <list list-type="order">
+ <list-item>
+ <p>
+ sublist
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ sublist
+ </p>
+ </list-item>
+ </list>
+ </def>
+ </def-item>
+ </def-list>
+</sec>
+<sec id="html-blocks">
+ <title>HTML Blocks</title>
+ <p>
+ Simple block on one line:
+ </p>
+ <boxed-text>
+ <p>
+ foo
+ </p>
+ </boxed-text>
+ <p>
+ And nested without indentation:
+ </p>
+ <boxed-text>
+ <boxed-text>
+ <boxed-text>
+ <p>
+ foo
+ </p>
+ </boxed-text>
+ </boxed-text>
+ <boxed-text>
+ <p>
+ bar
+ </p>
+ </boxed-text>
+ </boxed-text>
+ <p>
+ Interpreted markdown in a table:
+ </p>
+ <p>
+ This is <italic>emphasized</italic>
+ </p>
+ <p>
+ And this is <bold role="strong">strong</bold>
+ </p>
+ <p>
+ Here’s a simple block:
+ </p>
+ <boxed-text>
+ <p>
+ foo
+ </p>
+ </boxed-text>
+ <p>
+ This should be a code block, though:
+ </p>
+ <preformat>&lt;div&gt;
+ foo
+&lt;/div&gt;</preformat>
+ <p>
+ As should this:
+ </p>
+ <preformat>&lt;div&gt;foo&lt;/div&gt;</preformat>
+ <p>
+ Now, nested:
+ </p>
+ <boxed-text>
+ <boxed-text>
+ <boxed-text>
+ <p>
+ foo
+ </p>
+ </boxed-text>
+ </boxed-text>
+ </boxed-text>
+ <p>
+ This should just be an HTML comment:
+ </p>
+ <p>
+ Multiline:
+ </p>
+ <p>
+ Code block:
+ </p>
+ <preformat>&lt;!-- Comment --&gt;</preformat>
+ <p>
+ Just plain comment, with trailing spaces on the line:
+ </p>
+ <p>
+ Code:
+ </p>
+ <preformat>&lt;hr /&gt;</preformat>
+ <p>
+ Hr’s:
+ </p>
+</sec>
+<sec id="inline-markup">
+ <title>Inline Markup</title>
+ <p>
+ This is <italic>emphasized</italic>, and so <italic>is this</italic>.
+ </p>
+ <p>
+ This is <bold role="strong">strong</bold>, and so <bold role="strong">is
+ this</bold>.
+ </p>
+ <p>
+ An <italic><ext-link ext-link-type="uri" xlink:href="/url">emphasized
+ link</ext-link></italic>.
+ </p>
+ <p>
+ <bold role="strong"><italic>This is strong and em.</italic></bold>
+ </p>
+ <p>
+ So is <bold role="strong"><italic>this</italic></bold> word.
+ </p>
+ <p>
+ <bold role="strong"><italic>This is strong and em.</italic></bold>
+ </p>
+ <p>
+ So is <bold role="strong"><italic>this</italic></bold> word.
+ </p>
+ <p>
+ This is code: <monospace>&gt;</monospace>, <monospace>$</monospace>,
+ <monospace>\</monospace>, <monospace>\$</monospace>,
+ <monospace>&lt;html&gt;</monospace>.
+ </p>
+ <p>
+ <strike>This is <italic>strikeout</italic>.</strike>
+ </p>
+ <p>
+ Superscripts: a<sup>bc</sup>d a<sup><italic>hello</italic></sup>
+ a<sup>hello there</sup>.
+ </p>
+ <p>
+ Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.
+ </p>
+ <p>
+ These should not be superscripts or subscripts, because of the unescaped
+ spaces: a^b c^d, a~b c~d.
+ </p>
+</sec>
+<sec id="smart-quotes-ellipses-dashes">
+ <title>Smart quotes, ellipses, dashes</title>
+ <p>
+ “Hello,” said the spider. “‘Shelob’ is my name.”
+ </p>
+ <p>
+ ‘A’, ‘B’, and ‘C’ are letters.
+ </p>
+ <p>
+ ‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
+ </p>
+ <p>
+ ‘He said, “I want to go.”’ Were you alive in the 70’s?
+ </p>
+ <p>
+ Here is some quoted ‘<monospace>code</monospace>’ and a
+ “<ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&amp;bar=2">quoted
+ link</ext-link>”.
+ </p>
+ <p>
+ Some dashes: one—two — three—four — five.
+ </p>
+ <p>
+ Dashes between numbers: 5–7, 255–66, 1987–1999.
+ </p>
+ <p>
+ Ellipses…and…and….
+ </p>
+</sec>
+<sec id="latex">
+ <title>LaTeX</title>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ <inline-formula><alternatives>
+ <tex-math><![CDATA[2+2=4]]></tex-math>
+ <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>2</mml:mn><mml:mo>+</mml:mo><mml:mn>2</mml:mn><mml:mo>=</mml:mo><mml:mn>4</mml:mn></mml:mrow></mml:math></alternatives></inline-formula>
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ <inline-formula><alternatives>
+ <tex-math><![CDATA[x \in y]]></tex-math>
+ <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>x</mml:mi><mml:mo>∈</mml:mo><mml:mi>y</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ <inline-formula><alternatives>
+ <tex-math><![CDATA[\alpha \wedge \omega]]></tex-math>
+ <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>α</mml:mi><mml:mo>∧</mml:mo><mml:mi>ω</mml:mi></mml:mrow></mml:math></alternatives></inline-formula>
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ <inline-formula><alternatives>
+ <tex-math><![CDATA[223]]></tex-math>
+ <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>223</mml:mn></mml:math></alternatives></inline-formula>
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ <inline-formula><alternatives>
+ <tex-math><![CDATA[p]]></tex-math>
+ <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-Tree
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Here’s some display math: <disp-formula><alternatives>
+ <tex-math><![CDATA[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}]]></tex-math>
+ <mml:math display="block" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mfrac><mml:mi>d</mml:mi><mml:mrow><mml:mi>d</mml:mi><mml:mi>x</mml:mi></mml:mrow></mml:mfrac><mml:mi>f</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo>=</mml:mo><mml:munder><mml:mo>lim</mml:mo><mml:mrow><mml:mi>h</mml:mi><mml:mo>→</mml:mo><mml:mn>0</mml:mn></mml:mrow></mml:munder><mml:mfrac><mml:mrow><mml:mi>f</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo>+</mml:mo><mml:mi>h</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo>−</mml:mo><mml:mi>f</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow><mml:mi>h</mml:mi></mml:mfrac></mml:mrow></mml:math></alternatives></disp-formula>
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Here’s one that has a line break in it: <inline-formula><alternatives>
+ <tex-math><![CDATA[\alpha + \omega \times x^2]]></tex-math>
+ <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>α</mml:mi><mml:mo>+</mml:mo><mml:mi>ω</mml:mi><mml:mo>×</mml:mo><mml:msup><mml:mi>x</mml:mi><mml:mn>2</mml:mn></mml:msup></mml:mrow></mml:math></alternatives></inline-formula>.
+ </p>
+ </list-item>
+ </list>
+ <p>
+ These shouldn’t be math:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ To get the famous equation, write <monospace>$e = mc^2$</monospace>.
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ $22,000 is a <italic>lot</italic> of money. So is $34,000. (It worked
+ if “lot” is emphasized.)
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Shoes ($20) and socks ($5).
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ Escaped <monospace>$</monospace>: $73 <italic>this should be
+ emphasized</italic> 23$.
+ </p>
+ </list-item>
+ </list>
+ <p>
+ Here’s a LaTeX table:
+ </p>
+</sec>
+<sec id="special-characters">
+ <title>Special Characters</title>
+ <p>
+ Here is some unicode:
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ I hat: Î
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ o umlaut: ö
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ section: §
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ set membership: ∈
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ copyright: ©
+ </p>
+ </list-item>
+ </list>
+ <p>
+ AT&amp;T has an ampersand in their name.
+ </p>
+ <p>
+ AT&amp;T is another way to write it.
+ </p>
+ <p>
+ This &amp; that.
+ </p>
+ <p>
+ 4 &lt; 5.
+ </p>
+ <p>
+ 6 &gt; 5.
+ </p>
+ <p>
+ Backslash: \
+ </p>
+ <p>
+ Backtick: `
+ </p>
+ <p>
+ Asterisk: *
+ </p>
+ <p>
+ Underscore: _
+ </p>
+ <p>
+ Left brace: {
+ </p>
+ <p>
+ Right brace: }
+ </p>
+ <p>
+ Left bracket: [
+ </p>
+ <p>
+ Right bracket: ]
+ </p>
+ <p>
+ Left paren: (
+ </p>
+ <p>
+ Right paren: )
+ </p>
+ <p>
+ Greater-than: &gt;
+ </p>
+ <p>
+ Hash: #
+ </p>
+ <p>
+ Period: .
+ </p>
+ <p>
+ Bang: !
+ </p>
+ <p>
+ Plus: +
+ </p>
+ <p>
+ Minus: -
+ </p>
+</sec>
+<sec id="links">
+ <title>Links</title>
+ <sec id="explicit">
+ <title>Explicit</title>
+ <p>
+ Just a <ext-link ext-link-type="uri" xlink:href="/url/">URL</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title">URL
+ and title</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title preceded by two spaces">URL
+ and title</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title preceded by a tab">URL
+ and title</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title with &quot;quotes&quot; in it">URL
+ and title</ext-link>
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title with single quotes">URL
+ and title</ext-link>
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/with_underscore">with_underscore</ext-link>
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="mailto:nobody@nowhere.net">Email
+ link</ext-link>
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="">Empty</ext-link>.
+ </p>
+ </sec>
+ <sec id="reference">
+ <title>Reference</title>
+ <p>
+ Foo <ext-link ext-link-type="uri" xlink:href="/url/">bar</ext-link>.
+ </p>
+ <p>
+ With <ext-link ext-link-type="uri" xlink:href="/url/">embedded
+ [brackets]</ext-link>.
+ </p>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="/url/">b</ext-link> by itself
+ should be a link.
+ </p>
+ <p>
+ Indented
+ <ext-link ext-link-type="uri" xlink:href="/url">once</ext-link>.
+ </p>
+ <p>
+ Indented
+ <ext-link ext-link-type="uri" xlink:href="/url">twice</ext-link>.
+ </p>
+ <p>
+ Indented
+ <ext-link ext-link-type="uri" xlink:href="/url">thrice</ext-link>.
+ </p>
+ <p>
+ This should [not][] be a link.
+ </p>
+ <preformat>[not]: /url</preformat>
+ <p>
+ Foo
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="Title with &quot;quotes&quot; inside">bar</ext-link>.
+ </p>
+ <p>
+ Foo
+ <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="Title with &quot;quote&quot; inside">biz</ext-link>.
+ </p>
+ </sec>
+ <sec id="with-ampersands">
+ <title>With ampersands</title>
+ <p>
+ Here’s a
+ <ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&amp;bar=2">link
+ with an ampersand in the URL</ext-link>.
+ </p>
+ <p>
+ Here’s a link with an amersand in the link text:
+ <ext-link ext-link-type="uri" xlink:href="http://att.com/" xlink:title="AT&amp;T">AT&amp;T</ext-link>.
+ </p>
+ <p>
+ Here’s an
+ <ext-link ext-link-type="uri" xlink:href="/script?foo=1&amp;bar=2">inline
+ link</ext-link>.
+ </p>
+ <p>
+ Here’s an
+ <ext-link ext-link-type="uri" xlink:href="/script?foo=1&amp;bar=2">inline
+ link in pointy braces</ext-link>.
+ </p>
+ </sec>
+ <sec id="autolinks">
+ <title>Autolinks</title>
+ <p>
+ With an ampersand:
+ <ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</ext-link>
+ </p>
+ <list list-type="bullet">
+ <list-item>
+ <p>
+ In a list?
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link>
+ </p>
+ </list-item>
+ <list-item>
+ <p>
+ It should.
+ </p>
+ </list-item>
+ </list>
+ <p>
+ An e-mail address: <email>nobody@nowhere.net</email>
+ </p>
+ <disp-quote>
+ <p>
+ Blockquoted:
+ <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link>
+ </p>
+ </disp-quote>
+ <p>
+ Auto-links should not occur here:
+ <monospace>&lt;http://example.com/&gt;</monospace>
+ </p>
+ <preformat>or here: &lt;http://example.com/&gt;</preformat>
+ </sec>
+</sec>
+<sec id="images">
+ <title>Images</title>
+ <p>
+ From “Voyage dans la Lune” by Georges Melies (1902):
+ </p>
+ <fig>
+ <caption>lalune</caption>
+ <graphic mimetype="image" mime-subtype="jpeg" xlink:href="lalune.jpg" xlink:title="Voyage dans la Lune" />
+ </fig>
+ <p>
+ Here is a movie
+ <inline-graphic mimetype="image" mime-subtype="jpeg" xlink:href="movie.jpg" />
+ icon.
+ </p>
+</sec>
+<sec id="footnotes">
+ <title>Footnotes</title>
+ <p>
+ Here is a footnote reference,<fn>
+ <p>
+ Here is the footnote. It can go anywhere after the footnote reference.
+ It need not be placed at the end of the document.
+ </p>
+ </fn> and another.<fn>
+ <p>
+ Here’s the long note. This one contains multiple blocks.
+ </p>
+ <p>
+ Subsequent blocks are indented to show that they belong to the
+ footnote (as with list items).
+ </p>
+ <preformat> { &lt;code&gt; }</preformat>
+ <p>
+ If you want, you can indent every line, but you can also be lazy and
+ just indent the first line of each block.
+ </p>
+ </fn> This should <italic>not</italic> be a footnote reference, because it
+ contains a space.[^my note] Here is an inline note.<fn>
+ <p>
+ This is <italic>easier</italic> to type. Inline notes may contain
+ <ext-link ext-link-type="uri" xlink:href="http://google.com">links</ext-link>
+ and <monospace>]</monospace> verbatim characters, as well as
+ [bracketed text].
+ </p>
+ </fn>
+ </p>
+ <disp-quote>
+ <p>
+ Notes can go in quotes.<fn>
+ <p>
+ In quote.
+ </p>
+ </fn>
+ </p>
+ </disp-quote>
+ <list list-type="order">
+ <list-item>
+ <p>
+ And in list items.<fn>
+ <p>
+ In list.
+ </p>
+ </fn>
+ </p>
+ </list-item>
+ </list>
+ <p>
+ This paragraph should not be part of the note, as it is not indented.
+ </p>
+</sec>
+</body>
+<back>
+</back>
+</article>
diff --git a/test/writer.latex b/test/writer.latex
new file mode 100644
index 000000000..9500c7cf9
--- /dev/null
+++ b/test/writer.latex
@@ -0,0 +1,997 @@
+\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+\PassOptionsToPackage{hyphens}{url}
+%
+\documentclass[]{article}
+\usepackage{lmodern}
+\usepackage{amssymb,amsmath}
+\usepackage{ifxetex,ifluatex}
+\usepackage{fixltx2e} % provides \textsubscript
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+ \usepackage[T1]{fontenc}
+ \usepackage[utf8]{inputenc}
+ \usepackage{textcomp} % provides euro and other symbols
+\else % if luatex or xelatex
+ \usepackage{unicode-math}
+ \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
+\fi
+% use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+% use microtype if available
+\IfFileExists{microtype.sty}{%
+\usepackage[]{microtype}
+\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
+\usepackage{fancyvrb}
+\usepackage{hyperref}
+\hypersetup{
+ pdftitle={Pandoc Test Suite},
+ pdfauthor={John MacFarlane; Anonymous},
+ pdfborder={0 0 0},
+ breaklinks=true}
+\urlstyle{same} % don't use monospace font for urls
+\VerbatimFootnotes % allows verbatim text in footnotes
+\usepackage{graphicx,grffile}
+\makeatletter
+\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
+\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
+\makeatother
+% Scale images if necessary, so that they will not overflow the page
+% margins by default, and it is still possible to overwrite the defaults
+% using explicit options in \includegraphics[width, height, ...]{}
+\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
+\usepackage[normalem]{ulem}
+% avoid problems with \sout in headers with hyperref:
+\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+\setcounter{secnumdepth}{0}
+% Redefines (sub)paragraphs to behave more like sections
+\ifx\paragraph\undefined\else
+\let\oldparagraph\paragraph
+\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+\let\oldsubparagraph\subparagraph
+\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+
+% set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+
+
+\title{Pandoc Test Suite}
+\author{John MacFarlane \and Anonymous}
+\date{July 17, 2006}
+
+\begin{document}
+\maketitle
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber's
+markdown test suite.
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{headers}{%
+\section{Headers}\label{headers}}
+
+\hypertarget{level-2-with-an-embedded-link}{%
+\subsection{\texorpdfstring{Level 2 with an \href{/url}{embedded
+link}}{Level 2 with an embedded link}}\label{level-2-with-an-embedded-link}}
+
+\hypertarget{level-3-with-emphasis}{%
+\subsubsection{\texorpdfstring{Level 3 with
+\emph{emphasis}}{Level 3 with emphasis}}\label{level-3-with-emphasis}}
+
+\hypertarget{level-4}{%
+\paragraph{Level 4}\label{level-4}}
+
+\hypertarget{level-5}{%
+\subparagraph{Level 5}\label{level-5}}
+
+\hypertarget{level-1}{%
+\section{Level 1}\label{level-1}}
+
+\hypertarget{level-2-with-emphasis}{%
+\subsection{\texorpdfstring{Level 2 with
+\emph{emphasis}}{Level 2 with emphasis}}\label{level-2-with-emphasis}}
+
+\hypertarget{level-3}{%
+\subsubsection{Level 3}\label{level-3}}
+
+with no blank line
+
+\hypertarget{level-2}{%
+\subsection{Level 2}\label{level-2}}
+
+with no blank line
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{paragraphs}{%
+\section{Paragraphs}\label{paragraphs}}
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break\\
+here.
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{block-quotes}{%
+\section{Block Quotes}\label{block-quotes}}
+
+E-mail style:
+
+\begin{quote}
+This is a block quote. It is pretty short.
+\end{quote}
+
+\begin{quote}
+Code in a block quote:
+
+\begin{verbatim}
+sub status {
+ print "working";
+}
+\end{verbatim}
+
+A list:
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\tightlist
+\item
+ item one
+\item
+ item two
+\end{enumerate}
+
+Nested block quotes:
+
+\begin{quote}
+nested
+\end{quote}
+
+\begin{quote}
+nested
+\end{quote}
+\end{quote}
+
+This should not be a block quote: 2 \textgreater{} 1.
+
+And a following paragraph.
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{code-blocks}{%
+\section{Code Blocks}\label{code-blocks}}
+
+Code:
+
+\begin{verbatim}
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+\end{verbatim}
+
+And:
+
+\begin{verbatim}
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+\end{verbatim}
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{lists}{%
+\section{Lists}\label{lists}}
+
+\hypertarget{unordered}{%
+\subsection{Unordered}\label{unordered}}
+
+Asterisks tight:
+
+\begin{itemize}
+\tightlist
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\end{itemize}
+
+Asterisks loose:
+
+\begin{itemize}
+\item
+ asterisk 1
+\item
+ asterisk 2
+\item
+ asterisk 3
+\end{itemize}
+
+Pluses tight:
+
+\begin{itemize}
+\tightlist
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\end{itemize}
+
+Pluses loose:
+
+\begin{itemize}
+\item
+ Plus 1
+\item
+ Plus 2
+\item
+ Plus 3
+\end{itemize}
+
+Minuses tight:
+
+\begin{itemize}
+\tightlist
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\end{itemize}
+
+Minuses loose:
+
+\begin{itemize}
+\item
+ Minus 1
+\item
+ Minus 2
+\item
+ Minus 3
+\end{itemize}
+
+\hypertarget{ordered}{%
+\subsection{Ordered}\label{ordered}}
+
+Tight:
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\tightlist
+\item
+ First
+\item
+ Second
+\item
+ Third
+\end{enumerate}
+
+and:
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\tightlist
+\item
+ One
+\item
+ Two
+\item
+ Three
+\end{enumerate}
+
+Loose using tabs:
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\item
+ First
+\item
+ Second
+\item
+ Third
+\end{enumerate}
+
+and using spaces:
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\item
+ One
+\item
+ Two
+\item
+ Three
+\end{enumerate}
+
+Multiple paragraphs:
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\item
+ Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
+\item
+ Item 2.
+\item
+ Item 3.
+\end{enumerate}
+
+\hypertarget{nested}{%
+\subsection{Nested}\label{nested}}
+
+\begin{itemize}
+\tightlist
+\item
+ Tab
+
+ \begin{itemize}
+ \tightlist
+ \item
+ Tab
+
+ \begin{itemize}
+ \tightlist
+ \item
+ Tab
+ \end{itemize}
+ \end{itemize}
+\end{itemize}
+
+Here's another:
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\tightlist
+\item
+ First
+\item
+ Second:
+
+ \begin{itemize}
+ \tightlist
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \end{itemize}
+\item
+ Third
+\end{enumerate}
+
+Same thing but with paragraphs:
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\item
+ First
+\item
+ Second:
+
+ \begin{itemize}
+ \tightlist
+ \item
+ Fee
+ \item
+ Fie
+ \item
+ Foe
+ \end{itemize}
+\item
+ Third
+\end{enumerate}
+
+\hypertarget{tabs-and-spaces}{%
+\subsection{Tabs and spaces}\label{tabs-and-spaces}}
+
+\begin{itemize}
+\item
+ this is a list item indented with tabs
+\item
+ this is a list item indented with spaces
+
+ \begin{itemize}
+ \item
+ this is an example list item indented with tabs
+ \item
+ this is an example list item indented with spaces
+ \end{itemize}
+\end{itemize}
+
+\hypertarget{fancy-list-markers}{%
+\subsection{Fancy list markers}\label{fancy-list-markers}}
+
+\begin{enumerate}
+\def\labelenumi{(\arabic{enumi})}
+\setcounter{enumi}{1}
+\item
+ begins with 2
+\item
+ and now 3
+
+ with a continuation
+
+ \begin{enumerate}
+ \def\labelenumii{\roman{enumii}.}
+ \setcounter{enumii}{3}
+ \tightlist
+ \item
+ sublist with roman numerals, starting with 4
+ \item
+ more items
+
+ \begin{enumerate}
+ \def\labelenumiii{(\Alph{enumiii})}
+ \tightlist
+ \item
+ a subsublist
+ \item
+ a subsublist
+ \end{enumerate}
+ \end{enumerate}
+\end{enumerate}
+
+Nesting:
+
+\begin{enumerate}
+\def\labelenumi{\Alph{enumi}.}
+\tightlist
+\item
+ Upper Alpha
+
+ \begin{enumerate}
+ \def\labelenumii{\Roman{enumii}.}
+ \tightlist
+ \item
+ Upper Roman.
+
+ \begin{enumerate}
+ \def\labelenumiii{(\arabic{enumiii})}
+ \setcounter{enumiii}{5}
+ \tightlist
+ \item
+ Decimal start with 6
+
+ \begin{enumerate}
+ \def\labelenumiv{\alph{enumiv})}
+ \setcounter{enumiv}{2}
+ \tightlist
+ \item
+ Lower alpha with paren
+ \end{enumerate}
+ \end{enumerate}
+ \end{enumerate}
+\end{enumerate}
+
+Autonumbering:
+
+\begin{enumerate}
+\tightlist
+\item
+ Autonumber.
+\item
+ More.
+
+ \begin{enumerate}
+ \tightlist
+ \item
+ Nested.
+ \end{enumerate}
+\end{enumerate}
+
+Should not be a list item:
+
+M.A.~2007
+
+B. Williams
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{definition-lists}{%
+\section{Definition Lists}\label{definition-lists}}
+
+Tight using spaces:
+
+\begin{description}
+\tightlist
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+
+Tight using tabs:
+
+\begin{description}
+\tightlist
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+
+Loose:
+
+\begin{description}
+\item[apple]
+red fruit
+\item[orange]
+orange fruit
+\item[banana]
+yellow fruit
+\end{description}
+
+Multiple blocks with italics:
+
+\begin{description}
+\item[\emph{apple}]
+red fruit
+
+contains seeds, crisp, pleasant to taste
+\item[\emph{orange}]
+orange fruit
+
+\begin{verbatim}
+{ orange code block }
+\end{verbatim}
+
+\begin{quote}
+orange block quote
+\end{quote}
+\end{description}
+
+Multiple definitions, tight:
+
+\begin{description}
+\tightlist
+\item[apple]
+red fruit
+
+computer
+\item[orange]
+orange fruit
+
+bank
+\end{description}
+
+Multiple definitions, loose:
+
+\begin{description}
+\item[apple]
+red fruit
+
+computer
+\item[orange]
+orange fruit
+
+bank
+\end{description}
+
+Blank line after term, indented marker, alternate markers:
+
+\begin{description}
+\item[apple]
+red fruit
+
+computer
+\item[orange]
+orange fruit
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\tightlist
+\item
+ sublist
+\item
+ sublist
+\end{enumerate}
+\end{description}
+
+\hypertarget{html-blocks}{%
+\section{HTML Blocks}\label{html-blocks}}
+
+Simple block on one line:
+
+foo
+
+And nested without indentation:
+
+foo
+
+bar
+
+Interpreted markdown in a table:
+
+This is \emph{emphasized}
+
+And this is \textbf{strong}
+
+Here's a simple block:
+
+foo
+
+This should be a code block, though:
+
+\begin{verbatim}
+<div>
+ foo
+</div>
+\end{verbatim}
+
+As should this:
+
+\begin{verbatim}
+<div>foo</div>
+\end{verbatim}
+
+Now, nested:
+
+foo
+
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+\begin{verbatim}
+<!-- Comment -->
+\end{verbatim}
+
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+\begin{verbatim}
+<hr />
+\end{verbatim}
+
+Hr's:
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{inline-markup}{%
+\section{Inline Markup}\label{inline-markup}}
+
+This is \emph{emphasized}, and so \emph{is this}.
+
+This is \textbf{strong}, and so \textbf{is this}.
+
+An \emph{\href{/url}{emphasized link}}.
+
+\textbf{\emph{This is strong and em.}}
+
+So is \textbf{\emph{this}} word.
+
+\textbf{\emph{This is strong and em.}}
+
+So is \textbf{\emph{this}} word.
+
+This is code: \texttt{\textgreater{}}, \texttt{\$}, \texttt{\textbackslash{}},
+\texttt{\textbackslash{}\$}, \texttt{\textless{}html\textgreater{}}.
+
+\sout{This is \emph{strikeout}.}
+
+Superscripts: a\textsuperscript{bc}d a\textsuperscript{\emph{hello}}
+a\textsuperscript{hello~there}.
+
+Subscripts: H\textsubscript{2}O, H\textsubscript{23}O,
+H\textsubscript{many~of~them}O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a\^{}b c\^{}d, a\textasciitilde{}b c\textasciitilde{}d.
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{smart-quotes-ellipses-dashes}{%
+\section{Smart quotes, ellipses, dashes}\label{smart-quotes-ellipses-dashes}}
+
+``Hello,'' said the spider. ``\,`Shelob' is my name.''
+
+`A', `B', and `C' are letters.
+
+`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
+
+`He said, ``I want to go.''\,' Were you alive in the 70's?
+
+Here is some quoted `\texttt{code}' and a
+``\href{http://example.com/?foo=1\&bar=2}{quoted link}''.
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses\ldots{}and\ldots{}and\ldots{}.
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{latex}{%
+\section{LaTeX}\label{latex}}
+
+\begin{itemize}
+\tightlist
+\item
+ \cite[22-23]{smith.1899}
+\item
+ \(2+2=4\)
+\item
+ \(x \in y\)
+\item
+ \(\alpha \wedge \omega\)
+\item
+ \(223\)
+\item
+ \(p\)-Tree
+\item
+ Here's some display math:
+ \[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\]
+\item
+ Here's one that has a line break in it: \(\alpha + \omega \times x^2\).
+\end{itemize}
+
+These shouldn't be math:
+
+\begin{itemize}
+\tightlist
+\item
+ To get the famous equation, write \texttt{\$e\ =\ mc\^{}2\$}.
+\item
+ \$22,000 is a \emph{lot} of money. So is \$34,000. (It worked if ``lot'' is
+ emphasized.)
+\item
+ Shoes (\$20) and socks (\$5).
+\item
+ Escaped \texttt{\$}: \$73 \emph{this should be emphasized} 23\$.
+\end{itemize}
+
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{special-characters}{%
+\section{Special Characters}\label{special-characters}}
+
+Here is some unicode:
+
+\begin{itemize}
+\tightlist
+\item
+ I hat: Î
+\item
+ o umlaut: ö
+\item
+ section: §
+\item
+ set membership: ∈
+\item
+ copyright: ©
+\end{itemize}
+
+AT\&T has an ampersand in their name.
+
+AT\&T is another way to write it.
+
+This \& that.
+
+4 \textless{} 5.
+
+6 \textgreater{} 5.
+
+Backslash: \textbackslash{}
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: {[}
+
+Right bracket: {]}
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: \textgreater{}
+
+Hash: \#
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{links}{%
+\section{Links}\label{links}}
+
+\hypertarget{explicit}{%
+\subsection{Explicit}\label{explicit}}
+
+Just a \href{/url/}{URL}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}.
+
+\href{/url/}{URL and title}
+
+\href{/url/}{URL and title}
+
+\href{/url/with_underscore}{with\_underscore}
+
+\href{mailto:nobody@nowhere.net}{Email link}
+
+\href{}{Empty}.
+
+\hypertarget{reference}{%
+\subsection{Reference}\label{reference}}
+
+Foo \href{/url/}{bar}.
+
+With \href{/url/}{embedded {[}brackets{]}}.
+
+\href{/url/}{b} by itself should be a link.
+
+Indented \href{/url}{once}.
+
+Indented \href{/url}{twice}.
+
+Indented \href{/url}{thrice}.
+
+This should {[}not{]}{[}{]} be a link.
+
+\begin{verbatim}
+[not]: /url
+\end{verbatim}
+
+Foo \href{/url/}{bar}.
+
+Foo \href{/url/}{biz}.
+
+\hypertarget{with-ampersands}{%
+\subsection{With ampersands}\label{with-ampersands}}
+
+Here's a \href{http://example.com/?foo=1\&bar=2}{link with an ampersand in the
+URL}.
+
+Here's a link with an amersand in the link text:
+\href{http://att.com/}{AT\&T}.
+
+Here's an \href{/script?foo=1\&bar=2}{inline link}.
+
+Here's an \href{/script?foo=1\&bar=2}{inline link in pointy braces}.
+
+\hypertarget{autolinks}{%
+\subsection{Autolinks}\label{autolinks}}
+
+With an ampersand: \url{http://example.com/?foo=1\&bar=2}
+
+\begin{itemize}
+\tightlist
+\item
+ In a list?
+\item
+ \url{http://example.com/}
+\item
+ It should.
+\end{itemize}
+
+An e-mail address:
+\href{mailto:nobody@nowhere.net}{\nolinkurl{nobody@nowhere.net}}
+
+\begin{quote}
+Blockquoted: \url{http://example.com/}
+\end{quote}
+
+Auto-links should not occur here:
+\texttt{\textless{}http://example.com/\textgreater{}}
+
+\begin{verbatim}
+or here: <http://example.com/>
+\end{verbatim}
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{images}{%
+\section{Images}\label{images}}
+
+From ``Voyage dans la Lune'' by Georges Melies (1902):
+
+\begin{figure}
+\centering
+\includegraphics{lalune.jpg}
+\caption{lalune}
+\end{figure}
+
+Here is a movie \includegraphics{movie.jpg} icon.
+
+\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
+
+\hypertarget{footnotes}{%
+\section{Footnotes}\label{footnotes}}
+
+Here is a footnote reference,\footnote{Here is the footnote. It can go
+ anywhere after the footnote reference. It need not be placed at the end of
+ the document.} and another.\footnote{Here's the long note. This one contains
+ multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the footnote (as
+ with list items).
+
+\begin{Verbatim}
+ { <code> }
+\end{Verbatim}
+
+ If you want, you can indent every line, but you can also be lazy and just
+ indent the first line of each block.} This should \emph{not} be a footnote
+reference, because it contains a space.{[}\^{}my note{]} Here is an inline
+note.\footnote{This is \emph{easier} to type. Inline notes may contain
+ \href{http://google.com}{links} and \texttt{{]}} verbatim characters, as
+ well as {[}bracketed text{]}.}
+
+\begin{quote}
+Notes can go in quotes.\footnote{In quote.}
+\end{quote}
+
+\begin{enumerate}
+\def\labelenumi{\arabic{enumi}.}
+\tightlist
+\item
+ And in list items.\footnote{In list.}
+\end{enumerate}
+
+This paragraph should not be part of the note, as it is not indented.
+
+\end{document}
diff --git a/test/writer.man b/test/writer.man
new file mode 100644
index 000000000..f6d0deb92
--- /dev/null
+++ b/test/writer.man
@@ -0,0 +1,791 @@
+.TH "Pandoc Test Suite" "" "July 17, 2006" "" ""
+.hy
+.PP
+This is a set of tests for pandoc.
+Most of them are adapted from John Gruber's markdown test suite.
+.PP
+ * * * * *
+.SH Headers
+.SS Level 2 with an embedded link (/url)
+.SS Level 3 with \f[I]emphasis\f[]
+.SS Level 4
+.SS Level 5
+.SH Level 1
+.SS Level 2 with \f[I]emphasis\f[]
+.SS Level 3
+.PP
+with no blank line
+.SS Level 2
+.PP
+with no blank line
+.PP
+ * * * * *
+.SH Paragraphs
+.PP
+Here's a regular paragraph.
+.PP
+In Markdown 1.0.0 and earlier.
+Version 8.
+This line turns into a list item.
+Because a hard\-wrapped line in the middle of a paragraph looked like a list
+item.
+.PP
+Here's one with a bullet.
+* criminey.
+.PP
+There should be a hard line break
+.PD 0
+.P
+.PD
+here.
+.PP
+ * * * * *
+.SH Block Quotes
+.PP
+E\-mail style:
+.RS
+.PP
+This is a block quote.
+It is pretty short.
+.RE
+.RS
+.PP
+Code in a block quote:
+.IP
+.nf
+\f[C]
+sub\ status\ {
+\ \ \ \ print\ "working";
+}
+\f[]
+.fi
+.PP
+A list:
+.IP "1." 3
+item one
+.IP "2." 3
+item two
+.PP
+Nested block quotes:
+.RS
+.PP
+nested
+.RE
+.RS
+.PP
+nested
+.RE
+.RE
+.PP
+This should not be a block quote: 2 > 1.
+.PP
+And a following paragraph.
+.PP
+ * * * * *
+.SH Code Blocks
+.PP
+Code:
+.IP
+.nf
+\f[C]
+\-\-\-\-\ (should\ be\ four\ hyphens)
+
+sub\ status\ {
+\ \ \ \ print\ "working";
+}
+
+this\ code\ block\ is\ indented\ by\ one\ tab
+\f[]
+.fi
+.PP
+And:
+.IP
+.nf
+\f[C]
+\ \ \ \ this\ code\ block\ is\ indented\ by\ two\ tabs
+
+These\ should\ not\ be\ escaped:\ \ \\$\ \\\\\ \\>\ \\[\ \\{
+\f[]
+.fi
+.PP
+ * * * * *
+.SH Lists
+.SS Unordered
+.PP
+Asterisks tight:
+.IP \[bu] 2
+asterisk 1
+.IP \[bu] 2
+asterisk 2
+.IP \[bu] 2
+asterisk 3
+.PP
+Asterisks loose:
+.IP \[bu] 2
+asterisk 1
+.IP \[bu] 2
+asterisk 2
+.IP \[bu] 2
+asterisk 3
+.PP
+Pluses tight:
+.IP \[bu] 2
+Plus 1
+.IP \[bu] 2
+Plus 2
+.IP \[bu] 2
+Plus 3
+.PP
+Pluses loose:
+.IP \[bu] 2
+Plus 1
+.IP \[bu] 2
+Plus 2
+.IP \[bu] 2
+Plus 3
+.PP
+Minuses tight:
+.IP \[bu] 2
+Minus 1
+.IP \[bu] 2
+Minus 2
+.IP \[bu] 2
+Minus 3
+.PP
+Minuses loose:
+.IP \[bu] 2
+Minus 1
+.IP \[bu] 2
+Minus 2
+.IP \[bu] 2
+Minus 3
+.SS Ordered
+.PP
+Tight:
+.IP "1." 3
+First
+.IP "2." 3
+Second
+.IP "3." 3
+Third
+.PP
+and:
+.IP "1." 3
+One
+.IP "2." 3
+Two
+.IP "3." 3
+Three
+.PP
+Loose using tabs:
+.IP "1." 3
+First
+.IP "2." 3
+Second
+.IP "3." 3
+Third
+.PP
+and using spaces:
+.IP "1." 3
+One
+.IP "2." 3
+Two
+.IP "3." 3
+Three
+.PP
+Multiple paragraphs:
+.IP "1." 3
+Item 1, graf one.
+.RS 4
+.PP
+Item 1.
+graf two.
+The quick brown fox jumped over the lazy dog's back.
+.RE
+.IP "2." 3
+Item 2.
+.IP "3." 3
+Item 3.
+.SS Nested
+.IP \[bu] 2
+Tab
+.RS 2
+.IP \[bu] 2
+Tab
+.RS 2
+.IP \[bu] 2
+Tab
+.RE
+.RE
+.PP
+Here's another:
+.IP "1." 3
+First
+.IP "2." 3
+Second:
+.RS 4
+.IP \[bu] 2
+Fee
+.IP \[bu] 2
+Fie
+.IP \[bu] 2
+Foe
+.RE
+.IP "3." 3
+Third
+.PP
+Same thing but with paragraphs:
+.IP "1." 3
+First
+.IP "2." 3
+Second:
+.RS 4
+.IP \[bu] 2
+Fee
+.IP \[bu] 2
+Fie
+.IP \[bu] 2
+Foe
+.RE
+.IP "3." 3
+Third
+.SS Tabs and spaces
+.IP \[bu] 2
+this is a list item indented with tabs
+.IP \[bu] 2
+this is a list item indented with spaces
+.RS 2
+.IP \[bu] 2
+this is an example list item indented with tabs
+.IP \[bu] 2
+this is an example list item indented with spaces
+.RE
+.SS Fancy list markers
+.IP "(2)" 4
+begins with 2
+.IP "(3)" 4
+and now 3
+.RS 4
+.PP
+with a continuation
+.IP "iv." 4
+sublist with roman numerals, starting with 4
+.IP " v." 4
+more items
+.RS 4
+.IP "(A)" 4
+a subsublist
+.IP "(B)" 4
+a subsublist
+.RE
+.RE
+.PP
+Nesting:
+.IP "A." 3
+Upper Alpha
+.RS 4
+.IP "I." 3
+Upper Roman.
+.RS 4
+.IP "(6)" 4
+Decimal start with 6
+.RS 4
+.IP "c)" 3
+Lower alpha with paren
+.RE
+.RE
+.RE
+.PP
+Autonumbering:
+.IP "1." 3
+Autonumber.
+.IP "2." 3
+More.
+.RS 4
+.IP "1." 3
+Nested.
+.RE
+.PP
+Should not be a list item:
+.PP
+M.A.\ 2007
+.PP
+B.
+Williams
+.PP
+ * * * * *
+.SH Definition Lists
+.PP
+Tight using spaces:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.RE
+.TP
+.B banana
+yellow fruit
+.RS
+.RE
+.PP
+Tight using tabs:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.RE
+.TP
+.B banana
+yellow fruit
+.RS
+.RE
+.PP
+Loose:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.RE
+.TP
+.B banana
+yellow fruit
+.RS
+.RE
+.PP
+Multiple blocks with italics:
+.TP
+.B \f[I]apple\f[]
+red fruit
+.RS
+.PP
+contains seeds, crisp, pleasant to taste
+.RE
+.TP
+.B \f[I]orange\f[]
+orange fruit
+.RS
+.IP
+.nf
+\f[C]
+{\ orange\ code\ block\ }
+\f[]
+.fi
+.RS
+.PP
+orange block quote
+.RE
+.RE
+.PP
+Multiple definitions, tight:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+computer
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.RE
+bank
+.RS
+.RE
+.PP
+Multiple definitions, loose:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+computer
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.RE
+bank
+.RS
+.RE
+.PP
+Blank line after term, indented marker, alternate markers:
+.TP
+.B apple
+red fruit
+.RS
+.RE
+computer
+.RS
+.RE
+.TP
+.B orange
+orange fruit
+.RS
+.IP "1." 3
+sublist
+.IP "2." 3
+sublist
+.RE
+.SH HTML Blocks
+.PP
+Simple block on one line:
+foo
+.PP
+And nested without indentation:
+.PP
+foo
+bar
+.PP
+Interpreted markdown in a table:
+This is \f[I]emphasized\f[]
+And this is \f[B]strong\f[]
+.PP
+Here's a simple block:
+.PP
+foo
+.PP
+This should be a code block, though:
+.IP
+.nf
+\f[C]
+<div>
+\ \ \ \ foo
+</div>
+\f[]
+.fi
+.PP
+As should this:
+.IP
+.nf
+\f[C]
+<div>foo</div>
+\f[]
+.fi
+.PP
+Now, nested:
+foo
+.PP
+This should just be an HTML comment:
+.PP
+Multiline:
+.PP
+Code block:
+.IP
+.nf
+\f[C]
+<!\-\-\ Comment\ \-\->
+\f[]
+.fi
+.PP
+Just plain comment, with trailing spaces on the line:
+.PP
+Code:
+.IP
+.nf
+\f[C]
+<hr\ />
+\f[]
+.fi
+.PP
+Hr's:
+.PP
+ * * * * *
+.SH Inline Markup
+.PP
+This is \f[I]emphasized\f[], and so \f[I]is this\f[].
+.PP
+This is \f[B]strong\f[], and so \f[B]is this\f[].
+.PP
+An \f[I]emphasized link (/url)\f[].
+.PP
+\f[B]\f[BI]This is strong and em.\f[B]\f[]
+.PP
+So is \f[B]\f[BI]this\f[B]\f[] word.
+.PP
+\f[B]\f[BI]This is strong and em.\f[B]\f[]
+.PP
+So is \f[B]\f[BI]this\f[B]\f[] word.
+.PP
+This is code: \f[C]>\f[], \f[C]$\f[], \f[C]\\\f[], \f[C]\\$\f[],
+\f[C]<html>\f[].
+.PP
+[STRIKEOUT:This is \f[I]strikeout\f[].]
+.PP
+Superscripts: a^bc^d a^\f[I]hello\f[]^ a^hello\ there^.
+.PP
+Subscripts: H~2~O, H~23~O, H~many\ of\ them~O.
+.PP
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a~b c~d.
+.PP
+ * * * * *
+.SH Smart quotes, ellipses, dashes
+.PP
+\[lq]Hello,\[rq] said the spider.
+\[lq]`Shelob' is my name.\[rq]
+.PP
+`A', `B', and `C' are letters.
+.PP
+`Oak,' `elm,' and `beech' are names of trees.
+So is `pine.'
+.PP
+`He said, \[lq]I want to go.\[rq]' Were you alive in the 70's?
+.PP
+Here is some quoted `\f[C]code\f[]' and a \[lq]quoted
+link (http://example.com/?foo=1&bar=2)\[rq].
+.PP
+Some dashes: one\[em]two \[em] three\[em]four \[em] five.
+.PP
+Dashes between numbers: 5\[en]7, 255\[en]66, 1987\[en]1999.
+.PP
+Ellipses\&...and\&...and\&....
+.PP
+ * * * * *
+.SH LaTeX
+.IP \[bu] 2
+.IP \[bu] 2
+2 + 2 = 4
+.IP \[bu] 2
+\f[I]x\f[] ∈ \f[I]y\f[]
+.IP \[bu] 2
+\f[I]α\f[] ∧ \f[I]ω\f[]
+.IP \[bu] 2
+223
+.IP \[bu] 2
+\f[I]p\f[]\-Tree
+.IP \[bu] 2
+Here's some display math:
+.RS
+$$\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)\-f(x)}{h}$$
+.RE
+.IP \[bu] 2
+Here's one that has a line break in it:
+\f[I]α\f[] + \f[I]ω\f[] × \f[I]x\f[]^2^.
+.PP
+These shouldn't be math:
+.IP \[bu] 2
+To get the famous equation, write \f[C]$e\ =\ mc^2$\f[].
+.IP \[bu] 2
+$22,000 is a \f[I]lot\f[] of money.
+So is $34,000.
+(It worked if \[lq]lot\[rq] is emphasized.)
+.IP \[bu] 2
+Shoes ($20) and socks ($5).
+.IP \[bu] 2
+Escaped \f[C]$\f[]: $73 \f[I]this should be emphasized\f[] 23$.
+.PP
+Here's a LaTeX table:
+.PP
+ * * * * *
+.SH Special Characters
+.PP
+Here is some unicode:
+.IP \[bu] 2
+I hat: Î
+.IP \[bu] 2
+o umlaut: ö
+.IP \[bu] 2
+section: §
+.IP \[bu] 2
+set membership: ∈
+.IP \[bu] 2
+copyright: ©
+.PP
+AT&T has an ampersand in their name.
+.PP
+AT&T is another way to write it.
+.PP
+This & that.
+.PP
+4 < 5.
+.PP
+6 > 5.
+.PP
+Backslash: \\
+.PP
+Backtick: `
+.PP
+Asterisk: *
+.PP
+Underscore: _
+.PP
+Left brace: {
+.PP
+Right brace: }
+.PP
+Left bracket: [
+.PP
+Right bracket: ]
+.PP
+Left paren: (
+.PP
+Right paren: )
+.PP
+Greater\-than: >
+.PP
+Hash: #
+.PP
+Period: .
+.PP
+Bang: !
+.PP
+Plus: +
+.PP
+Minus: \-
+.PP
+ * * * * *
+.SH Links
+.SS Explicit
+.PP
+Just a URL (/url/).
+.PP
+URL and title (/url/).
+.PP
+URL and title (/url/).
+.PP
+URL and title (/url/).
+.PP
+URL and title (/url/)
+.PP
+URL and title (/url/)
+.PP
+with_underscore (/url/with_underscore)
+.PP
+Email link (mailto:nobody@nowhere.net)
+.PP
+Empty ().
+.SS Reference
+.PP
+Foo bar (/url/).
+.PP
+With embedded [brackets] (/url/).
+.PP
+b (/url/) by itself should be a link.
+.PP
+Indented once (/url).
+.PP
+Indented twice (/url).
+.PP
+Indented thrice (/url).
+.PP
+This should [not][] be a link.
+.IP
+.nf
+\f[C]
+[not]:\ /url
+\f[]
+.fi
+.PP
+Foo bar (/url/).
+.PP
+Foo biz (/url/).
+.SS With ampersands
+.PP
+Here's a link with an ampersand in the URL (http://example.com/?foo=1&bar=2).
+.PP
+Here's a link with an amersand in the link text: AT&T (http://att.com/).
+.PP
+Here's an inline link (/script?foo=1&bar=2).
+.PP
+Here's an inline link in pointy braces (/script?foo=1&bar=2).
+.SS Autolinks
+.PP
+With an ampersand: <http://example.com/?foo=1&bar=2>
+.IP \[bu] 2
+In a list?
+.IP \[bu] 2
+<http://example.com/>
+.IP \[bu] 2
+It should.
+.PP
+An e\-mail address: <nobody@nowhere.net>
+.RS
+.PP
+Blockquoted: <http://example.com/>
+.RE
+.PP
+Auto\-links should not occur here: \f[C]<http://example.com/>\f[]
+.IP
+.nf
+\f[C]
+or\ here:\ <http://example.com/>
+\f[]
+.fi
+.PP
+ * * * * *
+.SH Images
+.PP
+From \[lq]Voyage dans la Lune\[rq] by Georges Melies (1902):
+.PP
+[IMAGE: lalune (lalune.jpg)]
+.PP
+Here is a movie [IMAGE: movie (movie.jpg)] icon.
+.PP
+ * * * * *
+.SH Footnotes
+.PP
+Here is a footnote reference,[1] and another.[2] This should \f[I]not\f[] be a
+footnote reference, because it contains a space.[^my note] Here is an inline
+note.[3]
+.RS
+.PP
+Notes can go in quotes.[4]
+.RE
+.IP "1." 3
+And in list items.[5]
+.PP
+This paragraph should not be part of the note, as it is not indented.
+.SH NOTES
+.SS [1]
+.PP
+Here is the footnote.
+It can go anywhere after the footnote reference.
+It need not be placed at the end of the document.
+.SS [2]
+.PP
+Here's the long note.
+This one contains multiple blocks.
+.PP
+Subsequent blocks are indented to show that they belong to the footnote (as
+with list items).
+.IP
+.nf
+\f[C]
+\ \ {\ <code>\ }
+\f[]
+.fi
+.PP
+If you want, you can indent every line, but you can also be lazy and just
+indent the first line of each block.
+.SS [3]
+.PP
+This is \f[I]easier\f[] to type.
+Inline notes may contain links (http://google.com) and \f[C]]\f[] verbatim
+characters, as well as [bracketed text].
+.SS [4]
+.PP
+In quote.
+.SS [5]
+.PP
+In list.
+.SH AUTHORS
+John MacFarlane; Anonymous.
diff --git a/test/writer.markdown b/test/writer.markdown
new file mode 100644
index 000000000..0cc465f1e
--- /dev/null
+++ b/test/writer.markdown
@@ -0,0 +1,742 @@
+---
+author:
+- John MacFarlane
+- Anonymous
+date: 'July 17, 2006'
+title: Pandoc Test Suite
+---
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber's
+markdown test suite.
+
+------------------------------------------------------------------------------
+
+Headers
+=======
+
+Level 2 with an [embedded link](/url)
+-------------------------------------
+
+### Level 3 with *emphasis*
+
+#### Level 4
+
+##### Level 5
+
+Level 1
+=======
+
+Level 2 with *emphasis*
+-----------------------
+
+### Level 3
+
+with no blank line
+
+Level 2
+-------
+
+with no blank line
+
+------------------------------------------------------------------------------
+
+Paragraphs
+==========
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here's one with a bullet. \* criminey.
+
+There should be a hard line break\
+here.
+
+------------------------------------------------------------------------------
+
+Block Quotes
+============
+
+E-mail style:
+
+> This is a block quote. It is pretty short.
+
+> Code in a block quote:
+>
+> sub status {
+> print "working";
+> }
+>
+> A list:
+>
+> 1. item one
+> 2. item two
+>
+> Nested block quotes:
+>
+> > nested
+>
+> > nested
+
+This should not be a block quote: 2 \> 1.
+
+And a following paragraph.
+
+------------------------------------------------------------------------------
+
+Code Blocks
+===========
+
+Code:
+
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+
+And:
+
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+
+------------------------------------------------------------------------------
+
+Lists
+=====
+
+Unordered
+---------
+
+Asterisks tight:
+
+- asterisk 1
+- asterisk 2
+- asterisk 3
+
+Asterisks loose:
+
+- asterisk 1
+
+- asterisk 2
+
+- asterisk 3
+
+Pluses tight:
+
+- Plus 1
+- Plus 2
+- Plus 3
+
+Pluses loose:
+
+- Plus 1
+
+- Plus 2
+
+- Plus 3
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+Ordered
+-------
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
+
+2. Item 2.
+
+3. Item 3.
+
+Nested
+------
+
+- Tab
+ - Tab
+ - Tab
+
+Here's another:
+
+1. First
+2. Second:
+ - Fee
+ - Fie
+ - Foe
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+Tabs and spaces
+---------------
+
+- this is a list item indented with tabs
+
+- this is a list item indented with spaces
+
+ - this is an example list item indented with tabs
+
+ - this is an example list item indented with spaces
+
+Fancy list markers
+------------------
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+ iv. sublist with roman numerals, starting with 4
+ v. more items
+ (A) a subsublist
+ (B) a subsublist
+
+Nesting:
+
+A. Upper Alpha
+ I. Upper Roman.
+ (6) Decimal start with 6
+ c) Lower alpha with paren
+
+Autonumbering:
+
+1. Autonumber.
+2. More.
+ 1. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+------------------------------------------------------------------------------
+
+Definition Lists
+================
+
+Tight using spaces:
+
+apple
+: red fruit
+
+orange
+: orange fruit
+
+banana
+: yellow fruit
+
+Tight using tabs:
+
+apple
+: red fruit
+
+orange
+: orange fruit
+
+banana
+: yellow fruit
+
+Loose:
+
+apple
+
+: red fruit
+
+orange
+
+: orange fruit
+
+banana
+
+: yellow fruit
+
+Multiple blocks with italics:
+
+*apple*
+
+: red fruit
+
+ contains seeds, crisp, pleasant to taste
+
+*orange*
+
+: orange fruit
+
+ { orange code block }
+
+ > orange block quote
+
+Multiple definitions, tight:
+
+apple
+: red fruit
+: computer
+
+orange
+: orange fruit
+: bank
+
+Multiple definitions, loose:
+
+apple
+
+: red fruit
+
+: computer
+
+orange
+
+: orange fruit
+
+: bank
+
+Blank line after term, indented marker, alternate markers:
+
+apple
+
+: red fruit
+
+: computer
+
+orange
+
+: orange fruit
+
+ 1. sublist
+ 2. sublist
+
+HTML Blocks
+===========
+
+Simple block on one line:
+
+<div>
+
+foo
+
+</div>
+
+And nested without indentation:
+
+<div>
+
+<div>
+
+<div>
+
+foo
+
+</div>
+
+</div>
+
+<div>
+
+bar
+
+</div>
+
+</div>
+
+Interpreted markdown in a table:
+
+<table>
+<tr>
+<td>
+This is *emphasized*
+</td>
+<td>
+And this is **strong**
+</td>
+</tr>
+</table>
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+Here's a simple block:
+
+<div>
+
+foo
+
+</div>
+
+This should be a code block, though:
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+ <div>foo</div>
+
+Now, nested:
+
+<div>
+
+<div>
+
+<div>
+
+foo
+
+</div>
+
+</div>
+
+</div>
+
+This should just be an HTML comment:
+
+<!-- Comment -->
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+<!--
+ This is another comment.
+-->
+Code block:
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+Code:
+
+ <hr />
+
+Hr's:
+
+<hr>
+<hr />
+<hr />
+<hr>
+<hr />
+<hr />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar">
+
+------------------------------------------------------------------------------
+
+Inline Markup
+=============
+
+This is *emphasized*, and so *is this*.
+
+This is **strong**, and so **is this**.
+
+An *[emphasized link](/url)*.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+This is code: `>`, `$`, `\`, `\$`, `<html>`.
+
+~~This is *strikeout*.~~
+
+Superscripts: a^bc^d a^*hello*^ a^hello there^.
+
+Subscripts: H~2~O, H~23~O, H~many of them~O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a\^b c\^d, a\~b c\~d.
+
+------------------------------------------------------------------------------
+
+Smart quotes, ellipses, dashes
+==============================
+
+"Hello," said the spider. "'Shelob' is my name."
+
+'A', 'B', and 'C' are letters.
+
+'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
+
+'He said, "I want to go."' Were you alive in the 70's?
+
+Here is some quoted '`code`' and a "[quoted
+link](http://example.com/?foo=1&bar=2)".
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses...and...and....
+
+------------------------------------------------------------------------------
+
+LaTeX
+=====
+
+- \cite[22-23]{smith.1899}
+- $2+2=4$
+- $x \in y$
+- $\alpha \wedge \omega$
+- $223$
+- $p$-Tree
+- Here's some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+- Here's one that has a line break in it: $\alpha + \omega \times x^2$.
+
+These shouldn't be math:
+
+- To get the famous equation, write `$e = mc^2$`.
+- \$22,000 is a *lot* of money. So is \$34,000. (It worked if "lot" is
+ emphasized.)
+- Shoes (\$20) and socks (\$5).
+- Escaped `$`: \$73 *this should be emphasized* 23\$.
+
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+------------------------------------------------------------------------------
+
+Special Characters
+==================
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 \< 5.
+
+6 \> 5.
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: \[
+
+Right bracket: \]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: \>
+
+Hash: \#
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+------------------------------------------------------------------------------
+
+Links
+=====
+
+Explicit
+--------
+
+Just a [URL](/url/).
+
+[URL and title](/url/ "title").
+
+[URL and title](/url/ "title preceded by two spaces").
+
+[URL and title](/url/ "title preceded by a tab").
+
+[URL and title](/url/ "title with "quotes" in it")
+
+[URL and title](/url/ "title with single quotes")
+
+[with\_underscore](/url/with_underscore)
+
+[Email link](mailto:nobody@nowhere.net)
+
+[Empty]().
+
+Reference
+---------
+
+Foo [bar](/url/).
+
+With [embedded \[brackets\]](/url/).
+
+[b](/url/) by itself should be a link.
+
+Indented [once](/url).
+
+Indented [twice](/url).
+
+Indented [thrice](/url).
+
+This should \[not\]\[\] be a link.
+
+ [not]: /url
+
+Foo [bar](/url/ "Title with "quotes" inside").
+
+Foo [biz](/url/ "Title with "quote" inside").
+
+With ampersands
+---------------
+
+Here's a [link with an ampersand in the URL](http://example.com/?foo=1&bar=2).
+
+Here's a link with an amersand in the link text:
+[AT&T](http://att.com/ "AT&T").
+
+Here's an [inline link](/script?foo=1&bar=2).
+
+Here's an [inline link in pointy braces](/script?foo=1&bar=2).
+
+Autolinks
+---------
+
+With an ampersand: <http://example.com/?foo=1&bar=2>
+
+- In a list?
+- <http://example.com/>
+- It should.
+
+An e-mail address: <nobody@nowhere.net>
+
+> Blockquoted: <http://example.com/>
+
+Auto-links should not occur here: `<http://example.com/>`
+
+ or here: <http://example.com/>
+
+------------------------------------------------------------------------------
+
+Images
+======
+
+From "Voyage dans la Lune" by Georges Melies (1902):
+
+![lalune](lalune.jpg "Voyage dans la Lune")
+
+Here is a movie ![movie](movie.jpg) icon.
+
+------------------------------------------------------------------------------
+
+Footnotes
+=========
+
+Here is a footnote reference,[^1] and another.[^2] This should *not* be a
+footnote reference, because it contains a space.\[\^my note\] Here is an
+inline note.[^3]
+
+> Notes can go in quotes.[^4]
+
+1. And in list items.[^5]
+
+This paragraph should not be part of the note, as it is not indented.
+
+[^1]: Here is the footnote. It can go anywhere after the footnote reference.
+ It need not be placed at the end of the document.
+
+[^2]: Here's the long note. This one contains multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the footnote
+ (as with list items).
+
+ { <code> }
+
+ If you want, you can indent every line, but you can also be lazy and just
+ indent the first line of each block.
+
+[^3]: This is *easier* to type. Inline notes may contain
+ [links](http://google.com) and `]` verbatim characters, as well as
+ \[bracketed text\].
+
+[^4]: In quote.
+
+[^5]: In list.
diff --git a/test/writer.mediawiki b/test/writer.mediawiki
new file mode 100644
index 000000000..968eef388
--- /dev/null
+++ b/test/writer.mediawiki
@@ -0,0 +1,645 @@
+This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.
+
+
+-----
+
+= Headers =
+
+== Level 2 with an [[url|embedded link]] ==
+
+=== Level 3 with ''emphasis'' ===
+
+==== Level 4 ====
+
+===== Level 5 =====
+
+= Level 1 =
+
+== Level 2 with ''emphasis'' ==
+
+=== Level 3 ===
+
+with no blank line
+
+== Level 2 ==
+
+with no blank line
+
+
+-----
+
+= Paragraphs =
+
+Here’s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
+
+Here’s one with a bullet. * criminey.
+
+There should be a hard line break<br />
+here.
+
+
+-----
+
+= Block Quotes =
+
+E-mail style:
+
+<blockquote>This is a block quote. It is pretty short.
+</blockquote>
+<blockquote>Code in a block quote:
+
+<pre>sub status {
+ print &quot;working&quot;;
+}</pre>
+A list:
+
+# item one
+# item two
+
+Nested block quotes:
+
+<blockquote>nested
+</blockquote>
+<blockquote>nested
+</blockquote></blockquote>
+This should not be a block quote: 2 &gt; 1.
+
+And a following paragraph.
+
+
+-----
+
+= Code Blocks =
+
+Code:
+
+<pre>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</pre>
+And:
+
+<pre> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</pre>
+
+-----
+
+= Lists =
+
+== Unordered ==
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Asterisks loose:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Pluses tight:
+
+* Plus 1
+* Plus 2
+* Plus 3
+
+Pluses loose:
+
+* Plus 1
+* Plus 2
+* Plus 3
+
+Minuses tight:
+
+* Minus 1
+* Minus 2
+* Minus 3
+
+Minuses loose:
+
+* Minus 1
+* Minus 2
+* Minus 3
+
+== Ordered ==
+
+Tight:
+
+# First
+# Second
+# Third
+
+and:
+
+# One
+# Two
+# Three
+
+Loose using tabs:
+
+# First
+# Second
+# Third
+
+and using spaces:
+
+# One
+# Two
+# Three
+
+Multiple paragraphs:
+
+<ol style="list-style-type: decimal;">
+<li><p>Item 1, graf one.</p>
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.</p></li>
+<li><p>Item 2.</p></li>
+<li><p>Item 3.</p></li></ol>
+
+== Nested ==
+
+* Tab
+** Tab
+*** Tab
+
+Here’s another:
+
+# First
+# Second:
+#* Fee
+#* Fie
+#* Foe
+# Third
+
+Same thing but with paragraphs:
+
+# First
+# Second:
+#* Fee
+#* Fie
+#* Foe
+# Third
+
+== Tabs and spaces ==
+
+* this is a list item indented with tabs
+* this is a list item indented with spaces
+** this is an example list item indented with tabs
+** this is an example list item indented with spaces
+
+== Fancy list markers ==
+
+<ol start="2" style="list-style-type: decimal;">
+<li>begins with 2</li>
+<li><p>and now 3</p>
+<p>with a continuation</p>
+<ol start="4" style="list-style-type: lower-roman;">
+<li>sublist with roman numerals, starting with 4</li>
+<li>more items
+<ol style="list-style-type: upper-alpha;">
+<li>a subsublist</li>
+<li>a subsublist</li></ol>
+</li></ol>
+</li></ol>
+
+Nesting:
+
+<ol style="list-style-type: upper-alpha;">
+<li>Upper Alpha
+<ol style="list-style-type: upper-roman;">
+<li>Upper Roman.
+<ol start="6" style="list-style-type: decimal;">
+<li>Decimal start with 6
+<ol start="3" style="list-style-type: lower-alpha;">
+<li>Lower alpha with paren</li></ol>
+</li></ol>
+</li></ol>
+</li></ol>
+
+Autonumbering:
+
+# Autonumber.
+# More.
+## Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+
+-----
+
+= Definition Lists =
+
+Tight using spaces:
+
+; apple
+: red fruit
+; orange
+: orange fruit
+; banana
+: yellow fruit
+
+Tight using tabs:
+
+; apple
+: red fruit
+; orange
+: orange fruit
+; banana
+: yellow fruit
+
+Loose:
+
+; apple
+: red fruit
+; orange
+: orange fruit
+; banana
+: yellow fruit
+
+Multiple blocks with italics:
+
+<dl>
+<dt>''apple''</dt>
+<dd><p>red fruit</p>
+<p>contains seeds, crisp, pleasant to taste</p></dd>
+<dt>''orange''</dt>
+<dd><p>orange fruit</p>
+<pre>{ orange code block }</pre>
+<blockquote><p>orange block quote</p></blockquote></dd></dl>
+
+Multiple definitions, tight:
+
+; apple
+: red fruit
+: computer
+; orange
+: orange fruit
+: bank
+
+Multiple definitions, loose:
+
+; apple
+: red fruit
+: computer
+; orange
+: orange fruit
+: bank
+
+Blank line after term, indented marker, alternate markers:
+
+; apple
+: red fruit
+: computer
+; orange
+: orange fruit
+;# sublist
+;# sublist
+
+= HTML Blocks =
+
+Simple block on one line:
+
+<div>
+
+foo
+
+</div>
+And nested without indentation:
+
+<div>
+
+<div>
+
+<div>
+
+foo
+
+
+</div>
+
+</div>
+<div>
+
+bar
+
+</div>
+
+</div>
+Interpreted markdown in a table:
+
+<table>
+<tr>
+<td>
+This is ''emphasized''
+</td>
+<td>
+And this is '''strong'''
+</td>
+</tr>
+</table>
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+Here’s a simple block:
+
+<div>
+
+foo
+
+
+</div>
+This should be a code block, though:
+
+<pre>&lt;div&gt;
+ foo
+&lt;/div&gt;</pre>
+As should this:
+
+<pre>&lt;div&gt;foo&lt;/div&gt;</pre>
+Now, nested:
+
+<div>
+
+<div>
+
+<div>
+
+foo
+
+</div>
+
+</div>
+
+</div>
+This should just be an HTML comment:
+
+<!-- Comment -->
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+<!--
+ This is another comment.
+-->
+Code block:
+
+<pre>&lt;!-- Comment --&gt;</pre>
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+Code:
+
+<pre>&lt;hr /&gt;</pre>
+Hr’s:
+
+<hr>
+<hr />
+<hr />
+<hr>
+<hr />
+<hr />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar">
+
+-----
+
+= Inline Markup =
+
+This is ''emphasized'', and so ''is this''.
+
+This is '''strong''', and so '''is this'''.
+
+An ''[[url|emphasized link]]''.
+
+'''''This is strong and em.'''''
+
+So is '''''this''''' word.
+
+'''''This is strong and em.'''''
+
+So is '''''this''''' word.
+
+This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.
+
+<s>This is ''strikeout''.</s>
+
+Superscripts: a<sup>bc</sup>d a<sup>''hello''</sup> a<sup>hello there</sup>.
+
+Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.
+
+These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
+
+
+-----
+
+= Smart quotes, ellipses, dashes =
+
+“Hello,” said the spider. “‘Shelob’ is my name.”
+
+‘A’, ‘B’, and ‘C’ are letters.
+
+‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
+
+‘He said, “I want to go.”’ Were you alive in the 70’s?
+
+Here is some quoted ‘<code>code</code>’ and a “[http://example.com/?foo=1&bar=2 quoted link]”.
+
+Some dashes: one—two — three—four — five.
+
+Dashes between numbers: 5–7, 255–66, 1987–1999.
+
+Ellipses…and…and….
+
+
+-----
+
+= LaTeX =
+
+*
+* <math display="inline">2+2=4</math>
+* <math display="inline">x \in y</math>
+* <math display="inline">\alpha \wedge \omega</math>
+* <math display="inline">223</math>
+* <math display="inline">p</math>-Tree
+* Here’s some display math: <math display="block">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</math>
+* Here’s one that has a line break in it: <math display="inline">\alpha + \omega \times x^2</math>.
+
+These shouldn’t be math:
+
+* To get the famous equation, write <code>$e = mc^2$</code>.
+* $22,000 is a ''lot'' of money. So is $34,000. (It worked if “lot” is emphasized.)
+* Shoes ($20) and socks ($5).
+* Escaped <code>$</code>: $73 ''this should be emphasized'' 23$.
+
+Here’s a LaTeX table:
+
+
+
+-----
+
+= Special Characters =
+
+Here is some unicode:
+
+* I hat: Î
+* o umlaut: ö
+* section: §
+* set membership: ∈
+* copyright: ©
+
+AT&amp;T has an ampersand in their name.
+
+AT&amp;T is another way to write it.
+
+This &amp; that.
+
+4 &lt; 5.
+
+6 &gt; 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: &gt;
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+
+-----
+
+= Links =
+
+== Explicit ==
+
+Just a [[url/|URL]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]]
+
+[[url/|URL and title]]
+
+[[url/with_underscore|with_underscore]]
+
+[mailto:nobody@nowhere.net Email link]
+
+[[|Empty]].
+
+== Reference ==
+
+Foo [[url/|bar]].
+
+With [[url/|embedded [brackets]]].
+
+[[url/|b]] by itself should be a link.
+
+Indented [[url|once]].
+
+Indented [[url|twice]].
+
+Indented [[url|thrice]].
+
+This should [not][] be a link.
+
+<pre>[not]: /url</pre>
+Foo [[url/|bar]].
+
+Foo [[url/|biz]].
+
+== With ampersands ==
+
+Here’s a [http://example.com/?foo=1&bar=2 link with an ampersand in the URL].
+
+Here’s a link with an amersand in the link text: [http://att.com/ AT&amp;T].
+
+Here’s an [[script?foo=1&bar=2|inline link]].
+
+Here’s an [[script?foo=1&bar=2|inline link in pointy braces]].
+
+== Autolinks ==
+
+With an ampersand: http://example.com/?foo=1&bar=2
+
+* In a list?
+* http://example.com/
+* It should.
+
+An e-mail address: [mailto:nobody@nowhere.net nobody@nowhere.net]
+
+<blockquote>Blockquoted: http://example.com/
+</blockquote>
+Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code>
+
+<pre>or here: &lt;http://example.com/&gt;</pre>
+
+-----
+
+= Images =
+
+From “Voyage dans la Lune” by Georges Melies (1902):
+
+[[File:lalune.jpg|frame|none|alt=Voyage dans la Lune|caption lalune]]
+
+Here is a movie [[File:movie.jpg|movie]] icon.
+
+
+-----
+
+= Footnotes =
+
+Here is a footnote reference,<ref>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</ref> and another.<ref>Here’s the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the footnote (as with list items).
+
+<pre> { &lt;code&gt; }</pre>
+If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</ref> This should ''not'' be a footnote reference, because it contains a space.[^my note] Here is an inline note.<ref>This is ''easier'' to type. Inline notes may contain [http://google.com links] and <code>]</code> verbatim characters, as well as [bracketed text].</ref>
+
+<blockquote>Notes can go in quotes.<ref>In quote.</ref>
+</blockquote>
+# And in list items.<ref>In list.</ref>
+
+This paragraph should not be part of the note, as it is not indented.
+
+<references />
diff --git a/test/writer.ms b/test/writer.ms
new file mode 100644
index 000000000..7e079c55d
--- /dev/null
+++ b/test/writer.ms
@@ -0,0 +1,1005 @@
+.\" **** Custom macro definitions *********************************
+.\" * Super/subscript
+.\" (https://lists.gnu.org/archive/html/groff/2012-07/msg00046.html)
+.ds { \v'-0.3m'\\s[\\n[.s]*9u/12u]
+.ds } \s0\v'0.3m'
+.ds < \v'0.3m'\s[\\n[.s]*9u/12u]
+.ds > \s0\v'-0.3m'
+.\" * Horizontal line
+.de HLINE
+.LP
+.ce
+\l'20'
+..
+.\" **** Settings *************************************************
+.\" text width
+.nr LL 5.5i
+.\" left margin
+.nr PO 1.25i
+.\" top margin
+.nr HM 1.25i
+.\" bottom margin
+.nr FM 1.25i
+.\" header/footer width
+.nr LT \n[LL]
+.\" point size
+.nr PS 10p
+.\" line height
+.nr VS 12p
+.\" font family: A, BM, H, HN, N, P, T, ZCM
+.fam T
+.\" paragraph indent
+.nr PI 2m
+.\" interparagraph space
+.nr PD 0.33v
+.\" footnote width
+.nr FL \n[LL]
+.\" footnote point size
+.nr FPS (\n[PS] - 2000)
+.\" color used for strikeout
+.defcolor strikecolor rgb 0.7 0.7 0.7
+.\" color for links (rgb)
+.ds PDFHREF.COLOUR 0.35 0.00 0.60
+.\" border for links (default none)
+.ds PDFHREF.BORDER 0 0 0
+.\" point size difference between heading levels
+.nr PSINCR 1p
+.\" heading level above which point size no longer changes
+.nr GROWPS 2
+.\" comment these out if you want a dot after section numbers:
+.als SN SN-NO-DOT
+.als SN-STYLE SN-NO-DOT
+.\" pdf outline fold level
+.nr PDFOUTLINE.FOLDLEVEL 3
+.\" start out in outline view
+.pdfview /PageMode /UseOutlines
+.\" ***************************************************************
+.\" PDF metadata
+.pdfinfo /Title "Pandoc Test Suite"
+.pdfinfo /Author "John MacFarlane; Anonymous"
+.hy
+.EQ
+delim @@
+.EN
+.TL
+Pandoc Test Suite
+.AU
+John MacFarlane
+.AU
+Anonymous
+.ND "July 17, 2006"
+.\" 1 column (use .2C for two column)
+.1C
+.LP
+This is a set of tests for pandoc.
+Most of them are adapted from John Gruber's markdown test suite.
+.HLINE
+.SH 1
+Headers
+.pdfhref O 1 "Headers"
+.pdfhref M "headers"
+.SH 2
+Level 2 with an \c
+.pdfhref W -D "/url" -A "\c" \
+ -- "embedded link"
+\&
+.pdfhref O 2 "Level 2 with an embedded link"
+.pdfhref M "level-2-with-an-embedded-link"
+.SH 3
+Level 3 with \f[I]emphasis\f[]
+.pdfhref O 3 "Level 3 with emphasis"
+.pdfhref M "level-3-with-emphasis"
+.SH 4
+Level 4
+.pdfhref O 4 "Level 4"
+.pdfhref M "level-4"
+.SH 5
+Level 5
+.pdfhref O 5 "Level 5"
+.pdfhref M "level-5"
+.SH 1
+Level 1
+.pdfhref O 1 "Level 1"
+.pdfhref M "level-1"
+.SH 2
+Level 2 with \f[I]emphasis\f[]
+.pdfhref O 2 "Level 2 with emphasis"
+.pdfhref M "level-2-with-emphasis"
+.SH 3
+Level 3
+.pdfhref O 3 "Level 3"
+.pdfhref M "level-3"
+.LP
+with no blank line
+.SH 2
+Level 2
+.pdfhref O 2 "Level 2"
+.pdfhref M "level-2"
+.LP
+with no blank line
+.HLINE
+.SH 1
+Paragraphs
+.pdfhref O 1 "Paragraphs"
+.pdfhref M "paragraphs"
+.LP
+Here's a regular paragraph.
+.PP
+In Markdown 1.0.0 and earlier.
+Version 8.
+This line turns into a list item.
+Because a hard\-wrapped line in the middle of a paragraph looked like a list
+item.
+.PP
+Here's one with a bullet.
+* criminey.
+.PP
+There should be a hard line break
+.br
+here.
+.HLINE
+.SH 1
+Block Quotes
+.pdfhref O 1 "Block Quotes"
+.pdfhref M "block-quotes"
+.LP
+E\-mail style:
+.RS
+.LP
+This is a block quote.
+It is pretty short.
+.RE
+.RS
+.LP
+Code in a block quote:
+.IP
+.nf
+\f[C]
+sub\ status\ {
+\ \ \ \ print\ \[dq]working\[dq];
+}
+\f[]
+.fi
+.LP
+A list:
+.IP " 1." 4
+item one
+.IP " 2." 4
+item two
+.LP
+Nested block quotes:
+.RS
+.LP
+nested
+.RE
+.RS
+.LP
+nested
+.RE
+.RE
+.LP
+This should not be a block quote: 2 > 1.
+.PP
+And a following paragraph.
+.HLINE
+.SH 1
+Code Blocks
+.pdfhref O 1 "Code Blocks"
+.pdfhref M "code-blocks"
+.LP
+Code:
+.IP
+.nf
+\f[C]
+\-\-\-\-\ (should\ be\ four\ hyphens)
+
+sub\ status\ {
+\ \ \ \ print\ \[dq]working\[dq];
+}
+
+this\ code\ block\ is\ indented\ by\ one\ tab
+\f[]
+.fi
+.LP
+And:
+.IP
+.nf
+\f[C]
+\ \ \ \ this\ code\ block\ is\ indented\ by\ two\ tabs
+
+These\ should\ not\ be\ escaped:\ \ \\$\ \\\\\ \\>\ \\[\ \\{
+\f[]
+.fi
+.HLINE
+.SH 1
+Lists
+.pdfhref O 1 "Lists"
+.pdfhref M "lists"
+.SH 2
+Unordered
+.pdfhref O 2 "Unordered"
+.pdfhref M "unordered"
+.LP
+Asterisks tight:
+.IP \[bu] 3
+asterisk 1
+.IP \[bu] 3
+asterisk 2
+.IP \[bu] 3
+asterisk 3
+.LP
+Asterisks loose:
+.IP \[bu] 3
+asterisk 1
+.IP \[bu] 3
+asterisk 2
+.IP \[bu] 3
+asterisk 3
+.LP
+Pluses tight:
+.IP \[bu] 3
+Plus 1
+.IP \[bu] 3
+Plus 2
+.IP \[bu] 3
+Plus 3
+.LP
+Pluses loose:
+.IP \[bu] 3
+Plus 1
+.IP \[bu] 3
+Plus 2
+.IP \[bu] 3
+Plus 3
+.LP
+Minuses tight:
+.IP \[bu] 3
+Minus 1
+.IP \[bu] 3
+Minus 2
+.IP \[bu] 3
+Minus 3
+.LP
+Minuses loose:
+.IP \[bu] 3
+Minus 1
+.IP \[bu] 3
+Minus 2
+.IP \[bu] 3
+Minus 3
+.SH 2
+Ordered
+.pdfhref O 2 "Ordered"
+.pdfhref M "ordered"
+.LP
+Tight:
+.IP " 1." 4
+First
+.IP " 2." 4
+Second
+.IP " 3." 4
+Third
+.LP
+and:
+.IP " 1." 4
+One
+.IP " 2." 4
+Two
+.IP " 3." 4
+Three
+.LP
+Loose using tabs:
+.IP " 1." 4
+First
+.IP " 2." 4
+Second
+.IP " 3." 4
+Third
+.LP
+and using spaces:
+.IP " 1." 4
+One
+.IP " 2." 4
+Two
+.IP " 3." 4
+Three
+.LP
+Multiple paragraphs:
+.IP " 1." 4
+Item 1, graf one.
+.RS 4
+.PP
+Item 1.
+graf two.
+The quick brown fox jumped over the lazy dog's back.
+.RE
+.IP " 2." 4
+Item 2.
+.IP " 3." 4
+Item 3.
+.SH 2
+Nested
+.pdfhref O 2 "Nested"
+.pdfhref M "nested"
+.IP \[bu] 3
+Tab
+.RS 3
+.IP \[bu] 3
+Tab
+.RS 3
+.IP \[bu] 3
+Tab
+.RE
+.RE
+.LP
+Here's another:
+.IP " 1." 4
+First
+.IP " 2." 4
+Second:
+.RS 4
+.IP \[bu] 3
+Fee
+.IP \[bu] 3
+Fie
+.IP \[bu] 3
+Foe
+.RE
+.IP " 3." 4
+Third
+.LP
+Same thing but with paragraphs:
+.IP " 1." 4
+First
+.IP " 2." 4
+Second:
+.RS 4
+.IP \[bu] 3
+Fee
+.IP \[bu] 3
+Fie
+.IP \[bu] 3
+Foe
+.RE
+.IP " 3." 4
+Third
+.SH 2
+Tabs and spaces
+.pdfhref O 2 "Tabs and spaces"
+.pdfhref M "tabs-and-spaces"
+.IP \[bu] 3
+this is a list item indented with tabs
+.IP \[bu] 3
+this is a list item indented with spaces
+.RS 3
+.IP \[bu] 3
+this is an example list item indented with tabs
+.IP \[bu] 3
+this is an example list item indented with spaces
+.RE
+.SH 2
+Fancy list markers
+.pdfhref O 2 "Fancy list markers"
+.pdfhref M "fancy-list-markers"
+.IP " (2)" 5
+begins with 2
+.IP " (3)" 5
+and now 3
+.RS 5
+.LP
+with a continuation
+.IP " iv." 5
+sublist with roman numerals, starting with 4
+.IP " v." 5
+more items
+.RS 5
+.IP " (A)" 5
+a subsublist
+.IP " (B)" 5
+a subsublist
+.RE
+.RE
+.LP
+Nesting:
+.IP " A." 4
+Upper Alpha
+.RS 4
+.IP " I." 4
+Upper Roman.
+.RS 4
+.IP " (6)" 5
+Decimal start with 6
+.RS 5
+.IP " c)" 4
+Lower alpha with paren
+.RE
+.RE
+.RE
+.LP
+Autonumbering:
+.IP " 1." 4
+Autonumber.
+.IP " 2." 4
+More.
+.RS 4
+.IP " 1." 4
+Nested.
+.RE
+.LP
+Should not be a list item:
+.PP
+M.A.\~2007
+.PP
+B.
+Williams
+.HLINE
+.SH 1
+Definition Lists
+.pdfhref O 1 "Definition Lists"
+.pdfhref M "definition-lists"
+.LP
+Tight using spaces:
+.IP "apple"
+red fruit
+.RS
+.RE
+.IP "orange"
+orange fruit
+.RS
+.RE
+.IP "banana"
+yellow fruit
+.RS
+.RE
+.LP
+Tight using tabs:
+.IP "apple"
+red fruit
+.RS
+.RE
+.IP "orange"
+orange fruit
+.RS
+.RE
+.IP "banana"
+yellow fruit
+.RS
+.RE
+.LP
+Loose:
+.IP "apple"
+red fruit
+.RS
+.RE
+.IP "orange"
+orange fruit
+.RS
+.RE
+.IP "banana"
+yellow fruit
+.RS
+.RE
+.LP
+Multiple blocks with italics:
+.IP "\f[I]apple\f[]"
+red fruit
+.RS
+.PP
+contains seeds, crisp, pleasant to taste
+.RE
+.IP "\f[I]orange\f[]"
+orange fruit
+.RS
+.IP
+.nf
+\f[C]
+{\ orange\ code\ block\ }
+\f[]
+.fi
+.RS
+.LP
+orange block quote
+.RE
+.RE
+.LP
+Multiple definitions, tight:
+.IP "apple"
+red fruit
+.RS
+.RE
+computer
+.RS
+.RE
+.IP "orange"
+orange fruit
+.RS
+.RE
+bank
+.RS
+.RE
+.LP
+Multiple definitions, loose:
+.IP "apple"
+red fruit
+.RS
+.RE
+computer
+.RS
+.RE
+.IP "orange"
+orange fruit
+.RS
+.RE
+bank
+.RS
+.RE
+.LP
+Blank line after term, indented marker, alternate markers:
+.IP "apple"
+red fruit
+.RS
+.RE
+computer
+.RS
+.RE
+.IP "orange"
+orange fruit
+.RS
+.IP " 1." 4
+sublist
+.IP " 2." 4
+sublist
+.RE
+.SH 1
+HTML Blocks
+.pdfhref O 1 "HTML Blocks"
+.pdfhref M "html-blocks"
+.LP
+Simple block on one line:
+foo
+.LP
+And nested without indentation:
+.LP
+foo
+bar
+.LP
+Interpreted markdown in a table:
+This is \f[I]emphasized\f[]
+And this is \f[B]strong\f[]
+.PP
+Here's a simple block:
+.LP
+foo
+.LP
+This should be a code block, though:
+.IP
+.nf
+\f[C]
+<div>
+\ \ \ \ foo
+</div>
+\f[]
+.fi
+.LP
+As should this:
+.IP
+.nf
+\f[C]
+<div>foo</div>
+\f[]
+.fi
+.LP
+Now, nested:
+foo
+.LP
+This should just be an HTML comment:
+.PP
+Multiline:
+.PP
+Code block:
+.IP
+.nf
+\f[C]
+<!\-\-\ Comment\ \-\->
+\f[]
+.fi
+.LP
+Just plain comment, with trailing spaces on the line:
+.PP
+Code:
+.IP
+.nf
+\f[C]
+<hr\ />
+\f[]
+.fi
+.LP
+Hr's:
+.HLINE
+.SH 1
+Inline Markup
+.pdfhref O 1 "Inline Markup"
+.pdfhref M "inline-markup"
+.LP
+This is \f[I]emphasized\f[], and so \f[I]is this\f[].
+.PP
+This is \f[B]strong\f[], and so \f[B]is this\f[].
+.PP
+An \f[I]\c
+.pdfhref W -D "/url" -A "\c" \
+ -- "emphasized link"
+\&\f[].
+.PP
+\f[B]\f[BI]This is strong and em.\f[B]\f[]
+.PP
+So is \f[B]\f[BI]this\f[B]\f[] word.
+.PP
+\f[B]\f[BI]This is strong and em.\f[B]\f[]
+.PP
+So is \f[B]\f[BI]this\f[B]\f[] word.
+.PP
+This is code: \f[C]>\f[], \f[C]$\f[], \f[C]\\\f[], \f[C]\\$\f[],
+\f[C]<html>\f[].
+.PP
+\m[strikecolor]This is \f[I]strikeout\f[].\m[]
+.PP
+Superscripts: a\*{bc\*}d a\*{\f[I]hello\f[]\*} a\*{hello\~there\*}.
+.PP
+Subscripts: H\*<2\*>O, H\*<23\*>O, H\*<many\~of\~them\*>O.
+.PP
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a\[ha]b c\[ha]d, a\[ti]b c\[ti]d.
+.HLINE
+.SH 1
+Smart quotes, ellipses, dashes
+.pdfhref O 1 "Smart quotes, ellipses, dashes"
+.pdfhref M "smart-quotes-ellipses-dashes"
+.LP
+\[lq]Hello,\[rq] said the spider.
+\[lq]`Shelob' is my name.\[rq]
+.PP
+`A', `B', and `C' are letters.
+.PP
+`Oak,' `elm,' and `beech' are names of trees.
+So is `pine.'
+.PP
+`He said, \[lq]I want to go.\[rq]' Were you alive in the 70's?
+.PP
+Here is some quoted `\f[C]code\f[]' and a \[lq]\c
+.pdfhref W -D "http://example.com/?foo=1&bar=2" -A "\c" \
+ -- "quoted link"
+\&\[rq].
+.PP
+Some dashes: one\[em]two \[em] three\[em]four \[em] five.
+.PP
+Dashes between numbers: 5\[en]7, 255\[en]66, 1987\[en]1999.
+.PP
+Ellipses\&...and\&...and\&....
+.HLINE
+.SH 1
+LaTeX
+.pdfhref O 1 "LaTeX"
+.pdfhref M "latex"
+.IP \[bu] 3
+.IP \[bu] 3
+@2 + 2 = 4@
+.IP \[bu] 3
+@x \[u2208] y@
+.IP \[bu] 3
+@alpha \[u2227] omega@
+.IP \[bu] 3
+@223@
+.IP \[bu] 3
+@p@\-Tree
+.IP \[bu] 3
+Here's some display math:
+.EQ
+d over {d x} f ( x ) = lim sub {h -> 0} {f ( x + h ) \[u2212] f ( x )} over h
+.EN
+.IP \[bu] 3
+Here's one that has a line break in it: @alpha + omega times x sup 2@.
+.LP
+These shouldn't be math:
+.IP \[bu] 3
+To get the famous equation, write \f[C]$e\ =\ mc\[ha]2$\f[].
+.IP \[bu] 3
+$22,000 is a \f[I]lot\f[] of money.
+So is $34,000.
+(It worked if \[lq]lot\[rq] is emphasized.)
+.IP \[bu] 3
+Shoes ($20) and socks ($5).
+.IP \[bu] 3
+Escaped \f[C]$\f[]: $73 \f[I]this should be emphasized\f[] 23$.
+.LP
+Here's a LaTeX table:
+.HLINE
+.SH 1
+Special Characters
+.pdfhref O 1 "Special Characters"
+.pdfhref M "special-characters"
+.LP
+Here is some unicode:
+.IP \[bu] 3
+I hat: Î
+.IP \[bu] 3
+o umlaut: ö
+.IP \[bu] 3
+section: §
+.IP \[bu] 3
+set membership: ∈
+.IP \[bu] 3
+copyright: ©
+.LP
+AT&T has an ampersand in their name.
+.PP
+AT&T is another way to write it.
+.PP
+This & that.
+.PP
+4 < 5.
+.PP
+6 > 5.
+.PP
+Backslash: \\
+.PP
+Backtick: \`
+.PP
+Asterisk: *
+.PP
+Underscore: _
+.PP
+Left brace: {
+.PP
+Right brace: }
+.PP
+Left bracket: [
+.PP
+Right bracket: ]
+.PP
+Left paren: (
+.PP
+Right paren: )
+.PP
+Greater\-than: >
+.PP
+Hash: #
+.PP
+Period: .
+.PP
+Bang: !
+.PP
+Plus: +
+.PP
+Minus: \-
+.HLINE
+.SH 1
+Links
+.pdfhref O 1 "Links"
+.pdfhref M "links"
+.SH 2
+Explicit
+.pdfhref O 2 "Explicit"
+.pdfhref M "explicit"
+.LP
+Just a \c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "URL"
+\&.
+.PP
+\c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "URL and title"
+\&.
+.PP
+\c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "URL and title"
+\&.
+.PP
+\c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "URL and title"
+\&.
+.PP
+\c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "URL and title"
+\&
+.PP
+\c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "URL and title"
+\&
+.PP
+\c
+.pdfhref W -D "/url/with_underscore" -A "\c" \
+ -- "with_underscore"
+\&
+.PP
+\c
+.pdfhref W -D "mailto:nobody%40nowhere.net" -A "\c" \
+ -- "Email link"
+\&
+.PP
+\c
+.pdfhref W -D "" -A "\c" \
+ -- "Empty"
+\&.
+.SH 2
+Reference
+.pdfhref O 2 "Reference"
+.pdfhref M "reference"
+.LP
+Foo \c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "bar"
+\&.
+.PP
+With \c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "embedded [brackets]"
+\&.
+.PP
+\c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "b"
+\& by itself should be a link.
+.PP
+Indented \c
+.pdfhref W -D "/url" -A "\c" \
+ -- "once"
+\&.
+.PP
+Indented \c
+.pdfhref W -D "/url" -A "\c" \
+ -- "twice"
+\&.
+.PP
+Indented \c
+.pdfhref W -D "/url" -A "\c" \
+ -- "thrice"
+\&.
+.PP
+This should [not][] be a link.
+.IP
+.nf
+\f[C]
+[not]:\ /url
+\f[]
+.fi
+.LP
+Foo \c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "bar"
+\&.
+.PP
+Foo \c
+.pdfhref W -D "/url/" -A "\c" \
+ -- "biz"
+\&.
+.SH 2
+With ampersands
+.pdfhref O 2 "With ampersands"
+.pdfhref M "with-ampersands"
+.LP
+Here's a \c
+.pdfhref W -D "http://example.com/?foo=1&bar=2" -A "\c" \
+ -- "link with an ampersand in the URL"
+\&.
+.PP
+Here's a link with an amersand in the link text: \c
+.pdfhref W -D "http://att.com/" -A "\c" \
+ -- "AT&T"
+\&.
+.PP
+Here's an \c
+.pdfhref W -D "/script?foo=1&bar=2" -A "\c" \
+ -- "inline link"
+\&.
+.PP
+Here's an \c
+.pdfhref W -D "/script?foo=1&bar=2" -A "\c" \
+ -- "inline link in pointy braces"
+\&.
+.SH 2
+Autolinks
+.pdfhref O 2 "Autolinks"
+.pdfhref M "autolinks"
+.LP
+With an ampersand: \c
+.pdfhref W -D "http://example.com/?foo=1&bar=2" -A "\c" \
+ -- "http://example.com/?foo=1&bar=2"
+\&
+.IP \[bu] 3
+In a list?
+.IP \[bu] 3
+\c
+.pdfhref W -D "http://example.com/" -A "\c" \
+ -- "http://example.com/"
+\&
+.IP \[bu] 3
+It should.
+.LP
+An e\-mail address: \c
+.pdfhref W -D "mailto:nobody%40nowhere.net" -A "\c" \
+ -- "nobody\@nowhere.net"
+\&
+.RS
+.LP
+Blockquoted: \c
+.pdfhref W -D "http://example.com/" -A "\c" \
+ -- "http://example.com/"
+\&
+.RE
+.LP
+Auto\-links should not occur here: \f[C]<http://example.com/>\f[]
+.IP
+.nf
+\f[C]
+or\ here:\ <http://example.com/>
+\f[]
+.fi
+.HLINE
+.SH 1
+Images
+.pdfhref O 1 "Images"
+.pdfhref M "images"
+.LP
+From \[lq]Voyage dans la Lune\[rq] by Georges Melies (1902):
+.PP
+[IMAGE: lalune]
+.PP
+Here is a movie [IMAGE: movie] icon.
+.HLINE
+.SH 1
+Footnotes
+.pdfhref O 1 "Footnotes"
+.pdfhref M "footnotes"
+.LP
+Here is a footnote reference,\**
+.FS
+Here is the footnote.
+It can go anywhere after the footnote reference.
+It need not be placed at the end of the document.
+.FE
+and another.\**
+.FS
+Here's the long note.
+This one contains multiple blocks.
+.PP
+Subsequent blocks are indented to show that they belong to the footnote (as
+with list items).
+.IP
+.nf
+\f[C]
+\ \ {\ <code>\ }
+\f[]
+.fi
+.LP
+If you want, you can indent every line, but you can also be lazy and just
+indent the first line of each block.
+.FE
+This should \f[I]not\f[] be a footnote reference, because it contains a
+space.[\[ha]my note] Here is an inline note.\**
+.FS
+This is \f[I]easier\f[] to type.
+Inline notes may contain \c
+.pdfhref W -D "http://google.com" -A "\c" \
+ -- "links"
+\& and \f[C]]\f[] verbatim characters, as well as [bracketed text].
+.FE
+.RS
+.LP
+Notes can go in quotes.\**
+.FS
+In quote.
+.FE
+.RE
+.IP " 1." 4
+And in list items.\**
+.FS
+In list.
+.FE
+.LP
+This paragraph should not be part of the note, as it is not indented.
+.pdfsync
diff --git a/test/writer.muse b/test/writer.muse
new file mode 100644
index 000000000..6cb766955
--- /dev/null
+++ b/test/writer.muse
@@ -0,0 +1,725 @@
+#author John MacFarlane
+#title Pandoc Test Suite
+#date July 17, 2006
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
+markdown test suite.
+
+----
+
+* Headers
+
+** Level 2 with an [[/url][embedded link]]
+
+*** Level 3 with <em>emphasis</em>
+
+**** Level 4
+
+***** Level 5
+
+* Level 1
+
+** Level 2 with <em>emphasis</em>
+
+*** Level 3
+
+with no blank line
+
+** Level 2
+
+with no blank line
+
+----
+
+* Paragraphs
+
+Here’s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here’s one with a bullet. <verbatim>*</verbatim> criminey.
+
+There should be a hard line break<br>
+here.
+
+----
+
+* Block Quotes
+
+E-mail style:
+
+<quote>
+This is a block quote. It is pretty short.
+</quote>
+
+<quote>
+Code in a block quote:
+
+<example>
+sub status {
+ print "working";
+}
+</example>
+
+A list:
+
+ 1. item one
+ 2. item two
+
+Nested block quotes:
+
+<quote>
+nested
+</quote>
+
+<quote>
+nested
+</quote>
+</quote>
+
+This should not be a block quote: 2 <verbatim>></verbatim> 1.
+
+And a following paragraph.
+
+----
+
+* Code Blocks
+
+Code:
+
+<example>
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+</example>
+
+And:
+
+<example>
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+</example>
+
+----
+
+* Lists
+
+** Unordered
+
+Asterisks tight:
+
+ - asterisk 1
+ - asterisk 2
+ - asterisk 3
+
+Asterisks loose:
+
+ - asterisk 1
+ - asterisk 2
+ - asterisk 3
+
+Pluses tight:
+
+ - Plus 1
+ - Plus 2
+ - Plus 3
+
+Pluses loose:
+
+ - Plus 1
+ - Plus 2
+ - Plus 3
+
+Minuses tight:
+
+ - Minus 1
+ - Minus 2
+ - Minus 3
+
+Minuses loose:
+
+ - Minus 1
+ - Minus 2
+ - Minus 3
+
+** Ordered
+
+Tight:
+
+ 1. First
+ 2. Second
+ 3. Third
+
+and:
+
+ 1. One
+ 2. Two
+ 3. Three
+
+Loose using tabs:
+
+ 1. First
+ 2. Second
+ 3. Third
+
+and using spaces:
+
+ 1. One
+ 2. Two
+ 3. Three
+
+Multiple paragraphs:
+
+ 1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
+ 2. Item 2.
+ 3. Item 3.
+
+** Nested
+
+ - Tab
+ - Tab
+ - Tab
+
+Here’s another:
+
+ 1. First
+ 2. Second:
+ - Fee
+ - Fie
+ - Foe
+ 3. Third
+
+Same thing but with paragraphs:
+
+ 1. First
+ 2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+ 3. Third
+
+** Tabs and spaces
+
+ - this is a list item indented with tabs
+ - this is a list item indented with spaces
+
+ - this is an example list item indented with tabs
+ - this is an example list item indented with spaces
+
+** Fancy list markers
+
+ 2. begins with 2
+ 3. and now 3
+
+ with a continuation
+
+ iv. sublist with roman numerals, starting with 4
+ v. more items
+ A. a subsublist
+ B. a subsublist
+
+Nesting:
+
+ A. Upper Alpha
+ I. Upper Roman.
+ 6. Decimal start with 6
+ c. Lower alpha with paren
+
+Autonumbering:
+
+ 1. Autonumber.
+ 2. More.
+ 1. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+----
+
+* Definition Lists
+
+Tight using spaces:
+
+ apple :: red fruit
+ orange :: orange fruit
+ banana :: yellow fruit
+
+Tight using tabs:
+
+ apple :: red fruit
+ orange :: orange fruit
+ banana :: yellow fruit
+
+Loose:
+
+ apple :: red fruit
+ orange :: orange fruit
+ banana :: yellow fruit
+
+Multiple blocks with italics:
+
+ <em>apple</em> :: red fruit
+
+ contains seeds, crisp, pleasant to taste
+ <em>orange</em> :: orange fruit
+
+ <example>
+ { orange code block }
+ </example>
+
+ <quote>
+ orange block quote
+ </quote>
+
+Multiple definitions, tight:
+
+ apple :: red fruit
+ :: computer
+ orange :: orange fruit
+ :: bank
+
+Multiple definitions, loose:
+
+ apple :: red fruit
+ :: computer
+ orange :: orange fruit
+ :: bank
+
+Blank line after term, indented marker, alternate markers:
+
+ apple :: red fruit
+ :: computer
+ orange :: orange fruit
+
+ 1. sublist
+ 2. sublist
+
+* HTML Blocks
+
+Simple block on one line:
+
+foo
+And nested without indentation:
+
+foo
+
+bar
+Interpreted markdown in a table:
+
+<literal style="html">
+<table>
+</literal>
+
+<literal style="html">
+<tr>
+</literal>
+
+<literal style="html">
+<td>
+</literal>
+
+This is <em>emphasized</em>
+
+<literal style="html">
+</td>
+</literal>
+
+<literal style="html">
+<td>
+</literal>
+
+And this is <strong>strong</strong>
+
+<literal style="html">
+</td>
+</literal>
+
+<literal style="html">
+</tr>
+</literal>
+
+<literal style="html">
+</table>
+</literal>
+
+<literal style="html">
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+</literal>
+
+Here’s a simple block:
+
+foo
+
+This should be a code block, though:
+
+<example>
+<div>
+ foo
+</div>
+</example>
+
+As should this:
+
+<example>
+<div>foo</div>
+</example>
+
+Now, nested:
+
+foo
+This should just be an HTML comment:
+
+<literal style="html">
+<!-- Comment -->
+</literal>
+
+Multiline:
+
+<literal style="html">
+<!--
+Blah
+Blah
+-->
+</literal>
+
+<literal style="html">
+<!--
+ This is another comment.
+-->
+</literal>
+
+Code block:
+
+<example>
+<!-- Comment -->
+</example>
+
+Just plain comment, with trailing spaces on the line:
+
+<literal style="html">
+<!-- foo -->
+</literal>
+
+Code:
+
+<example>
+<hr />
+</example>
+
+Hr’s:
+
+<literal style="html">
+<hr>
+</literal>
+
+<literal style="html">
+<hr />
+</literal>
+
+<literal style="html">
+<hr />
+</literal>
+
+<literal style="html">
+<hr>
+</literal>
+
+<literal style="html">
+<hr />
+</literal>
+
+<literal style="html">
+<hr />
+</literal>
+
+<literal style="html">
+<hr class="foo" id="bar" />
+</literal>
+
+<literal style="html">
+<hr class="foo" id="bar" />
+</literal>
+
+<literal style="html">
+<hr class="foo" id="bar">
+</literal>
+
+----
+
+* Inline Markup
+
+This is <em>emphasized</em>, and so <em>is this</em>.
+
+This is <strong>strong</strong>, and so <strong>is this</strong>.
+
+An <em>[[/url][emphasized link]]</em>.
+
+<strong><em>This is strong and em.</em></strong>
+
+So is <strong><em>this</em></strong> word.
+
+<strong><em>This is strong and em.</em></strong>
+
+So is <strong><em>this</em></strong> word.
+
+This is code: <code>></code>, <code>$</code>, <code>\</code>, <code>\$</code>,
+<code><html></code>.
+
+<del>This is <em>strikeout</em>.</del>
+
+Superscripts: a<sup>bc</sup>d a<sup><em>hello</em></sup>
+a<sup>hello there</sup>.
+
+Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a~b c~d.
+
+----
+
+* Smart quotes, ellipses, dashes
+
+“Hello,” said the spider. “‘Shelob’ is my name.”
+
+‘A’, ‘B’, and ‘C’ are letters.
+
+‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
+
+‘He said, “I want to go.”’ Were you alive in the 70’s?
+
+Here is some quoted ‘<code>code</code>’ and a
+“[[http://example.com/?foo=1&bar=2][quoted link]]”.
+
+Some dashes: one—two — three—four — five.
+
+Dashes between numbers: 5–7, 255–66, 1987–1999.
+
+Ellipses…and…and….
+
+----
+
+* LaTeX
+
+ - <literal style="tex">\cite[22-23]{smith.1899}</literal>
+ - <verbatim>2 + 2 = 4</verbatim>
+ - <em>x</em> ∈ <em>y</em>
+ - <em>α</em> ∧ <em>ω</em>
+ - 223
+ - <em>p</em>-Tree
+ - Here’s some display math:
+ <verbatim>$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</verbatim>
+ - Here’s one that has a line break in it:
+ <em>α</em> + <em>ω</em> × <em>x</em><sup>2</sup>.
+
+These shouldn’t be math:
+
+ - To get the famous equation, write <code>$e = mc^2$</code>.
+ - $22,000 is a <em>lot</em> of money. So is $34,000. (It worked if “lot” is
+ emphasized.)
+ - Shoes ($20) and socks ($5).
+ - Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.
+
+Here’s a LaTeX table:
+
+<literal style="latex">
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+</literal>
+
+----
+
+* Special Characters
+
+Here is some unicode:
+
+ - I hat: Î
+ - o umlaut: ö
+ - section: §
+ - set membership: ∈
+ - copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 <verbatim><</verbatim> 5.
+
+6 <verbatim>></verbatim> 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: <verbatim>*</verbatim>
+
+Underscore: _
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: <verbatim>[</verbatim>
+
+Right bracket: <verbatim>]</verbatim>
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: <verbatim>></verbatim>
+
+Hash: <verbatim>#</verbatim>
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+----
+
+* Links
+
+** Explicit
+
+Just a [[/url/][URL]].
+
+[[/url/][URL and title]].
+
+[[/url/][URL and title]].
+
+[[/url/][URL and title]].
+
+[[/url/][URL and title]]
+
+[[/url/][URL and title]]
+
+[[/url/with_underscore][with_underscore]]
+
+[[mailto:nobody@nowhere.net][Email link]]
+
+[[][Empty]].
+
+** Reference
+
+Foo [[/url/][bar]].
+
+With [[/url/][embedded <verbatim>[brackets]</verbatim>]].
+
+[[/url/][b]] by itself should be a link.
+
+Indented [[/url][once]].
+
+Indented [[/url][twice]].
+
+Indented [[/url][thrice]].
+
+This should <verbatim>[not][]</verbatim> be a link.
+
+<example>
+[not]: /url
+</example>
+
+Foo [[/url/][bar]].
+
+Foo [[/url/][biz]].
+
+** With ampersands
+
+Here’s a [[http://example.com/?foo=1&bar=2][link with an ampersand in the
+URL]].
+
+Here’s a link with an amersand in the link text: [[http://att.com/][AT&T]].
+
+Here’s an [[/script?foo=1&bar=2][inline link]].
+
+Here’s an [[/script?foo=1&bar=2][inline link in pointy braces]].
+
+** Autolinks
+
+With an ampersand: [[http://example.com/?foo=1&bar=2]]
+
+ - In a list?
+ - [[http://example.com/]]
+ - It should.
+
+An e-mail address: [[mailto:nobody@nowhere.net][nobody@nowhere.net]]
+
+<quote>
+Blockquoted: [[http://example.com/]]
+</quote>
+
+Auto-links should not occur here: <code><http://example.com/></code>
+
+<example>
+or here: <http://example.com/>
+</example>
+
+----
+
+* Images
+
+From “Voyage dans la Lune” by Georges Melies (1902):
+
+[[lalune.jpg][Voyage dans la Lune]]
+
+Here is a movie [[movie.jpg][movie]] icon.
+
+----
+
+* Footnotes
+
+Here is a footnote reference,[1] and another.[2] This should <em>not</em> be a
+footnote reference, because it contains a <verbatim>space.[^my</verbatim>
+<verbatim>note]</verbatim> Here is an inline note.[3]
+
+<quote>
+Notes can go in quotes.[4]
+</quote>
+
+ 1. And in list items.[5]
+
+This paragraph should not be part of the note, as it is not indented.
+
+[1] Here is the footnote. It can go anywhere after the footnote reference. It
+ need not be placed at the end of the document.
+
+[2] Here’s the long note. This one contains multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the footnote
+ (as with list items).
+
+ <example>
+ { <code> }
+ </example>
+
+ If you want, you can indent every line, but you can also be lazy and just
+ indent the first line of each block.
+
+[3] This is <em>easier</em> to type. Inline notes may contain
+ [[http://google.com][links]] and <code>]</code> verbatim characters, as
+ well as <verbatim>[bracketed</verbatim> <verbatim>text].</verbatim>
+
+[4] In quote.
+
+[5] In list.
diff --git a/test/writer.native b/test/writer.native
new file mode 100644
index 000000000..0587bddb8
--- /dev/null
+++ b/test/writer.native
@@ -0,0 +1,409 @@
+Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
+[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",SoftBreak,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
+,HorizontalRule
+,Header 1 ("headers",[],[]) [Str "Headers"]
+,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
+,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
+,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
+,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
+,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
+,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
+,HorizontalRule
+,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
+,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",SoftBreak,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",SoftBreak,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",SoftBreak,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",SoftBreak,Str "list",Space,Str "item."]
+,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",SoftBreak,Str "*",Space,Str "criminey."]
+,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
+,HorizontalRule
+,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
+,Para [Str "E-mail",Space,Str "style:"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",SoftBreak,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
+,BlockQuote
+ [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
+ ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
+ ,Para [Str "A",Space,Str "list:"]
+ ,OrderedList (1,Decimal,Period)
+ [[Plain [Str "item",Space,Str "one"]]
+ ,[Plain [Str "item",Space,Str "two"]]]
+ ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
+ ,BlockQuote
+ [Para [Str "nested"]]
+ ,BlockQuote
+ [Para [Str "nested"]]]
+,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",SoftBreak,Str ">",Space,Str "1."]
+,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
+,HorizontalRule
+,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
+,Para [Str "And:"]
+,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
+,HorizontalRule
+,Header 1 ("lists",[],[]) [Str "Lists"]
+,Header 2 ("unordered",[],[]) [Str "Unordered"]
+,Para [Str "Asterisks",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "asterisk",Space,Str "1"]]
+ ,[Plain [Str "asterisk",Space,Str "2"]]
+ ,[Plain [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Asterisks",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "asterisk",Space,Str "1"]]
+ ,[Para [Str "asterisk",Space,Str "2"]]
+ ,[Para [Str "asterisk",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "Plus",Space,Str "1"]]
+ ,[Plain [Str "Plus",Space,Str "2"]]
+ ,[Plain [Str "Plus",Space,Str "3"]]]
+,Para [Str "Pluses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Plus",Space,Str "1"]]
+ ,[Para [Str "Plus",Space,Str "2"]]
+ ,[Para [Str "Plus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "tight:"]
+,BulletList
+ [[Plain [Str "Minus",Space,Str "1"]]
+ ,[Plain [Str "Minus",Space,Str "2"]]
+ ,[Plain [Str "Minus",Space,Str "3"]]]
+,Para [Str "Minuses",Space,Str "loose:"]
+,BulletList
+ [[Para [Str "Minus",Space,Str "1"]]
+ ,[Para [Str "Minus",Space,Str "2"]]
+ ,[Para [Str "Minus",Space,Str "3"]]]
+,Header 2 ("ordered",[],[]) [Str "Ordered"]
+,Para [Str "Tight:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second"]]
+ ,[Plain [Str "Third"]]]
+,Para [Str "and:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "One"]]
+ ,[Plain [Str "Two"]]
+ ,[Plain [Str "Three"]]]
+,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second"]]
+ ,[Para [Str "Third"]]]
+,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "One"]]
+ ,[Para [Str "Two"]]
+ ,[Para [Str "Three"]]]
+,Para [Str "Multiple",Space,Str "paragraphs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
+ ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",SoftBreak,Str "back."]]
+ ,[Para [Str "Item",Space,Str "2."]]
+ ,[Para [Str "Item",Space,Str "3."]]]
+,Header 2 ("nested",[],[]) [Str "Nested"]
+,BulletList
+ [[Plain [Str "Tab"]
+ ,BulletList
+ [[Plain [Str "Tab"]
+ ,BulletList
+ [[Plain [Str "Tab"]]]]]]]
+,Para [Str "Here\8217s",Space,Str "another:"]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "First"]]
+ ,[Plain [Str "Second:"]
+ ,BulletList
+ [[Plain [Str "Fee"]]
+ ,[Plain [Str "Fie"]]
+ ,[Plain [Str "Foe"]]]]
+ ,[Plain [Str "Third"]]]
+,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "First"]]
+ ,[Para [Str "Second:"]
+ ,BulletList
+ [[Plain [Str "Fee"]]
+ ,[Plain [Str "Fie"]]
+ ,[Plain [Str "Foe"]]]]
+ ,[Para [Str "Third"]]]
+,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "spaces"]
+ ,BulletList
+ [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "tabs"]]
+ ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
+,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
+,OrderedList (2,Decimal,TwoParens)
+ [[Plain [Str "begins",Space,Str "with",Space,Str "2"]]
+ ,[Para [Str "and",Space,Str "now",Space,Str "3"]
+ ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
+ ,OrderedList (4,LowerRoman,Period)
+ [[Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",SoftBreak,Str "starting",Space,Str "with",Space,Str "4"]]
+ ,[Plain [Str "more",Space,Str "items"]
+ ,OrderedList (1,UpperAlpha,TwoParens)
+ [[Plain [Str "a",Space,Str "subsublist"]]
+ ,[Plain [Str "a",Space,Str "subsublist"]]]]]]]
+,Para [Str "Nesting:"]
+,OrderedList (1,UpperAlpha,Period)
+ [[Plain [Str "Upper",Space,Str "Alpha"]
+ ,OrderedList (1,UpperRoman,Period)
+ [[Plain [Str "Upper",Space,Str "Roman."]
+ ,OrderedList (6,Decimal,TwoParens)
+ [[Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
+ ,OrderedList (3,LowerAlpha,OneParen)
+ [[Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
+,Para [Str "Autonumbering:"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Autonumber."]]
+ ,[Plain [Str "More."]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Nested."]]]]]
+,Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
+,Para [Str "M.A.\160\&2007"]
+,Para [Str "B.",Space,Str "Williams"]
+,HorizontalRule
+,Header 1 ("definition-lists",[],[]) [Str "Definition",Space,Str "Lists"]
+,Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Plain [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Plain [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Plain [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Plain [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Plain [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Plain [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Loose:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]]])
+ ,([Str "banana"],
+ [[Para [Str "yellow",Space,Str "fruit"]]])]
+,Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
+,DefinitionList
+ [([Emph [Str "apple"]],
+ [[Para [Str "red",Space,Str "fruit"]
+ ,Para [Str "contains",Space,Str "seeds,",SoftBreak,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"]]])
+ ,([Emph [Str "orange"]],
+ [[Para [Str "orange",Space,Str "fruit"]
+ ,CodeBlock ("",[],[]) "{ orange code block }"
+ ,BlockQuote
+ [Para [Str "orange",Space,Str "block",Space,Str "quote"]]]])]
+,Para [Str "Multiple",Space,Str "definitions,",Space,Str "tight:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Plain [Str "red",Space,Str "fruit"]]
+ ,[Plain [Str "computer"]]])
+ ,([Str "orange"],
+ [[Plain [Str "orange",Space,Str "fruit"]]
+ ,[Plain [Str "bank"]]])]
+,Para [Str "Multiple",Space,Str "definitions,",Space,Str "loose:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]
+ ,[Para [Str "computer"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]]
+ ,[Para [Str "bank"]]])]
+,Para [Str "Blank",Space,Str "line",Space,Str "after",Space,Str "term,",Space,Str "indented",Space,Str "marker,",Space,Str "alternate",Space,Str "markers:"]
+,DefinitionList
+ [([Str "apple"],
+ [[Para [Str "red",Space,Str "fruit"]]
+ ,[Para [Str "computer"]]])
+ ,([Str "orange"],
+ [[Para [Str "orange",Space,Str "fruit"]
+ ,OrderedList (1,Decimal,Period)
+ [[Plain [Str "sublist"]]
+ ,[Plain [Str "sublist"]]]]])]
+,Header 1 ("html-blocks",[],[]) [Str "HTML",Space,Str "Blocks"]
+,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
+,Div ("",[],[])
+ [Plain [Str "foo"]]
+,Para [Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
+,Div ("",[],[])
+ [Div ("",[],[])
+ [Div ("",[],[])
+ [Para [Str "foo"]]]
+ ,Div ("",[],[])
+ [Plain [Str "bar"]]]
+,Para [Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
+,RawBlock (Format "html") "<table>"
+,RawBlock (Format "html") "<tr>"
+,RawBlock (Format "html") "<td>"
+,Plain [Str "This",Space,Str "is",Space,Emph [Str "emphasized"]]
+,RawBlock (Format "html") "</td>"
+,RawBlock (Format "html") "<td>"
+,Plain [Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"]]
+,RawBlock (Format "html") "</td>"
+,RawBlock (Format "html") "</tr>"
+,RawBlock (Format "html") "</table>"
+,RawBlock (Format "html") "<script type=\"text/javascript\">document.write('This *should not* be interpreted as markdown');</script>"
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
+,Div ("",[],[])
+ [Para [Str "foo"]]
+,Para [Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
+,CodeBlock ("",[],[]) "<div>\n foo\n</div>"
+,Para [Str "As",Space,Str "should",Space,Str "this:"]
+,CodeBlock ("",[],[]) "<div>foo</div>"
+,Para [Str "Now,",Space,Str "nested:"]
+,Div ("",[],[])
+ [Div ("",[],[])
+ [Div ("",[],[])
+ [Plain [Str "foo"]]]]
+,Para [Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
+,RawBlock (Format "html") "<!-- Comment -->"
+,Para [Str "Multiline:"]
+,RawBlock (Format "html") "<!--\nBlah\nBlah\n-->"
+,RawBlock (Format "html") "<!--\n This is another comment.\n-->"
+,Para [Str "Code",Space,Str "block:"]
+,CodeBlock ("",[],[]) "<!-- Comment -->"
+,Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
+,RawBlock (Format "html") "<!-- foo -->"
+,Para [Str "Code:"]
+,CodeBlock ("",[],[]) "<hr />"
+,Para [Str "Hr\8217s:"]
+,RawBlock (Format "html") "<hr>"
+,RawBlock (Format "html") "<hr />"
+,RawBlock (Format "html") "<hr />"
+,RawBlock (Format "html") "<hr>"
+,RawBlock (Format "html") "<hr />"
+,RawBlock (Format "html") "<hr />"
+,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\" />"
+,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\" />"
+,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\">"
+,HorizontalRule
+,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
+,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
+,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
+,Para [Str "An",Space,Emph [Link ("",[],[]) [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
+,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
+,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
+,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
+,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello\160there"],Str "."]
+,Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",Space,Str "H",Subscript [Str "many\160of\160them"],Str "O."]
+,Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",SoftBreak,Str "because",Space,Str "of",Space,Str "the",Space,Str "unescaped",Space,Str "spaces:",Space,Str "a^b",Space,Str "c^d,",Space,Str "a~b",Space,Str "c~d."]
+,HorizontalRule
+,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+,Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
+,Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
+,Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",SoftBreak,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine."]]
+,Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",SoftBreak,Str "70\8217s?"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code ("",[],[]) "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
+,Para [Str "Some",Space,Str "dashes:",Space,Str "one\8212two",Space,Str "\8212",Space,Str "three\8212four",Space,Str "\8212",Space,Str "five."]
+,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5\8211\&7,",Space,Str "255\8211\&66,",Space,Str "1987\8211\&1999."]
+,Para [Str "Ellipses\8230and\8230and\8230."]
+,HorizontalRule
+,Header 1 ("latex",[],[]) [Str "LaTeX"]
+,BulletList
+ [[Plain [RawInline (Format "tex") "\\cite[22-23]{smith.1899}"]]
+ ,[Plain [Math InlineMath "2+2=4"]]
+ ,[Plain [Math InlineMath "x \\in y"]]
+ ,[Plain [Math InlineMath "\\alpha \\wedge \\omega"]]
+ ,[Plain [Math InlineMath "223"]]
+ ,[Plain [Math InlineMath "p",Str "-Tree"]]
+ ,[Plain [Str "Here\8217s",Space,Str "some",Space,Str "display",Space,Str "math:",SoftBreak,Math DisplayMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"]]
+ ,[Plain [Str "Here\8217s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."]]]
+,Para [Str "These",Space,Str "shouldn\8217t",Space,Str "be",Space,Str "math:"]
+,BulletList
+ [[Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code ("",[],[]) "$e = mc^2$",Str "."]]
+ ,[Plain [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",SoftBreak,Str "(It",Space,Str "worked",Space,Str "if",Space,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized.)"]]
+ ,[Plain [Str "Shoes",Space,Str "($20)",Space,Str "and",Space,Str "socks",Space,Str "($5)."]]
+ ,[Plain [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
+,RawBlock (Format "latex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"
+,HorizontalRule
+,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
+,BulletList
+ [[Plain [Str "I",Space,Str "hat:",Space,Str "\206"]]
+ ,[Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
+ ,[Plain [Str "section:",Space,Str "\167"]]
+ ,[Plain [Str "set",Space,Str "membership:",Space,Str "\8712"]]
+ ,[Plain [Str "copyright:",Space,Str "\169"]]]
+,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
+,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
+,Para [Str "This",Space,Str "&",Space,Str "that."]
+,Para [Str "4",Space,Str "<",Space,Str "5."]
+,Para [Str "6",Space,Str ">",Space,Str "5."]
+,Para [Str "Backslash:",Space,Str "\\"]
+,Para [Str "Backtick:",Space,Str "`"]
+,Para [Str "Asterisk:",Space,Str "*"]
+,Para [Str "Underscore:",Space,Str "_"]
+,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
+,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
+,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
+,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
+,Para [Str "Left",Space,Str "paren:",Space,Str "("]
+,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
+,Para [Str "Greater-than:",Space,Str ">"]
+,Para [Str "Hash:",Space,Str "#"]
+,Para [Str "Period:",Space,Str "."]
+,Para [Str "Bang:",Space,Str "!"]
+,Para [Str "Plus:",Space,Str "+"]
+,Para [Str "Minus:",Space,Str "-"]
+,HorizontalRule
+,Header 1 ("links",[],[]) [Str "Links"]
+,Header 2 ("explicit",[],[]) [Str "Explicit"]
+,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
+,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
+,Para [Link ("",[],[]) [Str "with_underscore"] ("/url/with_underscore","")]
+,Para [Link ("",[],[]) [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
+,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
+,Header 2 ("reference",[],[]) [Str "Reference"]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
+,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
+,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
+,Para [Str "Indented",Space,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
+,Para [Str "This",Space,Str "should",Space,Str "[not][]",Space,Str "be",Space,Str "a",Space,Str "link."]
+,CodeBlock ("",[],[]) "[not]: /url"
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
+,Para [Str "Foo",Space,Link ("",[],[]) [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
+,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
+,Para [Str "Here\8217s",Space,Str "a",Space,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link ("",[],[]) [Str "AT&T"] ("http://att.com/","AT&T"),Str "."]
+,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
+,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
+,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
+,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
+,BulletList
+ [[Plain [Str "In",Space,Str "a",Space,Str "list?"]]
+ ,[Plain [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+ ,[Plain [Str "It",Space,Str "should."]]]
+,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
+,BlockQuote
+ [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
+,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
+,CodeBlock ("",[],[]) "or here: <http://example.com/>"
+,HorizontalRule
+,Header 1 ("images",[],[]) [Str "Images"]
+,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
+,Para [Image ("",[],[]) [Str "lalune"] ("lalune.jpg","fig:Voyage dans la Lune")]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
+,HorizontalRule
+,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",SoftBreak,Str "reference.",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document."]],Space,Str "and",Space,Str "another.",Note [Para [Str "Here\8217s",Space,Str "the",Space,Str "long",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",SoftBreak,Str "blocks."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",SoftBreak,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",SoftBreak,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block."]],SoftBreak,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",SoftBreak,Str "contains",Space,Str "a",Space,Str "space.[^my",Space,Str "note]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note.",Note [Para [Str "This",SoftBreak,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type.",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",SoftBreak,Link ("",[],[]) [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code ("",[],[]) "]",Space,Str "verbatim",Space,Str "characters,",SoftBreak,Str "as",Space,Str "well",Space,Str "as",Space,Str "[bracketed",Space,Str "text]."]]]
+,BlockQuote
+ [Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes.",Note [Para [Str "In",Space,Str "quote."]]]]
+,OrderedList (1,Decimal,Period)
+ [[Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]]]]
+,Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented."]]
diff --git a/test/writer.opendocument b/test/writer.opendocument
new file mode 100644
index 000000000..081b33971
--- /dev/null
+++ b/test/writer.opendocument
@@ -0,0 +1,1537 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.2">
+ <office:font-face-decls>
+ <style:font-face style:name="Courier New" style:font-family-generic="modern" style:font-pitch="fixed" svg:font-family="'Courier New'" />
+ </office:font-face-decls>
+ <office:automatic-styles>
+ <text:list-style style:name="L1">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L2">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L3">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L4">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L5">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L6">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L7">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L8">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L9">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L10">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L11">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L12">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L13">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L14">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L15">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L16">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L17">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L18">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L19">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L20">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L21">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L22">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="2" style:num-prefix="(" style:num-suffix=")">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="i" text:start-value="4" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-format="A" text:start-value="1" style:num-prefix="(" style:num-suffix=")">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L23">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="A" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="I" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="6" style:num-prefix="(" style:num-suffix=")">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-format="a" text:start-value="3" style:num-suffix=")">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L24">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L25">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="L26">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L27">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L28">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L29">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="0.4in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="0.8in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2000000000000002in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="1.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="2.4000000000000004in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦">
+ <style:list-level-properties text:space-before="2.8000000000000003in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪">
+ <style:list-level-properties text:space-before="3.2in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
+ <style:list-level-properties text:space-before="3.6in" text:min-label-width="0.4in" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="L30">
+ <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
+ <style:list-level-properties text:space-before="0.0in" text:min-label-width="0.4in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <style:style style:name="T1" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
+ <style:style style:name="T2" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T3" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
+ <style:style style:name="T4" style:family="text"><style:text-properties style:text-line-through-style="solid" /></style:style>
+ <style:style style:name="T5" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" style:text-line-through-style="solid" /></style:style>
+ <style:style style:name="T6" style:family="text"><style:text-properties style:text-position="super 58%" /></style:style>
+ <style:style style:name="T7" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" style:text-position="super 58%" /></style:style>
+ <style:style style:name="T8" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
+ <style:style style:name="fr2" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" style:wrap="none" /></style:style>
+ <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" /></style:style>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L1">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="1.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="1.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P10" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P11" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P12" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P13" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P14" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P15" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P16" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P17" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P18" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P19" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L2">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P20" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L3">
+ </style:style>
+ <style:style style:name="P21" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L4">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P22" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L5">
+ </style:style>
+ <style:style style:name="P23" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L6">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P24" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L7">
+ </style:style>
+ <style:style style:name="P25" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L8">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P26" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L9">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P27" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L10">
+ </style:style>
+ <style:style style:name="P28" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L11">
+ </style:style>
+ <style:style style:name="P29" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L12">
+ </style:style>
+ <style:style style:name="P30" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L13">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P31" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L14">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P32" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L15">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P33" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L16">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P34" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L17">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P35" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L18">
+ </style:style>
+ <style:style style:name="P36" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L19">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P37" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L20">
+ </style:style>
+ <style:style style:name="P38" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L21">
+ </style:style>
+ <style:style style:name="P39" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L22">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P40" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L23">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P41" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L24">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P42" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P43" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P44" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L25">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P45" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P46" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P47" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P48" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P49" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P50" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P51" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L26">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P52" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L27">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P53" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L28">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P54" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P55" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L29">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ <style:style style:name="P56" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P57" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P58" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
+ </style:style>
+ <style:style style:name="P59" style:family="paragraph" style:parent-style-name="Quotations">
+ <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="P60" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L30">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
+ </style:style>
+ </office:automatic-styles>
+<office:body>
+<office:text>
+<text:p text:style-name="Title">Pandoc Test Suite</text:p>
+<text:p text:style-name="Author">John MacFarlane</text:p>
+<text:p text:style-name="Author">Anonymous</text:p>
+<text:p text:style-name="Date">July 17, 2006</text:p>
+<text:p text:style-name="Text_20_body">This is a set of tests for pandoc. Most
+of them are adapted from John Gruber’s markdown test suite.</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Headers</text:h>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Level 2 with an
+<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">embedded
+link</text:span></text:a></text:h>
+<text:h text:style-name="Heading_20_3" text:outline-level="3">Level 3 with
+<text:span text:style-name="T1">emphasis</text:span></text:h>
+<text:h text:style-name="Heading_20_4" text:outline-level="4">Level 4</text:h>
+<text:h text:style-name="Heading_20_5" text:outline-level="5">Level 5</text:h>
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Level 1</text:h>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Level 2 with
+<text:span text:style-name="T1">emphasis</text:span></text:h>
+<text:h text:style-name="Heading_20_3" text:outline-level="3">Level 3</text:h>
+<text:p text:style-name="First_20_paragraph">with no blank line</text:p>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Level 2</text:h>
+<text:p text:style-name="First_20_paragraph">with no blank line</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Paragraphs</text:h>
+<text:p text:style-name="First_20_paragraph">Here’s a regular
+paragraph.</text:p>
+<text:p text:style-name="Text_20_body">In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item. Because a hard-wrapped line in the middle
+of a paragraph looked like a list item.</text:p>
+<text:p text:style-name="Text_20_body">Here’s one with a bullet. *
+criminey.</text:p>
+<text:p text:style-name="Text_20_body">There should be a hard line
+break<text:line-break />here.</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Block
+Quotes</text:h>
+<text:p text:style-name="First_20_paragraph">E-mail style:</text:p>
+<text:p text:style-name="P1">This is a block quote. It is pretty
+short.</text:p>
+<text:p text:style-name="P2">Code in a block quote:</text:p>
+<text:p text:style-name="P3">sub status {</text:p>
+<text:p text:style-name="P4"><text:s text:c="4" />print &quot;working&quot;;</text:p>
+<text:p text:style-name="P5">}</text:p>
+<text:p text:style-name="P2">A list:</text:p>
+<text:list text:style-name="L1">
+ <text:list-item>
+ <text:p text:style-name="P6">item one</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P6">item two</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="P2">Nested block quotes:</text:p>
+<text:p text:style-name="P7">nested</text:p>
+<text:p text:style-name="P8">nested</text:p>
+<text:p text:style-name="First_20_paragraph">This should not be a block quote:
+2 &gt; 1.</text:p>
+<text:p text:style-name="Text_20_body">And a following paragraph.</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Code
+Blocks</text:h>
+<text:p text:style-name="First_20_paragraph">Code:</text:p>
+<text:p text:style-name="P9">---- (should be four hyphens)</text:p>
+<text:p text:style-name="P10"></text:p>
+<text:p text:style-name="P11">sub status {</text:p>
+<text:p text:style-name="P12"><text:s text:c="4" />print &quot;working&quot;;</text:p>
+<text:p text:style-name="P13">}</text:p>
+<text:p text:style-name="P14"></text:p>
+<text:p text:style-name="P15">this code block is indented by one tab</text:p>
+<text:p text:style-name="First_20_paragraph">And:</text:p>
+<text:p text:style-name="P16"><text:s text:c="4" />this code block is indented by two tabs</text:p>
+<text:p text:style-name="P17"></text:p>
+<text:p text:style-name="P18">These should not be escaped: <text:s text:c="1" />\$ \\ \&gt; \[ \{</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Lists</text:h>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Unordered</text:h>
+<text:p text:style-name="First_20_paragraph">Asterisks tight:</text:p>
+<text:list text:style-name="L2">
+ <text:list-item>
+ <text:p text:style-name="P19">asterisk 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P19">asterisk 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P19">asterisk 3</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Asterisks loose:</text:p>
+<text:list text:style-name="L3">
+ <text:list-item>
+ <text:p text:style-name="P20">asterisk 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P20">asterisk 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P20">asterisk 3</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Pluses tight:</text:p>
+<text:list text:style-name="L4">
+ <text:list-item>
+ <text:p text:style-name="P21">Plus 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P21">Plus 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P21">Plus 3</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Pluses loose:</text:p>
+<text:list text:style-name="L5">
+ <text:list-item>
+ <text:p text:style-name="P22">Plus 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P22">Plus 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P22">Plus 3</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Minuses tight:</text:p>
+<text:list text:style-name="L6">
+ <text:list-item>
+ <text:p text:style-name="P23">Minus 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P23">Minus 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P23">Minus 3</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Minuses loose:</text:p>
+<text:list text:style-name="L7">
+ <text:list-item>
+ <text:p text:style-name="P24">Minus 1</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P24">Minus 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P24">Minus 3</text:p>
+ </text:list-item>
+</text:list>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Ordered</text:h>
+<text:p text:style-name="First_20_paragraph">Tight:</text:p>
+<text:list text:style-name="L8">
+ <text:list-item>
+ <text:p text:style-name="P25">First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P25">Second</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P25">Third</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">and:</text:p>
+<text:list text:style-name="L9">
+ <text:list-item>
+ <text:p text:style-name="P26">One</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P26">Two</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P26">Three</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Loose using tabs:</text:p>
+<text:list text:style-name="L10">
+ <text:list-item>
+ <text:p text:style-name="P27">First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P27">Second</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P27">Third</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">and using spaces:</text:p>
+<text:list text:style-name="L11">
+ <text:list-item>
+ <text:p text:style-name="P28">One</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P28">Two</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P28">Three</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Multiple paragraphs:</text:p>
+<text:list text:style-name="L12">
+ <text:list-item>
+ <text:p text:style-name="P29">Item 1, graf one.</text:p>
+ <text:p text:style-name="P29">Item 1. graf two. The quick brown fox jumped
+ over the lazy dog’s back.</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P29">Item 2.</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P29">Item 3.</text:p>
+ </text:list-item>
+</text:list>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Nested</text:h>
+<text:list text:style-name="L13">
+ <text:list-item>
+ <text:p text:style-name="P30">Tab</text:p><text:list text:style-name="L14">
+ <text:list-item>
+ <text:p text:style-name="P31">Tab</text:p><text:list text:style-name="L15">
+ <text:list-item>
+ <text:p text:style-name="P32">Tab</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Here’s another:</text:p>
+<text:list text:style-name="L16">
+ <text:list-item>
+ <text:p text:style-name="P33">First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P33">Second:</text:p>
+ <text:list text:style-name="L17">
+ <text:list-item>
+ <text:p text:style-name="P34">Fee</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P34">Fie</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P34">Foe</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P33">Third</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Same thing but with
+paragraphs:</text:p>
+<text:list text:style-name="L18">
+ <text:list-item>
+ <text:p text:style-name="P35">First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P35">Second:</text:p>
+ <text:list text:style-name="L19">
+ <text:list-item>
+ <text:p text:style-name="P36">Fee</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P36">Fie</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P36">Foe</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P35">Third</text:p>
+ </text:list-item>
+</text:list>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Tabs and
+spaces</text:h>
+<text:list text:style-name="L20">
+ <text:list-item>
+ <text:p text:style-name="P37">this is a list item indented with
+ tabs</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P37">this is a list item indented with
+ spaces</text:p><text:list text:style-name="L21">
+ <text:list-item>
+ <text:p text:style-name="P38">this is an example list item indented
+ with tabs</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P38">this is an example list item indented
+ with spaces</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+</text:list>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Fancy list
+markers</text:h>
+<text:list text:style-name="L22">
+ <text:list-item>
+ <text:p text:style-name="P39">begins with 2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P39">and now 3</text:p>
+ <text:p text:style-name="P39">with a continuation</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P39">sublist with roman numerals, starting
+ with 4</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P39">more items</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P39">a subsublist</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P39">a subsublist</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Nesting:</text:p>
+<text:list text:style-name="L23">
+ <text:list-item>
+ <text:p text:style-name="P40">Upper Alpha</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P40">Upper Roman.</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P40">Decimal start with 6</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P40">Lower alpha with paren</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Autonumbering:</text:p>
+<text:list text:style-name="L24">
+ <text:list-item>
+ <text:p text:style-name="P41">Autonumber.</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P41">More.</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p text:style-name="P41">Nested.</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Should not be a list
+item:</text:p>
+<text:p text:style-name="Text_20_body">M.A. 2007</text:p>
+<text:p text:style-name="Text_20_body">B. Williams</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Definition
+Lists</text:h>
+<text:p text:style-name="First_20_paragraph">Tight using spaces:</text:p>
+<text:p text:style-name="Definition_20_Term_20_Tight">apple</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">red fruit</text:p>
+<text:p text:style-name="Definition_20_Term_20_Tight">orange</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">orange
+fruit</text:p>
+<text:p text:style-name="Definition_20_Term_20_Tight">banana</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">yellow
+fruit</text:p>
+<text:p text:style-name="First_20_paragraph">Tight using tabs:</text:p>
+<text:p text:style-name="Definition_20_Term_20_Tight">apple</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">red fruit</text:p>
+<text:p text:style-name="Definition_20_Term_20_Tight">orange</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">orange
+fruit</text:p>
+<text:p text:style-name="Definition_20_Term_20_Tight">banana</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">yellow
+fruit</text:p>
+<text:p text:style-name="First_20_paragraph">Loose:</text:p>
+<text:p text:style-name="Definition_20_Term">apple</text:p>
+<text:p text:style-name="Definition_20_Definition">red fruit</text:p>
+<text:p text:style-name="Definition_20_Term">orange</text:p>
+<text:p text:style-name="Definition_20_Definition">orange fruit</text:p>
+<text:p text:style-name="Definition_20_Term">banana</text:p>
+<text:p text:style-name="Definition_20_Definition">yellow fruit</text:p>
+<text:p text:style-name="First_20_paragraph">Multiple blocks with
+italics:</text:p>
+<text:p text:style-name="Definition_20_Term"><text:span text:style-name="T1">apple</text:span></text:p>
+<text:p text:style-name="Definition_20_Definition">red
+fruit</text:p><text:p text:style-name="Definition_20_Definition">contains
+seeds, crisp, pleasant to taste</text:p>
+<text:p text:style-name="Definition_20_Term"><text:span text:style-name="T1">orange</text:span></text:p>
+<text:p text:style-name="Definition_20_Definition">orange fruit</text:p><text:p text:style-name="P42">{ orange code block }</text:p><text:p text:style-name="P43">orange
+block quote</text:p>
+<text:p text:style-name="First_20_paragraph">Multiple definitions,
+tight:</text:p>
+<text:p text:style-name="Definition_20_Term_20_Tight">apple</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">red fruit</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">computer</text:p>
+<text:p text:style-name="Definition_20_Term_20_Tight">orange</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">orange
+fruit</text:p>
+<text:p text:style-name="Definition_20_Definition_20_Tight">bank</text:p>
+<text:p text:style-name="First_20_paragraph">Multiple definitions,
+loose:</text:p>
+<text:p text:style-name="Definition_20_Term">apple</text:p>
+<text:p text:style-name="Definition_20_Definition">red fruit</text:p>
+<text:p text:style-name="Definition_20_Definition">computer</text:p>
+<text:p text:style-name="Definition_20_Term">orange</text:p>
+<text:p text:style-name="Definition_20_Definition">orange fruit</text:p>
+<text:p text:style-name="Definition_20_Definition">bank</text:p>
+<text:p text:style-name="First_20_paragraph">Blank line after term, indented
+marker, alternate markers:</text:p>
+<text:p text:style-name="Definition_20_Term">apple</text:p>
+<text:p text:style-name="Definition_20_Definition">red fruit</text:p>
+<text:p text:style-name="Definition_20_Definition">computer</text:p>
+<text:p text:style-name="Definition_20_Term">orange</text:p>
+<text:p text:style-name="Definition_20_Definition">orange
+fruit</text:p><text:list text:style-name="L25">
+ <text:list-item>
+ <text:p text:style-name="P44">sublist</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P44">sublist</text:p>
+ </text:list-item>
+</text:list>
+<text:h text:style-name="Heading_20_1" text:outline-level="1">HTML
+Blocks</text:h>
+<text:p text:style-name="First_20_paragraph">Simple block on one
+line:</text:p>
+<text:p text:style-name="Text_20_body">foo</text:p>
+<text:p text:style-name="Text_20_body">And nested without
+indentation:</text:p>
+<text:p text:style-name="Text_20_body">foo</text:p>
+<text:p text:style-name="Text_20_body">bar</text:p>
+<text:p text:style-name="Text_20_body">Interpreted markdown in a
+table:</text:p>
+<text:p text:style-name="Text_20_body">This is
+<text:span text:style-name="T1">emphasized</text:span></text:p>
+<text:p text:style-name="Text_20_body">And this is
+<text:span text:style-name="T2">strong</text:span></text:p>
+<text:p text:style-name="Text_20_body">Here’s a simple block:</text:p>
+<text:p text:style-name="Text_20_body">foo</text:p>
+<text:p text:style-name="Text_20_body">This should be a code block,
+though:</text:p>
+<text:p text:style-name="P45">&lt;div&gt;</text:p>
+<text:p text:style-name="P46"><text:s text:c="4" />foo</text:p>
+<text:p text:style-name="P47">&lt;/div&gt;</text:p>
+<text:p text:style-name="First_20_paragraph">As should this:</text:p>
+<text:p text:style-name="P48">&lt;div&gt;foo&lt;/div&gt;</text:p>
+<text:p text:style-name="First_20_paragraph">Now, nested:</text:p>
+<text:p text:style-name="Text_20_body">foo</text:p>
+<text:p text:style-name="Text_20_body">This should just be an HTML
+comment:</text:p>
+<text:p text:style-name="Text_20_body">Multiline:</text:p>
+<text:p text:style-name="Text_20_body">Code block:</text:p>
+<text:p text:style-name="P49">&lt;!-- Comment --&gt;</text:p>
+<text:p text:style-name="First_20_paragraph">Just plain comment, with trailing
+spaces on the line:</text:p>
+<text:p text:style-name="Text_20_body">Code:</text:p>
+<text:p text:style-name="P50">&lt;hr /&gt;</text:p>
+<text:p text:style-name="First_20_paragraph">Hr’s:</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Inline
+Markup</text:h>
+<text:p text:style-name="First_20_paragraph">This is
+<text:span text:style-name="T1">emphasized</text:span>, and so
+<text:span text:style-name="T1">is this</text:span>.</text:p>
+<text:p text:style-name="Text_20_body">This is
+<text:span text:style-name="T2">strong</text:span>, and so
+<text:span text:style-name="T2">is this</text:span>.</text:p>
+<text:p text:style-name="Text_20_body">An
+<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition"><text:span text:style-name="T1">emphasized
+link</text:span></text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body"><text:span text:style-name="T3">This is
+strong and em.</text:span></text:p>
+<text:p text:style-name="Text_20_body">So is
+<text:span text:style-name="T3">this</text:span> word.</text:p>
+<text:p text:style-name="Text_20_body"><text:span text:style-name="T3">This is
+strong and em.</text:span></text:p>
+<text:p text:style-name="Text_20_body">So is
+<text:span text:style-name="T3">this</text:span> word.</text:p>
+<text:p text:style-name="Text_20_body">This is code:
+<text:span text:style-name="Source_Text">&gt;</text:span>,
+<text:span text:style-name="Source_Text">$</text:span>,
+<text:span text:style-name="Source_Text">\</text:span>,
+<text:span text:style-name="Source_Text">\$</text:span>,
+<text:span text:style-name="Source_Text">&lt;html&gt;</text:span>.</text:p>
+<text:p text:style-name="Text_20_body"><text:span text:style-name="T4">This is
+</text:span><text:span text:style-name="T5">strikeout</text:span><text:span text:style-name="T4">.</text:span></text:p>
+<text:p text:style-name="Text_20_body">Superscripts:
+a<text:span text:style-name="T6">bc</text:span>d
+a<text:span text:style-name="T7">hello</text:span>
+a<text:span text:style-name="T6">hello there</text:span>.</text:p>
+<text:p text:style-name="Text_20_body">Subscripts:
+H<text:span text:style-name="T8">2</text:span>O,
+H<text:span text:style-name="T8">23</text:span>O,
+H<text:span text:style-name="T8">many of them</text:span>O.</text:p>
+<text:p text:style-name="Text_20_body">These should not be superscripts or
+subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Smart quotes,
+ellipses, dashes</text:h>
+<text:p text:style-name="First_20_paragraph">“Hello,” said the spider.
+“‘Shelob’ is my name.”</text:p>
+<text:p text:style-name="Text_20_body">‘A’, ‘B’, and ‘C’ are letters.</text:p>
+<text:p text:style-name="Text_20_body">‘Oak,’ ‘elm,’ and ‘beech’ are names of
+trees. So is ‘pine.’</text:p>
+<text:p text:style-name="Text_20_body">‘He said, “I want to go.”’ Were you
+alive in the 70’s?</text:p>
+<text:p text:style-name="Text_20_body">Here is some quoted
+‘<text:span text:style-name="Source_Text">code</text:span>’ and a
+“<text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">quoted
+link</text:span></text:a>”.</text:p>
+<text:p text:style-name="Text_20_body">Some dashes: one—two — three—four —
+five.</text:p>
+<text:p text:style-name="Text_20_body">Dashes between numbers: 5–7, 255–66,
+1987–1999.</text:p>
+<text:p text:style-name="Text_20_body">Ellipses…and…and….</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">LaTeX</text:h>
+<text:list text:style-name="L26">
+ <text:list-item>
+ <text:p text:style-name="P51"></text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51">2 + 2 = 4</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51"><text:span text:style-name="T1">x</text:span> ∈ <text:span text:style-name="T1">y</text:span></text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51"><text:span text:style-name="T1">α</text:span> ∧ <text:span text:style-name="T1">ω</text:span></text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51">223</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51"><text:span text:style-name="T1">p</text:span>-Tree</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51">Here’s some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P51">Here’s one that has a line break in it:
+ <text:span text:style-name="T1">α</text:span> + <text:span text:style-name="T1">ω</text:span> × <text:span text:style-name="T1">x</text:span><text:span text:style-name="T6">2</text:span>.</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">These shouldn’t be math:</text:p>
+<text:list text:style-name="L27">
+ <text:list-item>
+ <text:p text:style-name="P52">To get the famous equation, write
+ <text:span text:style-name="Source_Text">$e = mc^2$</text:span>.</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P52">$22,000 is a
+ <text:span text:style-name="T1">lot</text:span> of money. So is $34,000.
+ (It worked if “lot” is emphasized.)</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P52">Shoes ($20) and socks ($5).</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P52">Escaped
+ <text:span text:style-name="Source_Text">$</text:span>: $73
+ <text:span text:style-name="T1">this should be emphasized</text:span>
+ 23$.</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">Here’s a LaTeX table:</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Special
+Characters</text:h>
+<text:p text:style-name="First_20_paragraph">Here is some unicode:</text:p>
+<text:list text:style-name="L28">
+ <text:list-item>
+ <text:p text:style-name="P53">I hat: Î</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P53">o umlaut: ö</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P53">section: §</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P53">set membership: ∈</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P53">copyright: ©</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">AT&amp;T has an ampersand in
+their name.</text:p>
+<text:p text:style-name="Text_20_body">AT&amp;T is another way to write
+it.</text:p>
+<text:p text:style-name="Text_20_body">This &amp; that.</text:p>
+<text:p text:style-name="Text_20_body">4 &lt; 5.</text:p>
+<text:p text:style-name="Text_20_body">6 &gt; 5.</text:p>
+<text:p text:style-name="Text_20_body">Backslash: \</text:p>
+<text:p text:style-name="Text_20_body">Backtick: `</text:p>
+<text:p text:style-name="Text_20_body">Asterisk: *</text:p>
+<text:p text:style-name="Text_20_body">Underscore: _</text:p>
+<text:p text:style-name="Text_20_body">Left brace: {</text:p>
+<text:p text:style-name="Text_20_body">Right brace: }</text:p>
+<text:p text:style-name="Text_20_body">Left bracket: [</text:p>
+<text:p text:style-name="Text_20_body">Right bracket: ]</text:p>
+<text:p text:style-name="Text_20_body">Left paren: (</text:p>
+<text:p text:style-name="Text_20_body">Right paren: )</text:p>
+<text:p text:style-name="Text_20_body">Greater-than: &gt;</text:p>
+<text:p text:style-name="Text_20_body">Hash: #</text:p>
+<text:p text:style-name="Text_20_body">Period: .</text:p>
+<text:p text:style-name="Text_20_body">Bang: !</text:p>
+<text:p text:style-name="Text_20_body">Plus: +</text:p>
+<text:p text:style-name="Text_20_body">Minus: -</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Links</text:h>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Explicit</text:h>
+<text:p text:style-name="First_20_paragraph">Just a
+<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">URL</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title"><text:span text:style-name="Definition">URL
+and title</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title preceded by two spaces"><text:span text:style-name="Definition">URL
+and title</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title preceded by a tab"><text:span text:style-name="Definition">URL
+and title</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title with &quot;quotes&quot; in it"><text:span text:style-name="Definition">URL
+and title</text:span></text:a></text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title with single quotes"><text:span text:style-name="Definition">URL
+and title</text:span></text:a></text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/with_underscore" office:name=""><text:span text:style-name="Definition">with_underscore</text:span></text:a></text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="mailto:nobody@nowhere.net" office:name=""><text:span text:style-name="Definition">Email
+link</text:span></text:a></text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="" office:name=""><text:span text:style-name="Definition">Empty</text:span></text:a>.</text:p>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Reference</text:h>
+<text:p text:style-name="First_20_paragraph">Foo
+<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body">With
+<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">embedded
+[brackets]</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">b</text:span></text:a>
+by itself should be a link.</text:p>
+<text:p text:style-name="Text_20_body">Indented
+<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">once</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body">Indented
+<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">twice</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body">Indented
+<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">thrice</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body">This should [not][] be a link.</text:p>
+<text:p text:style-name="P54">[not]: /url</text:p>
+<text:p text:style-name="First_20_paragraph">Foo
+<text:a xlink:type="simple" xlink:href="/url/" office:name="Title with &quot;quotes&quot; inside"><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body">Foo
+<text:a xlink:type="simple" xlink:href="/url/" office:name="Title with &quot;quote&quot; inside"><text:span text:style-name="Definition">biz</text:span></text:a>.</text:p>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">With
+ampersands</text:h>
+<text:p text:style-name="First_20_paragraph">Here’s a
+<text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">link
+with an ampersand in the URL</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body">Here’s a link with an amersand in the
+link text:
+<text:a xlink:type="simple" xlink:href="http://att.com/" office:name="AT&amp;T"><text:span text:style-name="Definition">AT&amp;T</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body">Here’s an
+<text:a xlink:type="simple" xlink:href="/script?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">inline
+link</text:span></text:a>.</text:p>
+<text:p text:style-name="Text_20_body">Here’s an
+<text:a xlink:type="simple" xlink:href="/script?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">inline
+link in pointy braces</text:span></text:a>.</text:p>
+<text:h text:style-name="Heading_20_2" text:outline-level="2">Autolinks</text:h>
+<text:p text:style-name="First_20_paragraph">With an ampersand:
+<text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">http://example.com/?foo=1&amp;bar=2</text:span></text:a></text:p>
+<text:list text:style-name="L29">
+ <text:list-item>
+ <text:p text:style-name="P55">In a list?</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P55"><text:a xlink:type="simple" xlink:href="http://example.com/" office:name=""><text:span text:style-name="Definition">http://example.com/</text:span></text:a></text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p text:style-name="P55">It should.</text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">An e-mail address:
+<text:a xlink:type="simple" xlink:href="mailto:nobody@nowhere.net" office:name=""><text:span text:style-name="Definition">nobody@nowhere.net</text:span></text:a></text:p>
+<text:p text:style-name="P56">Blockquoted:
+<text:a xlink:type="simple" xlink:href="http://example.com/" office:name=""><text:span text:style-name="Definition">http://example.com/</text:span></text:a></text:p>
+<text:p text:style-name="First_20_paragraph">Auto-links should not occur here:
+<text:span text:style-name="Source_Text">&lt;http://example.com/&gt;</text:span></text:p>
+<text:p text:style-name="P57">or here: &lt;http://example.com/&gt;</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Images</text:h>
+<text:p text:style-name="First_20_paragraph">From “Voyage dans la Lune” by
+Georges Melies (1902):</text:p>
+<text:p text:style-name="FigureWithCaption"><draw:frame draw:name="img1"><draw:image xlink:href="lalune.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame></text:p>
+<text:p text:style-name="FigureCaption">lalune</text:p>
+<text:p text:style-name="Text_20_body">Here is a movie
+<draw:frame draw:name="img2"><draw:image xlink:href="movie.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame>
+icon.</text:p>
+<text:p text:style-name="Horizontal_20_Line" />
+<text:h text:style-name="Heading_20_1" text:outline-level="1">Footnotes</text:h>
+<text:p text:style-name="First_20_paragraph">Here is a footnote
+reference,<text:note text:id="ftn0" text:note-class="footnote"><text:note-citation>1</text:note-citation><text:note-body><text:p text:style-name="Footnote">Here
+is the footnote. It can go anywhere after the footnote reference. It need not
+be placed at the end of the document.</text:p></text:note-body></text:note>
+and
+another.<text:note text:id="ftn1" text:note-class="footnote"><text:note-citation>2</text:note-citation><text:note-body><text:p text:style-name="Footnote">Here’s
+the long note. This one contains multiple
+blocks.</text:p><text:p text:style-name="Footnote">Subsequent blocks are
+indented to show that they belong to the footnote (as with list
+items).</text:p><text:p text:style-name="P58"><text:s text:c="2" />{ &lt;code&gt; }</text:p><text:p text:style-name="Footnote">If
+you want, you can indent every line, but you can also be lazy and just indent
+the first line of each block.</text:p></text:note-body></text:note> This
+should <text:span text:style-name="T1">not</text:span> be a footnote
+reference, because it contains a space.[^my note] Here is an inline
+note.<text:note text:id="ftn2" text:note-class="footnote"><text:note-citation>3</text:note-citation><text:note-body><text:p text:style-name="Footnote">This
+is <text:span text:style-name="T1">easier</text:span> to type. Inline notes
+may contain
+<text:a xlink:type="simple" xlink:href="http://google.com" office:name=""><text:span text:style-name="Definition">links</text:span></text:a>
+and <text:span text:style-name="Source_Text">]</text:span> verbatim
+characters, as well as [bracketed
+text].</text:p></text:note-body></text:note></text:p>
+<text:p text:style-name="P59">Notes can go in
+quotes.<text:note text:id="ftn3" text:note-class="footnote"><text:note-citation>4</text:note-citation><text:note-body><text:p text:style-name="Footnote">In
+quote.</text:p></text:note-body></text:note></text:p>
+<text:list text:style-name="L30">
+ <text:list-item>
+ <text:p text:style-name="P60">And in list
+ items.<text:note text:id="ftn4" text:note-class="footnote"><text:note-citation>5</text:note-citation><text:note-body><text:p text:style-name="Footnote">In
+ list.</text:p></text:note-body></text:note></text:p>
+ </text:list-item>
+</text:list>
+<text:p text:style-name="First_20_paragraph">This paragraph should not be part
+of the note, as it is not indented.</text:p>
+</office:text>
+</office:body>
+</office:document-content>
diff --git a/test/writer.opml b/test/writer.opml
new file mode 100644
index 000000000..4e67652d2
--- /dev/null
+++ b/test/writer.opml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<opml version="2.0">
+ <head>
+ <title>Pandoc Test Suite</title>
+ <dateModified>Mon, 17 Jul 2006 00:00:00 UTC</dateModified>
+ <ownerName>John MacFarlane; Anonymous</ownerName>
+ </head>
+ <body>
+<outline text="Headers">
+ <outline text="Level 2 with an &lt;a href=&quot;/url&quot;&gt;embedded link&lt;/a&gt;">
+ <outline text="Level 3 with &lt;em&gt;emphasis&lt;/em&gt;">
+ <outline text="Level 4">
+ <outline text="Level 5">
+ </outline>
+ </outline>
+ </outline>
+ </outline>
+</outline>
+<outline text="Level 1">
+ <outline text="Level 2 with &lt;em&gt;emphasis&lt;/em&gt;">
+ <outline text="Level 3" _note="with no blank line">
+ </outline>
+ </outline>
+ <outline text="Level 2" _note="with no blank line&#10;&#10;------------------------------------------------------------------------">
+ </outline>
+</outline>
+<outline text="Paragraphs" _note="Here’s a regular paragraph.&#10;&#10;In Markdown 1.0.0 and earlier. Version 8. This line turns into a list&#10;item. Because a hard-wrapped line in the middle of a paragraph looked&#10;like a list item.&#10;&#10;Here’s one with a bullet. \* criminey.&#10;&#10;There should be a hard line break &#10;here.&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="Block Quotes" _note="E-mail style:&#10;&#10;&gt; This is a block quote. It is pretty short.&#10;&#10;&gt; Code in a block quote:&#10;&gt;&#10;&gt; sub status {&#10;&gt; print &quot;working&quot;;&#10;&gt; }&#10;&gt;&#10;&gt; A list:&#10;&gt;&#10;&gt; 1. item one&#10;&gt; 2. item two&#10;&gt;&#10;&gt; Nested block quotes:&#10;&gt;&#10;&gt; &gt; nested&#10;&gt;&#10;&gt; &gt; nested&#10;&#10;This should not be a block quote: 2 &amp;gt; 1.&#10;&#10;And a following paragraph.&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="Code Blocks" _note="Code:&#10;&#10; ---- (should be four hyphens)&#10;&#10; sub status {&#10; print &quot;working&quot;;&#10; }&#10;&#10; this code block is indented by one tab&#10;&#10;And:&#10;&#10; this code block is indented by two tabs&#10;&#10; These should not be escaped: \$ \\ \&gt; \[ \{&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="Lists">
+ <outline text="Unordered" _note="Asterisks tight:&#10;&#10;- asterisk 1&#10;- asterisk 2&#10;- asterisk 3&#10;&#10;Asterisks loose:&#10;&#10;- asterisk 1&#10;&#10;- asterisk 2&#10;&#10;- asterisk 3&#10;&#10;Pluses tight:&#10;&#10;- Plus 1&#10;- Plus 2&#10;- Plus 3&#10;&#10;Pluses loose:&#10;&#10;- Plus 1&#10;&#10;- Plus 2&#10;&#10;- Plus 3&#10;&#10;Minuses tight:&#10;&#10;- Minus 1&#10;- Minus 2&#10;- Minus 3&#10;&#10;Minuses loose:&#10;&#10;- Minus 1&#10;&#10;- Minus 2&#10;&#10;- Minus 3">
+ </outline>
+ <outline text="Ordered" _note="Tight:&#10;&#10;1. First&#10;2. Second&#10;3. Third&#10;&#10;and:&#10;&#10;1. One&#10;2. Two&#10;3. Three&#10;&#10;Loose using tabs:&#10;&#10;1. First&#10;&#10;2. Second&#10;&#10;3. Third&#10;&#10;and using spaces:&#10;&#10;1. One&#10;&#10;2. Two&#10;&#10;3. Three&#10;&#10;Multiple paragraphs:&#10;&#10;1. Item 1, graf one.&#10;&#10; Item 1. graf two. The quick brown fox jumped over the lazy dog’s&#10; back.&#10;&#10;2. Item 2.&#10;&#10;3. Item 3.">
+ </outline>
+ <outline text="Nested" _note="- Tab&#10; - Tab&#10; - Tab&#10;&#10;Here’s another:&#10;&#10;1. First&#10;2. Second:&#10; - Fee&#10; - Fie&#10; - Foe&#10;3. Third&#10;&#10;Same thing but with paragraphs:&#10;&#10;1. First&#10;&#10;2. Second:&#10;&#10; - Fee&#10; - Fie&#10; - Foe&#10;&#10;3. Third">
+ </outline>
+ <outline text="Tabs and spaces" _note="- this is a list item indented with tabs&#10;&#10;- this is a list item indented with spaces&#10;&#10; - this is an example list item indented with tabs&#10;&#10; - this is an example list item indented with spaces">
+ </outline>
+ <outline text="Fancy list markers" _note="1. begins with 2&#10;2. and now 3&#10;&#10; with a continuation&#10;&#10; 1. sublist with roman numerals, starting with 4&#10; 2. more items&#10; 1. a subsublist&#10; 2. a subsublist&#10;&#10;Nesting:&#10;&#10;1. Upper Alpha&#10; 1. Upper Roman.&#10; 1. Decimal start with 6&#10; 1. Lower alpha with paren&#10;&#10;Autonumbering:&#10;&#10;1. Autonumber.&#10;2. More.&#10; 1. Nested.&#10;&#10;Should not be a list item:&#10;&#10;M.A. 2007&#10;&#10;B. Williams&#10;&#10;------------------------------------------------------------------------">
+ </outline>
+</outline>
+<outline text="Definition Lists" _note="Tight using spaces:&#10;&#10;apple &#10;red fruit&#10;&#10;orange &#10;orange fruit&#10;&#10;banana &#10;yellow fruit&#10;&#10;Tight using tabs:&#10;&#10;apple &#10;red fruit&#10;&#10;orange &#10;orange fruit&#10;&#10;banana &#10;yellow fruit&#10;&#10;Loose:&#10;&#10;apple &#10;red fruit&#10;&#10;orange &#10;orange fruit&#10;&#10;banana &#10;yellow fruit&#10;&#10;Multiple blocks with italics:&#10;&#10;*apple* &#10;red fruit&#10;&#10;contains seeds, crisp, pleasant to taste&#10;&#10;*orange* &#10;orange fruit&#10;&#10; { orange code block }&#10;&#10;&gt; orange block quote&#10;&#10;Multiple definitions, tight:&#10;&#10;apple &#10;red fruit&#10;&#10;computer&#10;&#10;orange &#10;orange fruit&#10;&#10;bank&#10;&#10;Multiple definitions, loose:&#10;&#10;apple &#10;red fruit&#10;&#10;computer&#10;&#10;orange &#10;orange fruit&#10;&#10;bank&#10;&#10;Blank line after term, indented marker, alternate markers:&#10;&#10;apple &#10;red fruit&#10;&#10;computer&#10;&#10;orange &#10;orange fruit&#10;&#10;1. sublist&#10;2. sublist">
+</outline>
+<outline text="HTML Blocks" _note="Simple block on one line:&#10;&#10;foo&#10;&#10;And nested without indentation:&#10;&#10;foo&#10;&#10;bar&#10;&#10;Interpreted markdown in a table:&#10;&#10;This is *emphasized*&#10;And this is **strong**&#10;Here’s a simple block:&#10;&#10;foo&#10;&#10;This should be a code block, though:&#10;&#10; &lt;div&gt;&#10; foo&#10; &lt;/div&gt;&#10;&#10;As should this:&#10;&#10; &lt;div&gt;foo&lt;/div&gt;&#10;&#10;Now, nested:&#10;&#10;foo&#10;&#10;This should just be an HTML comment:&#10;&#10;Multiline:&#10;&#10;Code block:&#10;&#10; &lt;!-- Comment --&gt;&#10;&#10;Just plain comment, with trailing spaces on the line:&#10;&#10;Code:&#10;&#10; &lt;hr /&gt;&#10;&#10;Hr’s:&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="Inline Markup" _note="This is *emphasized*, and so *is this*.&#10;&#10;This is **strong**, and so **is this**.&#10;&#10;An *[emphasized link](/url)*.&#10;&#10;***This is strong and em.***&#10;&#10;So is ***this*** word.&#10;&#10;***This is strong and em.***&#10;&#10;So is ***this*** word.&#10;&#10;This is code: `&gt;`, `$`, `\`, `\$`, `&lt;html&gt;`.&#10;&#10;This is *strikeout*.&#10;&#10;Superscripts: a^(bc)d a^(*hello*) a^(hello there).&#10;&#10;Subscripts: H₂O, H₂₃O, H_(many of them)O.&#10;&#10;These should not be superscripts or subscripts, because of the unescaped&#10;spaces: a^b c^d, a~b c~d.&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="Smart quotes, ellipses, dashes" _note="“Hello,” said the spider. “‘Shelob’ is my name.”&#10;&#10;‘A’, ‘B’, and ‘C’ are letters.&#10;&#10;‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’&#10;&#10;‘He said, “I want to go.”’ Were you alive in the 70’s?&#10;&#10;Here is some quoted ‘`code`’ and a “[quoted&#10;link](http://example.com/?foo=1&amp;bar=2)”.&#10;&#10;Some dashes: one—two — three—four — five.&#10;&#10;Dashes between numbers: 5–7, 255–66, 1987–1999.&#10;&#10;Ellipses…and…and….&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="LaTeX" _note="- &#10;- 2 + 2 = 4&#10;- *x* ∈ *y*&#10;- *α* ∧ *ω*&#10;- 223&#10;- *p*-Tree&#10;- Here’s some display math:&#10; $$\\frac{d}{dx}f(x)=\\lim\_{h\\to 0}\\frac{f(x+h)-f(x)}{h}$$&#10;- Here’s one that has a line break in it: *α* + *ω* × *x*².&#10;&#10;These shouldn’t be math:&#10;&#10;- To get the famous equation, write `$e = mc^2$`.&#10;- $22,000 is a *lot* of money. So is $34,000. (It worked if “lot” is&#10; emphasized.)&#10;- Shoes ($20) and socks ($5).&#10;- Escaped `$`: $73 *this should be emphasized* 23$.&#10;&#10;Here’s a LaTeX table:&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="Special Characters" _note="Here is some unicode:&#10;&#10;- I hat: Î&#10;- o umlaut: ö&#10;- section: §&#10;- set membership: ∈&#10;- copyright: ©&#10;&#10;AT&amp;T has an ampersand in their name.&#10;&#10;AT&amp;T is another way to write it.&#10;&#10;This &amp; that.&#10;&#10;4 &amp;lt; 5.&#10;&#10;6 &amp;gt; 5.&#10;&#10;Backslash: \\&#10;&#10;Backtick: \`&#10;&#10;Asterisk: \*&#10;&#10;Underscore: \_&#10;&#10;Left brace: {&#10;&#10;Right brace: }&#10;&#10;Left bracket: \[&#10;&#10;Right bracket: \]&#10;&#10;Left paren: (&#10;&#10;Right paren: )&#10;&#10;Greater-than: &amp;gt;&#10;&#10;Hash: \#&#10;&#10;Period: .&#10;&#10;Bang: !&#10;&#10;Plus: +&#10;&#10;Minus: -&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="Links">
+ <outline text="Explicit" _note="Just a [URL](/url/).&#10;&#10;[URL and title](/url/ &quot;title&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by two spaces&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by a tab&quot;).&#10;&#10;[URL and title](/url/ &quot;title with &quot;quotes&quot; in it&quot;)&#10;&#10;[URL and title](/url/ &quot;title with single quotes&quot;)&#10;&#10;[with\_underscore](/url/with_underscore)&#10;&#10;[Email link](mailto:nobody@nowhere.net)&#10;&#10;[Empty]().">
+ </outline>
+ <outline text="Reference" _note="Foo [bar](/url/).&#10;&#10;With [embedded \[brackets\]](/url/).&#10;&#10;[b](/url/) by itself should be a link.&#10;&#10;Indented [once](/url).&#10;&#10;Indented [twice](/url).&#10;&#10;Indented [thrice](/url).&#10;&#10;This should \[not\]\[\] be a link.&#10;&#10; [not]: /url&#10;&#10;Foo [bar](/url/ &quot;Title with &quot;quotes&quot; inside&quot;).&#10;&#10;Foo [biz](/url/ &quot;Title with &quot;quote&quot; inside&quot;).">
+ </outline>
+ <outline text="With ampersands" _note="Here’s a [link with an ampersand in the&#10;URL](http://example.com/?foo=1&amp;bar=2).&#10;&#10;Here’s a link with an amersand in the link text:&#10;[AT&amp;T](http://att.com/ &quot;AT&amp;T&quot;).&#10;&#10;Here’s an [inline link](/script?foo=1&amp;bar=2).&#10;&#10;Here’s an [inline link in pointy braces](/script?foo=1&amp;bar=2).">
+ </outline>
+ <outline text="Autolinks" _note="With an ampersand: &lt;http://example.com/?foo=1&amp;bar=2&gt;&#10;&#10;- In a list?&#10;- &lt;http://example.com/&gt;&#10;- It should.&#10;&#10;An e-mail address: &lt;nobody@nowhere.net&gt;&#10;&#10;&gt; Blockquoted: &lt;http://example.com/&gt;&#10;&#10;Auto-links should not occur here: `&lt;http://example.com/&gt;`&#10;&#10; or here: &lt;http://example.com/&gt;&#10;&#10;------------------------------------------------------------------------">
+ </outline>
+</outline>
+<outline text="Images" _note="From “Voyage dans la Lune” by Georges Melies (1902):&#10;&#10;![lalune](lalune.jpg &quot;Voyage dans la Lune&quot;)&#10;&#10;Here is a movie ![movie](movie.jpg) icon.&#10;&#10;------------------------------------------------------------------------">
+</outline>
+<outline text="Footnotes" _note="Here is a footnote reference,[1] and another.[2] This should *not* be a&#10;footnote reference, because it contains a space.\[^my note\] Here is an&#10;inline note.[3]&#10;&#10;&gt; Notes can go in quotes.[4]&#10;&#10;1. And in list items.[5]&#10;&#10;This paragraph should not be part of the note, as it is not indented.&#10;&#10;[1] Here is the footnote. It can go anywhere after the footnote&#10;reference. It need not be placed at the end of the document.&#10;&#10;[2] Here’s the long note. This one contains multiple blocks.&#10;&#10;Subsequent blocks are indented to show that they belong to the footnote&#10;(as with list items).&#10;&#10; { &lt;code&gt; }&#10;&#10;If you want, you can indent every line, but you can also be lazy and&#10;just indent the first line of each block.&#10;&#10;[3] This is *easier* to type. Inline notes may contain&#10;[links](http://google.com) and `]` verbatim characters, as well as&#10;\[bracketed text\].&#10;&#10;[4] In quote.&#10;&#10;[5] In list.">
+</outline>
+ </body>
+</opml>
diff --git a/test/writer.org b/test/writer.org
new file mode 100644
index 000000000..1ae0ca8f3
--- /dev/null
+++ b/test/writer.org
@@ -0,0 +1,851 @@
+#+TITLE: Pandoc Test Suite
+
+#+AUTHOR: John MacFarlane; Anonymous
+#+DATE: July 17, 2006
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber's
+markdown test suite.
+
+--------------
+
+* Headers
+ :PROPERTIES:
+ :CUSTOM_ID: headers
+ :END:
+
+** Level 2 with an [[/url][embedded link]]
+ :PROPERTIES:
+ :CUSTOM_ID: level-2-with-an-embedded-link
+ :END:
+
+*** Level 3 with /emphasis/
+ :PROPERTIES:
+ :CUSTOM_ID: level-3-with-emphasis
+ :END:
+
+**** Level 4
+ :PROPERTIES:
+ :CUSTOM_ID: level-4
+ :END:
+
+***** Level 5
+ :PROPERTIES:
+ :CUSTOM_ID: level-5
+ :END:
+
+* Level 1
+ :PROPERTIES:
+ :CUSTOM_ID: level-1
+ :END:
+
+** Level 2 with /emphasis/
+ :PROPERTIES:
+ :CUSTOM_ID: level-2-with-emphasis
+ :END:
+
+*** Level 3
+ :PROPERTIES:
+ :CUSTOM_ID: level-3
+ :END:
+
+with no blank line
+
+** Level 2
+ :PROPERTIES:
+ :CUSTOM_ID: level-2
+ :END:
+
+with no blank line
+
+--------------
+
+* Paragraphs
+ :PROPERTIES:
+ :CUSTOM_ID: paragraphs
+ :END:
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break\\
+here.
+
+--------------
+
+* Block Quotes
+ :PROPERTIES:
+ :CUSTOM_ID: block-quotes
+ :END:
+
+E-mail style:
+
+#+BEGIN_QUOTE
+ This is a block quote. It is pretty short.
+#+END_QUOTE
+
+#+BEGIN_QUOTE
+ Code in a block quote:
+
+ #+BEGIN_EXAMPLE
+ sub status {
+ print "working";
+ }
+ #+END_EXAMPLE
+
+ A list:
+
+ 1. item one
+ 2. item two
+
+ Nested block quotes:
+
+ #+BEGIN_QUOTE
+ nested
+ #+END_QUOTE
+
+ #+BEGIN_QUOTE
+ nested
+ #+END_QUOTE
+#+END_QUOTE
+
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+--------------
+
+* Code Blocks
+ :PROPERTIES:
+ :CUSTOM_ID: code-blocks
+ :END:
+
+Code:
+
+#+BEGIN_EXAMPLE
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+#+END_EXAMPLE
+
+And:
+
+#+BEGIN_EXAMPLE
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+#+END_EXAMPLE
+
+--------------
+
+* Lists
+ :PROPERTIES:
+ :CUSTOM_ID: lists
+ :END:
+
+** Unordered
+ :PROPERTIES:
+ :CUSTOM_ID: unordered
+ :END:
+
+Asterisks tight:
+
+- asterisk 1
+- asterisk 2
+- asterisk 3
+
+Asterisks loose:
+
+- asterisk 1
+
+- asterisk 2
+
+- asterisk 3
+
+Pluses tight:
+
+- Plus 1
+- Plus 2
+- Plus 3
+
+Pluses loose:
+
+- Plus 1
+
+- Plus 2
+
+- Plus 3
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+** Ordered
+ :PROPERTIES:
+ :CUSTOM_ID: ordered
+ :END:
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
+
+2. Item 2.
+
+3. Item 3.
+
+** Nested
+ :PROPERTIES:
+ :CUSTOM_ID: nested
+ :END:
+
+- Tab
+
+ - Tab
+
+ - Tab
+
+Here's another:
+
+1. First
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+** Tabs and spaces
+ :PROPERTIES:
+ :CUSTOM_ID: tabs-and-spaces
+ :END:
+
+- this is a list item indented with tabs
+
+- this is a list item indented with spaces
+
+ - this is an example list item indented with tabs
+
+ - this is an example list item indented with spaces
+
+** Fancy list markers
+ :PROPERTIES:
+ :CUSTOM_ID: fancy-list-markers
+ :END:
+
+2) begins with 2
+3) and now 3
+
+ with a continuation
+
+ 4. sublist with roman numerals, starting with 4
+ 5. more items
+
+ 1) a subsublist
+ 2) a subsublist
+
+Nesting:
+
+1. Upper Alpha
+
+ 1. Upper Roman.
+
+ 6) Decimal start with 6
+
+ 3) Lower alpha with paren
+
+Autonumbering:
+
+1. Autonumber.
+2. More.
+
+ 1. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+--------------
+
+* Definition Lists
+ :PROPERTIES:
+ :CUSTOM_ID: definition-lists
+ :END:
+
+Tight using spaces:
+
+- apple :: red fruit
+- orange :: orange fruit
+- banana :: yellow fruit
+
+Tight using tabs:
+
+- apple :: red fruit
+- orange :: orange fruit
+- banana :: yellow fruit
+
+Loose:
+
+- apple :: red fruit
+
+- orange :: orange fruit
+
+- banana :: yellow fruit
+
+Multiple blocks with italics:
+
+- /apple/ :: red fruit
+
+ contains seeds, crisp, pleasant to taste
+
+- /orange/ :: orange fruit
+
+ #+BEGIN_EXAMPLE
+ { orange code block }
+ #+END_EXAMPLE
+
+ #+BEGIN_QUOTE
+ orange block quote
+ #+END_QUOTE
+
+Multiple definitions, tight:
+
+- apple :: red fruit
+ computer
+- orange :: orange fruit
+ bank
+
+Multiple definitions, loose:
+
+- apple :: red fruit
+
+ computer
+
+- orange :: orange fruit
+
+ bank
+
+Blank line after term, indented marker, alternate markers:
+
+- apple :: red fruit
+
+ computer
+
+- orange :: orange fruit
+
+ 1. sublist
+ 2. sublist
+
+* HTML Blocks
+ :PROPERTIES:
+ :CUSTOM_ID: html-blocks
+ :END:
+
+Simple block on one line:
+
+foo
+
+And nested without indentation:
+
+foo
+
+bar
+
+Interpreted markdown in a table:
+
+#+BEGIN_HTML
+ <table>
+#+END_HTML
+
+#+BEGIN_HTML
+ <tr>
+#+END_HTML
+
+#+BEGIN_HTML
+ <td>
+#+END_HTML
+
+This is /emphasized/
+
+#+BEGIN_HTML
+ </td>
+#+END_HTML
+
+#+BEGIN_HTML
+ <td>
+#+END_HTML
+
+And this is *strong*
+
+#+BEGIN_HTML
+ </td>
+#+END_HTML
+
+#+BEGIN_HTML
+ </tr>
+#+END_HTML
+
+#+BEGIN_HTML
+ </table>
+#+END_HTML
+
+#+BEGIN_HTML
+ <script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+#+END_HTML
+
+Here's a simple block:
+
+foo
+
+This should be a code block, though:
+
+#+BEGIN_EXAMPLE
+ <div>
+ foo
+ </div>
+#+END_EXAMPLE
+
+As should this:
+
+#+BEGIN_EXAMPLE
+ <div>foo</div>
+#+END_EXAMPLE
+
+Now, nested:
+
+foo
+
+This should just be an HTML comment:
+
+#+BEGIN_HTML
+ <!-- Comment -->
+#+END_HTML
+
+Multiline:
+
+#+BEGIN_HTML
+ <!--
+ Blah
+ Blah
+ -->
+#+END_HTML
+
+#+BEGIN_HTML
+ <!--
+ This is another comment.
+ -->
+#+END_HTML
+
+Code block:
+
+#+BEGIN_EXAMPLE
+ <!-- Comment -->
+#+END_EXAMPLE
+
+Just plain comment, with trailing spaces on the line:
+
+#+BEGIN_HTML
+ <!-- foo -->
+#+END_HTML
+
+Code:
+
+#+BEGIN_EXAMPLE
+ <hr />
+#+END_EXAMPLE
+
+Hr's:
+
+#+BEGIN_HTML
+ <hr>
+#+END_HTML
+
+#+BEGIN_HTML
+ <hr />
+#+END_HTML
+
+#+BEGIN_HTML
+ <hr />
+#+END_HTML
+
+#+BEGIN_HTML
+ <hr>
+#+END_HTML
+
+#+BEGIN_HTML
+ <hr />
+#+END_HTML
+
+#+BEGIN_HTML
+ <hr />
+#+END_HTML
+
+#+BEGIN_HTML
+ <hr class="foo" id="bar" />
+#+END_HTML
+
+#+BEGIN_HTML
+ <hr class="foo" id="bar" />
+#+END_HTML
+
+#+BEGIN_HTML
+ <hr class="foo" id="bar">
+#+END_HTML
+
+--------------
+
+* Inline Markup
+ :PROPERTIES:
+ :CUSTOM_ID: inline-markup
+ :END:
+
+This is /emphasized/, and so /is this/.
+
+This is *strong*, and so *is this*.
+
+An /[[/url][emphasized link]]/.
+
+*/This is strong and em./*
+
+So is */this/* word.
+
+*/This is strong and em./*
+
+So is */this/* word.
+
+This is code: =>=, =$=, =\=, =\$=, =<html>=.
+
++This is /strikeout/.+
+
+Superscripts: a^{bc}d a^{/hello/} a^{hello there}.
+
+Subscripts: H_{2}O, H_{23}O, H_{many of them}O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a\^b c\^d, a~b c~d.
+
+--------------
+
+* Smart quotes, ellipses, dashes
+ :PROPERTIES:
+ :CUSTOM_ID: smart-quotes-ellipses-dashes
+ :END:
+
+"Hello," said the spider. "'Shelob' is my name."
+
+'A', 'B', and 'C' are letters.
+
+'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
+
+'He said, "I want to go."' Were you alive in the 70's?
+
+Here is some quoted '=code=' and a "[[http://example.com/?foo=1&bar=2][quoted
+link]]".
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses...and...and....
+
+--------------
+
+* LaTeX
+ :PROPERTIES:
+ :CUSTOM_ID: latex
+ :END:
+
+- \cite[22-23]{smith.1899}
+- $2+2=4$
+- $x \in y$
+- $\alpha \wedge \omega$
+- $223$
+- $p$-Tree
+- Here's some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+- Here's one that has a line break in it: $\alpha + \omega \times x^2$.
+
+These shouldn't be math:
+
+- To get the famous equation, write =$e = mc^2$=.
+- $22,000 is a /lot/ of money. So is $34,000. (It worked if "lot" is
+ emphasized.)
+- Shoes ($20) and socks ($5).
+- Escaped =$=: $73 /this should be emphasized/ 23$.
+
+Here's a LaTeX table:
+
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+
+--------------
+
+* Special Characters
+ :PROPERTIES:
+ :CUSTOM_ID: special-characters
+ :END:
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: \_
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+--------------
+
+* Links
+ :PROPERTIES:
+ :CUSTOM_ID: links
+ :END:
+
+** Explicit
+ :PROPERTIES:
+ :CUSTOM_ID: explicit
+ :END:
+
+Just a [[/url/][URL]].
+
+[[/url/][URL and title]].
+
+[[/url/][URL and title]].
+
+[[/url/][URL and title]].
+
+[[/url/][URL and title]]
+
+[[/url/][URL and title]]
+
+[[/url/with_underscore][with\_underscore]]
+
+[[mailto:nobody@nowhere.net][Email link]]
+
+[[][Empty]].
+
+** Reference
+ :PROPERTIES:
+ :CUSTOM_ID: reference
+ :END:
+
+Foo [[/url/][bar]].
+
+With [[/url/][embedded [brackets]]].
+
+[[/url/][b]] by itself should be a link.
+
+Indented [[/url][once]].
+
+Indented [[/url][twice]].
+
+Indented [[/url][thrice]].
+
+This should [not][] be a link.
+
+#+BEGIN_EXAMPLE
+ [not]: /url
+#+END_EXAMPLE
+
+Foo [[/url/][bar]].
+
+Foo [[/url/][biz]].
+
+** With ampersands
+ :PROPERTIES:
+ :CUSTOM_ID: with-ampersands
+ :END:
+
+Here's a [[http://example.com/?foo=1&bar=2][link with an ampersand in the
+URL]].
+
+Here's a link with an amersand in the link text: [[http://att.com/][AT&T]].
+
+Here's an [[/script?foo=1&bar=2][inline link]].
+
+Here's an [[/script?foo=1&bar=2][inline link in pointy braces]].
+
+** Autolinks
+ :PROPERTIES:
+ :CUSTOM_ID: autolinks
+ :END:
+
+With an ampersand: [[http://example.com/?foo=1&bar=2]]
+
+- In a list?
+- [[http://example.com/]]
+- It should.
+
+An e-mail address: [[mailto:nobody@nowhere.net][nobody@nowhere.net]]
+
+#+BEGIN_QUOTE
+ Blockquoted: [[http://example.com/]]
+#+END_QUOTE
+
+Auto-links should not occur here: =<http://example.com/>=
+
+#+BEGIN_EXAMPLE
+ or here: <http://example.com/>
+#+END_EXAMPLE
+
+--------------
+
+* Images
+ :PROPERTIES:
+ :CUSTOM_ID: images
+ :END:
+
+From "Voyage dans la Lune" by Georges Melies (1902):
+
+#+CAPTION: lalune
+[[file:lalune.jpg]]
+
+Here is a movie [[file:movie.jpg]] icon.
+
+--------------
+
+* Footnotes
+ :PROPERTIES:
+ :CUSTOM_ID: footnotes
+ :END:
+
+Here is a footnote reference,[fn:1] and another.[fn:2] This should /not/ be a
+footnote reference, because it contains a space.[\^my note] Here is an inline
+note.[fn:3]
+
+#+BEGIN_QUOTE
+ Notes can go in quotes.[fn:4]
+#+END_QUOTE
+
+1. And in list items.[fn:5]
+
+This paragraph should not be part of the note, as it is not indented.
+
+[fn:1] Here is the footnote. It can go anywhere after the footnote reference.
+ It need not be placed at the end of the document.
+
+[fn:2] Here's the long note. This one contains multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the footnote
+ (as with list items).
+
+ #+BEGIN_EXAMPLE
+ { <code> }
+ #+END_EXAMPLE
+
+ If you want, you can indent every line, but you can also be lazy and
+ just indent the first line of each block.
+
+[fn:3] This is /easier/ to type. Inline notes may contain
+ [[http://google.com][links]] and =]= verbatim characters, as well as
+ [bracketed text].
+
+[fn:4] In quote.
+
+[fn:5] In list.
diff --git a/test/writer.plain b/test/writer.plain
new file mode 100644
index 000000000..031c4a3e6
--- /dev/null
+++ b/test/writer.plain
@@ -0,0 +1,691 @@
+Pandoc Test Suite
+John MacFarlane; Anonymous
+July 17, 2006
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
+markdown test suite.
+
+------------------------------------------------------------------------------
+
+
+
+HEADERS
+
+
+Level 2 with an embedded link
+
+Level 3 with _emphasis_
+
+Level 4
+
+Level 5
+
+
+
+LEVEL 1
+
+
+Level 2 with _emphasis_
+
+Level 3
+
+with no blank line
+
+
+Level 2
+
+with no blank line
+
+------------------------------------------------------------------------------
+
+
+
+PARAGRAPHS
+
+
+Here’s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here’s one with a bullet. * criminey.
+
+There should be a hard line break
+here.
+
+------------------------------------------------------------------------------
+
+
+
+BLOCK QUOTES
+
+
+E-mail style:
+
+ This is a block quote. It is pretty short.
+
+ Code in a block quote:
+
+ sub status {
+ print "working";
+ }
+
+ A list:
+
+ 1. item one
+ 2. item two
+
+ Nested block quotes:
+
+ nested
+
+ nested
+
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+------------------------------------------------------------------------------
+
+
+
+CODE BLOCKS
+
+
+Code:
+
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+
+And:
+
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+
+------------------------------------------------------------------------------
+
+
+
+LISTS
+
+
+Unordered
+
+Asterisks tight:
+
+- asterisk 1
+- asterisk 2
+- asterisk 3
+
+Asterisks loose:
+
+- asterisk 1
+
+- asterisk 2
+
+- asterisk 3
+
+Pluses tight:
+
+- Plus 1
+- Plus 2
+- Plus 3
+
+Pluses loose:
+
+- Plus 1
+
+- Plus 2
+
+- Plus 3
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+
+Ordered
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
+
+2. Item 2.
+
+3. Item 3.
+
+
+Nested
+
+- Tab
+ - Tab
+ - Tab
+
+Here’s another:
+
+1. First
+2. Second:
+ - Fee
+ - Fie
+ - Foe
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+
+Tabs and spaces
+
+- this is a list item indented with tabs
+
+- this is a list item indented with spaces
+
+ - this is an example list item indented with tabs
+
+ - this is an example list item indented with spaces
+
+
+Fancy list markers
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+ iv. sublist with roman numerals, starting with 4
+ v. more items
+ (A) a subsublist
+ (B) a subsublist
+
+Nesting:
+
+A. Upper Alpha
+ I. Upper Roman.
+ (6) Decimal start with 6
+ c) Lower alpha with paren
+
+Autonumbering:
+
+1. Autonumber.
+2. More.
+ 1. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+------------------------------------------------------------------------------
+
+
+
+DEFINITION LISTS
+
+
+Tight using spaces:
+
+apple
+ red fruit
+
+orange
+ orange fruit
+
+banana
+ yellow fruit
+
+Tight using tabs:
+
+apple
+ red fruit
+
+orange
+ orange fruit
+
+banana
+ yellow fruit
+
+Loose:
+
+apple
+
+ red fruit
+
+orange
+
+ orange fruit
+
+banana
+
+ yellow fruit
+
+Multiple blocks with italics:
+
+_apple_
+
+ red fruit
+
+ contains seeds, crisp, pleasant to taste
+
+_orange_
+
+ orange fruit
+
+ { orange code block }
+
+ orange block quote
+
+Multiple definitions, tight:
+
+apple
+ red fruit
+ computer
+
+orange
+ orange fruit
+ bank
+
+Multiple definitions, loose:
+
+apple
+
+ red fruit
+
+ computer
+
+orange
+
+ orange fruit
+
+ bank
+
+Blank line after term, indented marker, alternate markers:
+
+apple
+
+ red fruit
+
+ computer
+
+orange
+
+ orange fruit
+
+ 1. sublist
+ 2. sublist
+
+
+
+HTML BLOCKS
+
+
+Simple block on one line:
+
+foo
+
+And nested without indentation:
+
+foo
+
+bar
+
+Interpreted markdown in a table:
+
+This is _emphasized_
+And this is STRONG
+Here’s a simple block:
+
+foo
+
+This should be a code block, though:
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+ <div>foo</div>
+
+Now, nested:
+
+foo
+
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+ <hr />
+
+Hr’s:
+
+------------------------------------------------------------------------------
+
+
+
+INLINE MARKUP
+
+
+This is _emphasized_, and so _is this_.
+
+This is STRONG, and so IS THIS.
+
+An _emphasized link_.
+
+_THIS IS STRONG AND EM._
+
+So is _THIS_ word.
+
+_THIS IS STRONG AND EM._
+
+So is _THIS_ word.
+
+This is code: >, $, \, \$, <html>.
+
+~~This is _strikeout_.~~
+
+Superscripts: a^(bc)d a^(_hello_) a^(hello there).
+
+Subscripts: H₂O, H₂₃O, H_(many of them)O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a~b c~d.
+
+------------------------------------------------------------------------------
+
+
+
+SMART QUOTES, ELLIPSES, DASHES
+
+
+“Hello,” said the spider. “‘Shelob’ is my name.”
+
+‘A’, ‘B’, and ‘C’ are letters.
+
+‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
+
+‘He said, “I want to go.”’ Were you alive in the 70’s?
+
+Here is some quoted ‘code’ and a “quoted link”.
+
+Some dashes: one—two — three—four — five.
+
+Dashes between numbers: 5–7, 255–66, 1987–1999.
+
+Ellipses…and…and….
+
+------------------------------------------------------------------------------
+
+
+
+LATEX
+
+
+-
+- 2 + 2 = 4
+- x ∈ y
+- α ∧ ω
+- 223
+- p-Tree
+- Here’s some display math:
+ $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+- Here’s one that has a line break in it: α + ω × x².
+
+These shouldn’t be math:
+
+- To get the famous equation, write $e = mc^2$.
+- $22,000 is a _lot_ of money. So is $34,000. (It worked if “lot” is
+ emphasized.)
+- Shoes ($20) and socks ($5).
+- Escaped $: $73 _this should be emphasized_ 23$.
+
+Here’s a LaTeX table:
+
+------------------------------------------------------------------------------
+
+
+
+SPECIAL CHARACTERS
+
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+------------------------------------------------------------------------------
+
+
+
+LINKS
+
+
+Explicit
+
+Just a URL.
+
+URL and title.
+
+URL and title.
+
+URL and title.
+
+URL and title
+
+URL and title
+
+with_underscore
+
+Email link
+
+Empty.
+
+
+Reference
+
+Foo bar.
+
+With embedded [brackets].
+
+b by itself should be a link.
+
+Indented once.
+
+Indented twice.
+
+Indented thrice.
+
+This should [not][] be a link.
+
+ [not]: /url
+
+Foo bar.
+
+Foo biz.
+
+
+With ampersands
+
+Here’s a link with an ampersand in the URL.
+
+Here’s a link with an amersand in the link text: AT&T.
+
+Here’s an inline link.
+
+Here’s an inline link in pointy braces.
+
+
+Autolinks
+
+With an ampersand: http://example.com/?foo=1&bar=2
+
+- In a list?
+- http://example.com/
+- It should.
+
+An e-mail address: nobody@nowhere.net
+
+ Blockquoted: http://example.com/
+
+Auto-links should not occur here: <http://example.com/>
+
+ or here: <http://example.com/>
+
+------------------------------------------------------------------------------
+
+
+
+IMAGES
+
+
+From “Voyage dans la Lune” by Georges Melies (1902):
+
+[lalune]
+
+Here is a movie [movie] icon.
+
+------------------------------------------------------------------------------
+
+
+
+FOOTNOTES
+
+
+Here is a footnote reference,[1] and another.[2] This should _not_ be a
+footnote reference, because it contains a space.[^my note] Here is an inline
+note.[3]
+
+ Notes can go in quotes.[4]
+
+1. And in list items.[5]
+
+This paragraph should not be part of the note, as it is not indented.
+
+[1] Here is the footnote. It can go anywhere after the footnote reference. It
+need not be placed at the end of the document.
+
+[2] Here’s the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the footnote (as
+with list items).
+
+ { <code> }
+
+If you want, you can indent every line, but you can also be lazy and just
+indent the first line of each block.
+
+[3] This is _easier_ to type. Inline notes may contain links and ] verbatim
+characters, as well as [bracketed text].
+
+[4] In quote.
+
+[5] In list.
diff --git a/test/writer.rst b/test/writer.rst
new file mode 100644
index 000000000..93158f0c3
--- /dev/null
+++ b/test/writer.rst
@@ -0,0 +1,890 @@
+=================
+Pandoc Test Suite
+=================
+
+:Author: John MacFarlane
+:Author: Anonymous
+:Date: July 17, 2006
+
+.. role:: raw-latex(raw)
+ :format: latex
+..
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
+markdown test suite.
+
+--------------
+
+Headers
+=======
+
+Level 2 with an `embedded link </url>`__
+----------------------------------------
+
+Level 3 with *emphasis*
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Level 4
+^^^^^^^
+
+Level 5
+'''''''
+
+Level 1
+=======
+
+Level 2 with *emphasis*
+-----------------------
+
+Level 3
+~~~~~~~
+
+with no blank line
+
+Level 2
+-------
+
+with no blank line
+
+--------------
+
+Paragraphs
+==========
+
+Here’s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here’s one with a bullet. \* criminey.
+
+| There should be a hard line break
+| here.
+
+--------------
+
+Block Quotes
+============
+
+E-mail style:
+
+ This is a block quote. It is pretty short.
+
+..
+
+ Code in a block quote:
+
+ ::
+
+ sub status {
+ print "working";
+ }
+
+ A list:
+
+ 1. item one
+ 2. item two
+
+ Nested block quotes:
+
+ nested
+
+ ..
+
+ nested
+
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+--------------
+
+Code Blocks
+===========
+
+Code:
+
+::
+
+ ---- (should be four hyphens)
+
+ sub status {
+ print "working";
+ }
+
+ this code block is indented by one tab
+
+And:
+
+::
+
+ this code block is indented by two tabs
+
+ These should not be escaped: \$ \\ \> \[ \{
+
+--------------
+
+Lists
+=====
+
+Unordered
+---------
+
+Asterisks tight:
+
+- asterisk 1
+- asterisk 2
+- asterisk 3
+
+Asterisks loose:
+
+- asterisk 1
+
+- asterisk 2
+
+- asterisk 3
+
+Pluses tight:
+
+- Plus 1
+- Plus 2
+- Plus 3
+
+Pluses loose:
+
+- Plus 1
+
+- Plus 2
+
+- Plus 3
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+Ordered
+-------
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
+
+2. Item 2.
+
+3. Item 3.
+
+Nested
+------
+
+- Tab
+
+ - Tab
+
+ - Tab
+
+Here’s another:
+
+1. First
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+
+ - Fee
+ - Fie
+ - Foe
+
+3. Third
+
+Tabs and spaces
+---------------
+
+- this is a list item indented with tabs
+
+- this is a list item indented with spaces
+
+ - this is an example list item indented with tabs
+
+ - this is an example list item indented with spaces
+
+Fancy list markers
+------------------
+
+(2) begins with 2
+(3) and now 3
+
+ with a continuation
+
+ iv. sublist with roman numerals, starting with 4
+ v. more items
+
+ (A) a subsublist
+ (B) a subsublist
+
+Nesting:
+
+A. Upper Alpha
+
+ I. Upper Roman.
+
+ (6) Decimal start with 6
+
+ c) Lower alpha with paren
+
+Autonumbering:
+
+#. Autonumber.
+#. More.
+
+ #. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+--------------
+
+Definition Lists
+================
+
+Tight using spaces:
+
+apple
+ red fruit
+orange
+ orange fruit
+banana
+ yellow fruit
+
+Tight using tabs:
+
+apple
+ red fruit
+orange
+ orange fruit
+banana
+ yellow fruit
+
+Loose:
+
+apple
+ red fruit
+
+orange
+ orange fruit
+
+banana
+ yellow fruit
+
+Multiple blocks with italics:
+
+*apple*
+ red fruit
+
+ contains seeds, crisp, pleasant to taste
+
+*orange*
+ orange fruit
+
+ ::
+
+ { orange code block }
+
+ ..
+
+ orange block quote
+
+Multiple definitions, tight:
+
+apple
+ red fruit
+ computer
+orange
+ orange fruit
+ bank
+
+Multiple definitions, loose:
+
+apple
+ red fruit
+
+ computer
+
+orange
+ orange fruit
+
+ bank
+
+Blank line after term, indented marker, alternate markers:
+
+apple
+ red fruit
+
+ computer
+
+orange
+ orange fruit
+
+ 1. sublist
+ 2. sublist
+
+HTML Blocks
+===========
+
+Simple block on one line:
+
+.. raw:: html
+
+ <div>
+
+foo
+
+.. raw:: html
+
+ </div>
+
+And nested without indentation:
+
+.. raw:: html
+
+ <div>
+
+.. raw:: html
+
+ <div>
+
+.. raw:: html
+
+ <div>
+
+foo
+
+.. raw:: html
+
+ </div>
+
+.. raw:: html
+
+ </div>
+
+.. raw:: html
+
+ <div>
+
+bar
+
+.. raw:: html
+
+ </div>
+
+.. raw:: html
+
+ </div>
+
+Interpreted markdown in a table:
+
+.. raw:: html
+
+ <table>
+
+.. raw:: html
+
+ <tr>
+
+.. raw:: html
+
+ <td>
+
+This is *emphasized*
+
+.. raw:: html
+
+ </td>
+
+.. raw:: html
+
+ <td>
+
+And this is **strong**
+
+.. raw:: html
+
+ </td>
+
+.. raw:: html
+
+ </tr>
+
+.. raw:: html
+
+ </table>
+
+.. raw:: html
+
+ <script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+Here’s a simple block:
+
+.. raw:: html
+
+ <div>
+
+foo
+
+.. raw:: html
+
+ </div>
+
+This should be a code block, though:
+
+::
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+::
+
+ <div>foo</div>
+
+Now, nested:
+
+.. raw:: html
+
+ <div>
+
+.. raw:: html
+
+ <div>
+
+.. raw:: html
+
+ <div>
+
+foo
+
+.. raw:: html
+
+ </div>
+
+.. raw:: html
+
+ </div>
+
+.. raw:: html
+
+ </div>
+
+This should just be an HTML comment:
+
+.. raw:: html
+
+ <!-- Comment -->
+
+Multiline:
+
+.. raw:: html
+
+ <!--
+ Blah
+ Blah
+ -->
+
+.. raw:: html
+
+ <!--
+ This is another comment.
+ -->
+
+Code block:
+
+::
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+.. raw:: html
+
+ <!-- foo -->
+
+Code:
+
+::
+
+ <hr />
+
+Hr’s:
+
+.. raw:: html
+
+ <hr>
+
+.. raw:: html
+
+ <hr />
+
+.. raw:: html
+
+ <hr />
+
+.. raw:: html
+
+ <hr>
+
+.. raw:: html
+
+ <hr />
+
+.. raw:: html
+
+ <hr />
+
+.. raw:: html
+
+ <hr class="foo" id="bar" />
+
+.. raw:: html
+
+ <hr class="foo" id="bar" />
+
+.. raw:: html
+
+ <hr class="foo" id="bar">
+
+--------------
+
+Inline Markup
+=============
+
+This is *emphasized*, and so *is this*.
+
+This is **strong**, and so **is this**.
+
+An *`emphasized link </url>`__*.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+***This is strong and em.***
+
+So is ***this*** word.
+
+This is code: ``>``, ``$``, ``\``, ``\$``, ``<html>``.
+
+[STRIKEOUT:This is *strikeout*.]
+
+Superscripts: a\ :sup:`bc`\ d a\ :sup:`*hello*` a\ :sup:`hello there`.
+
+Subscripts: H\ :sub:`2`\ O, H\ :sub:`23`\ O, H\ :sub:`many of them`\ O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a~b c~d.
+
+--------------
+
+Smart quotes, ellipses, dashes
+==============================
+
+“Hello,” said the spider. “‘Shelob’ is my name.”
+
+‘A’, ‘B’, and ‘C’ are letters.
+
+‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
+
+‘He said, “I want to go.”’ Were you alive in the 70’s?
+
+Here is some quoted ‘``code``’ and a “`quoted
+link <http://example.com/?foo=1&bar=2>`__”.
+
+Some dashes: one—two — three—four — five.
+
+Dashes between numbers: 5–7, 255–66, 1987–1999.
+
+Ellipses…and…and….
+
+--------------
+
+LaTeX
+=====
+
+- :raw-latex:`\cite[22-23]{smith.1899}`
+- :math:`2+2=4`
+- :math:`x \in y`
+- :math:`\alpha \wedge \omega`
+- :math:`223`
+- :math:`p`-Tree
+- Here’s some display math:
+
+ .. math:: \frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}
+
+- Here’s one that has a line break in it: :math:`\alpha + \omega \times x^2`.
+
+These shouldn’t be math:
+
+- To get the famous equation, write ``$e = mc^2$``.
+- $22,000 is a *lot* of money. So is $34,000. (It worked if “lot” is
+ emphasized.)
+- Shoes ($20) and socks ($5).
+- Escaped ``$``: $73 *this should be emphasized* 23$.
+
+Here’s a LaTeX table:
+
+.. raw:: latex
+
+ \begin{tabular}{|l|l|}\hline
+ Animal & Number \\ \hline
+ Dog & 2 \\
+ Cat & 1 \\ \hline
+ \end{tabular}
+
+--------------
+
+Special Characters
+==================
+
+Here is some unicode:
+
+- I hat: Î
+- o umlaut: ö
+- section: §
+- set membership: ∈
+- copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+--------------
+
+Links
+=====
+
+Explicit
+--------
+
+Just a `URL </url/>`__.
+
+`URL and title </url/>`__.
+
+`URL and title </url/>`__.
+
+`URL and title </url/>`__.
+
+`URL and title </url/>`__
+
+`URL and title </url/>`__
+
+`with_underscore </url/with_underscore>`__
+
+`Email link <mailto:nobody@nowhere.net>`__
+
+`Empty <>`__.
+
+Reference
+---------
+
+Foo `bar </url/>`__.
+
+With `embedded [brackets] </url/>`__.
+
+`b </url/>`__ by itself should be a link.
+
+Indented `once </url>`__.
+
+Indented `twice </url>`__.
+
+Indented `thrice </url>`__.
+
+This should [not][] be a link.
+
+::
+
+ [not]: /url
+
+Foo `bar </url/>`__.
+
+Foo `biz </url/>`__.
+
+With ampersands
+---------------
+
+Here’s a `link with an ampersand in the
+URL <http://example.com/?foo=1&bar=2>`__.
+
+Here’s a link with an amersand in the link text: `AT&T <http://att.com/>`__.
+
+Here’s an `inline link </script?foo=1&bar=2>`__.
+
+Here’s an `inline link in pointy braces </script?foo=1&bar=2>`__.
+
+Autolinks
+---------
+
+With an ampersand: http://example.com/?foo=1&bar=2
+
+- In a list?
+- http://example.com/
+- It should.
+
+An e-mail address: nobody@nowhere.net
+
+ Blockquoted: http://example.com/
+
+Auto-links should not occur here: ``<http://example.com/>``
+
+::
+
+ or here: <http://example.com/>
+
+--------------
+
+Images
+======
+
+From “Voyage dans la Lune” by Georges Melies (1902):
+
+.. figure:: lalune.jpg
+ :alt: Voyage dans la Lune
+
+ lalune
+
+Here is a movie |movie| icon.
+
+--------------
+
+Footnotes
+=========
+
+Here is a footnote reference, [1]_ and another. [2]_ This should *not* be a
+footnote reference, because it contains a space.[^my note] Here is an inline
+note. [3]_
+
+ Notes can go in quotes. [4]_
+
+1. And in list items. [5]_
+
+This paragraph should not be part of the note, as it is not indented.
+
+.. [1]
+ Here is the footnote. It can go anywhere after the footnote reference. It
+ need not be placed at the end of the document.
+
+.. [2]
+ Here’s the long note. This one contains multiple blocks.
+
+ Subsequent blocks are indented to show that they belong to the footnote (as
+ with list items).
+
+ ::
+
+ { <code> }
+
+ If you want, you can indent every line, but you can also be lazy and just
+ indent the first line of each block.
+
+.. [3]
+ This is *easier* to type. Inline notes may contain
+ `links <http://google.com>`__ and ``]`` verbatim characters, as well as
+ [bracketed text].
+
+.. [4]
+ In quote.
+
+.. [5]
+ In list.
+
+.. |movie| image:: movie.jpg
diff --git a/test/writer.rtf b/test/writer.rtf
new file mode 100644
index 000000000..c67c67a83
--- /dev/null
+++ b/test/writer.rtf
@@ -0,0 +1,443 @@
+{\rtf1\ansi\deff0{\fonttbl{\f0 \fswiss Helvetica;}{\f1 Courier;}}
+{\colortbl;\red255\green0\blue0;\red0\green0\blue255;}
+\widowctrl\hyphauto
+
+{\pard \qc \f0 \sa180 \li0 \fi0 \b \fs36 Pandoc Test Suite\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 John MacFarlane\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 Anonymous\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 July 17, 2006\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This is a set of tests for pandoc. Most of them are adapted from John Gruber\u8217's markdown test suite.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Headers\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2 with an {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+embedded link
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Level 3 with {\i emphasis}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Level 4\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs20 Level 5\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Level 1\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2 with {\i emphasis}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Level 3\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 with no blank line\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 with no blank line\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Paragraphs\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a regular paragraph.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's one with a bullet. * criminey.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 There should be a hard line break\line here.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Block Quotes\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 E-mail style:\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 This is a block quote. It is pretty short.\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 Code in a block quote:\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 \f1 sub status \{\line
+ print "working";\line
+\}\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 A list:\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 1.\tx360\tab item one\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 2.\tx360\tab item two\sa180\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 Nested block quotes:\par}
+{\pard \ql \f0 \sa180 \li1440 \fi0 nested\par}
+{\pard \ql \f0 \sa180 \li1440 \fi0 nested\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This should not be a block quote: 2 > 1.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 And a following paragraph.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Code Blocks\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Code:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 ---- (should be four hyphens)\line
+\line
+sub status \{\line
+ print "working";\line
+\}\line
+\line
+this code block is indented by one tab\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 And:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 this code block is indented by two tabs\line
+\line
+These should not be escaped: \\$ \\\\ \\> \\[ \\\{\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Lists\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Unordered\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Asterisks tight:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 1\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 2\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Asterisks loose:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 1\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 2\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Pluses tight:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 1\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 2\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Pluses loose:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 1\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 2\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Minuses tight:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 1\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 2\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Minuses loose:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 1\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 2\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 3\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Ordered\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Tight:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab First\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Second\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 and:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab One\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Two\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Three\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Loose using tabs:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab First\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Second\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 and using spaces:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab One\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Two\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Three\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiple paragraphs:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab Item 1, graf one.\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 Item 1. graf two. The quick brown fox jumped over the lazy dog\u8217's back.\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Item 2.\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Item 3.\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Nested\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Tab\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Tab\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 \bullet \tx360\tab Tab\sa180\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's another:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab First\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Second:\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fee\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fie\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Foe\sa180\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Same thing but with paragraphs:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab First\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Second:\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fee\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fie\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Foe\sa180\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Tabs and spaces\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab this is a list item indented with tabs\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab this is a list item indented with spaces\par}
+{\pard \ql \f0 \sa180 \li720 \fi-360 \endash \tx360\tab this is an example list item indented with tabs\par}
+{\pard \ql \f0 \sa180 \li720 \fi-360 \endash \tx360\tab this is an example list item indented with spaces\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Fancy list markers\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 (2)\tx360\tab begins with 2\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 (3)\tx360\tab and now 3\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 with a continuation\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 iv.\tx360\tab sublist with roman numerals, starting with 4\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 v.\tx360\tab more items\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 (A)\tx360\tab a subsublist\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 (B)\tx360\tab a subsublist\sa180\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Nesting:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 A.\tx360\tab Upper Alpha\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 I.\tx360\tab Upper Roman.\par}
+{\pard \ql \f0 \sa0 \li1080 \fi-360 (6)\tx360\tab Decimal start with 6\par}
+{\pard \ql \f0 \sa0 \li1440 \fi-360 c)\tx360\tab Lower alpha with paren\sa180\sa180\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Autonumbering:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab Autonumber.\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab More.\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 a.\tx360\tab Nested.\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Should not be a list item:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 M.A.\u160?2007\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 B. Williams\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Definition Lists\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Tight using spaces:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 yellow fruit\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Tight using tabs:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 yellow fruit\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Loose:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 yellow fruit\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiple blocks with italics:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 {\i apple}\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 contains seeds, crisp, pleasant to taste\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 {\i orange}\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 \f1 \{ orange code block \}\par}
+{\pard \ql \f0 \sa180 \li1080 \fi0 orange block quote\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiple definitions, tight:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 computer\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa0 \li360 \fi0 bank\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiple definitions, loose:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 computer\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 bank\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Blank line after term, indented marker, alternate markers:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 computer\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
+{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 1.\tx360\tab sublist\par}
+{\pard \ql \f0 \sa0 \li720 \fi-360 2.\tx360\tab sublist\sa180\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 HTML Blocks\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Simple block on one line:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 foo\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 And nested without indentation:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 foo\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 bar\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Interpreted markdown in a table:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 This is {\i emphasized}\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 And this is {\b strong}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a simple block:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 foo\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This should be a code block, though:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <div>\line
+ foo\line
+</div>\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 As should this:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <div>foo</div>\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Now, nested:\par}
+{\pard \ql \f0 \sa0 \li0 \fi0 foo\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This should just be an HTML comment:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiline:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Code block:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <!-- Comment -->\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Just plain comment, with trailing spaces on the line:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Code:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <hr />\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Hr\u8217's:\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Inline Markup\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This is {\i emphasized}, and so {\i is this}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This is {\b strong}, and so {\b is this}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 An {\i {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+emphasized link
+}}}
+}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\b {\i This is strong and em.}}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 So is {\b {\i this}} word.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\b {\i This is strong and em.}}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 So is {\b {\i this}} word.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This is code: {\f1 >}, {\f1 $}, {\f1 \\}, {\f1 \\$}, {\f1 <html>}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\strike This is {\i strikeout}.}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Superscripts: a{\super bc}d a{\super {\i hello}} a{\super hello\u160?there}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Subscripts: H{\sub 2}O, H{\sub 23}O, H{\sub many\u160?of\u160?them}O.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Smart quotes, ellipses, dashes\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \u8220"Hello,\u8221" said the spider. \u8220"\u8216'Shelob\u8217' is my name.\u8221"\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'A\u8217', \u8216'B\u8217', and \u8216'C\u8217' are letters.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'Oak,\u8217' \u8216'elm,\u8217' and \u8216'beech\u8217' are names of trees. So is \u8216'pine.\u8217'\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'He said, \u8220"I want to go.\u8221"\u8217' Were you alive in the 70\u8217's?\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here is some quoted \u8216'{\f1 code}\u8217' and a \u8220"{\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
+quoted link
+}}}
+\u8221".\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Some dashes: one\u8212-two \u8212- three\u8212-four \u8212- five.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Dashes between numbers: 5\u8211-7, 255\u8211-66, 1987\u8211-1999.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Ellipses\u8230?and\u8230?and\u8230?.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 LaTeX\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab \par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab 2\u8197?+\u8197?2\u8196?=\u8196?4\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\i x}\u8196?\u8712?\u8196?{\i y}\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\i \u945?}\u8197?\u8743?\u8197?{\i \u969?}\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab 223\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\i p}-Tree\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Here\u8217's some display math: $$\\frac\{d\}\{dx\}f(x)=\\lim_\{h\\to 0\}\\frac\{f(x+h)-f(x)\}\{h\}$$\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Here\u8217's one that has a line break in it: {\i \u945?}\u8197?+\u8197?{\i \u969?}\u8197?\u215?\u8197?{\i x}{\super 2}.\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 These shouldn\u8217't be math:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab To get the famous equation, write {\f1 $e = mc^2$}.\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab $22,000 is a {\i lot} of money. So is $34,000. (It worked if \u8220"lot\u8221" is emphasized.)\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Shoes ($20) and socks ($5).\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Escaped {\f1 $}: $73 {\i this should be emphasized} 23$.\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a LaTeX table:\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Special Characters\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here is some unicode:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab I hat: \u206?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab o umlaut: \u246?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab section: \u167?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab set membership: \u8712?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab copyright: \u169?\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 AT&T has an ampersand in their name.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 AT&T is another way to write it.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This & that.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 4 < 5.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 6 > 5.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Backslash: \\\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Backtick: `\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Asterisk: *\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Underscore: _\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Left brace: \{\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Right brace: \}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Left bracket: [\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Right bracket: ]\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Left paren: (\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Right paren: )\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Greater-than: >\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Hash: #\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Period: .\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Bang: !\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Plus: +\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Minus: -\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Links\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Explicit\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Just a {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+URL and title
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/with_underscore"}}{\fldrslt{\ul
+with_underscore
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "mailto:nobody@nowhere.net"}}{\fldrslt{\ul
+Email link
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK ""}}{\fldrslt{\ul
+Empty
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Reference\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+bar
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 With {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+embedded [brackets]
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+b
+}}}
+ by itself should be a link.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+once
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+twice
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
+thrice
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This should [not][] be a link.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 [not]: /url\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+bar
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
+biz
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 With ampersands\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a {\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
+link with an ampersand in the URL
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a link with an amersand in the link text: {\field{\*\fldinst{HYPERLINK "http://att.com/"}}{\fldrslt{\ul
+AT&T
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's an {\field{\*\fldinst{HYPERLINK "/script?foo=1&bar=2"}}{\fldrslt{\ul
+inline link
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's an {\field{\*\fldinst{HYPERLINK "/script?foo=1&bar=2"}}{\fldrslt{\ul
+inline link in pointy braces
+}}}
+.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Autolinks\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 With an ampersand: {\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
+http://example.com/?foo=1&bar=2
+}}}
+\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab In a list?\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\field{\*\fldinst{HYPERLINK "http://example.com/"}}{\fldrslt{\ul
+http://example.com/
+}}}
+\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab It should.\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 An e-mail address: {\field{\*\fldinst{HYPERLINK "mailto:nobody@nowhere.net"}}{\fldrslt{\ul
+nobody@nowhere.net
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 Blockquoted: {\field{\*\fldinst{HYPERLINK "http://example.com/"}}{\fldrslt{\ul
+http://example.com/
+}}}
+\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Auto-links should not occur here: {\f1 <http://example.com/>}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 or here: <http://example.com/>\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Images\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 From \u8220"Voyage dans la Lune\u8221" by Georges Melies (1902):\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\pict\jpegblip\picw250\pich250\picwgoal3000\pichgoal3000\bin ffd8ffe000104a46494600010101007800780000ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a2828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828ffc000110800fa00fa03011100021101031101ffc4001c0000000701010000000000000000000000010203040506070008ffc4003e100002010303020404040502050500030001020300041105122106311322415107617181143291a1234252b1c115f016336272d1082443e1f1265382ffc40017010101010100000000000000000000000000010204ffc4001b11010101010003010000000000000000000001110212213141ffda000c03010002110311003f00dadd18a10a704f6a95ccc57e37750782b0d8d9ea0cd32e7c5446e07e9f4ad723119a7b89e61e348f260719278aad613cbb640002938c76a182b264fc87bd13009c0c019c76e3d68a072e1cf6f4cd502d330c28269a61bb39c923923d4fad44c08dccb95cfd28b8280769ee08a263891e1808739e4f1d8d149392172cc714050dbb9fde8960ed8c60b79b1ed44103b05c331dbdb1dc5026ac1946d20ff8140aa631c773ec738a0346a003bf93e9cf02801895e7b9a01886796c923bd0090a06393c76a0142003ce3d86680d8dd9392303f5341ccc1b3cf7a2c812c37e4923d381429757013209fa511c18146c9247a0f6a007900c0c671c6280854e086c673eb45c27c038fd68aedff2fda836ef881f136f25d5e6b7d1262964aa02b03f98fbf153131935edcc97576f35c33349212cc4f39f7ab26186dfce5b200f73451f7600dcb8cf27e7400c0b291914046c9e0718fde81371b8e7273f4ef4007691919240e714097f31f376e7b5008caee27807b0f5a02c8e1b3c6d27d33cd0201d839523144d1a149ae084b78da47638211771fd050d582c3a0faab5119b6d12f8ab1c06788a0fd4e2ac356fd1fe08754ddccaba849696309e598c9e2103fed1dcfdeadc44fea5ff00a7f956366d375e492403ca935bedcf1eea4ff6ac68a55efc1beb3b552574f8e7009ff933a927ec715bc82b3a8f4d6bba5ca1352d22fe061cf9a0383f71dea5119cc6c0baed3eaac0f1fad40897dcc3d81f7a052366c1007df3400f21edefc5008c28f30c9c5170ee4fc37830086395250a7c66770c18e78da31c0c63de8609b41f7c515c5172a30c3b76344a3e377cb2339cf7a242aea89808cce368272b8c1a2e107c672a49f5c1a181c9c7ae7da8a2119e7b1f5068099ffa68258a132062d8f9e0f34059502b61bf2824e681bb297ced2a71efda80f19c47b9c77fdbe74057c13e539cf3c1a0eeeb9c73f33405ddb4f18249c1e28062b79ae242902024465b9214614649e7bd0362a7249eddc513456e5720f38f5a1a98e96e95d6baa6ebc2d1ad1e65521649bb469f563534d6d7d31f04347d2a2fc5f535db6a0e83718906c887cbbe5a9a8bef44dce9f731ca9a2e89169d6d6f2184b1455dc07b11dcfeb4d16f119c649a681285b03d3e5500f87820ff006a0e098191de80ac9b8904647b55d11da9681a56a31f87a869f6970b8ffe4883629a289aefc16e92d441682da5b098f21ed9f033f353914d19b751fc08d66cc16d12fe2bf45ec92ff0df1fdbfb559ec667aff4eeb1a04db359d3ae6d40eccebe53f46ec7f5ab82263da7dcf3eb5174e5181076918c7de869503232491ee4515c1803824f03b51287f30e0e7d803449494832c157278a2e8c71fcb9f9d144639236824d01e142efb1768cfb9c7ef40512a818de78ff00a682518e7cc30ab9e00a02cce9953247bd41e467191ed9a04205ee99da4e4e3d283a524b0427b5026c18a8e082067db8341ce0e39ed409b6502907391edda80f2dfdc496f0c124ac6184b144cf0a4e338fd2894f7a7342d4ba9b568f4fd261f12571966270a8bfd47d8511bae85f02b47b7fc34bac5d5c5dc88a0c90ab6c8d9bedce3ef4d1ad691a6dae976a96d616d15b409f9638d70054a1dbc68ea51d4329f4619a8022b78e04548515117b05000a035c5c4702a995c26e3819f534047bcb68a458cce866719540724d02e41c0f7a012a40f6141cbc8e7bd01719e38e6838af1c0a04ca8206d3cd037bdb082fad9e0bd8a39e0718649141047d0d5d18f759fc0cd3af164b8e9999acae4e4f81236e898f7c0f55fed574615aee83a96817ef67abda3db4ebdb7f66f983d88a061bb8db9e3d45165076db83c1f950a53780d8247c80a2398f182724f1c7ad080c608cfa7a51a0062adc7afbd0130173bb9c5070f071cb37e82826106e8f615e01c9e680d6b35bc534be3c1e3831b2aa962bb188f2b71df1de819ae4b1048c7f57bd01a58268e332642ae0704f7cf6207af6a01b99e17b7b6416e227407c494139909ed9f4c0a04a4e501e0f1eb40d263e53dce7fa682c9d0bd13abf58dd6db18bc2b157c4975270ab8ef8f563f21447a73a03a1f4de8eb031582b497328066b97fcd21ff038edfde88b7e32703bd64188e7e6283864b73400cd804b67ca3268317eacea6d56ff005233592f8b6303f953fa4af7c2fa93417fe98b763e0ea171297bab98558068f695ce0e08fdbd281e5c6a57ba5e9d14d716ef7774f2ec112601da4f27ec2827ada74bab559a20e148fcae36b0f91140283729c77a0e0a7777a01dac68395719e39a029607cb901b19c501480ab9279f4a086ea8d0b48d76c0586b7143224a76c61ce1831fe93e86b43cd1f12fe19ea7d2533dcdbeebcd20b612651e68f9ece3fcf6fa5067cbcf20ff009a051724905411e94032799060723da8406d6c67e7ea68d0e1770fe5cfb5026c37039ef9a02eca098c91e6e01e71c500b1d8a49c12786cf6a06a4e256008e3d050119958007920e2801154e32fb4120927b014017eb1c523ac5209a356215c291b87be28957ef853f0d66eaa99352d515e1d190f947669ce7b0ffa7e74a8f4be996569a5d9c56b6704705b46bb5238d42851f2ac875712bc70b3c30f892019540704d01ad2669a0491936330c95ce7140b2e4939a03638c7e8680ae485e33bbe540d60d3ada162c90a02c7270a39340a4f28b68da4645007a8f6a069a746f73235ddcefc391e12b2e1916824948742c99382473c73404791c617695279dc0640f9502c578c9efeb4095cb4cb0830ba21cf999c6401f4f5a05061d430c8079a02e03b3004311c7d281b5e3cd676c65489ee594e4aafe6c7ae07a9a0a075bbea3a8ea96f047d3935ebc404f04ad29411e08e011d98fed416fd212ee5b05b4d5ad6300c615807f1171eaa49eff5ad418c7c55f8466dd66d57a521f20cbcd66a7247a9283dbe5418a63862479877cf1f6c5008e400bdf1ce684016fe53dfbd1a73794600e08ce3d6800377c8c7d6800a9cf75fd4503d91492460f7ee3d28247a7b459f5fd592d22711c206f9e563858a31f99cfd050583518ba75247b1d134f9aed21396d4669769931dc01c003f7a329c4d17458ac5b55d36c12e040a3f1da75c1cb04ede2447f7f6a94567ad7a66db4fbbb29ba7d65b8b4bd8ccd09c8231eaa07b8ab04a7c2cf87b3f53ea8d77abc72c1a5dabe2452bb5a561fc83e5ee7e541e988218ed2dd22b7855228d76a46a00000ec00a510bd4dd511f4fe84da95cc31f880022da4902b1e7d3e99ac86fd03d631f565b4ee6d4dbbc649009cab2e48c83f514165b8b94b6895c44f279c280839e78ce28178ae6de46748a789e453865570483ec6812d42e85a421fc37918b00a883924d024c6e99b7a2a966c0009e17dc9f9fed40f81c77e28139218e4ff9815b9cf23340a01c907b9140201038ed402fcafd28386464e4fd33c50272bc60032609cf00fbd024f722dc66f24822ddf972f8feff00e280f69b24844919cac9ce7de83a447f30ded823007b50459d6ecacb528349b979127651b1dc795f1f3f7a0990148054823dc5015d491c0a0c3be337c2ff00c489b5ee9c87172016b9b541c49ff5a8f7f71eb560c1fc43e0a47e1aa94277310431f91fa551c1727f29ed409b641c86e31839a3454805739c1f6a026f1fd740f64665fc8c31cfde82db79bb40e9e8f49b62eb7d7e8b717ec832c91ff247fa1dc7df2281bcc9369d671493c422b7911654c1215f92bb8827bf068624ba635392df5eb4b9924558ee5bc19b71cee43c6dc7cf34c657be8db0b0b9d0f51d2afe668934dbf9628ddb8c2b8c0073f3a80da37546a7d25174fd95dc125c69f7313ee5655dfc313bd483cf07b1f6a68d5b48d5ec758b612e9d7293211c8fe653f35ee2a084eb9e8bb1eafb3582fe496278f3e1c919fcb9f97ad03ee8dd017a6741b6d3229dae161057c5750a48249ec3eb4139238568f6a9e7b103b5037934cb3793c610a2cd9277a8da73f5140ee38f6280c4b11c65b934023006d50050030e4647de80c846de3b500fcf9fbd0197273ed4007b91400e580c8e45074a82400e72682b36fd2162b7f25ddc09af2766ceeb872db79cf00f6a0b3229550140e07007a50092db860673de818df473c862686dad6470d9cce3b7b63e740fa1de6252ebb5bd81cd00bee2d800d003a6464004763ce683ce9f1cbe1f1d3a67ea1d1a30b68edffba814708c7f9c63d0fafceaca31e6dc71e1f07daa82608c83819f7a1a11ce149238fd68d0a579ec682cfd27a7c3a86bd10bc38b3b756b8b93c1fe1a8c91f7381f7a034f752ea5aa5c5eb292f732128037619c018f6ec282e5a2cb047abda74d5ce9b6da80f136de4a496219b3e48c92000323ea73467519d3da5bb757dbda410ac90c77c23058f99007ee7ec31416882ee47d23acb5185caf8bab4691b1efe57fff0038a9457ee75a82f6e7429350466b482f2742c0f74241c80c38c64541a9cfa1e89ac0177d33ab3d8de28f2b5bca429f91140e2c7a9b5ae9fb85b6ea9b46b9b3c796fe040768f76ec0fafb1f9505df4ebdb3d4edd6e74db98ee216fe68ce47d280648f75e2485a44da385ddc13f4a025ddbdbea16a633286566ce55f9c8f6c502ad750db2c514f30dec428247e6340bbf04100b73402afb943ed2b9e30683836defe9403bc1e06734020e06280cafe8683a375941d841c77c1a0151b467b50159f00e4127e5402872371040c5046eb5aadbe9b1c02e2f6dad25b89047099c677b7b0140fe3f1010afc803f3018e68160c3041ee2823f5dba92d34db89a1d9e2843b03b6d05bd013560c1748d57aa2797c6b35bab78e6959dc47231580ff336dcfb03c1a58364b5bbb7d7fa7b7427f1f673830c8664285bd1815238fad20f2c7c41e979ba43aa2e2c1cb1b663bede438f3a13c7dc76fb5515e9065b851f7a02950002a09c51a1b83cf14176e90d3645e9ad7752752aac23b3439c066665c827e944d29a6410aea725c4567135bd840d3c88a723728c29c9efe6c50d3ee9545b0bf8ef2e6e3c2fc2c6f72f2920e5f19039ee4938a9a875d03278377acf52ddf867f036ef71923932bfe51fbd3475cdc369df0db4fb389d4ea37970fa9cc0b00511795ce7d4f181eb4cd2451755fc45ac16d637381b14ca36b641dfce723e4053170d6cb52bbb362f6d3cb19241f2b9029862f09f143549ba7e7d2eef6caf2797c66ee17fdfd69862d1a069da7dfdac579d17adcda5ea9e1a992376c4723e39e3b024fd7e94c458ac3e25dee8d31d3bae74e7b79002bf8b8549471db38f5f4ed4c165e943a06a328d4ba605b4b22a1523c420c64fbaf38a82d36f0ce7cf7463790729b53017e940e0b0ceceed8ce0500e1b70daa08f5c9ed41d271cd0132476e7d7ff00aa069797d2411168ed9a41fcc858211f73c5075acb25ca6fb82aa31e58a36c81f561dcd033d42169e158ac64b98151b3981c2966cf639f4a064c7a8ac55e4865b7d493701e1c8e52403ea3cbfda827e390ca3f2c914aa81991bd281cdacc2747215c60e0ee5c67e940cb51b0b2bcbd824bfb08ee1a252d1caea1821cfa67b1fa504982b2283ce08f518a08abb82f6dd0369a5662081e14ce40c7ae1b04fda82275cb0bfd4f4536f7114589a5412461f3e4ce4e0e060f63f6ab2893d3b4b5b5b78e22ed22aae3cc3cc7e64fad3449a22a461500007602a0cd7e3b74c26b5d2ad79147baf34eccca40e4a7f30ff3f6aba3cd0543267eb5427b86f1f4c76ef45d0eca1ad5ef224d13e1cf4fd9b22192fa67bc955f8c8c617fba9fb510d7a6ed3fd43a735e5b54964be658c048fb6cdd9e7eb8a186bac97d174e6d22e23437b7ac26b95e77c68bf950fa7279e2b22dba45b59e97a669fa4ea36aeff89cea9a90451fc355ff0096ad9f4ce3f41570675d4fa8c77da8de5cde5be26bc653171ca47dc1f6c9fed5562b97f70276808da7c24f0c1c63804e33fa8a2928c0e0383c8f7ed41d92a41393f4a2548595c2c37493db4cd04e8a08f139566edfef3445b6e7aeaf65d2df48ea2b11776ae02a93e564c772adef409f4ee8ba9a21d73a36fa579ad9f325afe599171ed9c30a960d5ba0fe2843abb47a6f510fc26a4c36890f9558fcc6783506a1147b510024e30339ce680d2c6ae9861eb9a009178a0205443b989e39cd01d8075e3047ce80563057ca381ed4011c4531e503d85013c91b804a21279c903341131cda8c3abdc8650f6d20c4321232adec3dc504bab2c113c9293bb1963df3408dd4b75e1efb2856463dbc43b4631fad047e9177ad4fe32ea16b1db4b8fe1aa92571f5f5a0916bc8e0895af5c46c17cd8c9ff7da80f6d736f7f6915c59cab35bc837238ed8a072a31c1ef4062870718a06f7702dc5b3c522ee4752ae0fa8230683c75d6ba3b74ef535fe984929149e4278ca9e47edfdab42058003763ed409f88ffd6dfad06b1f12ae612fa0c76e0b471e9916d23f973eb4158d3efeff004a984da5debc1295d8e4018dbf3145d583a2ad96f356bbd7f5d90dc59587f1e79a6392f28fcaa3ee47159444ea3aa5ddfc7acf50dcdc344d7a4dbc317f52641200f6000fdeb41b5ef51d8eab672ffa9e971c97c11638268e431a46000012a3b9a351567db823b11f3ef40948e428048207a8340ab48ae83cb83ee0f3428a982719edf3e68c9cc97d3fe15ad8c9be138f2bf38e7b8f6ef40f7a5f55bdd3f56b46d3649127f1405f08e7249c76f5fa50689d48ba5f545cdcbdb462cba9206411b2b055bb07d4fb1c73528d4fa8f52d62cf47b6b8d2e65fc458c49f8a818795c151939f977a823ba0fe253750eb7fe937b04293f9f6c90be41dbdc7ff006283473c1efc1a06f69776d73bbf0f2aca32572bc80470450284a46dfca19f819f5a04e799614def26c0bdce09cfd85045dc75769d12dc3c3e2491db0dd3c85195235f7c91cfd066ae0cdba9be31f4ec61a386c1ef9d4ee473e45cfb1cf34c101d3ff1ac9d481d46c628ed24751881880833f988e7b0fa5328dfed2f2def2ce2b9b79925b791772ca87208f7a60182ee2b95cc0c48f53823fbd40ac658b30f4f4a086d4ee1d75bb6b78f4e965596366fc5211b23238008fde81f43692da5bc30d97831a0397dc09e3d714087506bf61a2c4cd77324726d2caaec141f9fd2ae0c435bf8c57173ad7876f7a2daca10489121244cdf319ce3dbf5a834fe81f881a6f57bcb6ba7c53c72c11873e28cee1db391dbef4199ff00ea4348116a5a66a8a8a04aad04847a90723f6ad7d18c312ddc02a3815423ba0f63fa541687bd9efe1b533b3c9e0a78473e899e318a09bd0ba6eef543e3b2bd8e9b10064bd9e4da001dc81401aeeb29a984d0ba7d5e1d06d4e6594f06523bc8e7f5c0ac8af752dfc17d7090d9218ec6d9447129ee71fcc4fb9cd6842ab10dc0014f3e5a2c1704b671dfdc734525226dc939e283a362c7f940344a380393df144733e2276e38f5efcd01b4bbbfc3dda4a9298a44395902e4a9c70682660d4265d62de40b1bdc1545054f95c8fe627df141af7c3af8808f3dd68dd5d2a45765884b8908d8c3b6c27b7a77a945d7a5fa474bd2ba8e4d5748b28624955d5d8b13b79ee9e983d8d40a753758c7a46b96f6114725dc92279a2810b3a64f94900763cfafa503fd3b59b79ed84da34713c0cd890f0a158fa1f981de826e1b548959fc4dc5cee24b6467e59ed4101ff19e9f676baa5d6a72c50adb4ad1ac790ccc076200f7ad41e7df881d79a87576a5f87b0f161d381db1c2a36e7e6d8ff3416bf87ff082c6f208ef7a82f22b9761bd6d619785f6dc477fa53705ab57f83bd297ceb1e9caf67708db9c4526723e849e3e94f212dd25d117fd29a8c09a76b534fa39cf8b6b71ced38e36fb73417f52e64548e34007e673e9f21ef590a1c918c90718dc281a69b68f67118d9da5058b798f6fa7fe280daadd1b2d36eae70710c4d263df0a4d583cc7a668fd4bf11b5837d7c93dcd9a3146959822a0e781f4cfa55161e9dd7fa67a4f55b9e9aea3e9f81fc09ca0ba118998fcdb2338c7b528d39f4cd2ba76e2d357d292df4eb391809963420ce1b1b576fa1e7359119f1eb4e17dd033ca172d6b2a4df303383fdeb5c8f2eef3bce4e0e335684cb0c9f354160d36f64b0baf16072b91b5f03391f43c51aab23a5debe91c4fad4d73689e6fc3a290573ff4f03e59f4a3280d67581ce916567f84b58ce0a1fccec3d58fa9a084de08c90464e4d1a8e419059b201f4a05630a176918efc50176293872c17bf14042aa0125b03db14046c60b60123fde6827fa0c68edd5365ff11346ba6292ee64194240c807e59a32b7fc51bfe8bd5ed5db424860beb62b89218422ce09c11c01dbbd0660ae110bf1bf2154838dbebfefeb41a8f4cdac7f117458f4d9ecd2df53b4cf81a822808c47255c0f7c8e7fb54a2ec2cfabba3b4b4b8d3af12eedad40926b0f070a13f9b633649f7a82eba6ea4357d321d4ecad512daf20df26e016507fa4fbfaf3e98f9d067dd2bd2faac9aa4d72d72d1e9510ca46a7631c7a320e18f1dfd7bd059afb7da816d23de4ba5de211346a1e4785f190548e4648c63b64e6b43ce9d5baafe3b539c5b452dbda46c638a167cb281c73ee4ff9340e3a3fa5f5aea4ba58f4bb57dbfcf2b02a8bf7f7a0de3a5fa0b50d2a2d92eb3e048c0a97c867dbedcf6a944e5cf4f6b76d1b3d8ea42795066266c87c81c65b9cfaf15048e83af3cd64abac08edaf01546c38dae4e0657ee6826e5b892de3702292e2545ddb55700fd0fbfca81c4b3bc718716eef9eeaa402280d14ab3c0b2c65c06fe571823ed40df56b217fa6dd5ab9216689a33f2c8c558307e83b8d77a37aaa7d22f2512c28768800c9954671b3d33ebef568d0ef7a7749eb0b5bbbb162d657b32b46d2e1564c8ed9c5644d1b0b9bbd261d2a440af6cb0e2e5b1e7dbc1238e0f7a0375b696daa7496a3a4dac8a92cf078685b271db04d391e40d5ec4586a1716de2a49e0c8c85d3b120f715ba1899173ff305413070abd89cfe9f5a2d3ee9c8639fa874eb6b804c52dc46b20c9f302c3bd11e84d47e1af4d5dc6521d3e3b662c19a58721ff5a9a321f89bd27a374b456d158dccd34d333332c9b4b2afbe47a7cb1f7aa33d2bc0d8c0f1c8f6a2c14b6d501b39cf63450897380c319e3de8065031c038f7ed40d8faf1ce41e4d004876a8dc3cc7e743025c956c818028c904579e7f0e15695c9c0541924f6c00283d0bf07f42d6b48820b8d62d20b2b58d656404959e52f83c8ff00fcfafbd4a35bb06f12391a48dd55cee2b2f3818ed8f6a8158a159890f02242079147623e631c502b0db436d1ecb7458d4738038fb0a087d6eeb508f48bb7d32d95750752b6c26c905b3ddb6f61eb574794f5cb6b9d0fa9678b512b25d24bbe52b8c1638278fbd582c57ff12afaed45b5bc0d0d8a8c08a2731ee3eec5793f40450466a1d59af446293c186cd53ca0c36eab93dc649e49fbd048e89f1675ed35e301e293919dcbf9867b37cbe94a35fe94ea4d33aba6824306dc48015750d86c6e247b0cf63591a40b8dc23fc30f14138dcac3000f9d03687547f12e8dd5af816b13148dddbcd29039c0f6f6f7a0eb5d62caf5636825db70c9bc4328f0dc0271c8a090627d3073ce681acf6505ccf14d35bc2f2c2731bb28254fb8a075144a83ca806792400334049ee6281e2496408656d880ff0031f61fa50446bd76058ea1b9e21025a3bb48afe71df9c7b71de9c8f196a0de23ca7b827d4f7add117e0cbfd4b5059392369663ff004e71c51aa97e8f555eadd258f2bf8a889cff00dc28cbd0bf123a926e96d163bdb74490bca2321c678209ff001591e71eafd7a7d7ef45cde2c20aae144638033fb9ad2e1b5e69d058da431ccf21d4a5c3b4631b62523807feaf5c7a50222f2d648c25f5aeec8c2cd19dae3d3e87e944d3eb7e90d425b49ef2292de38224f1505c3f8724a9eeaa7bd0d57a60406059436306868a7803839c7ad1a158039c13f4a33a716767f8cb9b6b55e1ae2458813e9938cd07a9f42d0b4de99b4b7d1f41b58ff19b03c93ba06607fa8b1f5f619a5b8266d74a65d42da6ba90cce996dcdc8c9fff006a5a2c2635083b05ef83eb5028076341db4b1ed9f7a04651fc41db18ed419d75b744dbea335fcb0db0335f2057901c05da73c8f9d5d18a75174a3f4c47335e35da4ce418a489374254f707d463d33565d1529b569a489a17944b06ec8057d71dcd037b4b6b8bfba31584124b27e62a8a4f1ea68357f83da7ea5a76bfe0912453ccabb49194653cb60f6ce3dfda983d196cd108c2401711f9768e306b2297d73fc6d02773a8b591922693c5004bb9d72542fa2f6efde8314ff867aeeec27500b77bb5670e36ca19b1dff2e7f2fd2837ce8bd5dd348b78b552219022870d9c46e792a4f6c608a0b846c8e03232b29ec41cd0199f1410fd4b24b1e8f712c0a5e4452d851e6c639dbf3238a0afa42ba77475e4ba8470896681da45180b18da76af3c9029c8f26dc1df2b9c606e273e86b743331924f27f4a82c12280e59b008e79f6a2d4d74188ff00e30d203a82ad7519c1ff00b860d11ba7c5e86c9fa3afae6f4091e043e021270b21e01c7dcd6479ab4dd3aeb56be4b7b184cf2b301b57d07bfd2b4bad0fe25e9f6960ba7c7a55ac50cd750335ccaade7723b83b8f6e38a2207a5ba4e7ea3d93780cb616ca53781f99fbff009a0b675a5be9765d43a75a6ad3b25adb4185429b831c70303dfdfd2831eb8954ca48f3827819c71ed406b2b1b9bf9a5fc1c4ce2253238047957dc9345d122b792eee522811a495ce1157b93ed444ff0049f476b1aaf51c761345269d25be269259570c833c6077249e062a68f53e8ef0da69509d4ae225b92a04af232ab16f98cf1f4a5a266d4dbca8af13a329ecca723f51502d14f0cb9f05d1c8ee01c91f6a0393b4edfe63c8a031608859b38f97340d84d04e5846eae50f9829ce3eb400fb24466041f5e3d2823f56d22db57b192d6e61468a41c823ff0035651916bbf04ada7badda5cad6d1b72c09dc33f2a6875d25f0865d06fe2bc6d4c4d3282026cca8cfafcfd29a34cd234a10c768f711a78f1bb392a3001208e3ec69a26a58d640c832091c90706a084ea1d3eeafdadf4f86da3166c0b4b397c18f046140f5ce4d04f4702436e91c28a9122e028ed8a0a9f5a5b6a09a1bc5a135bc72cce048b3c5bc15c638f9d59043fc2db997481aa69dae49e1cb6bb643239211939e467818f97bd305965ebce9a10bc8da9dbaa2679dd9ce3d8530572cfac87566ab05ae9f1490692b9696e1f833738555f96793504df5f25945d2576b7ec16dc46792381c7b7ad5e60f234980e42f6c9c56a82ec3eff00bd4124e49700f1c646e3cd169ce9575f83d52cee324347323f6e3861ff008a23d47d4ba6a75074fdcd8ef317e2e2ff0098bdd4706a60c3f4ae8cd5f44eb8fc3e97248a638cbc73bf90483d463b373e9574685abf42a6b5649fea72bbdeac4a8d3b018cfae31f7a6895b6b29b41d30d8e9f6bbed9213e1b7a994e724fcbb5064bd7835a9752d3af75d8116354778f660788cbd9483dbb0a0cd20b2b8d43528ad2088bdcccf854039cff00e2827a0d34e9da1de896f2182492efc0976f998aa827d3d334113a74aa9a9298628e74570478bc0c7cf1da83724bb8246d3e6416b0384da61b5501c9f5c3704f152c037561a95f5fce61d3ad6db4ab950f34b331dd9f4191db8fdcd406d67a675ab4b6d325d1af248272a43430315ddec7038f6ad4b3f448bf47eb71cb69abddebf21d5e26896203846c30c8603b9c6452d9835901405660376319ac84bf13180779d8bb82827d4fb0a06f777367a75acd7170f1430a9f331200cfceae061a0cf6dac692d7365266191db0578f5edf3a6075a6c9278b3433188a467860d96fbd40fe540471409aa0c1140750001ed8ed4058e15133c983960077edf6a06faade5c5b7822d2d926766cb967da2341dd8f0727d85033d27597d62e2ee3163756915bbf8799d71e2f19dcbf2a092b88dd9a311950a0e5b70ce47fe6ac18af53f5b69da9752dd69da9ca906876e24465d9e69881c6ff005c679c0aa2bfd267a347512c93dbb5d42d90d3c800b68c9ce0ec3cfa528db74ad034db5905ee8be1ac728dc153984f3f980f4fb56453be2de8f647a6aff53796596f0aed46798ec033ce149c0fb0ad71479c9bb9dc3bf3c55a0b95f65a825150b481a407b93c0fda8a29c06671dc93803bd131eafd0af6dffe18d2ee25982a4b04603b7a9c631fad03bbe586381bc5945b96385718c827db3eb5288eb8ba934eb15fc3c535f05427796dcccdec7150637d5bd55d5362b7975aa4d0d919018adec8637807bb60723000e4f7cd58203538aefa8aeb478a7b9beba924547b8774cf8608036a80704639cf1f9855d1a7f4c68b67a03de5e5d59dad8d988c62e1c0f107a1e7fdf7a082ea6d07a6e3e99375a7cb6b3db093c727701e2360f7f53dfb50653d4130d42ee18f48b3f0232a15218936963ebf5fbd06dbf0cfa74855b9d46e04b730c6144691e12307d33ea7de8348ba6b5478a279a004f98c479247b81f5a9438805ac0be2e02e73c9ef8fbd40c2346d43578eefc40da7da1dc8b8eefea4fcb9fef419beabf12a4bcebcb2d2fa7ee0dc58492084b30236bb6467dce383f6a0b87556a67a7f4d95a0bbb5468816f0a69c78b2e072572719ce78357079dfab3af2e7a92c963b88d94abbbf91cedc93edf418aa2c5f0dbe2a6a9a0c90d8de34773a6a8da1186d6403fa48fec682d9adeb7a9b4c9d572dacc9a6c9700456e5ca910e000ecbd8e580352fb1ae7476bd6dd49a325e5a9f3025245fe961dea097523cc0919a032af039a006936c81423104649c703ef40dcce64bc3035a87b6f0c378f9fe7cf2b8fdf340a4b6e25962915d94a67807839f7a043586922b5636ec44c061063f31f6ab079d7fe19b7eb2d4efeef55d5d74f992e9a0fc3a441dcb13927b838c9aa2d4bf042c618e178efee6e18104870172318edf5c1e6945bbe1a748ea7d2315edbea3a99bcb190030c401010e4e783ee0fa56455be3d6b90c1a6268d69e17f1486900ee98ec29ccc183119419e7e55ba11f089f523ef5058363a8059fb8e31e9421b491056c01819e28d3d0ff07eea3d53a1e3b6b8db235aca63c139c0eea68ca47a9fa6ef757b83ff00bf68ad428c2f248c7a8f9fcea518df516adac74e7544f63a2ea172f1800291e6cee19ec78cd5826344e85b6bad25ba8fade5b99dae0ee11efc71e858f7e7d054a2d7d39a75ae8f7b6b00b8917f1516624b78429da327cec493db1db1d8540cf4aea28f58d6aeae2f6dd64b498082d880488d149fcea7d4939ab04175e6850a8d32de3b78e380c8de32c4db4e18e430fef543cf86fd0d691b4fabdf6648b3b2db69ce7dd87be68342d2f4fb9b5b891af1a28a2dc05bc5036d001e0eef7352884b961a2ea9aa7555c885e08d45b5bc52b61b686c120fb939fb541276bd4b61d53624d942e2f6200bc32290633e99f4233416dd3ad3f0d611c0c77b632e71dc9ef41156dd27a45addcb3dbd9c513b1dd941821bdc7b558333b9f873757fd69a85e3f813e9c7723b5d93265d872473c11544a68ff08fa75e290b42ec4e4124e70738fa5048e89f0f745d2aeadd2decedda6525c975121183c77f7a945c754d0e0d563682ed43425369403bff00bcd58308ba7d5fe13f5a05889974a9d8b46aede4914f707d88ff001528ddf4fd7edb54d1a1d56c312dab2e64dbc9418e78f5c541296d70b716d1cd6f8789977230ecc280cb7519b816f212b205de4e0843ce300f6cfcb39a0545c42cee88e0b458ddec33ee680eac92266360debc7b5056fad2d354b9b189745744be121daf27e550548ce3d4d58324d07a725e98ea2b7ff5381f5169a7579d021fe13904ee43ddfbe49038ab46e76cf05cc714f6d309232a4a98ce54fd6b2196bb7f2e9b631b2c427b891b6851db3eff002007341e5bf887aa2ea3d4f77378be381e42fdb711ed5a1554395caf1cd07617dcd04fc85402101da791421b49920331381c60d1a69bf02f56f03a925b12c162b98c955f775e47df19a32d99b518268e4491668704a79d4aeec7b7bd4a30feb7e9144d76e265697c3e2693631674273803e556087d76f35fd49859e9925ccf611141106f2e182e3241f727f5a94681a268f79ad1b1b8b9dd66b1c2b1ce9bb06361c1e7bf3fe6a096b0d3ba57488e485b52b40909c386901607d47bf7a0ae758eb69ac4d15be81a748f0a9c35cc90b2eff4c03c1c638a0b77405c5d5d45f87be5fe359a88b81b401dc1c7d38fb50586fed18ea3015790091591e447c1518c8c7a0a0a5754d8c9d49a8d9f4ee9dba0b3b5224b9692327728f627e7c6682f9a7e996b6b3a8b6b748a348820c7720761412c064e3041ce282b5d4bd73d3bd3f33daea97ac2e540dd0a292dc8cd043c1f15ba2a7923b65bb910371b9a12141f9d02edf13ba2ade56857551e5e77244c54fd0e280746ebfe99bbbd655d56dcdc9ce08465565f4ee3bfca82d53eb3a6dac3e25c5f5ba646402e33fa77a0aff5b74ad8757e9ca972844aa37c520fcca7d3f5ab067bd369a8f467544d626c98e9f7118f0200e4465c903049c8c9e6ad1b24334b6fa6249716cab20037c309dd83db03b5640dddac3764a4f02cb1103863919fa7a1a06d6f600c37162911b7b252b87dc773f1927393f4a079f868edae1ae6328a8b1ed38e30050226e85d5dc1f879011b3c47c2f604719f9d01eff4f4b83e3c6b18bb452b1cac9b8a83de80b16e8208a3b7b58e1407cc061427cc0ff1560ce7a8f592d69a97504cad2dac01a2b53900c3e9e51ea58f727d0551e73bfb86b99a49a46dcf21c96340dc13804f20f6f9501c0e3b8a0963316fcc4607007f57bd084d64dec01200ce483468ff0040d525d1755b4d4206ff0095207c11dc67ff0019a18f56584f6daad9dade4211e39104a8ded9152b235cd8c530613229c8c1c8ef50472e81690ee00322b0c100f0debdbb7ca8111ace856371358cba85aa5cc407891ccf83f2ef4048b4ad2e59bf116769672c72f99dd1437239078e2824a4d3e1b94559234110e781839fa0a0561b38ad532a12319c86c6307e740a9732a3a00cac870cd8e0faf0681be8b6db965bb909df3c85806eeabced5a09523647e6e0fef419a6adf116daf7ac34be9dd1da686e7f1ca2e243b76320ce57df9ff1560cc3e3f470ff00c78255b842b35bc6c4af9b6e323d3e95467b6365f8dbcf062beb68c119595d8aaff6e282422e9899b4f6bb5d46cda2562a76316c1078f4a0859e1b9b762c0bf94f0e84feb4125a57505c58ea70dd5d0174a986d92b1c13f6f5a0de7a5be366877260b5d42dee2d2423124a487507ebdf15289dd3fac7a7bab6feded74d61733473acdb5a162142ff00313d81ed505fa58fc6d809380c1b9f5c502e0e05040ea367a85dea454de2ff00a610375b04c16c7a16ef8340b5f6930dce9375636acf6a278f04c5dd4f1dbf4a084e91d06f3a52dee62bbd4a2b882494ced3c8a448063b63b638fde803ab7ae749b2b3096d792c93c8c109b55dcd18ce3710473ffdd043dc758dc5869044565aa5dda4c3c2b7bc78c1f14e3963db03e7c0ab066bf1327d41ba76ca6bc48ecad24c456f6b0c87cf8e4bbfa138c0fa9aa3297c83dd4e28395811cf2680a5b93c7ed413cd1ff0f3c797b8031406645236b0508406f30e68ba49c051b97d0e0e7d28ad57e19f575c5be8f269515dac772877c11bc464dea7ba8c739ce78f9d3193bb8ebfea2bcbd6b5b6b8b58bb7f13c2f0ce31cf0deb4c0f2dbad6d743d2ee99efae752d6c02a86e0054524f6383c7ff94c0b6af274c75149a46a5a82c46f1e1479fc3190bd8156fbe7f4a960bf74e9d253f1167a3ac09e0856610e3041ec7f6c540f67b892cee7f8d18368232ef2af2508c7047cf340ead5bf130accc9b1186541e723d09ffc5033bbb1b82d74d6b37f1244daa1b38073df3f4a08eeb1d3b50d4fa6a5b4d32f12cef1902ee73e523d476fde8306eb0d3fabfa4ba92c278af67bb7281606472f90bdd58558253a6afb40ea1d62283a8b461a66a6f931cf6a7c2466f7cfb939e7b5515fbed3747b5eb8f06eb78d35080a2ec9719c76f98049a0b4ebdd37d1bad869acbf0b03c5c16b29444adf50ded41995f68564a263a66b31cd02be152505493f51c1a088bab69ad1bc179e320f07c37c8a0692b46c4995f0381db39a0b2fc34e971d57d4705bc8db6c50ef9dd97b81fcbf7381528f5ae97a1d8e996d1db69b0c7648855b10a81b80f43c739c54134147b9a036063279fb5046e957726a0f2cfe04915b06db1788305ffeac7a0a00d72f8d9c491c06337533050ac7185cf2df6a06da2da4293488f34973328c34aea428c9ec3eded40ee7d2ad249448f6b133820ee2833df3fde819ea96897461b05b87815f2ee919e5d47704fa039ab079b3e326b70eafd4ef6d6650d8e9ebf868b69c8247723efebf2aa280eb9193ebedc5002a124e015340018fb8fde82cf32b1603d0678cd02406dce3008e47ce81b499c331383c9c9f5a2e9c69377369f7d6f796a4acf148acb83fb511e91b3b3d0bab745b7d45acedd8e3732b71b1fd73f7a5a19eafd09a56a0a96b1c705b49c48510761ce4fcfbd4d0d752826b2b583476fc3daacb295b79d768de8a32b1e71f989e49f6a7d14dd1af5ba275a45b8b093c054492ea769092373765c1da4679fbd306e36ba9595fe9f0dcdbcc92c33e1579cf27d0d409ea178f68521b6b76926ee8a7853f7ff140bc768d78f6f73748d1cd103b543f0091cf6efc502f7319dac194371d8b6326829f0c501d7ae6fa568d5d4942c806d4db81839f53c8cd59456fae6e628749b5bab8b1865b08e4726588ec11e7f2e49071c93da9a31dd4341d675e9a5bad374f9858162d0b4ac70e18f0573df35a0c759f87bd53a404f174f965dfff00f479b1ef570576e34bd4b4cc0bdb3b9b7258a00e846e3f2a94376475cee4914af7ca9150685f09ba61efb52fc7dd69bf8eb7c158d1d0b47bb38f37efde968d6eeb4eb5e91d6ad25b660aee59974db6881690918e31ce39279e062a5a34bb57b88adedd1e379679065d80036679e6a07e8391bce7e940c659ef5afe1286de3b16f2b8903094b7b2fa7ce81eb380c4260ed193f2a0cd6fa5d4a4ea0fc7bdadcce923158a3039db83c038e3ef41a0e96b2ad8a35e009291b8a939d9f227e43bd590436bbd6fa269202c974b7123602c76e779624e00e29833bf897d493e896525dbcb2a6b5a9c3e1456b91b6d60cf989c7f31f7a60c02490961ebcf3eb541308e39e067b507007b96007a67fb50178f97eb4165ce18165c2927b773fad023202d9c8dbb7818ff003408300b87f2f1c107d0d0c15a4f2e339c90467f6a18bdfc2cea8ff4bd561b4b9ba686d6e64552c4f954e7d7e46a60f4688d240af1b2bc6cbf5047ca960617ba658de1b792f2d94a5ab33461b18524633fa1a81b5c8b5168967369d23c0e0a24622dc981d81c76aba29df0bb48d660d52fceb88d069f04aeb69130037127f37b9c0ed9a8350781240bbc06da72323b1f7a0eb8816e633192ebc8c9472a78fa50349b4c83c068e24f0ddbcc1c13b837be4d055b57e98b996d4db5b4a893dc1e6620b6ccf2c467efc504ce97a38d3f4d874bf09af6d46e2f25cb82724e791db15650a43f878b51fc34f3da8f132b6d6a98c80a39ff007e99aba249631b58b9047239ec3e55368aeeb7d2da6f52c0eb7f16e87f2c6e836ba90724ab7a67b55d115ac7c3e8aed2182def4c56a14096368959a423d77e3229a27b41e9d8343b01069c8a8dc9660aa3713df3c64d4a1c695d3d6b67a8cba94b9b8d4e61869e4e4a8c636a7f4afcaa09a485519caae19b966f7a0435196582c656b74df3e308beec7b50629375775b691ac5bdb6b16d6378779f019b00a31cf391c9c2f1daae0b35ef52f5374de88d77aa45a6cd25ddc0108694ee2188c28007603d6a0d16c92430a4b2ed3230dc401855cfa0a0a07c45d7b5db9d462e9ee960b14b2ee134ef8c850012147ec78ab0670b643a2efae753d72686e6e2da211db42176079c8e768f65e39f7aa332d6f58bbd635096f6fe6692695b24f603d801e82823cb900ee00e68006460051dfd680ed9f0c905b713d8d006d5f5419fa505a18f94e40501b1b81a04186d62402c87be3d6810b81290aea8467201231cd1749dbc437f9f1e201db3de8ba07dc0175c027f28a335b17c26f888d6b6d0e8fabf892a29c453b1e547f49f7a946d6424f08236491c833ee0835073294888894120700f0280813c40a6711bc8843e00fca7d3ef40e41dc081f9a811681c6f7565329185623b7e9de812b3bcf11ff0b74563bd50494cf120071b97e5fda80d7577046c9019d5669dbc340324eec67fb734103d5da96bf67a7cf0e916f6e2765f25ddc4c11107ab1c8c647cce2816d3ec7f0f6564cae6e67da375e6d52cc4af2e4fb13ed4145f899d47b3499f4bb6d46cda49b69b92921565c3648e3dd40c81cd5c0ae89f13ec246d3e379ed2d6da180b5d34849da1780b128e49271c9f4a60ba685d5fa36bc42d95c324ec7090cc9b1d87b81ed50588958977cacaaa3b9341c655f12348d1dcb8dc1946540f99a019e2134454eeda7bed3839cd052fe2136b536b5d3563a1ca53c49da4b9507198940ce7e5c9fbe281c6b7a974cf4ee4ea7242d76dc784a3c595b3e9b464e3f6ad0ac745ccbd4fadcbabea42da56959a382ce7460d6b1a93c01f97272093ebf6a82f1ad6af0e9da5cb3cecf6902216919f82aa3818c7a9f4c530649a9f5269ba7429d472239bc991a1b0d3c3152880f0f23039e7bf3de90635ab6a377aa5ebdcdecef2c9239e59f3827e5ed54302195fcc38cd01245395c1f5f4a05b606538e483c501b6939e3b5077860f3914165754c33e549000dbe87de813b820c27fa7baafb8a04a69c98e281e42618c795338033df1f3a06c03e4e029247007ad010093c35674da71f977640340081a190658e41c820f141b0fc33f8926c218b4ed609366a02249bb2d19ce3ea4528dbece68eead926b7916689c643a9e0d643387521fea2f693c2d6efc786ee46d9bfed3eff2a04669edf5295ff057a60bd865309246d3bbbedc1efef41d63a8dec9ab4fa7dd4510fc3c69234ca186e2d9c003b7a67bd034bad0a5bb96e25d575267889cc1b54446d9bd0a37bfbfbd02925945a72cba8dddc48b3f87b1e58f23c623f292bdb7fa7cf38a0a5750f54ebba56a9a67fc516b6d6fd3970ea9234677c8dc7f38f6e4640ce282d1ac4b16bfa72c1d2bad430cd1ba822061865f5007d3daac19cf547c189357d561bbd3eee683c62cd786e9b73337b8c7bd512bd39f06adedec2de0d5ae639da372e6485363107f97767b505cee755d03a5e58ac228659af123184b7b733322e38c91dbf5a943ab3d52e64b49ee755d2e64950e238e35f10c884e17cbe87dc540e6d7509a4f110e9f7566a471712850abf6ce463e6280bacea36fd33a4497f773cf32c698dcc4beee33938edc7ad05534aea683ae61d64c4d2a69b6b88d16d5ca5c303f3e386cf61db140e27b5e99e96b64bdd562b6b30aa36c6c37cac7dc9eec6b42c1a66a962fa70beb6b516d0cbe76322f86c78f6c66831bf8b5d5d2dfa35a5dce60b1933b6ce3c788769f2b331ec1b8fd2831b79649984b239773c1dc68129725c1c640e73400ec781d8fb1a03c4a85d0c8582640257bd01e51fc42236263c9c67be280429c6037eb405dbf5fd682c2a0bb976cf07d3fc5009279ef8ec4e68193a9902b28e7dc71fb501d95b098e0f6dd9e0d0049131019b047b8390281bb292484e47c8500c4f242c3076bf704704739a0be7c3febfbae9a5daf23cd017c7e19fb107bb67d0f6fd6837cd2757d1fab34f4f05e37dde630b1c3a91edf4f7159103d6eb7da65fdbdf59dadb5e2460ac876ed9e1c8c060f9efe9c8a0a75cfc42d5742d2ee5a7e9dbb494b6d6b9bc930cce4f940e3cd81ed4160e98f88315e689fff0022b57664199cc5196f0c7a164ef8f98cd0589baffa68590985eb15c0db1985839f6c2919340b69d03f5285bdd6f4bf021424db4329cb153fccc3d09c76a090d3340d2f479a7bab3b38e2924e5e451cfd280d7dafe936f6c5e4bd89813b02a36589ce318a0358dc35cc4e17f9bf234cdbb78fa0c607a7340e6cec20b1596610c6934b8323226379edda81da8dcb9ec40a042f50b5bb21645473b58b11dbd7bfca8304f8add5d67a9ea8ba5d8ea72c1a4d8a952f10f2c920e368cf71e99fad5833dd0754d6ed66bdb2e9a91a5babb2a310465a57c1ddc1038e7bd5171d3748b8d46ee1ff005298dc6a764c27d4eeaee7fe1c01795881c9e7804fe940dbe287c4b6d75a1b1d1c986d62277c91bf131f4c0f6fad0663737135d3b497124924871f98e7803007d2811dc5b83903dc0a0333f03be7de8122df2c9a05a11e5f51f7a05ce7071804fca8033e5da0734020b0183bb23e5416269577ed0e5323078ceeefdff6a03dbcd62914c2f629a47c622689800879e4fbd046f9d8a2a03e31385c0e73da8b83ca590947dcaead8208e73da8849b3e19ce704f7c5015586d006431f5cf61f3a04ee586ff002481c8fe6191408f0011eb8e30682774dea9bbb5784492ca6385832e1ca95e3d2834be9df8c312e2db5eb4375080337000f1303d18763591a469baef4d755989ec6f6dae5a23e20b599406dd8e080ddbed41272f4dd8caf1c86d163910f9595882a3d718a035edd695d3b6a926b57d0ac65b10b4e06eedd863bf141077fd7af2782bd3fa26a1a8891d57c630948c0279393dcd04cf5875258f4de9f0cb7b7b6d66d2b81ba752d85f5214724fed41036bd79d2fe319d7a8f4b9c81e58de2f04827b9ce09a07a3acecf54b790685ace8697606009e52c377b7f2e682b097d7d36acf0f55df5edbdc0977412468cb6ce3be10af3c63b9c8a0b0751f505be9690dd5d752436f62a3fe4c6448f3b7b0c64e38f615734651f107e3045ac42b67a7693018633b965bc1bc838ee173807bf7cd33065baaeb1a95f2c11dfcd2bc51fe48880aa3e8a062a8b059f595df4ae9a74de9e9ec499d43c97b1427c6e47e525bb63e4282ad3ea3712893c599dbc4259c1627713c927de81043950df97db1406da8411c92063be280230839627078e79a0390a71b5bb5003a8c1232338e4507025573e9fbd02a0e41dc0e680c3691cf714053bb34160895dc16f291d98d02322aa39f3e14707ffaa06f202a5bb0c7201f4a343aca51090497efdfbfce89840c8db8e46573923ff14410b00490d9f5c1a0425dd8ce4673e873cd0265e4dbe7041ed814009b8cbb8e5863bd07163b7716e0607b6698060b96b7b9478dc8643918247ee39a60b7e97f133a8b4e0c63d4ee597380923970a3ef4c0e13e25dfcfab457ba95bdbddb212016501867b9cfbfda982f907c74b282da34874a9048aa479c83838edc62982b7ac7c42d235cd67f15ac5b40c366418a2cb0c1c81e6f5e31db14c160d035de8cd4a3f18ea96562cc37359dfe9cac887fef039fd6b39446f56ea5d13a9dca4579a922496b1975b8d22dfc3566cf9557230703be715ac1431d4d2275325d7fae6b4f6f182a93ef1e32a9f41938f6a60afeb1a95c5fea53dccf772cf2c8c489240031f627e7565c0d67bbf160487c1801073bc0c31f91f953420f2bc8c7c52cc540032738a809905c0f4fa501940208e73df34028e703938a0577ae013f4a001300db4f03b71407461ce0502dca8c9c7dcf6a003fafcbdcd0070bc1e0fd734070db467b8a04cb9c9e68274b93bcb1daa40200ed4099765249ec476cf340849b8b264823bf34689ee009cb671df1409bc8e8b8e770e3ec68984d9c953cf97be2860b248caaebc107dc67f7a184c31232db88fd451031ce50e76039f5c8045026efb8f93279e0fd680b239504f0483d88ef409ee25bb90c79c0e050151c6e21b39ce783eb40adbcc2cefa17bdb61322387781c950e3dbdf9c8a066f28790b22e013db3dbef54726081e63c6460d34191b1bb0720f634060e7600412c781502409c8e3d7b500ed71dbef8ed40243f181c0a02e5d4e0fad006f644e4819e3b501f7e3049e7b501bc43b4e391da80558003392d40a23305e320d02e64cf998e1bf5a032b0c927b8e68049c8c8e71c6280377043118f4e680bbff00de0504ddbb3128371c1c64668024e59f3cd02521254e4fad1a2107e48fe6a6809ddb9e78a029e1463d05027ffc744a6c3857c7b1a205ff00e637fbf4a02b12b1794e39f4a02024e7249ed409924720906800005173fd7404989698ee39e4f7a04cf723d07a501fff0097ed406ffe36a018ff00281e99a037f4d0731f3bfd28007e53400ff99a810248c0cf140bc60123233cff008a0557f9beb4056eff007a07109243e79a03778b27bfbd02b128c27039a054001b818a06609de793da815006070283ffd9}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here is a movie {\pict\jpegblip\picw20\pich22\picwgoal400\pichgoal440\bin ffd8ffe000104a46494600010101004800480000fffe0050546869732061727420697320696e20746865207075626c696320646f6d61696e2e204b6576696e204875676865732c206b6576696e68406569742e636f6d2c2053657074656d6265722031393935ffdb00430001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101ffdb00430101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101ffc00011080016001403012200021101031101ffc4001a000100020301000000000000000000000000080905060a07ffc400231000010501000300010500000000000000060304050708020001090a11153976b7ffc400160101010100000000000000000000000000060800ffc400261101000102050109000000000000000000010200030405061121b33134365154717475b4ffda000c03010002110311003f00a90cf388f366a62aa720ed6ae07f96901f3831d973452b8cf36fe3570fc908e46d466433e5dd954f2e96992d9e498c7753faa44916e016ca91cc7d88b38fe60a5b97737defcbcc539c98d336a57f4fc2ca9a486bf07ab575ad9a3af4df221d8215e36df86c4504ff0024574551b3d687ee0575757b3ad64e311ee62bd94158d37e24198c43973099f1fc0c41614d950246513a081abf76cfe7061f6863281e6352fd1670949c148dd6dfb0d25f5b3689b1d5c965b0eacbf4e0932ad28e22ab9ae945633f4744bd3c8cee0a7fdf085b9000f449c5f7afa30b83e0b6fd7b0c8429c9467ff9715347c891e25fa24a205861aa715e6a09bd0488237dc2723414d9891381524e8ca7c0894664f835653631ab55ee7e3de433e4ff001b30949124e4c10c8b6ad0a479b3f9c937b2cf5bc0095ad600a0a41a0e9faee174a1c605e161c6c7a313539650b0113190f1a8368e60d5b24f30ff008ea7f0bf867fa6595feeb6978f1fe0f9c26177f4d63a51a9235184750e7d18811339cd000000c75f000e00380380ae390c350def826ed42ad051fa6f501c50f9b699c3b69cbeb76476d202bf3ac985b6e0e968be66572893e6a744540bd9722e5c87956848629bc2559306bd113e8653d3b6aff651dfad7a3ac8b02958cba02a93ccf525757039bae6cff090e1d90688e8aa233ee86a4c4a3e0586d6b2340522e47dcb7d0046d8a5acb05a123ee25d2b230b2ada6e2e2f9ede3c05202520ec2487b0d56562529d8b3393bca76adca4ec1bca508abb001babc007915d84fe3dd14e207e3c62f8379da2a3b861fb6629d28dba53b6ea388ebfed866bf6dfb553455e91ed547ae92e9445253a4fdf3efb4f8ebdfbe7d3c78f1ee0bb9e13e358e942a4ed49e22cff00eeb35fdd7ebfffd9} icon.\par}
+{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Footnotes\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Here is a footnote reference,{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.\par}
+} and another.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's the long note. This one contains multiple blocks.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Subsequent blocks are indented to show that they belong to the footnote (as with list items).\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 \{ <code> \}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.\par}
+} This should {\i not} be a footnote reference, because it contains a space.[^my note] Here is an inline note.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 This is {\i easier} to type. Inline notes may contain {\field{\*\fldinst{HYPERLINK "http://google.com"}}{\fldrslt{\ul
+links
+}}}
+ and {\f1 ]} verbatim characters, as well as [bracketed text].\par}
+}\par}
+{\pard \ql \f0 \sa180 \li720 \fi0 Notes can go in quotes.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 In quote.\par}
+}\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab And in list items.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 In list.\par}
+}\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This paragraph should not be part of the note, as it is not indented.\par}
+}
diff --git a/test/writer.tei b/test/writer.tei
new file mode 100644
index 000000000..779aa337b
--- /dev/null
+++ b/test/writer.tei
@@ -0,0 +1,859 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TEI xmlns="http://www.tei-c.org/ns/1.0">
+<teiHeader>
+ <fileDesc>
+ <titleStmt>
+ <title>Pandoc Test Suite</title>
+ <author>John MacFarlane</author>
+ <author>Anonymous</author>
+ </titleStmt>
+ <publicationStmt>
+ <p></p>
+ </publicationStmt>
+ <sourceDesc>
+ <p>Produced by pandoc.</p>
+ </sourceDesc>
+ </fileDesc>
+</teiHeader>
+<text>
+<body>
+<p>This is a set of tests for pandoc. Most of them are adapted from John
+Gruber’s markdown test suite.</p>
+<milestone unit="undefined" type="separator" rendition="line" />
+<div type="level1" xml:id="headers">
+ <head>Headers</head>
+ <div type="level2" xml:id="level-2-with-an-embedded-link">
+ <head>Level 2 with an <ref target="/url">embedded link</ref></head>
+ <div type="level3" xml:id="level-3-with-emphasis">
+ <head>Level 3 with <hi rendition="simple:italic">emphasis</hi></head>
+ <div type="level4" xml:id="level-4">
+ <head>Level 4</head>
+ <div type="level5" xml:id="level-5">
+ <head>Level 5</head>
+ <p></p>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<div type="level1" xml:id="level-1">
+ <head>Level 1</head>
+ <div type="level2" xml:id="level-2-with-emphasis">
+ <head>Level 2 with <hi rendition="simple:italic">emphasis</hi></head>
+ <div type="level3" xml:id="level-3">
+ <head>Level 3</head>
+ <p>with no blank line</p>
+ </div>
+ </div>
+ <div type="level2" xml:id="level-2">
+ <head>Level 2</head>
+ <p>with no blank line</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+ </div>
+</div>
+<div type="level1" xml:id="paragraphs">
+ <head>Paragraphs</head>
+ <p>Here’s a regular paragraph.</p>
+ <p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list
+ item. Because a hard-wrapped line in the middle of a paragraph looked like a
+ list item.</p>
+ <p>Here’s one with a bullet. * criminey.</p>
+ <p>There should be a hard line break<lb />here.</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="block-quotes">
+ <head>Block Quotes</head>
+ <p>E-mail style:</p>
+ <quote>
+ <p>This is a block quote. It is pretty short.</p>
+ </quote>
+ <quote>
+ <p>Code in a block quote:</p>
+ <ab type='codeblock '>
+sub status {
+ print &quot;working&quot;;
+}
+</ab>
+ <p>A list:</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>item one</p>
+ </item>
+ <item>
+ <p>item two</p>
+ </item>
+ </list>
+ <p>Nested block quotes:</p>
+ <quote>
+ <p>nested</p>
+ </quote>
+ <quote>
+ <p>nested</p>
+ </quote>
+ </quote>
+ <p>This should not be a block quote: 2 &gt; 1.</p>
+ <p>And a following paragraph.</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="code-blocks">
+ <head>Code Blocks</head>
+ <p>Code:</p>
+ <ab type='codeblock '>
+---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab
+</ab>
+ <p>And:</p>
+ <ab type='codeblock '>
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{
+</ab>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="lists">
+ <head>Lists</head>
+ <div type="level2" xml:id="unordered">
+ <head>Unordered</head>
+ <p>Asterisks tight:</p>
+ <list type="unordered">
+ <item>
+ <p>asterisk 1</p>
+ </item>
+ <item>
+ <p>asterisk 2</p>
+ </item>
+ <item>
+ <p>asterisk 3</p>
+ </item>
+ </list>
+ <p>Asterisks loose:</p>
+ <list type="unordered">
+ <item>
+ <p>asterisk 1</p>
+ </item>
+ <item>
+ <p>asterisk 2</p>
+ </item>
+ <item>
+ <p>asterisk 3</p>
+ </item>
+ </list>
+ <p>Pluses tight:</p>
+ <list type="unordered">
+ <item>
+ <p>Plus 1</p>
+ </item>
+ <item>
+ <p>Plus 2</p>
+ </item>
+ <item>
+ <p>Plus 3</p>
+ </item>
+ </list>
+ <p>Pluses loose:</p>
+ <list type="unordered">
+ <item>
+ <p>Plus 1</p>
+ </item>
+ <item>
+ <p>Plus 2</p>
+ </item>
+ <item>
+ <p>Plus 3</p>
+ </item>
+ </list>
+ <p>Minuses tight:</p>
+ <list type="unordered">
+ <item>
+ <p>Minus 1</p>
+ </item>
+ <item>
+ <p>Minus 2</p>
+ </item>
+ <item>
+ <p>Minus 3</p>
+ </item>
+ </list>
+ <p>Minuses loose:</p>
+ <list type="unordered">
+ <item>
+ <p>Minus 1</p>
+ </item>
+ <item>
+ <p>Minus 2</p>
+ </item>
+ <item>
+ <p>Minus 3</p>
+ </item>
+ </list>
+ </div>
+ <div type="level2" xml:id="ordered">
+ <head>Ordered</head>
+ <p>Tight:</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>First</p>
+ </item>
+ <item>
+ <p>Second</p>
+ </item>
+ <item>
+ <p>Third</p>
+ </item>
+ </list>
+ <p>and:</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>One</p>
+ </item>
+ <item>
+ <p>Two</p>
+ </item>
+ <item>
+ <p>Three</p>
+ </item>
+ </list>
+ <p>Loose using tabs:</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>First</p>
+ </item>
+ <item>
+ <p>Second</p>
+ </item>
+ <item>
+ <p>Third</p>
+ </item>
+ </list>
+ <p>and using spaces:</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>One</p>
+ </item>
+ <item>
+ <p>Two</p>
+ </item>
+ <item>
+ <p>Three</p>
+ </item>
+ </list>
+ <p>Multiple paragraphs:</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>Item 1, graf one.</p>
+ <p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s
+ back.</p>
+ </item>
+ <item>
+ <p>Item 2.</p>
+ </item>
+ <item>
+ <p>Item 3.</p>
+ </item>
+ </list>
+ </div>
+ <div type="level2" xml:id="nested">
+ <head>Nested</head>
+ <list type="unordered">
+ <item>
+ <p>Tab</p>
+ <list type="unordered">
+ <item>
+ <p>Tab</p>
+ <list type="unordered">
+ <item>
+ <p>Tab</p>
+ </item>
+ </list>
+ </item>
+ </list>
+ </item>
+ </list>
+ <p>Here’s another:</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>First</p>
+ </item>
+ <item>
+ <p>Second:</p>
+ <list type="unordered">
+ <item>
+ <p>Fee</p>
+ </item>
+ <item>
+ <p>Fie</p>
+ </item>
+ <item>
+ <p>Foe</p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p>Third</p>
+ </item>
+ </list>
+ <p>Same thing but with paragraphs:</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>First</p>
+ </item>
+ <item>
+ <p>Second:</p>
+ <list type="unordered">
+ <item>
+ <p>Fee</p>
+ </item>
+ <item>
+ <p>Fie</p>
+ </item>
+ <item>
+ <p>Foe</p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p>Third</p>
+ </item>
+ </list>
+ </div>
+ <div type="level2" xml:id="tabs-and-spaces">
+ <head>Tabs and spaces</head>
+ <list type="unordered">
+ <item>
+ <p>this is a list item indented with tabs</p>
+ </item>
+ <item>
+ <p>this is a list item indented with spaces</p>
+ <list type="unordered">
+ <item>
+ <p>this is an example list item indented with tabs</p>
+ </item>
+ <item>
+ <p>this is an example list item indented with spaces</p>
+ </item>
+ </list>
+ </item>
+ </list>
+ </div>
+ <div type="level2" xml:id="fancy-list-markers">
+ <head>Fancy list markers</head>
+ <list type="ordered:arabic">
+ <item n="2">
+ <p>begins with 2</p>
+ </item>
+ <item>
+ <p>and now 3</p>
+ <p>with a continuation</p>
+ <list type="ordered:lowerroman">
+ <item n="4">
+ <p>sublist with roman numerals, starting with 4</p>
+ </item>
+ <item>
+ <p>more items</p>
+ <list type="ordered:upperalpha">
+ <item>
+ <p>a subsublist</p>
+ </item>
+ <item>
+ <p>a subsublist</p>
+ </item>
+ </list>
+ </item>
+ </list>
+ </item>
+ </list>
+ <p>Nesting:</p>
+ <list type="ordered:upperalpha">
+ <item>
+ <p>Upper Alpha</p>
+ <list type="ordered:upperroman">
+ <item>
+ <p>Upper Roman.</p>
+ <list type="ordered:arabic">
+ <item n="6">
+ <p>Decimal start with 6</p>
+ <list type="ordered:loweralpha">
+ <item n="3">
+ <p>Lower alpha with paren</p>
+ </item>
+ </list>
+ </item>
+ </list>
+ </item>
+ </list>
+ </item>
+ </list>
+ <p>Autonumbering:</p>
+ <list>
+ <item>
+ <p>Autonumber.</p>
+ </item>
+ <item>
+ <p>More.</p>
+ <list>
+ <item>
+ <p>Nested.</p>
+ </item>
+ </list>
+ </item>
+ </list>
+ <p>Should not be a list item:</p>
+ <p>M.A. 2007</p>
+ <p>B. Williams</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+ </div>
+</div>
+<div type="level1" xml:id="definition-lists">
+ <head>Definition Lists</head>
+ <p>Tight using spaces:</p>
+ <list type="definition">
+ <label>
+ apple
+ </label>
+ <item>
+ <p>red fruit</p>
+ </item>
+ <label>
+ orange
+ </label>
+ <item>
+ <p>orange fruit</p>
+ </item>
+ <label>
+ banana
+ </label>
+ <item>
+ <p>yellow fruit</p>
+ </item>
+ </list>
+ <p>Tight using tabs:</p>
+ <list type="definition">
+ <label>
+ apple
+ </label>
+ <item>
+ <p>red fruit</p>
+ </item>
+ <label>
+ orange
+ </label>
+ <item>
+ <p>orange fruit</p>
+ </item>
+ <label>
+ banana
+ </label>
+ <item>
+ <p>yellow fruit</p>
+ </item>
+ </list>
+ <p>Loose:</p>
+ <list type="definition">
+ <label>
+ apple
+ </label>
+ <item>
+ <p>red fruit</p>
+ </item>
+ <label>
+ orange
+ </label>
+ <item>
+ <p>orange fruit</p>
+ </item>
+ <label>
+ banana
+ </label>
+ <item>
+ <p>yellow fruit</p>
+ </item>
+ </list>
+ <p>Multiple blocks with italics:</p>
+ <list type="definition">
+ <label>
+ <hi rendition="simple:italic">apple</hi>
+ </label>
+ <item>
+ <p>red fruit</p>
+ <p>contains seeds, crisp, pleasant to taste</p>
+ </item>
+ <label>
+ <hi rendition="simple:italic">orange</hi>
+ </label>
+ <item>
+ <p>orange fruit</p>
+ <ab type='codeblock '>
+{ orange code block }
+</ab>
+ <quote>
+ <p>orange block quote</p>
+ </quote>
+ </item>
+ </list>
+ <p>Multiple definitions, tight:</p>
+ <list type="definition">
+ <label>
+ apple
+ </label>
+ <item>
+ <p>red fruit</p>
+ <p>computer</p>
+ </item>
+ <label>
+ orange
+ </label>
+ <item>
+ <p>orange fruit</p>
+ <p>bank</p>
+ </item>
+ </list>
+ <p>Multiple definitions, loose:</p>
+ <list type="definition">
+ <label>
+ apple
+ </label>
+ <item>
+ <p>red fruit</p>
+ <p>computer</p>
+ </item>
+ <label>
+ orange
+ </label>
+ <item>
+ <p>orange fruit</p>
+ <p>bank</p>
+ </item>
+ </list>
+ <p>Blank line after term, indented marker, alternate markers:</p>
+ <list type="definition">
+ <label>
+ apple
+ </label>
+ <item>
+ <p>red fruit</p>
+ <p>computer</p>
+ </item>
+ <label>
+ orange
+ </label>
+ <item>
+ <p>orange fruit</p>
+ <list type="ordered:arabic">
+ <item>
+ <p>sublist</p>
+ </item>
+ <item>
+ <p>sublist</p>
+ </item>
+ </list>
+ </item>
+ </list>
+</div>
+<div type="level1" xml:id="html-blocks">
+ <head>HTML Blocks</head>
+ <p>Simple block on one line:</p>
+ <p>foo</p>
+ <p>And nested without indentation:</p>
+ <p>foo</p>
+ <p>bar</p>
+ <p>Interpreted markdown in a table:</p>
+ <p>This is <hi rendition="simple:italic">emphasized</hi></p>
+ <p>And this is <hi rendition="simple:bold">strong</hi></p>
+ <p>Here’s a simple block:</p>
+ <p>foo</p>
+ <p>This should be a code block, though:</p>
+ <ab type='codeblock '>
+&lt;div&gt;
+ foo
+&lt;/div&gt;
+</ab>
+ <p>As should this:</p>
+ <ab type='codeblock '>
+&lt;div&gt;foo&lt;/div&gt;
+</ab>
+ <p>Now, nested:</p>
+ <p>foo</p>
+ <p>This should just be an HTML comment:</p>
+ <p>Multiline:</p>
+ <p>Code block:</p>
+ <ab type='codeblock '>
+&lt;!-- Comment --&gt;
+</ab>
+ <p>Just plain comment, with trailing spaces on the line:</p>
+ <p>Code:</p>
+ <ab type='codeblock '>
+&lt;hr /&gt;
+</ab>
+ <p>Hr’s:</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="inline-markup">
+ <head>Inline Markup</head>
+ <p>This is <hi rendition="simple:italic">emphasized</hi>, and so
+ <hi rendition="simple:italic">is this</hi>.</p>
+ <p>This is <hi rendition="simple:bold">strong</hi>, and so
+ <hi rendition="simple:bold">is this</hi>.</p>
+ <p>An <hi rendition="simple:italic"><ref target="/url">emphasized
+ link</ref></hi>.</p>
+ <p><hi rendition="simple:bold"><hi rendition="simple:italic">This is strong
+ and em.</hi></hi></p>
+ <p>So is
+ <hi rendition="simple:bold"><hi rendition="simple:italic">this</hi></hi>
+ word.</p>
+ <p><hi rendition="simple:bold"><hi rendition="simple:italic">This is strong
+ and em.</hi></hi></p>
+ <p>So is
+ <hi rendition="simple:bold"><hi rendition="simple:italic">this</hi></hi>
+ word.</p>
+ <p>This is code: <seg type="code">&gt;</seg>, <seg type="code">$</seg>,
+ <seg type="code">\</seg>, <seg type="code">\$</seg>,
+ <seg type="code">&lt;html&gt;</seg>.</p>
+ <p><hi rendition="simple:strikethrough">This is
+ <hi rendition="simple:italic">strikeout</hi>.</hi></p>
+ <p>Superscripts: a<hi rendition="simple:superscript">bc</hi>d
+ a<hi rendition="simple:superscript"><hi rendition="simple:italic">hello</hi></hi>
+ a<hi rendition="simple:superscript">hello there</hi>.</p>
+ <p>Subscripts: H<hi rendition="simple:subscript">2</hi>O,
+ H<hi rendition="simple:subscript">23</hi>O,
+ H<hi rendition="simple:subscript">many of them</hi>O.</p>
+ <p>These should not be superscripts or subscripts, because of the unescaped
+ spaces: a^b c^d, a~b c~d.</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="smart-quotes-ellipses-dashes">
+ <head>Smart quotes, ellipses, dashes</head>
+ <p><quote>Hello,</quote> said the spider. <quote><quote>Shelob</quote> is my
+ name.</quote></p>
+ <p><quote>A</quote>, <quote>B</quote>, and <quote>C</quote> are letters.</p>
+ <p><quote>Oak,</quote> <quote>elm,</quote> and <quote>beech</quote> are
+ names of trees. So is <quote>pine.</quote></p>
+ <p><quote>He said, <quote>I want to go.</quote></quote> Were you alive in
+ the 70’s?</p>
+ <p>Here is some quoted <quote><seg type="code">code</seg></quote> and a
+ <quote><ref target="http://example.com/?foo=1&amp;bar=2">quoted
+ link</ref></quote>.</p>
+ <p>Some dashes: one—two — three—four — five.</p>
+ <p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p>
+ <p>Ellipses…and…and….</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="latex">
+ <head>LaTeX</head>
+ <list type="unordered">
+ <item>
+ <p></p>
+ </item>
+ <item>
+ <p><formula notation="TeX">2+2=4</formula></p>
+ </item>
+ <item>
+ <p><formula notation="TeX">x \in y</formula></p>
+ </item>
+ <item>
+ <p><formula notation="TeX">\alpha \wedge \omega</formula></p>
+ </item>
+ <item>
+ <p><formula notation="TeX">223</formula></p>
+ </item>
+ <item>
+ <p><formula notation="TeX">p</formula>-Tree</p>
+ </item>
+ <item>
+ <p>Here’s some display math: <figure type="math">
+ <formula notation="TeX">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</formula>
+ </figure></p>
+ </item>
+ <item>
+ <p>Here’s one that has a line break in it:
+ <formula notation="TeX">\alpha + \omega \times x^2</formula>.</p>
+ </item>
+ </list>
+ <p>These shouldn’t be math:</p>
+ <list type="unordered">
+ <item>
+ <p>To get the famous equation, write
+ <seg type="code">$e = mc^2$</seg>.</p>
+ </item>
+ <item>
+ <p>$22,000 is a <hi rendition="simple:italic">lot</hi> of money. So is
+ $34,000. (It worked if <quote>lot</quote> is emphasized.)</p>
+ </item>
+ <item>
+ <p>Shoes ($20) and socks ($5).</p>
+ </item>
+ <item>
+ <p>Escaped <seg type="code">$</seg>: $73
+ <hi rendition="simple:italic">this should be emphasized</hi> 23$.</p>
+ </item>
+ </list>
+ <p>Here’s a LaTeX table:</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="special-characters">
+ <head>Special Characters</head>
+ <p>Here is some unicode:</p>
+ <list type="unordered">
+ <item>
+ <p>I hat: Î</p>
+ </item>
+ <item>
+ <p>o umlaut: ö</p>
+ </item>
+ <item>
+ <p>section: §</p>
+ </item>
+ <item>
+ <p>set membership: ∈</p>
+ </item>
+ <item>
+ <p>copyright: ©</p>
+ </item>
+ </list>
+ <p>AT&amp;T has an ampersand in their name.</p>
+ <p>AT&amp;T is another way to write it.</p>
+ <p>This &amp; that.</p>
+ <p>4 &lt; 5.</p>
+ <p>6 &gt; 5.</p>
+ <p>Backslash: \</p>
+ <p>Backtick: `</p>
+ <p>Asterisk: *</p>
+ <p>Underscore: _</p>
+ <p>Left brace: {</p>
+ <p>Right brace: }</p>
+ <p>Left bracket: [</p>
+ <p>Right bracket: ]</p>
+ <p>Left paren: (</p>
+ <p>Right paren: )</p>
+ <p>Greater-than: &gt;</p>
+ <p>Hash: #</p>
+ <p>Period: .</p>
+ <p>Bang: !</p>
+ <p>Plus: +</p>
+ <p>Minus: -</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="links">
+ <head>Links</head>
+ <div type="level2" xml:id="explicit">
+ <head>Explicit</head>
+ <p>Just a <ref target="/url/">URL</ref>.</p>
+ <p><ref target="/url/">URL and title</ref>.</p>
+ <p><ref target="/url/">URL and title</ref>.</p>
+ <p><ref target="/url/">URL and title</ref>.</p>
+ <p><ref target="/url/">URL and title</ref></p>
+ <p><ref target="/url/">URL and title</ref></p>
+ <p><ref target="/url/with_underscore">with_underscore</ref></p>
+ <p>Email link (nobody@nowhere.net)</p>
+ <p><ref target="">Empty</ref>.</p>
+ </div>
+ <div type="level2" xml:id="reference">
+ <head>Reference</head>
+ <p>Foo <ref target="/url/">bar</ref>.</p>
+ <p>With <ref target="/url/">embedded [brackets]</ref>.</p>
+ <p><ref target="/url/">b</ref> by itself should be a link.</p>
+ <p>Indented <ref target="/url">once</ref>.</p>
+ <p>Indented <ref target="/url">twice</ref>.</p>
+ <p>Indented <ref target="/url">thrice</ref>.</p>
+ <p>This should [not][] be a link.</p>
+ <ab type='codeblock '>
+[not]: /url
+</ab>
+ <p>Foo <ref target="/url/">bar</ref>.</p>
+ <p>Foo <ref target="/url/">biz</ref>.</p>
+ </div>
+ <div type="level2" xml:id="with-ampersands">
+ <head>With ampersands</head>
+ <p>Here’s a <ref target="http://example.com/?foo=1&amp;bar=2">link with an
+ ampersand in the URL</ref>.</p>
+ <p>Here’s a link with an amersand in the link text:
+ <ref target="http://att.com/">AT&amp;T</ref>.</p>
+ <p>Here’s an <ref target="/script?foo=1&amp;bar=2">inline link</ref>.</p>
+ <p>Here’s an <ref target="/script?foo=1&amp;bar=2">inline link in pointy
+ braces</ref>.</p>
+ </div>
+ <div type="level2" xml:id="autolinks">
+ <head>Autolinks</head>
+ <p>With an ampersand:
+ <ref target="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</ref></p>
+ <list type="unordered">
+ <item>
+ <p>In a list?</p>
+ </item>
+ <item>
+ <p><ref target="http://example.com/">http://example.com/</ref></p>
+ </item>
+ <item>
+ <p>It should.</p>
+ </item>
+ </list>
+ <p>An e-mail address: nobody@nowhere.net</p>
+ <quote>
+ <p>Blockquoted:
+ <ref target="http://example.com/">http://example.com/</ref></p>
+ </quote>
+ <p>Auto-links should not occur here:
+ <seg type="code">&lt;http://example.com/&gt;</seg></p>
+ <ab type='codeblock '>
+or here: &lt;http://example.com/&gt;
+</ab>
+ <milestone unit="undefined" type="separator" rendition="line" />
+ </div>
+</div>
+<div type="level1" xml:id="images">
+ <head>Images</head>
+ <p>From <quote>Voyage dans la Lune</quote> by Georges Melies (1902):</p>
+ <p><figure>
+ <head>lalune</head>
+ <graphic url="lalune.jpg" />
+ <figDesc>fig:Voyage dans la Lune</figDesc>
+ </figure></p>
+ <p>Here is a movie <figure>
+ <head>movie</head>
+ <graphic url="movie.jpg" />
+ </figure> icon.</p>
+ <milestone unit="undefined" type="separator" rendition="line" />
+</div>
+<div type="level1" xml:id="footnotes">
+ <head>Footnotes</head>
+ <p>Here is a footnote reference,<note>
+ <p>Here is the footnote. It can go anywhere after the footnote reference.
+ It need not be placed at the end of the document.</p>
+ </note> and another.<note>
+ <p>Here’s the long note. This one contains multiple blocks.</p>
+ <p>Subsequent blocks are indented to show that they belong to the footnote
+ (as with list items).</p>
+ <ab type='codeblock '>
+ { &lt;code&gt; }
+</ab>
+ <p>If you want, you can indent every line, but you can also be lazy and
+ just indent the first line of each block.</p>
+ </note> This should <hi rendition="simple:italic">not</hi> be a footnote
+ reference, because it contains a space.[^my note] Here is an inline
+ note.<note>
+ <p>This is <hi rendition="simple:italic">easier</hi> to type. Inline notes
+ may contain <ref target="http://google.com">links</ref> and
+ <seg type="code">]</seg> verbatim characters, as well as [bracketed
+ text].</p>
+ </note></p>
+ <quote>
+ <p>Notes can go in quotes.<note>
+ <p>In quote.</p>
+ </note></p>
+ </quote>
+ <list type="ordered:arabic">
+ <item>
+ <p>And in list items.<note>
+ <p>In list.</p>
+ </note></p>
+ </item>
+ </list>
+ <p>This paragraph should not be part of the note, as it is not indented.</p>
+</div>
+</body>
+</text>
+</TEI>
diff --git a/test/writer.texinfo b/test/writer.texinfo
new file mode 100644
index 000000000..f5727d96d
--- /dev/null
+++ b/test/writer.texinfo
@@ -0,0 +1,1057 @@
+\input texinfo
+@documentencoding UTF-8
+
+@macro textstrikeout{text}
+~~\text\~~
+@end macro
+
+@macro textsubscript{text}
+@iftex
+@textsubscript{\text\}
+@end iftex
+@ifnottex
+_@{\text\@}
+@end ifnottex
+@end macro
+
+@macro textsuperscript{text}
+@iftex
+@textsuperscript{\text\}
+@end iftex
+@ifnottex
+^@{\text\@}
+@end ifnottex
+@end macro
+
+@ifnottex
+@paragraphindent 0
+@end ifnottex
+@titlepage
+@title Pandoc Test Suite
+@author John MacFarlane
+@author Anonymous
+July 17, 2006
+@end titlepage
+
+@node Top
+@top Pandoc Test Suite
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber's
+markdown test suite.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+@menu
+* Headers::
+* Level 1::
+* Paragraphs::
+* Block Quotes::
+* Code Blocks::
+* Lists::
+* Definition Lists::
+* HTML Blocks::
+* Inline Markup::
+* Smart quotes ellipses dashes::
+* LaTeX::
+* Special Characters::
+* Links::
+* Images::
+* Footnotes::
+@end menu
+
+@node Headers
+@chapter Headers
+@anchor{#headers}
+@menu
+* Level 2 with an embedded link::
+@end menu
+
+@node Level 2 with an embedded link
+@section Level 2 with an @uref{/url,embedded link}
+@anchor{#level-2-with-an-embedded-link}
+@menu
+* Level 3 with emphasis::
+@end menu
+
+@node Level 3 with emphasis
+@subsection Level 3 with @emph{emphasis}
+@anchor{#level-3-with-emphasis}
+@menu
+* Level 4::
+@end menu
+
+@node Level 4
+@subsubsection Level 4
+@anchor{#level-4}
+Level 5
+
+@node Level 1
+@chapter Level 1
+@anchor{#level-1}
+@menu
+* Level 2 with emphasis::
+* Level 2::
+@end menu
+
+@node Level 2 with emphasis
+@section Level 2 with @emph{emphasis}
+@anchor{#level-2-with-emphasis}
+@menu
+* Level 3::
+@end menu
+
+@node Level 3
+@subsection Level 3
+@anchor{#level-3}
+with no blank line
+
+@node Level 2
+@section Level 2
+@anchor{#level-2}
+with no blank line
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Paragraphs
+@chapter Paragraphs
+@anchor{#paragraphs}
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
+Because a hard-wrapped line in the middle of a paragraph looked like a list
+item.
+
+Here's one with a bullet. * criminey.
+
+There should be a hard line break@*
+here.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Block Quotes
+@chapter Block Quotes
+@anchor{#block-quotes}
+E-mail style:
+
+@quotation
+This is a block quote. It is pretty short.
+@end quotation
+@quotation
+Code in a block quote:
+
+@verbatim
+sub status {
+ print "working";
+}
+@end verbatim
+
+A list:
+
+@enumerate
+@item
+item one
+@item
+item two
+@end enumerate
+
+Nested block quotes:
+
+@quotation
+nested
+@end quotation
+@quotation
+nested
+@end quotation
+@end quotation
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Code Blocks
+@chapter Code Blocks
+@anchor{#code-blocks}
+Code:
+
+@verbatim
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+@end verbatim
+
+And:
+
+@verbatim
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+@end verbatim
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Lists
+@chapter Lists
+@anchor{#lists}
+@menu
+* Unordered::
+* Ordered::
+* Nested::
+* Tabs and spaces::
+* Fancy list markers::
+@end menu
+
+@node Unordered
+@section Unordered
+@anchor{#unordered}
+Asterisks tight:
+
+@itemize
+@item
+asterisk 1
+@item
+asterisk 2
+@item
+asterisk 3
+@end itemize
+
+Asterisks loose:
+
+@itemize
+@item
+asterisk 1
+
+@item
+asterisk 2
+
+@item
+asterisk 3
+
+@end itemize
+
+Pluses tight:
+
+@itemize
+@item
+Plus 1
+@item
+Plus 2
+@item
+Plus 3
+@end itemize
+
+Pluses loose:
+
+@itemize
+@item
+Plus 1
+
+@item
+Plus 2
+
+@item
+Plus 3
+
+@end itemize
+
+Minuses tight:
+
+@itemize
+@item
+Minus 1
+@item
+Minus 2
+@item
+Minus 3
+@end itemize
+
+Minuses loose:
+
+@itemize
+@item
+Minus 1
+
+@item
+Minus 2
+
+@item
+Minus 3
+
+@end itemize
+
+@node Ordered
+@section Ordered
+@anchor{#ordered}
+Tight:
+
+@enumerate
+@item
+First
+@item
+Second
+@item
+Third
+@end enumerate
+
+and:
+
+@enumerate
+@item
+One
+@item
+Two
+@item
+Three
+@end enumerate
+
+Loose using tabs:
+
+@enumerate
+@item
+First
+
+@item
+Second
+
+@item
+Third
+
+@end enumerate
+
+and using spaces:
+
+@enumerate
+@item
+One
+
+@item
+Two
+
+@item
+Three
+
+@end enumerate
+
+Multiple paragraphs:
+
+@enumerate
+@item
+Item 1, graf one.
+
+Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
+
+@item
+Item 2.
+
+@item
+Item 3.
+
+@end enumerate
+
+@node Nested
+@section Nested
+@anchor{#nested}
+@itemize
+@item
+Tab
+@itemize
+@item
+Tab
+@itemize
+@item
+Tab
+@end itemize
+
+@end itemize
+
+@end itemize
+
+Here's another:
+
+@enumerate
+@item
+First
+@item
+Second:
+@itemize
+@item
+Fee
+@item
+Fie
+@item
+Foe
+@end itemize
+
+@item
+Third
+@end enumerate
+
+Same thing but with paragraphs:
+
+@enumerate
+@item
+First
+
+@item
+Second:
+
+@itemize
+@item
+Fee
+@item
+Fie
+@item
+Foe
+@end itemize
+
+@item
+Third
+
+@end enumerate
+
+@node Tabs and spaces
+@section Tabs and spaces
+@anchor{#tabs-and-spaces}
+@itemize
+@item
+this is a list item indented with tabs
+
+@item
+this is a list item indented with spaces
+
+@itemize
+@item
+this is an example list item indented with tabs
+
+@item
+this is an example list item indented with spaces
+
+@end itemize
+
+@end itemize
+
+@node Fancy list markers
+@section Fancy list markers
+@anchor{#fancy-list-markers}
+@enumerate 2
+@item
+begins with 2
+@item
+and now 3
+
+with a continuation
+
+@enumerate 4
+@item
+sublist with roman numerals, starting with 4
+@item
+more items
+@enumerate A
+@item
+a subsublist
+@item
+a subsublist
+@end enumerate
+
+@end enumerate
+
+@end enumerate
+
+Nesting:
+
+@enumerate A
+@item
+Upper Alpha
+@enumerate
+@item
+Upper Roman.
+@enumerate 6
+@item
+Decimal start with 6
+@enumerate c
+@item
+Lower alpha with paren
+@end enumerate
+
+@end enumerate
+
+@end enumerate
+
+@end enumerate
+
+Autonumbering:
+
+@enumerate
+@item
+Autonumber.
+@item
+More.
+@enumerate
+@item
+Nested.
+@end enumerate
+
+@end enumerate
+
+Should not be a list item:
+
+M.A.@ 2007
+
+B. Williams
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Definition Lists
+@chapter Definition Lists
+@anchor{#definition-lists}
+Tight using spaces:
+
+@table @asis
+@item apple
+
+red fruit
+@item orange
+
+orange fruit
+@item banana
+
+yellow fruit
+@end table
+
+Tight using tabs:
+
+@table @asis
+@item apple
+
+red fruit
+@item orange
+
+orange fruit
+@item banana
+
+yellow fruit
+@end table
+
+Loose:
+
+@table @asis
+@item apple
+
+red fruit
+
+@item orange
+
+orange fruit
+
+@item banana
+
+yellow fruit
+
+@end table
+
+Multiple blocks with italics:
+
+@table @asis
+@item @emph{apple}
+
+red fruit
+
+contains seeds, crisp, pleasant to taste
+
+@item @emph{orange}
+
+orange fruit
+
+@verbatim
+{ orange code block }
+@end verbatim
+
+@quotation
+orange block quote
+@end quotation
+@end table
+
+Multiple definitions, tight:
+
+@table @asis
+@item apple
+
+red fruit
+computer
+@item orange
+
+orange fruit
+bank
+@end table
+
+Multiple definitions, loose:
+
+@table @asis
+@item apple
+
+red fruit
+
+computer
+
+@item orange
+
+orange fruit
+
+bank
+
+@end table
+
+Blank line after term, indented marker, alternate markers:
+
+@table @asis
+@item apple
+
+red fruit
+
+computer
+
+@item orange
+
+orange fruit
+
+@enumerate
+@item
+sublist
+@item
+sublist
+@end enumerate
+
+@end table
+
+@node HTML Blocks
+@chapter HTML Blocks
+@anchor{#html-blocks}
+Simple block on one line:
+
+foo
+And nested without indentation:
+
+foo
+bar
+Interpreted markdown in a table:
+
+This is @emph{emphasized}
+And this is @strong{strong}
+Here's a simple block:
+
+foo
+This should be a code block, though:
+
+@verbatim
+<div>
+ foo
+</div>
+@end verbatim
+
+As should this:
+
+@verbatim
+<div>foo</div>
+@end verbatim
+
+Now, nested:
+
+foo
+This should just be an HTML comment:
+
+Multiline:
+
+Code block:
+
+@verbatim
+<!-- Comment -->
+@end verbatim
+
+Just plain comment, with trailing spaces on the line:
+
+Code:
+
+@verbatim
+<hr />
+@end verbatim
+
+Hr's:
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Inline Markup
+@chapter Inline Markup
+@anchor{#inline-markup}
+This is @emph{emphasized}, and so @emph{is this}.
+
+This is @strong{strong}, and so @strong{is this}.
+
+An @emph{@uref{/url,emphasized link}}.
+
+@strong{@emph{This is strong and em.}}
+
+So is @strong{@emph{this}} word.
+
+@strong{@emph{This is strong and em.}}
+
+So is @strong{@emph{this}} word.
+
+This is code: @code{>}, @code{$}, @code{\}, @code{\$}, @code{<html>}.
+
+@textstrikeout{This is @emph{strikeout}.}
+
+Superscripts: a@textsuperscript{bc}d a@textsuperscript{@emph{hello}}
+a@textsuperscript{hello@ there}.
+
+Subscripts: H@textsubscript{2}O, H@textsubscript{23}O,
+H@textsubscript{many@ of@ them}O.
+
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a~b c~d.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Smart quotes ellipses dashes
+@chapter Smart quotes, ellipses, dashes
+@anchor{#smart-quotes-ellipses-dashes}
+``Hello,'' said the spider. ```Shelob' is my name.''
+
+`A', `B', and `C' are letters.
+
+`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
+
+`He said, ``I want to go.''' Were you alive in the 70's?
+
+Here is some quoted `@code{code}' and a
+``@uref{http://example.com/?foo=1&bar=2,quoted link}''.
+
+Some dashes: one---two --- three---four --- five.
+
+Dashes between numbers: 5--7, 255--66, 1987--1999.
+
+Ellipses@dots{}and@dots{}and@dots{}.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node LaTeX
+@chapter LaTeX
+@anchor{#latex}
+@itemize
+@item
+@tex
+\cite[22-23]{smith.1899}
+@end tex
+@item
+@math{2+2=4}
+@item
+@math{x \in y}
+@item
+@math{\alpha \wedge \omega}
+@item
+@math{223}
+@item
+@math{p}-Tree
+@item
+Here's some display math:
+@math{\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}}
+@item
+Here's one that has a line break in it: @math{\alpha + \omega \times x^2}.
+@end itemize
+
+These shouldn't be math:
+
+@itemize
+@item
+To get the famous equation, write @code{$e = mc^2$}.
+@item
+$22,000 is a @emph{lot} of money. So is $34,000. (It worked if ``lot'' is
+emphasized.)
+@item
+Shoes ($20) and socks ($5).
+@item
+Escaped @code{$}: $73 @emph{this should be emphasized} 23$.
+@end itemize
+
+Here's a LaTeX table:
+
+@tex
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog & 2 \\
+Cat & 1 \\ \hline
+\end{tabular}
+@end tex
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Special Characters
+@chapter Special Characters
+@anchor{#special-characters}
+Here is some unicode:
+
+@itemize
+@item
+I hat: Î
+@item
+o umlaut: ö
+@item
+section: §
+@item
+set membership: ∈
+@item
+copyright: ©
+@end itemize
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: @{
+
+Right brace: @}
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Links
+@chapter Links
+@anchor{#links}
+@menu
+* Explicit::
+* Reference::
+* With ampersands::
+* Autolinks::
+@end menu
+
+@node Explicit
+@section Explicit
+@anchor{#explicit}
+Just a @uref{/url/,URL}.
+
+@uref{/url/,URL and title}.
+
+@uref{/url/,URL and title}.
+
+@uref{/url/,URL and title}.
+
+@uref{/url/,URL and title}
+
+@uref{/url/,URL and title}
+
+@uref{/url/with_underscore,with_underscore}
+
+@uref{mailto:nobody@@nowhere.net,Email link}
+
+@uref{,Empty}.
+
+@node Reference
+@section Reference
+@anchor{#reference}
+Foo @uref{/url/,bar}.
+
+With @uref{/url/,embedded [brackets]}.
+
+@uref{/url/,b} by itself should be a link.
+
+Indented @uref{/url,once}.
+
+Indented @uref{/url,twice}.
+
+Indented @uref{/url,thrice}.
+
+This should [not][] be a link.
+
+@verbatim
+[not]: /url
+@end verbatim
+
+Foo @uref{/url/,bar}.
+
+Foo @uref{/url/,biz}.
+
+@node With ampersands
+@section With ampersands
+@anchor{#with-ampersands}
+Here's a @uref{http://example.com/?foo=1&bar=2,link with an ampersand in the
+URL}.
+
+Here's a link with an amersand in the link text: @uref{http://att.com/,AT&T}.
+
+Here's an @uref{/script?foo=1&bar=2,inline link}.
+
+Here's an @uref{/script?foo=1&bar=2,inline link in pointy braces}.
+
+@node Autolinks
+@section Autolinks
+@anchor{#autolinks}
+With an ampersand: @url{http://example.com/?foo=1&bar=2}
+
+@itemize
+@item
+In a list?
+@item
+@url{http://example.com/}
+@item
+It should.
+@end itemize
+
+An e-mail address: @uref{mailto:nobody@@nowhere.net,nobody@@nowhere.net}
+
+@quotation
+Blockquoted: @url{http://example.com/}
+@end quotation
+Auto-links should not occur here: @code{<http://example.com/>}
+
+@verbatim
+or here: <http://example.com/>
+@end verbatim
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Images
+@chapter Images
+@anchor{#images}
+From ``Voyage dans la Lune'' by Georges Melies (1902):
+
+@float
+@image{lalune,,,lalune,jpg}
+@caption{lalune}
+@end float
+
+Here is a movie @image{movie,,,movie,jpg} icon.
+
+@iftex
+@bigskip@hrule@bigskip
+@end iftex
+@ifnottex
+------------------------------------------------------------------------
+@end ifnottex
+
+@node Footnotes
+@chapter Footnotes
+@anchor{#footnotes}
+Here is a footnote reference,@footnote{Here is the footnote. It can go
+anywhere after the footnote reference. It need not be placed at the end of the
+document.} and another.@footnote{Here's the long note. This one contains
+multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the footnote (as
+with list items).
+
+@verbatim
+ { <code> }
+@end verbatim
+
+If you want, you can indent every line, but you can also be lazy and just
+indent the first line of each block.} This should @emph{not} be a footnote
+reference, because it contains a space.[^my note] Here is an inline
+note.@footnote{This is @emph{easier} to type. Inline notes may contain
+@uref{http://google.com,links} and @code{]} verbatim characters, as well as
+[bracketed text].}
+
+@quotation
+Notes can go in quotes.@footnote{In quote.}
+@end quotation
+@enumerate
+@item
+And in list items.@footnote{In list.}
+@end enumerate
+
+This paragraph should not be part of the note, as it is not indented.
+
+@bye
diff --git a/test/writer.textile b/test/writer.textile
new file mode 100644
index 000000000..d19b698f9
--- /dev/null
+++ b/test/writer.textile
@@ -0,0 +1,719 @@
+This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.
+
+<hr />
+
+h1(#headers). Headers
+
+h2(#level-2-with-an-embedded-link). Level 2 with an "embedded link":/url
+
+h3(#level-3-with-emphasis). Level 3 with _emphasis_
+
+h4(#level-4). Level 4
+
+h5(#level-5). Level 5
+
+h1(#level-1). Level 1
+
+h2(#level-2-with-emphasis). Level 2 with _emphasis_
+
+h3(#level-3). Level 3
+
+with no blank line
+
+h2(#level-2). Level 2
+
+with no blank line
+
+<hr />
+
+h1(#paragraphs). Paragraphs
+
+Here's a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard&#45;wrapped line in the middle of a paragraph looked like a list item.
+
+Here's one with a bullet. &#42; criminey.
+
+There should be a hard line break
+here.
+
+<hr />
+
+h1(#block-quotes). Block Quotes
+
+E&#45;mail style:
+
+bq. This is a block quote. It is pretty short.
+
+
+
+<blockquote>
+
+Code in a block quote:
+
+bc. sub status {
+ print "working";
+}
+
+
+A list:
+
+# item one
+# item two
+
+Nested block quotes:
+
+bq. nested
+
+
+
+bq. nested
+
+
+
+</blockquote>
+
+This should not be a block quote: 2 &gt; 1.
+
+And a following paragraph.
+
+<hr />
+
+h1(#code-blocks). Code Blocks
+
+Code:
+
+<pre>
+---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab
+</pre>
+
+And:
+
+<pre>
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{
+</pre>
+
+<hr />
+
+h1(#lists). Lists
+
+h2(#unordered). Unordered
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Asterisks loose:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+Pluses tight:
+
+* Plus 1
+* Plus 2
+* Plus 3
+
+Pluses loose:
+
+* Plus 1
+* Plus 2
+* Plus 3
+
+Minuses tight:
+
+* Minus 1
+* Minus 2
+* Minus 3
+
+Minuses loose:
+
+* Minus 1
+* Minus 2
+* Minus 3
+
+h2(#ordered). Ordered
+
+Tight:
+
+# First
+# Second
+# Third
+
+and:
+
+# One
+# Two
+# Three
+
+Loose using tabs:
+
+# First
+# Second
+# Third
+
+and using spaces:
+
+# One
+# Two
+# Three
+
+Multiple paragraphs:
+
+<ol style="list-style-type: decimal;">
+<li><p>Item 1, graf one.</p>
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog's back.</p></li>
+<li><p>Item 2.</p></li>
+<li><p>Item 3.</p></li>
+</ol>
+
+h2(#nested). Nested
+
+* Tab
+** Tab
+*** Tab
+
+Here's another:
+
+# First
+# Second:
+#* Fee
+#* Fie
+#* Foe
+# Third
+
+Same thing but with paragraphs:
+
+# First
+# Second:
+#* Fee
+#* Fie
+#* Foe
+# Third
+
+h2(#tabs-and-spaces). Tabs and spaces
+
+* this is a list item indented with tabs
+* this is a list item indented with spaces
+** this is an example list item indented with tabs
+** this is an example list item indented with spaces
+
+h2(#fancy-list-markers). Fancy list markers
+
+<ol start="2" style="list-style-type: decimal;">
+<li>begins with 2</li>
+<li><p>and now 3</p>
+<p>with a continuation</p>
+<ol start="4" style="list-style-type: lower-roman;">
+<li>sublist with roman numerals, starting with 4</li>
+<li>more items
+<ol style="list-style-type: upper-alpha;">
+<li>a subsublist</li>
+<li>a subsublist</li>
+</ol>
+</li>
+</ol>
+</li>
+</ol>
+
+Nesting:
+
+<ol style="list-style-type: upper-alpha;">
+<li>Upper Alpha
+<ol style="list-style-type: upper-roman;">
+<li>Upper Roman.
+<ol start="6" style="list-style-type: decimal;">
+<li>Decimal start with 6
+<ol start="3" style="list-style-type: lower-alpha;">
+<li>Lower alpha with paren</li>
+</ol>
+</li>
+</ol>
+</li>
+</ol>
+</li>
+</ol>
+
+Autonumbering:
+
+# Autonumber.
+# More.
+## Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+<hr />
+
+h1(#definition-lists). Definition Lists
+
+Tight using spaces:
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dt>banana</dt>
+<dd>yellow fruit</dd>
+</dl>
+
+Tight using tabs:
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dt>banana</dt>
+<dd>yellow fruit</dd>
+</dl>
+
+Loose:
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p></dd>
+<dt>banana</dt>
+<dd><p>yellow fruit</p></dd>
+</dl>
+
+Multiple blocks with italics:
+
+<dl>
+<dt>_apple_</dt>
+<dd><p>red fruit</p>
+<p>contains seeds, crisp, pleasant to taste</p></dd>
+<dt>_orange_</dt>
+<dd><p>orange fruit</p>
+bc. { orange code block }
+
+
+bq. <p>orange block quote</p>
+
+</dd>
+</dl>
+
+Multiple definitions, tight:
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dd>computer</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dd>bank</dd>
+</dl>
+
+Multiple definitions, loose:
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dd><p>computer</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p></dd>
+<dd><p>bank</p></dd>
+</dl>
+
+Blank line after term, indented marker, alternate markers:
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dd><p>computer</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+<ol style="list-style-type: decimal;">
+<li>sublist</li>
+<li>sublist</li>
+</ol>
+</dd>
+</dl>
+
+h1(#html-blocks). HTML Blocks
+
+Simple block on one line:
+
+<div>
+
+foo
+
+</div>
+
+And nested without indentation:
+
+<div>
+
+<div>
+
+<div>
+
+foo
+
+
+</div>
+
+
+</div>
+
+<div>
+
+bar
+
+</div>
+
+
+</div>
+
+Interpreted markdown in a table:
+
+<table>
+<tr>
+<td>
+This is _emphasized_
+</td>
+<td>
+And this is *strong*
+</td>
+</tr>
+</table>
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+Here's a simple block:
+
+<div>
+
+foo
+
+
+</div>
+
+This should be a code block, though:
+
+bc. <div>
+ foo
+</div>
+
+
+As should this:
+
+bc. <div>foo</div>
+
+
+Now, nested:
+
+<div>
+
+<div>
+
+<div>
+
+foo
+
+</div>
+
+
+</div>
+
+
+</div>
+
+This should just be an HTML comment:
+
+<!-- Comment -->
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+<!--
+ This is another comment.
+-->
+Code block:
+
+bc. <!-- Comment -->
+
+
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+Code:
+
+bc. <hr />
+
+
+Hr's:
+
+<hr>
+<hr />
+<hr />
+<hr>
+<hr />
+<hr />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar" />
+<hr class="foo" id="bar">
+<hr />
+
+h1(#inline-markup). Inline Markup
+
+This is _emphasized_, and so _is this_.
+
+This is *strong*, and so *is this*.
+
+An _"emphasized link":/url_.
+
+*_This is strong and em._*
+
+So is *_this_* word.
+
+*_This is strong and em._*
+
+So is *_this_* word.
+
+This is code: @>@, @$@, @\@, @\$@, @<html>@.
+
+-This is _strikeout_.-
+
+Superscripts: a[^bc^]d a[^_hello_^] a[^hello there^].
+
+Subscripts: H[~2~]O, H[~23~]O, H[~many of them~]O.
+
+These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
+
+<hr />
+
+h1(#smart-quotes-ellipses-dashes). Smart quotes, ellipses, dashes
+
+"Hello," said the spider. "'Shelob' is my name."
+
+'A', 'B', and 'C' are letters.
+
+'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
+
+'He said, "I want to go."' Were you alive in the 70's?
+
+Here is some quoted '@code@' and a ""quoted link":http://example.com/?foo=1&bar=2".
+
+Some dashes: one -- two -- three -- four -- five.
+
+Dashes between numbers: 5 - 7, 255 - 66, 1987 - 1999.
+
+Ellipses...and...and....
+
+<hr />
+
+h1(#latex). LaTeX
+
+*
+* <span class="math">2+2=4</math>
+* <span class="math">x \in y</math>
+* <span class="math">\alpha \wedge \omega</math>
+* <span class="math">223</math>
+* <span class="math">p</math>&#45;Tree
+* Here's some display math: <span class="math">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</math>
+* Here's one that has a line break in it: <span class="math">\alpha + \omega \times x^2</math>.
+
+These shouldn't be math:
+
+* To get the famous equation, write @$e = mc^2$@.
+* $22,000 is a _lot_ of money. So is $34,000. (It worked if "lot" is emphasized.)
+* Shoes ($20) and socks ($5).
+* Escaped @$@: $73 _this should be emphasized_ 23$.
+
+Here's a LaTeX table:
+
+
+<hr />
+
+h1(#special-characters). Special Characters
+
+Here is some unicode:
+
+* I hat: Î
+* o umlaut: ö
+* section: §
+* set membership: ∈
+* copyright: ©
+
+AT&amp;T has an ampersand in their name.
+
+AT&amp;T is another way to write it.
+
+This &amp; that.
+
+4 &lt; 5.
+
+6 &gt; 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: &#42;
+
+Underscore: &#95;
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater&#45;than: &gt;
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: &#43;
+
+Minus: &#45;
+
+<hr />
+
+h1(#links). Links
+
+h2(#explicit). Explicit
+
+Just a "URL":/url/.
+
+"URL and title":/url/.
+
+"URL and title":/url/.
+
+"URL and title":/url/.
+
+"URL and title":/url/
+
+"URL and title":/url/
+
+"with&#95;underscore":/url/with_underscore
+
+"Email link":mailto:nobody@nowhere.net
+
+"Empty":.
+
+h2(#reference). Reference
+
+Foo "bar":/url/.
+
+With "embedded [brackets]":/url/.
+
+"b":/url/ by itself should be a link.
+
+Indented "once":/url.
+
+Indented "twice":/url.
+
+Indented "thrice":/url.
+
+This should [not][] be a link.
+
+bc. [not]: /url
+
+
+Foo "bar":/url/.
+
+Foo "biz":/url/.
+
+h2(#with-ampersands). With ampersands
+
+Here's a "link with an ampersand in the URL":http://example.com/?foo=1&bar=2.
+
+Here's a link with an amersand in the link text: "AT&amp;T":http://att.com/.
+
+Here's an "inline link":/script?foo=1&bar=2.
+
+Here's an "inline link in pointy braces":/script?foo=1&bar=2.
+
+h2(#autolinks). Autolinks
+
+With an ampersand: "$":http://example.com/?foo=1&bar=2
+
+* In a list?
+* "$":http://example.com/
+* It should.
+
+An e&#45;mail address: "nobody&#64;nowhere.net":mailto:nobody@nowhere.net
+
+bq. Blockquoted: "$":http://example.com/
+
+
+
+Auto&#45;links should not occur here: @<http://example.com/>@
+
+bc. or here: <http://example.com/>
+
+
+<hr />
+
+h1(#images). Images
+
+From "Voyage dans la Lune" by Georges Melies (1902):
+
+!lalune.jpg(Voyage dans la Lune)!
+lalune
+
+Here is a movie !movie.jpg(movie)! icon.
+
+<hr />
+
+h1(#footnotes). Footnotes
+
+Here is a footnote reference,[1] and another.[2] This should _not_ be a footnote reference, because it contains a space.[^my note] Here is an inline note.[3]
+
+bq. Notes can go in quotes.[4]
+
+
+
+# And in list items.[5]
+
+This paragraph should not be part of the note, as it is not indented.
+
+
+fn1. Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
+
+
+fn2. Here's the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the footnote (as with list items).
+
+bc. { <code> }
+
+
+If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
+
+
+fn3. This is _easier_ to type. Inline notes may contain "links":http://google.com and @]@ verbatim characters, as well as [bracketed text].
+
+
+fn4. In quote.
+
+
+fn5. In list.
diff --git a/test/writer.zimwiki b/test/writer.zimwiki
new file mode 100644
index 000000000..91f018b52
--- /dev/null
+++ b/test/writer.zimwiki
@@ -0,0 +1,619 @@
+Content-Type: text/x-zim-wiki
+Wiki-Format: zim 0.4
+
+This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.
+
+
+----
+
+====== Headers ======
+
+===== Level 2 with an embedded link =====
+
+==== Level 3 with emphasis ====
+
+=== Level 4 ===
+
+== Level 5 ==
+
+====== Level 1 ======
+
+===== Level 2 with emphasis =====
+
+==== Level 3 ====
+
+with no blank line
+
+===== Level 2 =====
+
+with no blank line
+
+
+----
+
+====== Paragraphs ======
+
+Here’s a regular paragraph.
+
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
+
+Here’s one with a bullet. * criminey.
+
+There should be a hard line break
+here.
+
+
+----
+
+====== Block Quotes ======
+
+E-mail style:
+
+> This is a block quote. It is pretty short.
+
+> Code in a block quote:
+>
+> '''
+> sub status {
+> print "working";
+> }
+> '''
+>
+> A list:
+>
+> 1. item one
+> 1. item two
+>
+> Nested block quotes:
+>
+> > nested
+>
+> > nested
+
+This should not be a block quote: 2 > 1.
+
+And a following paragraph.
+
+
+----
+
+====== Code Blocks ======
+
+Code:
+
+'''
+---- (should be four hyphens)
+
+sub status {
+ print "working";
+}
+
+this code block is indented by one tab
+'''
+
+And:
+
+'''
+ this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \> \[ \{
+'''
+
+
+----
+
+====== Lists ======
+
+===== Unordered =====
+
+Asterisks tight:
+
+ * asterisk 1
+ * asterisk 2
+ * asterisk 3
+
+Asterisks loose:
+
+ * asterisk 1
+ * asterisk 2
+ * asterisk 3
+
+Pluses tight:
+
+ * Plus 1
+ * Plus 2
+ * Plus 3
+
+Pluses loose:
+
+ * Plus 1
+ * Plus 2
+ * Plus 3
+
+Minuses tight:
+
+ * Minus 1
+ * Minus 2
+ * Minus 3
+
+Minuses loose:
+
+ * Minus 1
+ * Minus 2
+ * Minus 3
+
+===== Ordered =====
+
+Tight:
+
+ 1. First
+ 1. Second
+ 1. Third
+
+and:
+
+ 1. One
+ 1. Two
+ 1. Three
+
+Loose using tabs:
+
+ 1. First
+ 1. Second
+ 1. Third
+
+and using spaces:
+
+ 1. One
+ 1. Two
+ 1. Three
+
+Multiple paragraphs:
+
+ 1. Item 1, graf one.
+Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
+ 1. Item 2.
+ 1. Item 3.
+
+===== Nested =====
+
+ * Tab
+ * Tab
+ * Tab
+
+Here’s another:
+
+ 1. First
+ 1. Second:
+ * Fee
+ * Fie
+ * Foe
+ 1. Third
+
+Same thing but with paragraphs:
+
+ 1. First
+ 1. Second:
+ * Fee
+ * Fie
+ * Foe
+ 1. Third
+
+===== Tabs and spaces =====
+
+ * this is a list item indented with tabs
+ * this is a list item indented with spaces
+ * this is an example list item indented with tabs
+ * this is an example list item indented with spaces
+
+===== Fancy list markers =====
+
+ 1. begins with 2
+ 1. and now 3
+with a continuation
+ 1. sublist with roman numerals, starting with 4
+ 1. more items
+ 1. a subsublist
+ 1. a subsublist
+
+Nesting:
+
+ 1. Upper Alpha
+ 1. Upper Roman.
+ 1. Decimal start with 6
+ 1. Lower alpha with paren
+
+Autonumbering:
+
+ 1. Autonumber.
+ 1. More.
+ 1. Nested.
+
+Should not be a list item:
+
+M.A. 2007
+
+B. Williams
+
+
+----
+
+====== Definition Lists ======
+
+Tight using spaces:
+
+* **apple** red fruit
+* **orange** orange fruit
+* **banana** yellow fruit
+Tight using tabs:
+
+* **apple** red fruit
+* **orange** orange fruit
+* **banana** yellow fruit
+Loose:
+
+* **apple** red fruit
+
+* **orange** orange fruit
+
+* **banana** yellow fruit
+
+Multiple blocks with italics:
+
+* **//apple//** red fruit
+
+contains seeds, crisp, pleasant to taste
+
+* **//orange//** orange fruit
+
+'''
+{ orange code block }
+'''
+
+> orange block quote
+
+Multiple definitions, tight:
+
+* **apple** red fruitcomputer
+* **orange** orange fruitbank
+Multiple definitions, loose:
+
+* **apple** red fruit
+computer
+
+* **orange** orange fruit
+bank
+
+Blank line after term, indented marker, alternate markers:
+
+* **apple** red fruit
+computer
+
+* **orange** orange fruit
+
+ 1. sublist
+ 1. sublist
+
+====== HTML Blocks ======
+
+Simple block on one line:
+
+foo
+
+And nested without indentation:
+
+foo
+
+
+
+bar
+
+
+Interpreted markdown in a table:
+
+
+
+
+This is //emphasized//
+
+
+And this is **strong**
+
+
+
+
+Here’s a simple block:
+
+foo
+
+
+This should be a code block, though:
+
+'''
+<div>
+ foo
+</div>
+'''
+
+As should this:
+
+'''
+<div>foo</div>
+'''
+
+Now, nested:
+
+foo
+
+
+
+This should just be an HTML comment:
+
+
+Multiline:
+
+
+
+Code block:
+
+'''
+<!-- Comment -->
+'''
+
+Just plain comment, with trailing spaces on the line:
+
+
+Code:
+
+'''
+<hr />
+'''
+
+Hr’s:
+
+
+
+
+
+
+
+
+
+
+
+----
+
+====== Inline Markup ======
+
+This is //emphasized//, and so //is this//.
+
+This is **strong**, and so **is this**.
+
+An //[[url|emphasized link]]//.
+
+**//This is strong and em.//**
+
+So is **//this//** word.
+
+**//This is strong and em.//**
+
+So is **//this//** word.
+
+This is code: ''>'', ''$'', ''\'', ''\$'', ''<html>''.
+
+~~This is //strikeout//.~~
+
+Superscripts: a^{bc}d a^{//hello//} a^{hello there}.
+
+Subscripts: H_{2}O, H_{23}O, H_{many of them}O.
+
+These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
+
+
+----
+
+====== Smart quotes, ellipses, dashes ======
+
+“Hello,” said the spider. “‘Shelob’ is my name.”
+
+‘A’, ‘B’, and ‘C’ are letters.
+
+‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
+
+‘He said, “I want to go.”’ Were you alive in the 70’s?
+
+Here is some quoted ‘''code''’ and a “[[http://example.com/?foo=1&bar=2|quoted link]]”.
+
+Some dashes: one—two — three—four — five.
+
+Dashes between numbers: 5–7, 255–66, 1987–1999.
+
+Ellipses…and…and….
+
+
+----
+
+====== LaTeX ======
+
+ *
+ * $2+2=4$
+ * $x \in y$
+ * $\alpha \wedge \omega$
+ * $223$
+ * $p$-Tree
+ * Here’s some display math: $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+ * Here’s one that has a line break in it: $\alpha + \omega \times x^2$.
+
+These shouldn’t be math:
+
+ * To get the famous equation, write ''$e = mc^2$''.
+ * $22,000 is a //lot// of money. So is $34,000. (It worked if “lot” is emphasized.)
+ * Shoes ($20) and socks ($5).
+ * Escaped ''$'': $73 //this should be emphasized// 23$.
+
+Here’s a LaTeX table:
+
+
+
+----
+
+====== Special Characters ======
+
+Here is some unicode:
+
+ * I hat: Î
+ * o umlaut: ö
+ * section: §
+ * set membership: ∈
+ * copyright: ©
+
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Backslash: \
+
+Backtick: `
+
+Asterisk: *
+
+Underscore: _
+
+Left brace: {
+
+Right brace: }
+
+Left bracket: [
+
+Right bracket: ]
+
+Left paren: (
+
+Right paren: )
+
+Greater-than: >
+
+Hash: #
+
+Period: .
+
+Bang: !
+
+Plus: +
+
+Minus: -
+
+
+----
+
+====== Links ======
+
+===== Explicit =====
+
+Just a [[url/|URL]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]].
+
+[[url/|URL and title]]
+
+[[url/|URL and title]]
+
+[[url/with_underscore|with_underscore]]
+
+[[mailto:nobody@nowhere.net|Email link]]
+
+[[|Empty]].
+
+===== Reference =====
+
+Foo [[url/|bar]].
+
+With [[url/|embedded [brackets]]].
+
+[[url/|b]] by itself should be a link.
+
+Indented [[url|once]].
+
+Indented [[url|twice]].
+
+Indented [[url|thrice]].
+
+This should [not][] be a link.
+
+'''
+[not]: /url
+'''
+
+Foo [[url/|bar]].
+
+Foo [[url/|biz]].
+
+===== With ampersands =====
+
+Here’s a [[http://example.com/?foo=1&bar=2|link with an ampersand in the URL]].
+
+Here’s a link with an amersand in the link text: [[http://att.com/|AT&T]].
+
+Here’s an [[script?foo=1&bar=2|inline link]].
+
+Here’s an [[script?foo=1&bar=2|inline link in pointy braces]].
+
+===== Autolinks =====
+
+With an ampersand: http://example.com/?foo=1&bar=2
+
+ * In a list?
+ * http://example.com/
+ * It should.
+
+An e-mail address: <nobody@nowhere.net>
+
+> Blockquoted: http://example.com/
+
+Auto-links should not occur here: ''<http://example.com/>''
+
+'''
+or here: <http://example.com/>
+'''
+
+
+----
+
+====== Images ======
+
+From “Voyage dans la Lune” by Georges Melies (1902):
+
+{{:lalune.jpg|Voyage dans la Lune lalune}}
+
+Here is a movie {{:movie.jpg|movie}} icon.
+
+
+----
+
+====== Footnotes ======
+
+Here is a footnote reference, **{Note:** Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.**}** and another. **{Note:** Here’s the long note. This one contains multiple blocks.
+
+Subsequent blocks are indented to show that they belong to the footnote (as with list items).
+
+'''
+ { <code> }
+'''
+
+If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.**}** This should //not// be a footnote reference, because it contains a space.[^my note] Here is an inline note. **{Note:** This is //easier// to type. Inline notes may contain [[http://google.com|links]] and '']'' verbatim characters, as well as [bracketed text].**}**
+
+> Notes can go in quotes. **{Note:** In quote.**}**
+
+ 1. And in list items. **{Note:** In list.**}**
+
+This paragraph should not be part of the note, as it is not indented.
diff --git a/test/writers-lang-and-dir.context b/test/writers-lang-and-dir.context
new file mode 100644
index 000000000..a1c87bb27
--- /dev/null
+++ b/test/writers-lang-and-dir.context
@@ -0,0 +1,123 @@
+% Enable hyperlinks
+\setupinteraction
+ [state=start,
+ style=,
+ color=,
+ contrastcolor=]
+
+% make chapter, section bookmarks visible when opening document
+\placebookmarks[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][chapter, section]
+\setupinteractionscreen[option=bookmark]
+\setuptagging[state=start]
+
+
+% use microtypography
+\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
+\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
+\setupalign[hz,hanging]
+\setupitaliccorrection[global, always]
+
+\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
+
+\definefallbackfamily[mainface][rm][DejaVu Serif][preset=range:greek, force=yes]
+\definefontfamily[mainface][rm][Latin Modern Roman]
+\definefontfamily[mainface][mm][Latin Modern Math]
+\definefontfamily[mainface][ss][Latin Modern Sans]
+\definefontfamily[mainface][tt][Latin Modern Typewriter][features=none]
+\setupbodyfont[mainface]
+
+\setupwhitespace[medium]
+
+\setuphead[chapter] [style=\tfd,header=empty]
+\setuphead[section] [style=\tfc]
+\setuphead[subsection] [style=\tfb]
+\setuphead[subsubsection] [style=\bf]
+\setuphead[subsubsubsection] [style=\sc]
+\setuphead[subsubsubsubsection][style=\it]
+
+\setuphead[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][number=no]
+
+\definedescription
+ [description]
+ [headstyle=bold, style=normal, location=hanging, width=broad, margin=1cm, alternative=hanging]
+
+\setupitemize[autointro] % prevent orphan list intro
+\setupitemize[indentnext=no]
+
+\setupfloat[figure][default={here,nonumber}]
+\setupfloat[table][default={here,nonumber}]
+
+\setupthinrules[width=15em] % width of horizontal rules
+
+\setupxtable[frame=off]
+\setupxtable[head][topframe=on,bottomframe=on]
+\setupxtable[body][]
+\setupxtable[foot][bottomframe=on]
+
+
+\starttext
+
+\section[title={Empty Divs and Spans},reference={empty-divs-and-spans}]
+
+Some text and
+
+div contents
+
+and more text.
+
+Next paragraph with a span and a word-thatincludesaspanright?
+
+\section[title={Directionality},reference={directionality}]
+
+Some text and
+
+\startalignment[righttoleft]
+rtl div contents
+
+\stopalignment
+
+and more text.
+
+\startalignment[lefttoright]
+and a ltr div. with a {\righttoleft rtl span}.
+
+\stopalignment
+
+Next paragraph with a {\righttoleft rtl span} and a
+word-that-includesa{\lefttoright ltrspan}right?
+
+\section[title={Languages},reference={languages}]
+
+Some text and
+
+\start\language[de]
+German div contents
+
+\stop
+
+and more text.
+
+Next paragraph with a \start\language[en-gb]British span\stop and a
+word-that-includesa\start\language[de-ch]Swiss German span\stop right?
+
+Some \start\language[es]Spanish text\stop .
+
+\section[title={Combined},reference={combined}]
+
+Some text and
+
+\start\language[fr]
+\startalignment[righttoleft]
+French rtl div contents
+
+\stopalignment
+\stop
+
+and more text.
+
+Next paragraph with a \start\language[en-gb]{\lefttoright British ltr
+span}\stop and a
+word-that-includesa\start\language[de-ch]{\lefttoright Swiss German ltr
+span}\stop right?
+
+\stoptext
diff --git a/test/writers-lang-and-dir.latex b/test/writers-lang-and-dir.latex
new file mode 100644
index 000000000..97c34010c
--- /dev/null
+++ b/test/writers-lang-and-dir.latex
@@ -0,0 +1,157 @@
+\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+\PassOptionsToPackage{hyphens}{url}
+%
+\documentclass[english,]{article}
+\usepackage{lmodern}
+\usepackage{amssymb,amsmath}
+\usepackage{ifxetex,ifluatex}
+\usepackage{fixltx2e} % provides \textsubscript
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+ \usepackage[T1]{fontenc}
+ \usepackage[utf8]{inputenc}
+ \usepackage{textcomp} % provides euro and other symbols
+\else % if luatex or xelatex
+ \usepackage{unicode-math}
+ \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
+\fi
+% use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+% use microtype if available
+\IfFileExists{microtype.sty}{%
+\usepackage[]{microtype}
+\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
+\usepackage{hyperref}
+\hypersetup{
+ pdfborder={0 0 0},
+ breaklinks=true}
+\urlstyle{same} % don't use monospace font for urls
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+\setcounter{secnumdepth}{0}
+% Redefines (sub)paragraphs to behave more like sections
+\ifx\paragraph\undefined\else
+\let\oldparagraph\paragraph
+\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+\let\oldsubparagraph\subparagraph
+\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+
+% set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+ \usepackage[shorthands=off,ngerman,british,nswissgerman,spanish,french,main=english]{babel}
+ \newcommand{\textgerman}[2][]{\foreignlanguage{ngerman}{#2}}
+ \newenvironment{german}[2][]{\begin{otherlanguage}{ngerman}}{\end{otherlanguage}}
+ \newcommand{\textenglish}[2][]{\foreignlanguage{british}{#2}}
+ \newenvironment{english}[2][]{\begin{otherlanguage}{british}}{\end{otherlanguage}}
+ \let\oritextspanish\textspanish
+ \AddBabelHook{spanish}{beforeextras}{\renewcommand{\textspanish}{\oritextspanish}}
+ \AddBabelHook{spanish}{afterextras}{\renewcommand{\textspanish}[2][]{\foreignlanguage{spanish}{##2}}}
+ \newcommand{\textfrench}[2][]{\foreignlanguage{french}{#2}}
+ \newenvironment{french}[2][]{\begin{otherlanguage}{french}}{\end{otherlanguage}}
+\else
+ % load polyglossia as late as possible as it *could* call bidi if RTL lang (e.g. Hebrew or Arabic)
+ \usepackage{polyglossia}
+ \setmainlanguage[]{english}
+ \setotherlanguage[]{german}
+ \setotherlanguage[variant=british]{english}
+ \setotherlanguage[variant=swiss]{german}
+ \setotherlanguage[]{spanish}
+ \setotherlanguage[]{french}
+\fi
+\ifxetex
+ % load bidi as late as possible as it modifies e.g. graphicx
+ \usepackage{bidi}
+ \fi
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+ \TeXXeTstate=1
+ \newcommand{\RL}[1]{\beginR #1\endR}
+ \newcommand{\LR}[1]{\beginL #1\endL}
+ \newenvironment{RTL}{\beginR}{\endR}
+ \newenvironment{LTR}{\beginL}{\endL}
+\fi
+
+\date{}
+
+\begin{document}
+
+\hypertarget{empty-divs-and-spans}{%
+\section{Empty Divs and Spans}\label{empty-divs-and-spans}}
+
+Some text and
+
+div contents
+
+and more text.
+
+Next paragraph with a {span} and a word-thatincludesa{span}right?
+
+\hypertarget{directionality}{%
+\section{Directionality}\label{directionality}}
+
+Some text and
+
+\begin{RTL}
+rtl div contents
+\end{RTL}
+
+and more text.
+
+\begin{LTR}
+and a ltr div. with a \RL{rtl span}.
+\end{LTR}
+
+Next paragraph with a \RL{rtl span} and a
+word-that-includesa\LR{ltrspan}right?
+
+\hypertarget{languages}{%
+\section{Languages}\label{languages}}
+
+Some text and
+
+\begin{german}
+
+German div contents
+
+\end{german}
+
+and more text.
+
+Next paragraph with a \textenglish[variant=british]{British span} and a
+word-that-includesa\textgerman[variant=swiss]{Swiss German span}right?
+
+Some \textspanish{Spanish text}.
+
+\hypertarget{combined}{%
+\section{Combined}\label{combined}}
+
+Some text and
+
+\begin{RTL}
+\begin{french}
+
+French rtl div contents
+
+\end{french}
+\end{RTL}
+
+and more text.
+
+Next paragraph with a \LR{\textenglish[variant=british]{British ltr
+span}} and a word-that-includesa\LR{\textgerman[variant=swiss]{Swiss
+German ltr span}}right?
+
+\end{document}
diff --git a/tests/writers-lang-and-dir.native b/test/writers-lang-and-dir.native
index 504bcf350..504bcf350 100644
--- a/tests/writers-lang-and-dir.native
+++ b/test/writers-lang-and-dir.native
diff --git a/tests/Tests/Helpers.hs b/tests/Tests/Helpers.hs
deleted file mode 100644
index 69f40fe48..000000000
--- a/tests/Tests/Helpers.hs
+++ /dev/null
@@ -1,85 +0,0 @@
-{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
--- Utility functions for the test suite.
-
-module Tests.Helpers ( test
- , (=?>)
- , property
- , ToString(..)
- , ToPandoc(..)
- )
- where
-
-import Text.Pandoc.Definition
-import Text.Pandoc.Builder (Inlines, Blocks, doc, plain)
-import Test.Framework
-import Test.Framework.Providers.HUnit
-import Test.Framework.Providers.QuickCheck2
-import Test.HUnit (assertBool)
-import Text.Pandoc.Shared (normalize, trimr)
-import Text.Pandoc.Options
-import Text.Pandoc.Writers.Native (writeNative)
-import qualified Test.QuickCheck.Property as QP
-import Data.Algorithm.Diff
-import qualified Data.Map as M
-
-test :: (ToString a, ToString b, ToString c)
- => (a -> b) -- ^ function to test
- -> String -- ^ name of test case
- -> (a, c) -- ^ (input, expected value)
- -> Test
-test fn name (input, expected) =
- testCase name $ assertBool msg (actual' == expected')
- where msg = nl ++ dashes "input" ++ nl ++ input' ++ nl ++
- dashes "result" ++ nl ++
- unlines (map vividize diff) ++
- dashes ""
- nl = "\n"
- input' = toString input
- actual' = lines $ toString $ fn input
- expected' = lines $ toString expected
- diff = getDiff expected' actual'
- dashes "" = replicate 72 '-'
- dashes x = replicate (72 - length x - 5) '-' ++ " " ++ x ++ " ---"
-
-vividize :: Diff String -> String
-vividize (Both s _) = " " ++ s
-vividize (First s) = "- " ++ s
-vividize (Second s) = "+ " ++ s
-
-property :: QP.Testable a => TestName -> a -> Test
-property = testProperty
-
-infix 5 =?>
-(=?>) :: a -> b -> (a,b)
-x =?> y = (x, y)
-
-class ToString a where
- toString :: a -> String
-
-instance ToString Pandoc where
- toString d = writeNative def{ writerTemplate = s } $ toPandoc d
- where s = case d of
- (Pandoc (Meta m) _)
- | M.null m -> Nothing
- | otherwise -> Just "" -- need this to get meta output
-
-instance ToString Blocks where
- toString = writeNative def . toPandoc
-
-instance ToString Inlines where
- toString = trimr . writeNative def . toPandoc
-
-instance ToString String where
- toString = id
-
-class ToPandoc a where
- toPandoc :: a -> Pandoc
-
-instance ToPandoc Pandoc where
- toPandoc = normalize
-
-instance ToPandoc Blocks where
- toPandoc = normalize . doc
-
-instance ToPandoc Inlines where
- toPandoc = normalize . doc . plain
diff --git a/tests/Tests/Old.hs b/tests/Tests/Old.hs
deleted file mode 100644
index ef21990ba..000000000
--- a/tests/Tests/Old.hs
+++ /dev/null
@@ -1,290 +0,0 @@
-module Tests.Old (tests) where
-
-import Test.Framework (testGroup, Test )
-import Test.Framework.Providers.HUnit
-import Test.HUnit ( assertBool )
-import System.Environment.Executable (getExecutablePath)
-import System.IO ( openTempFile, stderr )
-import System.Process ( runProcess, waitForProcess )
-import System.FilePath ( (</>), (<.>), takeDirectory, splitDirectories,
- joinPath )
-import System.Directory
-import System.Exit
-import Data.Algorithm.Diff
-import Text.Pandoc.Shared ( normalize )
-import Text.Pandoc.Options
-import Text.Pandoc.Writers.Native ( writeNative )
-import Text.Pandoc.Readers.Native ( readNative )
-import Prelude hiding ( readFile )
-import qualified Data.ByteString.Lazy as B
-import Text.Pandoc.UTF8 (toStringLazy)
-import Text.Printf
-import Text.Pandoc.Error
-
-readFileUTF8 :: FilePath -> IO String
-readFileUTF8 f = B.readFile f >>= return . toStringLazy
-
-data TestResult = TestPassed
- | TestError ExitCode
- | TestFailed String FilePath [Diff String]
- deriving (Eq)
-
-instance Show TestResult where
- show TestPassed = "PASSED"
- show (TestError ec) = "ERROR " ++ show ec
- show (TestFailed cmd file d) = '\n' : dash ++
- "\n--- " ++ file ++
- "\n+++ " ++ cmd ++ "\n" ++ showDiff (1,1) d ++
- dash
- where dash = replicate 72 '-'
-
-showDiff :: (Int,Int) -> [Diff String] -> String
-showDiff _ [] = ""
-showDiff (l,r) (First ln : ds) =
- printf "+%4d " l ++ ln ++ "\n" ++ showDiff (l+1,r) ds
-showDiff (l,r) (Second ln : ds) =
- printf "-%4d " r ++ ln ++ "\n" ++ showDiff (l,r+1) ds
-showDiff (l,r) (Both _ _ : ds) =
- showDiff (l+1,r+1) ds
-
-tests :: [Test]
-tests = [ testGroup "markdown"
- [ testGroup "writer"
- $ writerTests "markdown" ++ lhsWriterTests "markdown"
- , testGroup "reader"
- [ test "basic" ["-r", "markdown", "-w", "native", "-s", "-S"]
- "testsuite.txt" "testsuite.native"
- , test "tables" ["-r", "markdown", "-w", "native", "--columns=80"]
- "tables.txt" "tables.native"
- , test "pipe tables" ["-r", "markdown", "-w", "native", "--columns=80"]
- "pipe-tables.txt" "pipe-tables.native"
- , test "more" ["-r", "markdown", "-w", "native", "-s", "-S"]
- "markdown-reader-more.txt" "markdown-reader-more.native"
- , lhsReaderTest "markdown+lhs"
- ]
- , testGroup "citations"
- [ test "citations" ["-r", "markdown", "-w", "native"]
- "markdown-citations.txt" "markdown-citations.native"
- ]
- ]
- , testGroup "rst"
- [ testGroup "writer" (writerTests "rst" ++ lhsWriterTests "rst")
- , testGroup "reader"
- [ test "basic" ["-r", "rst", "-w", "native",
- "-s", "-S", "--columns=80"] "rst-reader.rst" "rst-reader.native"
- , test "tables" ["-r", "rst", "-w", "native", "--columns=80"]
- "tables.rst" "tables-rstsubset.native"
- , lhsReaderTest "rst+lhs"
- ]
- ]
- , testGroup "latex"
- [ testGroup "writer" (writerTests "latex" ++ lhsWriterTests "latex")
- , testGroup "reader"
- [ test "basic" ["-r", "latex", "-w", "native", "-s", "-R"]
- "latex-reader.latex" "latex-reader.native"
- , lhsReaderTest "latex+lhs"
- ]
- ]
- , testGroup "html"
- [ testGroup "writer" (writerTests "html" ++ lhsWriterTests "html")
- , test "reader" ["-r", "html", "-w", "native", "-s"]
- "html-reader.html" "html-reader.native"
- ]
- , testGroup "s5"
- [ s5WriterTest "basic" ["-s"] "s5"
- , s5WriterTest "fancy" ["-s","-m","-i"] "s5"
- , s5WriterTest "fragment" [] "html"
- , s5WriterTest "inserts" ["-s", "-H", "insert",
- "-B", "insert", "-A", "insert", "-c", "main.css"] "html"
- ]
- , testGroup "textile"
- [ testGroup "writer" $ writerTests "textile"
- , test "reader" ["-r", "textile", "-w", "native", "-s"]
- "textile-reader.textile" "textile-reader.native"
- ]
- , testGroup "docbook"
- [ testGroup "writer" $ writerTests "docbook"
- , test "reader" ["-r", "docbook", "-w", "native", "-s"]
- "docbook-reader.docbook" "docbook-reader.native"
- , test "reader" ["-r", "docbook", "-w", "native", "-s"]
- "docbook-xref.docbook" "docbook-xref.native"
- ]
- , testGroup "docbook5"
- [ testGroup "writer" $ writerTests "docbook5"
- ]
- , testGroup "native"
- [ testGroup "writer" $ writerTests "native"
- , test "reader" ["-r", "native", "-w", "native", "-s"]
- "testsuite.native" "testsuite.native"
- ]
- , testGroup "fb2"
- [ fb2WriterTest "basic" [] "fb2/basic.markdown" "fb2/basic.fb2"
- , fb2WriterTest "titles" [] "fb2/titles.markdown" "fb2/titles.fb2"
- , fb2WriterTest "images" [] "fb2/images.markdown" "fb2/images.fb2"
- , fb2WriterTest "images-embedded" [] "fb2/images-embedded.html" "fb2/images-embedded.fb2"
- , fb2WriterTest "math" [] "fb2/math.markdown" "fb2/math.fb2"
- , fb2WriterTest "tables" [] "tables.native" "tables.fb2"
- , fb2WriterTest "testsuite" [] "testsuite.native" "writer.fb2"
- ]
- , testGroup "mediawiki"
- [ testGroup "writer" $ writerTests "mediawiki"
- , test "reader" ["-r", "mediawiki", "-w", "native", "-s"]
- "mediawiki-reader.wiki" "mediawiki-reader.native"
- ]
- , testGroup "dokuwiki"
- [ testGroup "writer" $ writerTests "dokuwiki"
- , test "inline_formatting" ["-r", "native", "-w", "dokuwiki", "-s"]
- "dokuwiki_inline_formatting.native" "dokuwiki_inline_formatting.dokuwiki"
- , test "multiblock table" ["-r", "native", "-w", "dokuwiki", "-s"]
- "dokuwiki_multiblock_table.native" "dokuwiki_multiblock_table.dokuwiki"
- , test "external images" ["-r", "native", "-w", "dokuwiki", "-s"]
- "dokuwiki_external_images.native" "dokuwiki_external_images.dokuwiki"
- ]
- , testGroup "opml"
- [ test "basic" ["-r", "native", "-w", "opml", "--columns=78", "-s"]
- "testsuite.native" "writer.opml"
- , test "reader" ["-r", "opml", "-w", "native", "-s"]
- "opml-reader.opml" "opml-reader.native"
- ]
- , testGroup "haddock"
- [ testGroup "writer" $ writerTests "haddock"
- , test "reader" ["-r", "haddock", "-w", "native", "-s"]
- "haddock-reader.haddock" "haddock-reader.native"
- ]
- , testGroup "txt2tags"
- [ test "reader" ["-r", "t2t", "-w", "native", "-s"]
- "txt2tags.t2t" "txt2tags.native" ]
- , testGroup "epub" [
- test "features" ["-r", "epub", "-w", "native"]
- "epub/features.epub" "epub/features.native"
- , test "wasteland" ["-r", "epub", "-w", "native"]
- "epub/wasteland.epub" "epub/wasteland.native"
- , test "formatting" ["-r", "epub", "-w", "native"]
- "epub/formatting.epub" "epub/formatting.native"
- ]
- , testGroup "twiki"
- [ test "reader" ["-r", "twiki", "-w", "native", "-s"]
- "twiki-reader.twiki" "twiki-reader.native" ]
- , testGroup "other writers" $ map (\f -> testGroup f $ writerTests f)
- [ "opendocument" , "context" , "texinfo", "icml", "tei"
- , "man" , "plain" , "rtf", "org", "asciidoc", "zimwiki"
- ]
- , testGroup "writers-lang-and-dir"
- [ test "latex" ["-f", "native", "-t", "latex", "-s"]
- "writers-lang-and-dir.native" "writers-lang-and-dir.latex"
- , test "context" ["-f", "native", "-t", "context", "-s"]
- "writers-lang-and-dir.native" "writers-lang-and-dir.context"
- ]
- ]
-
--- makes sure file is fully closed after reading
-readFile' :: FilePath -> IO String
-readFile' f = do s <- readFileUTF8 f
- return $! (length s `seq` s)
-
-lhsWriterTests :: String -> [Test]
-lhsWriterTests format
- = [ t "lhs to normal" format
- , t "lhs to lhs" (format ++ "+lhs")
- ]
- where
- t n f = test n ["--wrap=preserve", "-r", "native", "-s", "-w", f]
- "lhs-test.native" ("lhs-test" <.> f)
-
-lhsReaderTest :: String -> Test
-lhsReaderTest format =
- testWithNormalize normalizer "lhs" ["-r", format, "-w", "native"]
- ("lhs-test" <.> format) norm
- where normalizer = writeNative def . normalize . handleError . readNative
- norm = if format == "markdown+lhs"
- then "lhs-test-markdown.native"
- else "lhs-test.native"
-
-writerTests :: String -> [Test]
-writerTests format
- = [ test "basic" (opts ++ ["-s"]) "testsuite.native" ("writer" <.> format)
- , test "tables" opts "tables.native" ("tables" <.> format)
- ]
- where
- opts = ["-r", "native", "-w", format, "--columns=78",
- "--variable", "pandoc-version="]
-
-s5WriterTest :: String -> [String] -> String -> Test
-s5WriterTest modifier opts format
- = test (format ++ " writer (" ++ modifier ++ ")")
- (["-r", "native", "-w", format] ++ opts)
- "s5.native" ("s5-" ++ modifier <.> "html")
-
-fb2WriterTest :: String -> [String] -> String -> String -> Test
-fb2WriterTest title opts inputfile normfile =
- testWithNormalize (ignoreBinary . formatXML)
- title (["-t", "fb2"]++opts) inputfile normfile
- where
- formatXML xml = splitTags $ zip xml (drop 1 xml)
- splitTags [] = []
- splitTags [end] = fst end : snd end : []
- splitTags (('>','<'):rest) = ">\n" ++ splitTags rest
- splitTags ((c,_):rest) = c : splitTags rest
- ignoreBinary = unlines . filter (not . startsWith "<binary ") . lines
- startsWith tag str = all (uncurry (==)) $ zip tag str
-
--- | Run a test without normalize function, return True if test passed.
-test :: String -- ^ Title of test
- -> [String] -- ^ Options to pass to pandoc
- -> String -- ^ Input filepath
- -> FilePath -- ^ Norm (for test results) filepath
- -> Test
-test = testWithNormalize id
-
--- | Run a test with normalize function, return True if test passed.
-testWithNormalize :: (String -> String) -- ^ Normalize function for output
- -> String -- ^ Title of test
- -> [String] -- ^ Options to pass to pandoc
- -> String -- ^ Input filepath
- -> FilePath -- ^ Norm (for test results) filepath
- -> Test
-testWithNormalize normalizer testname opts inp norm = testCase testname $ do
- -- find pandoc executable relative to test-pandoc
- -- First, try in same directory (e.g. if both in ~/.cabal/bin)
- -- Second, try ../pandoc (e.g. if in dist/XXX/build/test-pandoc)
- pandocPath <- do
- testExePath <- getExecutablePath
- let testExeDir = takeDirectory testExePath
- found <- doesFileExist (testExeDir </> "pandoc")
- return $ if found
- then testExeDir </> "pandoc"
- else case splitDirectories testExeDir of
- [] -> error "test-pandoc: empty testExeDir"
- xs -> joinPath (init xs) </> "pandoc" </> "pandoc"
- (outputPath, hOut) <- openTempFile "" "pandoc-test"
- let inpPath = inp
- let normPath = norm
- let options = ["--data-dir", ".." </> "data"] ++ [inpPath] ++ opts
- let cmd = pandocPath ++ " " ++ unwords options
- let findDynlibDir [] = Nothing
- findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build"
- findDynlibDir (_:xs) = findDynlibDir xs
- let mbDynlibDir = findDynlibDir (reverse $ splitDirectories pandocPath)
- let dynlibEnv = case mbDynlibDir of
- Nothing -> []
- Just d -> [("DYLD_LIBRARY_PATH", d),
- ("LD_LIBRARY_PATH", d)]
- let env = dynlibEnv ++ [("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./")]
- ph <- runProcess pandocPath options Nothing
- (Just env) Nothing (Just hOut) (Just stderr)
- ec <- waitForProcess ph
- result <- if ec == ExitSuccess
- then do
- -- filter \r so the tests will work on Windows machines
- outputContents <- readFile' outputPath >>=
- return . filter (/='\r') . normalizer
- normContents <- readFile' normPath >>=
- return . filter (/='\r') . normalizer
- if outputContents == normContents
- then return TestPassed
- else return
- $ TestFailed cmd normPath
- $ getDiff (lines outputContents) (lines normContents)
- else return $ TestError ec
- removeFile outputPath
- assertBool (show result) (result == TestPassed)
diff --git a/tests/Tests/Readers/Docx.hs b/tests/Tests/Readers/Docx.hs
deleted file mode 100644
index 0d31eb629..000000000
--- a/tests/Tests/Readers/Docx.hs
+++ /dev/null
@@ -1,343 +0,0 @@
-module Tests.Readers.Docx (tests) where
-
-import Text.Pandoc.Options
-import Text.Pandoc.Readers.Native
-import Text.Pandoc.Definition
-import Tests.Helpers
-import Test.Framework
-import Test.HUnit (assertBool)
-import Test.Framework.Providers.HUnit
-import qualified Data.ByteString.Lazy as B
-import Text.Pandoc.Readers.Docx
-import Text.Pandoc.Writers.Native (writeNative)
-import qualified Data.Map as M
-import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
-import Codec.Archive.Zip
-import Text.Pandoc.Error
-
--- We define a wrapper around pandoc that doesn't normalize in the
--- tests. Since we do our own normalization, we want to make sure
--- we're doing it right.
-
-data NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc}
- deriving Show
-
-noNorm :: Pandoc -> NoNormPandoc
-noNorm = NoNormPandoc
-
-instance ToString NoNormPandoc where
- toString d = writeNative def{ writerTemplate = s } $ toPandoc d
- where s = case d of
- NoNormPandoc (Pandoc (Meta m) _)
- | M.null m -> Nothing
- | otherwise -> Just "" -- need this to get meta output
-
-instance ToPandoc NoNormPandoc where
- toPandoc = unNoNorm
-
-compareOutput :: ReaderOptions
- -> FilePath
- -> FilePath
- -> IO (NoNormPandoc, NoNormPandoc)
-compareOutput opts docxFile nativeFile = do
- df <- B.readFile docxFile
- nf <- Prelude.readFile nativeFile
- let (p, _) = handleError $ readDocx opts df
- return $ (noNorm p, noNorm (handleError $ readNative nf))
-
-testCompareWithOptsIO :: ReaderOptions -> String -> FilePath -> FilePath -> IO Test
-testCompareWithOptsIO opts name docxFile nativeFile = do
- (dp, np) <- compareOutput opts docxFile nativeFile
- return $ test id name (dp, np)
-
-testCompareWithOpts :: ReaderOptions -> String -> FilePath -> FilePath -> Test
-testCompareWithOpts opts name docxFile nativeFile =
- buildTest $ testCompareWithOptsIO opts name docxFile nativeFile
-
-testCompare :: String -> FilePath -> FilePath -> Test
-testCompare = testCompareWithOpts def
-
-testForWarningsWithOptsIO :: ReaderOptions -> String -> FilePath -> [String] -> IO Test
-testForWarningsWithOptsIO opts name docxFile expected = do
- df <- B.readFile docxFile
- let (_, _, warns) = handleError $ readDocxWithWarnings opts df
- return $ test id name (unlines warns, unlines expected)
-
-testForWarningsWithOpts :: ReaderOptions -> String -> FilePath -> [String] -> Test
-testForWarningsWithOpts opts name docxFile expected =
- buildTest $ testForWarningsWithOptsIO opts name docxFile expected
-
--- testForWarnings :: String -> FilePath -> [String] -> Test
--- testForWarnings = testForWarningsWithOpts def
-
-getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString)
-getMedia archivePath mediaPath = do
- zf <- B.readFile archivePath >>= return . toArchive
- return $ findEntryByPath ("word/" ++ mediaPath) zf >>= (Just . fromEntry)
-
-compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool
-compareMediaPathIO mediaPath mediaBag docxPath = do
- docxMedia <- getMedia docxPath mediaPath
- let mbBS = case lookupMedia mediaPath mediaBag of
- Just (_, bs) -> bs
- Nothing -> error ("couldn't find " ++
- mediaPath ++
- " in media bag")
- docxBS = case docxMedia of
- Just bs -> bs
- Nothing -> error ("couldn't find " ++
- mediaPath ++
- " in media bag")
- return $ mbBS == docxBS
-
-compareMediaBagIO :: FilePath -> IO Bool
-compareMediaBagIO docxFile = do
- df <- B.readFile docxFile
- let (_, mb) = handleError $ readDocx def df
- bools <- mapM
- (\(fp, _, _) -> compareMediaPathIO fp mb docxFile)
- (mediaDirectory mb)
- return $ and bools
-
-testMediaBagIO :: String -> FilePath -> IO Test
-testMediaBagIO name docxFile = do
- outcome <- compareMediaBagIO docxFile
- return $ testCase name (assertBool
- ("Media didn't match media bag in file " ++ docxFile)
- outcome)
-
-testMediaBag :: String -> FilePath -> Test
-testMediaBag name docxFile = buildTest $ testMediaBagIO name docxFile
-
-tests :: [Test]
-tests = [ testGroup "inlines"
- [ testCompare
- "font formatting"
- "docx/inline_formatting.docx"
- "docx/inline_formatting.native"
- , testCompare
- "font formatting with character styles"
- "docx/char_styles.docx"
- "docx/char_styles.native"
- , testCompare
- "hyperlinks"
- "docx/links.docx"
- "docx/links.native"
- , testCompare
- "normalizing adjacent hyperlinks"
- "docx/adjacent_links.docx"
- "docx/adjacent_links.native"
- , testCompare
- "inline image"
- "docx/image.docx"
- "docx/image_no_embed.native"
- , testCompare
- "VML image"
- "docx/image_vml.docx"
- "docx/image_vml.native"
- , testCompare
- "inline image in links"
- "docx/inline_images.docx"
- "docx/inline_images.native"
- , testCompare
- "handling unicode input"
- "docx/unicode.docx"
- "docx/unicode.native"
- , testCompare
- "literal tabs"
- "docx/tabs.docx"
- "docx/tabs.native"
- , testCompare
- "special punctuation"
- "docx/special_punctuation.docx"
- "docx/special_punctuation.native"
- , testCompare
- "normalizing inlines"
- "docx/normalize.docx"
- "docx/normalize.native"
- , testCompare
- "normalizing inlines deep inside blocks"
- "docx/deep_normalize.docx"
- "docx/deep_normalize.native"
- , testCompare
- "move trailing spaces outside of formatting"
- "docx/trailing_spaces_in_formatting.docx"
- "docx/trailing_spaces_in_formatting.native"
- , testCompare
- "inline code (with VerbatimChar style)"
- "docx/inline_code.docx"
- "docx/inline_code.native"
- , testCompare
- "inline code in subscript and superscript"
- "docx/verbatim_subsuper.docx"
- "docx/verbatim_subsuper.native"
- ]
- , testGroup "blocks"
- [ testCompare
- "headers"
- "docx/headers.docx"
- "docx/headers.native"
- , testCompare
- "headers already having auto identifiers"
- "docx/already_auto_ident.docx"
- "docx/already_auto_ident.native"
- , testCompare
- "nested anchor spans in header"
- "docx/nested_anchors_in_header.docx"
- "docx/nested_anchors_in_header.native"
- , testCompare
- "single numbered item not made into list"
- "docx/numbered_header.docx"
- "docx/numbered_header.native"
- , testCompare
- "enumerated headers not made into numbered list"
- "docx/enumerated_headings.docx"
- "docx/enumerated_headings.native"
- , testCompare
- "i18n blocks (headers and blockquotes)"
- "docx/i18n_blocks.docx"
- "docx/i18n_blocks.native"
- , testCompare
- "lists"
- "docx/lists.docx"
- "docx/lists.native"
- , testCompare
- "definition lists"
- "docx/definition_list.docx"
- "docx/definition_list.native"
- , testCompare
- "custom defined lists in styles"
- "docx/german_styled_lists.docx"
- "docx/german_styled_lists.native"
- , testCompare
- "user deletes bullet after list item (=> part of item par)"
- "docx/dummy_item_after_list_item.docx"
- "docx/dummy_item_after_list_item.native"
- , testCompare
- "user deletes bullet after par (=> new par)"
- "docx/dummy_item_after_paragraph.docx"
- "docx/dummy_item_after_paragraph.native"
- , testCompare
- "footnotes and endnotes"
- "docx/notes.docx"
- "docx/notes.native"
- , testCompare
- "links in footnotes and endnotes"
- "docx/link_in_notes.docx"
- "docx/link_in_notes.native"
- , testCompare
- "blockquotes (parsing indent as blockquote)"
- "docx/block_quotes.docx"
- "docx/block_quotes_parse_indent.native"
- , testCompare
- "hanging indents"
- "docx/hanging_indent.docx"
- "docx/hanging_indent.native"
- , testCompare
- "tables"
- "docx/tables.docx"
- "docx/tables.native"
- , testCompare
- "tables with lists in cells"
- "docx/table_with_list_cell.docx"
- "docx/table_with_list_cell.native"
- , testCompare
- "tables with one row"
- "docx/table_one_row.docx"
- "docx/table_one_row.native"
- , testCompare
- "code block"
- "docx/codeblock.docx"
- "docx/codeblock.native"
- , testCompare
- "dropcap paragraphs"
- "docx/drop_cap.docx"
- "docx/drop_cap.native"
- ]
- , testGroup "track changes"
- [ testCompare
- "insertion (default)"
- "docx/track_changes_insertion.docx"
- "docx/track_changes_insertion_accept.native"
- , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
- "insert insertion (accept)"
- "docx/track_changes_insertion.docx"
- "docx/track_changes_insertion_accept.native"
- , testCompareWithOpts def{readerTrackChanges=RejectChanges}
- "remove insertion (reject)"
- "docx/track_changes_insertion.docx"
- "docx/track_changes_insertion_reject.native"
- , testCompare
- "deletion (default)"
- "docx/track_changes_deletion.docx"
- "docx/track_changes_deletion_accept.native"
- , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
- "remove deletion (accept)"
- "docx/track_changes_deletion.docx"
- "docx/track_changes_deletion_accept.native"
- , testCompareWithOpts def{readerTrackChanges=RejectChanges}
- "insert deletion (reject)"
- "docx/track_changes_deletion.docx"
- "docx/track_changes_deletion_reject.native"
- , testCompareWithOpts def{readerTrackChanges=AllChanges}
- "keep insertion (all)"
- "docx/track_changes_deletion.docx"
- "docx/track_changes_deletion_all.native"
- , testCompareWithOpts def{readerTrackChanges=AllChanges}
- "keep deletion (all)"
- "docx/track_changes_deletion.docx"
- "docx/track_changes_deletion_all.native"
- , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
- "move text (accept)"
- "docx/track_changes_move.docx"
- "docx/track_changes_move_accept.native"
- , testCompareWithOpts def{readerTrackChanges=RejectChanges}
- "move text (reject)"
- "docx/track_changes_move.docx"
- "docx/track_changes_move_reject.native"
- , testCompareWithOpts def{readerTrackChanges=AllChanges}
- "move text (all)"
- "docx/track_changes_move.docx"
- "docx/track_changes_move_all.native"
- , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
- "comments (accept -- no comments)"
- "docx/comments.docx"
- "docx/comments_no_comments.native"
- , testCompareWithOpts def{readerTrackChanges=RejectChanges}
- "comments (reject -- comments)"
- "docx/comments.docx"
- "docx/comments_no_comments.native"
- , testCompareWithOpts def{readerTrackChanges=AllChanges}
- "comments (all comments)"
- "docx/comments.docx"
- "docx/comments.native"
- , testForWarningsWithOpts def{readerTrackChanges=AcceptChanges}
- "comment warnings (accept -- no warnings)"
- "docx/comments_warning.docx"
- []
- , testForWarningsWithOpts def{readerTrackChanges=RejectChanges}
- "comment warnings (reject -- no warnings)"
- "docx/comments_warning.docx"
- []
- , testForWarningsWithOpts def{readerTrackChanges=AllChanges}
- "comment warnings (all)"
- "docx/comments_warning.docx"
- ["Docx comment 1 will not retain formatting"]
- ]
- , testGroup "media"
- [ testMediaBag
- "image extraction"
- "docx/image.docx"
- ]
- , testGroup "metadata"
- [ testCompareWithOpts def{readerStandalone=True}
- "metadata fields"
- "docx/metadata.docx"
- "docx/metadata.native"
- , testCompareWithOpts def{readerStandalone=True}
- "stop recording metadata with normal text"
- "docx/metadata_after_normal.docx"
- "docx/metadata_after_normal.native"
- ]
-
- ]
diff --git a/tests/Tests/Readers/EPUB.hs b/tests/Tests/Readers/EPUB.hs
deleted file mode 100644
index 2ad36eba6..000000000
--- a/tests/Tests/Readers/EPUB.hs
+++ /dev/null
@@ -1,37 +0,0 @@
-module Tests.Readers.EPUB (tests) where
-
-import Text.Pandoc.Options
-import Test.Framework
-import Test.HUnit (assertBool)
-import Test.Framework.Providers.HUnit
-import qualified Data.ByteString.Lazy as BL
-import Text.Pandoc.Readers.EPUB
-import Text.Pandoc.MediaBag (MediaBag, mediaDirectory)
-import Text.Pandoc.Error
-
-getMediaBag :: FilePath -> IO MediaBag
-getMediaBag fp = snd . handleError . readEPUB def <$> BL.readFile fp
-
-testMediaBag :: FilePath -> [(String, String, Int)] -> IO ()
-testMediaBag fp bag = do
- actBag <- (mediaDirectory <$> getMediaBag fp)
- assertBool (show "MediaBag did not match:\nExpected: "
- ++ show bag
- ++ "\nActual: "
- ++ show actBag)
- (actBag == bag)
-
-featuresBag :: [(String, String, Int)]
-featuresBag = [("img/check.gif","image/gif",1340)
- ,("img/check.jpg","image/jpeg",2661)
- ,("img/check.png","image/png",2815)
- ,("img/multiscripts_and_greek_alphabet.png","image/png",10060)
- ]
-
-tests :: [Test]
-tests =
- [ testGroup "EPUB Mediabag"
- [ testCase "features bag"
- (testMediaBag "epub/img.epub" featuresBag)
- ]
- ]
diff --git a/tests/Tests/Readers/HTML.hs b/tests/Tests/Readers/HTML.hs
deleted file mode 100644
index 1426a8bea..000000000
--- a/tests/Tests/Readers/HTML.hs
+++ /dev/null
@@ -1,33 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Readers.HTML (tests) where
-
-import Text.Pandoc.Definition
-import Test.Framework
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-import Text.Pandoc.Builder
-import Text.Pandoc
-
-html :: String -> Pandoc
-html = handleError . readHtml def
-
-tests :: [Test]
-tests = [ testGroup "base tag"
- [ test html "simple" $
- "<head><base href=\"http://www.w3schools.com/images/foo\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
- plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
- , test html "slash at end of base" $
- "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
- plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
- , test html "slash at beginning of href" $
- "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"/stickman.gif\" alt=\"Stickman\"></head>" =?>
- plain (image "http://www.w3schools.com/stickman.gif" "" (text "Stickman"))
- , test html "absolute URL" $
- "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"http://example.com/stickman.gif\" alt=\"Stickman\"></head>" =?>
- plain (image "http://example.com/stickman.gif" "" (text "Stickman"))
- ]
- , testGroup "anchors"
- [ test html "anchor without href" $ "<a name=\"anchor\"/>" =?>
- plain (spanWith ("anchor",[],[]) mempty)
- ]
- ]
diff --git a/tests/Tests/Readers/LaTeX.hs b/tests/Tests/Readers/LaTeX.hs
deleted file mode 100644
index 27e775724..000000000
--- a/tests/Tests/Readers/LaTeX.hs
+++ /dev/null
@@ -1,225 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Readers.LaTeX (tests) where
-
-import Text.Pandoc.Definition
-import Test.Framework
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-import Text.Pandoc.Builder
-import Text.Pandoc
-
-latex :: String -> Pandoc
-latex = handleError . readLaTeX def
-
-infix 4 =:
-(=:) :: ToString c
- => String -> (String, c) -> Test
-(=:) = test latex
-
-simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks
-simpleTable' aligns = table "" (zip aligns (repeat 0.0))
- (map (const mempty) aligns)
-
-tests :: [Test]
-tests = [ testGroup "basic"
- [ "simple" =:
- "word" =?> para "word"
- , "space" =:
- "some text" =?> para "some text"
- , "emphasized" =:
- "\\emph{emphasized}" =?> para (emph "emphasized")
- ]
-
- , testGroup "headers"
- [ "level 1" =:
- "\\section{header}" =?> headerWith ("header",[],[]) 1 "header"
- , "level 2" =:
- "\\subsection{header}" =?> headerWith ("header",[],[]) 2 "header"
- , "level 3" =:
- "\\subsubsection{header}" =?> headerWith ("header",[],[]) 3 "header"
- , "emph" =:
- "\\section{text \\emph{emph}}" =?>
- headerWith ("text-emph",[],[]) 1 ("text" <> space <> emph "emph")
- , "link" =:
- "\\section{text \\href{/url}{link}}" =?>
- headerWith ("text-link",[],[]) 1 ("text" <> space <> link "/url" "" "link")
- ]
-
- , testGroup "math"
- [ "escaped $" =:
- "$x=\\$4$" =?> para (math "x=\\$4")
- ]
-
- , testGroup "space and comments"
- [ "blank lines + space at beginning" =:
- "\n \n hi" =?> para "hi"
- , "blank lines + space + comments" =:
- "% my comment\n\n \n % another\n\nhi" =?> para "hi"
- , "comment in paragraph" =:
- "hi % this is a comment\nthere\n" =?> para "hi there"
- ]
-
- , testGroup "code blocks"
- [ "identifier" =:
- "\\begin{lstlisting}[label=test]\\end{lstlisting}" =?> codeBlockWith ("test", [], [("label","test")]) ""
- , "no identifier" =:
- "\\begin{lstlisting}\\end{lstlisting}" =?> codeBlock ""
- ]
-
- , testGroup "tables"
- [ "Single cell table" =:
- "\\begin{tabular}{|l|}Test\\\\\\end{tabular}" =?>
- simpleTable' [AlignLeft] [[plain "Test"]]
- , "Multi cell table" =:
- "\\begin{tabular}{|rl|}One & Two\\\\ \\end{tabular}" =?>
- simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
- , "Multi line table" =:
- unlines [ "\\begin{tabular}{|c|}"
- , "One\\\\"
- , "Two\\\\"
- , "Three\\\\"
- , "\\end{tabular}" ] =?>
- simpleTable' [AlignCenter]
- [[plain "One"], [plain "Two"], [plain "Three"]]
- , "Empty table" =:
- "\\begin{tabular}{}\\end{tabular}" =?>
- simpleTable' [] []
- , "Table with fixed column width" =:
- "\\begin{tabular}{|p{5cm}r|}One & Two\\\\ \\end{tabular}" =?>
- simpleTable' [AlignLeft,AlignRight] [[plain "One", plain "Two"]]
- , "Table with empty column separators" =:
- "\\begin{tabular}{@{}r@{}l}One & Two\\\\ \\end{tabular}" =?>
- simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
- , "Table with custom column separators" =:
- unlines [ "\\begin{tabular}{@{($\\to$)}r@{\\hspace{2cm}}l}"
- , "One&Two\\\\"
- , "\\end{tabular}" ] =?>
- simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
- , "Table with vertical alignment argument" =:
- "\\begin{tabular}[t]{r|r}One & Two\\\\ \\end{tabular}" =?>
- simpleTable' [AlignRight,AlignRight] [[plain "One", plain "Two"]]
- ]
-
- , testGroup "citations"
- [ natbibCitations
- , biblatexCitations
- ]
-
- , let hex = ['0'..'9']++['a'..'f'] in
- testGroup "Character Escapes"
- [ "Two-character escapes" =:
- concat ["^^"++[i,j] | i <- hex, j <- hex] =?>
- para (str ['\0'..'\255'])
- , "One-character escapes" =:
- concat ["^^"++[i] | i <- hex] =?>
- para (str $ ['p'..'y']++['!'..'&'])
- ]
- ]
-
-baseCitation :: Citation
-baseCitation = Citation{ citationId = "item1"
- , citationPrefix = []
- , citationSuffix = []
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
-
-rt :: String -> Inlines
-rt = rawInline "latex"
-
-natbibCitations :: Test
-natbibCitations = testGroup "natbib"
- [ "citet" =: "\\citet{item1}"
- =?> para (cite [baseCitation] (rt "\\citet{item1}"))
- , "suffix" =: "\\citet[p.~30]{item1}"
- =?> para
- (cite [baseCitation{ citationSuffix = toList $ text "p.\160\&30" }] (rt "\\citet[p.~30]{item1}"))
- , "suffix long" =: "\\citet[p.~30, with suffix]{item1}"
- =?> para (cite [baseCitation{ citationSuffix =
- toList $ text "p.\160\&30, with suffix" }] (rt "\\citet[p.~30, with suffix]{item1}"))
- , "multiple" =: "\\citeauthor{item1} \\citetext{\\citeyear{item1}; \\citeyear[p.~30]{item2}; \\citealp[see also][]{item3}}"
- =?> para (cite [baseCitation{ citationMode = AuthorInText }
- ,baseCitation{ citationMode = SuppressAuthor
- , citationSuffix = [Str "p.\160\&30"]
- , citationId = "item2" }
- ,baseCitation{ citationId = "item3"
- , citationPrefix = [Str "see",Space,Str "also"]
- , citationMode = NormalCitation }
- ] (rt "\\citetext{\\citeyear{item1}; \\citeyear[p.~30]{item2}; \\citealp[see also][]{item3}}"))
- , "group" =: "\\citetext{\\citealp[see][p.~34--35]{item1}; \\citealp[also][chap. 3]{item3}}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation
- , citationPrefix = [Str "see"]
- , citationSuffix = [Str "p.\160\&34\8211\&35"] }
- ,baseCitation{ citationMode = NormalCitation
- , citationId = "item3"
- , citationPrefix = [Str "also"]
- , citationSuffix = [Str "chap.",Space,Str "3"] }
- ] (rt "\\citetext{\\citealp[see][p.~34--35]{item1}; \\citealp[also][chap. 3]{item3}}"))
- , "suffix and locator" =: "\\citep[pp.~33, 35--37, and nowhere else]{item1}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation
- , 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}"))
- , "suffix only" =: "\\citep[and nowhere else]{item1}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation
- , citationSuffix = toList $ text "and nowhere else" }] (rt "\\citep[and nowhere else]{item1}"))
- , "no author" =: "\\citeyearpar{item1}, and now Doe with a locator \\citeyearpar[p.~44]{item2}"
- =?> para (cite [baseCitation{ citationMode = SuppressAuthor }] (rt "\\citeyearpar{item1}") <>
- text ", and now Doe with a locator " <>
- cite [baseCitation{ citationMode = SuppressAuthor
- , citationSuffix = [Str "p.\160\&44"]
- , citationId = "item2" }] (rt "\\citeyearpar[p.~44]{item2}"))
- , "markup" =: "\\citep[\\emph{see}][p. \\textbf{32}]{item1}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation
- , citationPrefix = [Emph [Str "see"]]
- , citationSuffix = [Str "p.",Space,
- Strong [Str "32"]] }] (rt "\\citep[\\emph{see}][p. \\textbf{32}]{item1}"))
- ]
-
-biblatexCitations :: Test
-biblatexCitations = testGroup "biblatex"
- [ "textcite" =: "\\textcite{item1}"
- =?> para (cite [baseCitation] (rt "\\textcite{item1}"))
- , "suffix" =: "\\textcite[p.~30]{item1}"
- =?> para
- (cite [baseCitation{ citationSuffix = toList $ text "p.\160\&30" }] (rt "\\textcite[p.~30]{item1}"))
- , "suffix long" =: "\\textcite[p.~30, with suffix]{item1}"
- =?> para (cite [baseCitation{ citationSuffix =
- toList $ text "p.\160\&30, with suffix" }] (rt "\\textcite[p.~30, with suffix]{item1}"))
- , "multiple" =: "\\textcites{item1}[p.~30]{item2}[see also][]{item3}"
- =?> para (cite [baseCitation{ citationMode = AuthorInText }
- ,baseCitation{ citationMode = NormalCitation
- , citationSuffix = [Str "p.\160\&30"]
- , citationId = "item2" }
- ,baseCitation{ citationId = "item3"
- , citationPrefix = [Str "see",Space,Str "also"]
- , citationMode = NormalCitation }
- ] (rt "\\textcites{item1}[p.~30]{item2}[see also][]{item3}"))
- , "group" =: "\\autocites[see][p.~34--35]{item1}[also][chap. 3]{item3}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation
- , citationPrefix = [Str "see"]
- , citationSuffix = [Str "p.\160\&34\8211\&35"] }
- ,baseCitation{ citationMode = NormalCitation
- , citationId = "item3"
- , citationPrefix = [Str "also"]
- , citationSuffix = [Str "chap.",Space,Str "3"] }
- ] (rt "\\autocites[see][p.~34--35]{item1}[also][chap. 3]{item3}"))
- , "suffix and locator" =: "\\autocite[pp.~33, 35--37, and nowhere else]{item1}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation
- , 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}"))
- , "suffix only" =: "\\autocite[and nowhere else]{item1}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation
- , citationSuffix = toList $ text "and nowhere else" }] (rt "\\autocite[and nowhere else]{item1}"))
- , "no author" =: "\\autocite*{item1}, and now Doe with a locator \\autocite*[p.~44]{item2}"
- =?> para (cite [baseCitation{ citationMode = SuppressAuthor }] (rt "\\autocite*{item1}") <>
- text ", and now Doe with a locator " <>
- cite [baseCitation{ citationMode = SuppressAuthor
- , citationSuffix = [Str "p.\160\&44"]
- , citationId = "item2" }] (rt "\\autocite*[p.~44]{item2}"))
- , "markup" =: "\\autocite[\\emph{see}][p. \\textbf{32}]{item1}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation
- , citationPrefix = [Emph [Str "see"]]
- , citationSuffix = [Str "p.",Space,
- Strong [Str "32"]] }] (rt "\\autocite[\\emph{see}][p. \\textbf{32}]{item1}"))
- , "parencite" =: "\\parencite{item1}"
- =?> para (cite [baseCitation{ citationMode = NormalCitation }] (rt "\\parencite{item1}"))
- ]
diff --git a/tests/Tests/Readers/Markdown.hs b/tests/Tests/Readers/Markdown.hs
deleted file mode 100644
index 439307dc9..000000000
--- a/tests/Tests/Readers/Markdown.hs
+++ /dev/null
@@ -1,459 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Readers.Markdown (tests) where
-
-import Text.Pandoc.Definition
-import Test.Framework
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-import Text.Pandoc.Builder
-import qualified Data.Set as Set
-import Text.Pandoc
-
-markdown :: String -> Pandoc
-markdown = handleError . readMarkdown def
-
-markdownSmart :: String -> Pandoc
-markdownSmart = handleError . readMarkdown def { readerSmart = True }
-
-markdownCDL :: String -> Pandoc
-markdownCDL = handleError . readMarkdown def { readerExtensions = Set.insert
- Ext_compact_definition_lists $ readerExtensions def }
-
-markdownGH :: String -> Pandoc
-markdownGH = handleError . readMarkdown def { readerExtensions = githubMarkdownExtensions }
-
-infix 4 =:
-(=:) :: ToString c
- => String -> (String, c) -> Test
-(=:) = test markdown
-
-testBareLink :: (String, Inlines) -> Test
-testBareLink (inp, ils) =
- test (handleError . readMarkdown def{ readerExtensions =
- Set.fromList [Ext_autolink_bare_uris, Ext_raw_html] })
- inp (inp, doc $ para ils)
-
-autolink :: String -> Inlines
-autolink = autolinkWith nullAttr
-
-autolinkWith :: Attr -> String -> Inlines
-autolinkWith attr s = linkWith attr s "" (str s)
-
-bareLinkTests :: [(String, Inlines)]
-bareLinkTests =
- [ ("http://google.com is a search engine.",
- autolink "http://google.com" <> " is a search engine.")
- , ("<a href=\"http://foo.bar.baz\">http://foo.bar.baz</a>",
- rawInline "html" "<a href=\"http://foo.bar.baz\">" <>
- "http://foo.bar.baz" <> rawInline "html" "</a>")
- , ("Try this query: http://google.com?search=fish&time=hour.",
- "Try this query: " <> autolink "http://google.com?search=fish&time=hour" <> ".")
- , ("HTTPS://GOOGLE.COM,",
- autolink "HTTPS://GOOGLE.COM" <> ",")
- , ("http://el.wikipedia.org/wiki/Τεχνολογία,",
- autolink "http://el.wikipedia.org/wiki/Τεχνολογία" <> ",")
- , ("doi:10.1000/182,",
- autolink "doi:10.1000/182" <> ",")
- , ("git://github.com/foo/bar.git,",
- autolink "git://github.com/foo/bar.git" <> ",")
- , ("file:///Users/joe/joe.txt, and",
- autolink "file:///Users/joe/joe.txt" <> ", and")
- , ("mailto:someone@somedomain.com.",
- autolink "mailto:someone@somedomain.com" <> ".")
- , ("Use http: this is not a link!",
- "Use http: this is not a link!")
- , ("(http://google.com).",
- "(" <> autolink "http://google.com" <> ").")
- , ("http://en.wikipedia.org/wiki/Sprite_(computer_graphics)",
- autolink "http://en.wikipedia.org/wiki/Sprite_(computer_graphics)")
- , ("http://en.wikipedia.org/wiki/Sprite_[computer_graphics]",
- link "http://en.wikipedia.org/wiki/Sprite_%5Bcomputer_graphics%5D" ""
- (str "http://en.wikipedia.org/wiki/Sprite_[computer_graphics]"))
- , ("http://en.wikipedia.org/wiki/Sprite_{computer_graphics}",
- link "http://en.wikipedia.org/wiki/Sprite_%7Bcomputer_graphics%7D" ""
- (str "http://en.wikipedia.org/wiki/Sprite_{computer_graphics}"))
- , ("http://example.com/Notification_Center-GitHub-20101108-140050.jpg",
- autolink "http://example.com/Notification_Center-GitHub-20101108-140050.jpg")
- , ("https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20",
- autolink "https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20")
- , ("http://www.rubyonrails.com",
- autolink "http://www.rubyonrails.com")
- , ("http://www.rubyonrails.com:80",
- autolink "http://www.rubyonrails.com:80")
- , ("http://www.rubyonrails.com/~minam",
- autolink "http://www.rubyonrails.com/~minam")
- , ("https://www.rubyonrails.com/~minam",
- autolink "https://www.rubyonrails.com/~minam")
- , ("http://www.rubyonrails.com/~minam/url%20with%20spaces",
- autolink "http://www.rubyonrails.com/~minam/url%20with%20spaces")
- , ("http://www.rubyonrails.com/foo.cgi?something=here",
- autolink "http://www.rubyonrails.com/foo.cgi?something=here")
- , ("http://www.rubyonrails.com/foo.cgi?something=here&and=here",
- autolink "http://www.rubyonrails.com/foo.cgi?something=here&and=here")
- , ("http://www.rubyonrails.com/contact;new",
- autolink "http://www.rubyonrails.com/contact;new")
- , ("http://www.rubyonrails.com/contact;new%20with%20spaces",
- autolink "http://www.rubyonrails.com/contact;new%20with%20spaces")
- , ("http://www.rubyonrails.com/contact;new?with=query&string=params",
- autolink "http://www.rubyonrails.com/contact;new?with=query&string=params")
- , ("http://www.rubyonrails.com/~minam/contact;new?with=query&string=params",
- autolink "http://www.rubyonrails.com/~minam/contact;new?with=query&string=params")
- , ("http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007",
- autolink "http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007")
- , ("http://www.mail-archive.com/rails@lists.rubyonrails.org/",
- autolink "http://www.mail-archive.com/rails@lists.rubyonrails.org/")
- , ("http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1",
- autolink "http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1")
- , ("http://en.wikipedia.org/wiki/Texas_hold%27em",
- autolink "http://en.wikipedia.org/wiki/Texas_hold%27em")
- , ("https://www.google.com/doku.php?id=gps:resource:scs:start",
- autolink "https://www.google.com/doku.php?id=gps:resource:scs:start")
- , ("http://www.rubyonrails.com",
- autolink "http://www.rubyonrails.com")
- , ("http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281",
- autolink "http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281")
- , ("http://foo.example.com/controller/action?parm=value&p2=v2#anchor123",
- autolink "http://foo.example.com/controller/action?parm=value&p2=v2#anchor123")
- , ("http://foo.example.com:3000/controller/action",
- autolink "http://foo.example.com:3000/controller/action")
- , ("http://foo.example.com:3000/controller/action+pack",
- autolink "http://foo.example.com:3000/controller/action+pack")
- , ("http://business.timesonline.co.uk/article/0,,9065-2473189,00.html",
- autolink "http://business.timesonline.co.uk/article/0,,9065-2473189,00.html")
- , ("http://www.mail-archive.com/ruby-talk@ruby-lang.org/",
- autolink "http://www.mail-archive.com/ruby-talk@ruby-lang.org/")
- , ("https://example.org/?anchor=lala-",
- autolink "https://example.org/?anchor=lala-")
- , ("https://example.org/?anchor=-lala",
- autolink "https://example.org/?anchor=-lala")
- ]
-
-{-
-p_markdown_round_trip :: Block -> Bool
-p_markdown_round_trip b = matches d' d''
- where d' = normalize $ Pandoc (Meta [] [] []) [b]
- d'' = normalize
- $ readMarkdown def { readerSmart = True }
- $ writeMarkdown def d'
- matches (Pandoc _ [Plain []]) (Pandoc _ []) = True
- matches (Pandoc _ [Para []]) (Pandoc _ []) = True
- matches (Pandoc _ [Plain xs]) (Pandoc _ [Para xs']) = xs == xs'
- matches x y = x == y
--}
-
-tests :: [Test]
-tests = [ testGroup "inline code"
- [ "with attribute" =:
- "`document.write(\"Hello\");`{.javascript}"
- =?> para
- (codeWith ("",["javascript"],[]) "document.write(\"Hello\");")
- , "with attribute space" =:
- "`*` {.haskell .special x=\"7\"}"
- =?> para (code "*" <> space <> str "{.haskell" <> space <>
- str ".special" <> space <> str "x=\"7\"}")
- ]
- , testGroup "emph and strong"
- [ "two strongs in emph" =:
- "***a**b **c**d*" =?> para (emph (strong (str "a") <> str "b" <> space
- <> strong (str "c") <> str "d"))
- , "emph and strong emph alternating" =:
- "*xxx* ***xxx*** xxx\n*xxx* ***xxx*** xxx"
- =?> para (emph "xxx" <> space <> strong (emph "xxx") <>
- space <> "xxx" <> softbreak <>
- emph "xxx" <> space <> strong (emph "xxx") <>
- space <> "xxx")
- , "emph with spaced strong" =:
- "*x **xx** x*"
- =?> para (emph ("x" <> space <> strong "xx" <> space <> "x"))
- , "intraword underscore with opening underscore (#1121)" =:
- "_foot_ball_" =?> para (emph (text "foot_ball"))
- ]
- , testGroup "raw LaTeX"
- [ "in URL" =:
- "\\begin\n" =?> para (text "\\begin")
- ]
- , testGroup "raw HTML"
- [ "nesting (issue #1330)" =:
- "<del>test</del>" =?>
- rawBlock "html" "<del>" <> plain (str "test") <>
- rawBlock "html" "</del>"
- , "invalid tag (issue #1820" =:
- "</ div></.div>" =?>
- para (text "</ div></.div>")
- , "technically invalid comment" =:
- "<!-- pandoc --help -->" =?>
- rawBlock "html" "<!-- pandoc --help -->"
- , test markdownGH "issue 2469" $
- "<\n\na>" =?>
- para (text "<") <> para (text "a>")
- ]
- , testGroup "raw email addresses"
- [ test markdownGH "issue 2940" $
- "**@user**" =?>
- para (strong (text "@user"))
- ]
- , testGroup "emoji"
- [ test markdownGH "emoji symbols" $
- ":smile: and :+1:" =?> para (text "😄 and 👍")
- ]
- , "unbalanced brackets" =:
- "[[[[[[[[[[[[[[[hi" =?> para (text "[[[[[[[[[[[[[[[hi")
- , testGroup "backslash escapes"
- [ "in URL" =:
- "[hi](/there\\))"
- =?> para (link "/there)" "" "hi")
- , "in title" =:
- "[hi](/there \"a\\\"a\")"
- =?> para (link "/there" "a\"a" "hi")
- , "in reference link title" =:
- "[hi]\n\n[hi]: /there (a\\)a)"
- =?> para (link "/there" "a)a" "hi")
- , "in reference link URL" =:
- "[hi]\n\n[hi]: /there\\.0"
- =?> para (link "/there.0" "" "hi")
- ]
- , testGroup "bare URIs"
- (map testBareLink bareLinkTests)
- , testGroup "autolinks"
- [ "with unicode dash following" =:
- "<http://foo.bar>\8212" =?> para (autolink "http://foo.bar" <>
- str "\8212")
- , "a partial URL (#2277)" =:
- "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>" =?>
- para (text "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>")
- , "with some attributes" =:
- "<http://foo.bar>{#i .j .z k=v}" =?>
- para (autolinkWith ("i", ["j", "z"], [("k", "v")]) "http://foo.bar")
- , "with some attributes and spaces" =:
- "<http://foo.bar> {#i .j .z k=v}" =?>
- para (autolink "http://foo.bar" <> space <> text "{#i .j .z k=v}")
- ]
- , testGroup "links"
- [ "no autolink inside link" =:
- "[<https://example.org>](url)" =?>
- para (link "url" "" (text "<https://example.org>"))
- , "no inline link inside link" =:
- "[[a](url2)](url)" =?>
- para (link "url" "" (text "[a](url2)"))
- , "no bare URI inside link" =:
- "[https://example.org(](url)" =?>
- para (link "url" "" (text "https://example.org("))
- ]
- , testGroup "Headers"
- [ "blank line before header" =:
- "\n# Header\n"
- =?> headerWith ("header",[],[]) 1 "Header"
- , "bracketed text (#2062)" =:
- "# [hi]\n"
- =?> headerWith ("hi",[],[]) 1 "[hi]"
- , "ATX header without trailing #s" =:
- "# Foo bar\n\n" =?>
- headerWith ("foo-bar",[],[]) 1 "Foo bar"
- , "ATX header without trailing #s" =:
- "# Foo bar with # #" =?>
- headerWith ("foo-bar-with",[],[]) 1 "Foo bar with #"
- , "setext header" =:
- "Foo bar\n=\n\n Foo bar 2 \n=" =?>
- headerWith ("foo-bar",[],[]) 1 "Foo bar"
- <> headerWith ("foo-bar-2",[],[]) 1 "Foo bar 2"
- ]
- , testGroup "Implicit header references"
- [ "ATX header without trailing #s" =:
- "# Header\n[header]\n\n[header ]\n\n[ header]" =?>
- headerWith ("header",[],[]) 1 "Header"
- <> para (link "#header" "" (text "header"))
- <> para (link "#header" "" (text "header"))
- <> para (link "#header" "" (text "header"))
- , "ATX header with trailing #s" =:
- "# Foo bar #\n[foo bar]\n\n[foo bar ]\n\n[ foo bar]" =?>
- headerWith ("foo-bar",[],[]) 1 "Foo bar"
- <> para (link "#foo-bar" "" (text "foo bar"))
- <> para (link "#foo-bar" "" (text "foo bar"))
- <> para (link "#foo-bar" "" (text "foo bar"))
- , "setext header" =:
- " Header \n=\n\n[header]\n\n[header ]\n\n[ header]" =?>
- headerWith ("header",[],[]) 1 "Header"
- <> para (link "#header" "" (text "header"))
- <> para (link "#header" "" (text "header"))
- <> para (link "#header" "" (text "header"))
- ]
- , testGroup "smart punctuation"
- [ test markdownSmart "quote before ellipses"
- ("'...hi'"
- =?> para (singleQuoted "…hi"))
- , test markdownSmart "apostrophe before emph"
- ("D'oh! A l'*aide*!"
- =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
- , test markdownSmart "apostrophe in French"
- ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
- =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
- , test markdownSmart "apostrophe after math" $ -- issue #1909
- "The value of the $x$'s and the systems' condition." =?>
- para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.")
- ]
- , testGroup "footnotes"
- [ "indent followed by newline and flush-left text" =:
- "[^1]\n\n[^1]: my note\n\n \nnot in note\n"
- =?> para (note (para "my note")) <> para "not in note"
- , "indent followed by newline and indented text" =:
- "[^1]\n\n[^1]: my note\n \n in note\n"
- =?> para (note (para "my note" <> para "in note"))
- , "recursive note" =:
- "[^1]\n\n[^1]: See [^1]\n"
- =?> para (note (para "See [^1]"))
- ]
- , testGroup "lhs"
- [ test (handleError . readMarkdown def{ readerExtensions = Set.insert
- Ext_literate_haskell $ readerExtensions def })
- "inverse bird tracks and html" $
- "> a\n\n< b\n\n<div>\n"
- =?> codeBlockWith ("",["sourceCode","literate","haskell"],[]) "a"
- <>
- codeBlockWith ("",["sourceCode","haskell"],[]) "b"
- <>
- rawBlock "html" "<div>\n\n"
- ]
--- the round-trip properties frequently fail
--- , testGroup "round trip"
--- [ property "p_markdown_round_trip" p_markdown_round_trip
--- ]
- , testGroup "definition lists"
- [ "no blank space" =:
- "foo1\n : bar\n\nfoo2\n : bar2\n : bar3\n" =?>
- definitionList [ (text "foo1", [plain (text "bar")])
- , (text "foo2", [plain (text "bar2"),
- plain (text "bar3")])
- ]
- , "blank space before first def" =:
- "foo1\n\n : bar\n\nfoo2\n\n : bar2\n : bar3\n" =?>
- definitionList [ (text "foo1", [para (text "bar")])
- , (text "foo2", [para (text "bar2"),
- plain (text "bar3")])
- ]
- , "blank space before second def" =:
- "foo1\n : bar\n\nfoo2\n : bar2\n\n : bar3\n" =?>
- definitionList [ (text "foo1", [plain (text "bar")])
- , (text "foo2", [plain (text "bar2"),
- para (text "bar3")])
- ]
- , "laziness" =:
- "foo1\n : bar\nbaz\n : bar2\n" =?>
- definitionList [ (text "foo1", [plain (text "bar" <>
- softbreak <> text "baz"),
- plain (text "bar2")])
- ]
- , "no blank space before first of two paragraphs" =:
- "foo1\n : bar\n\n baz\n" =?>
- definitionList [ (text "foo1", [para (text "bar") <>
- para (text "baz")])
- ]
- , "first line not indented" =:
- "foo\n: bar\n" =?>
- definitionList [ (text "foo", [plain (text "bar")]) ]
- , "list in definition" =:
- "foo\n: - bar\n" =?>
- definitionList [ (text "foo", [bulletList [plain (text "bar")]]) ]
- , "in div" =:
- "<div>foo\n: - bar\n</div>" =?>
- divWith nullAttr (definitionList
- [ (text "foo", [bulletList [plain (text "bar")]]) ])
- ]
- , testGroup "+compact_definition_lists"
- [ test markdownCDL "basic compact list" $
- "foo1\n: bar\n baz\nfoo2\n: bar2\n" =?>
- definitionList [ (text "foo1", [plain (text "bar" <> softbreak <>
- text "baz")])
- , (text "foo2", [plain (text "bar2")])
- ]
- ]
- , testGroup "lists"
- [ "issue #1154" =:
- " - <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"
- =?> bulletList [divWith nullAttr (para $ text "first div breaks") <>
- rawBlock "html" "<button>" <>
- plain (text "if this button exists") <>
- rawBlock "html" "</button>" <>
- divWith nullAttr (para $ text "with this div too.")]
- , test markdownGH "issue #1636" $
- unlines [ "* a"
- , "* b"
- , "* c"
- , " * d" ]
- =?>
- bulletList [ plain "a"
- , plain "b"
- , plain "c" <> bulletList [plain "d"] ]
- ]
- , testGroup "entities"
- [ "character references" =:
- "&lang; &ouml;" =?> para (text "\10216 ö")
- , "numeric" =:
- "&#44;&#x44;&#X44;" =?> para (text ",DD")
- , "in link title" =:
- "[link](/url \"title &lang; &ouml; &#44;\")" =?>
- para (link "/url" "title \10216 ö ," (text "link"))
- ]
- , testGroup "citations"
- [ "simple" =:
- "@item1" =?> para (cite [
- Citation{ citationId = "item1"
- , citationPrefix = []
- , citationSuffix = []
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- ] "@item1")
- , "key starts with digit" =:
- "@1657:huyghens" =?> para (cite [
- Citation{ citationId = "1657:huyghens"
- , citationPrefix = []
- , citationSuffix = []
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- ] "@1657:huyghens")
- ]
- , let citation = cite [Citation "cita" [] [] AuthorInText 0 0] (str "@cita")
- in testGroup "footnote/link following citation" -- issue #2083
- [ "footnote" =:
- unlines [ "@cita[^note]"
- , ""
- , "[^note]: note" ] =?>
- para (
- citation <> note (para $ str "note")
- )
- , "normal link" =:
- "@cita [link](http://www.com)" =?>
- para (
- citation <> space <> link "http://www.com" "" (str "link")
- )
- , "reference link" =:
- unlines [ "@cita [link][link]"
- , ""
- , "[link]: http://www.com" ] =?>
- para (
- citation <> space <> link "http://www.com" "" (str "link")
- )
- , "short reference link" =:
- unlines [ "@cita [link]"
- , ""
- , "[link]: http://www.com" ] =?>
- para (
- citation <> space <> link "http://www.com" "" (str "link")
- )
- , "implicit header link" =:
- unlines [ "# Header"
- , "@cita [Header]" ] =?>
- headerWith ("header",[],[]) 1 (str "Header") <> para (
- citation <> space <> link "#header" "" (str "Header")
- )
- , "regular citation" =:
- "@cita [foo]" =?>
- para (
- cite [Citation "cita" [] [Str "foo"] AuthorInText 0 0]
- (str "@cita" <> space <> str "[foo]")
- )
- ]
- ]
diff --git a/tests/Tests/Readers/Odt.hs b/tests/Tests/Readers/Odt.hs
deleted file mode 100644
index 56711c76b..000000000
--- a/tests/Tests/Readers/Odt.hs
+++ /dev/null
@@ -1,166 +0,0 @@
-module Tests.Readers.Odt (tests) where
-
-import Control.Monad ( liftM )
-import Text.Pandoc.Options
-import Text.Pandoc.Readers.Native
-import Text.Pandoc.Readers.Markdown
-import Text.Pandoc.Definition
-import Tests.Helpers
-import Test.Framework
-import qualified Data.ByteString.Lazy as B
-import Text.Pandoc.Readers.Odt
-import Text.Pandoc.Writers.Native (writeNative)
-import qualified Data.Map as M
-import Text.Pandoc.Error
-
-tests :: [Test]
-tests = testsComparingToMarkdown ++ testsComparingToNative
-
-testsComparingToMarkdown :: [Test]
-testsComparingToMarkdown = map nameToTest namesOfTestsComparingToMarkdown
- where nameToTest name = createTest
- compareOdtToMarkdown
- name
- (toOdtPath name)
- (toMarkdownPath name)
- toOdtPath name = "odt/odt/" ++ name ++ ".odt"
- toMarkdownPath name = "odt/markdown/" ++ name ++ ".md"
-
-testsComparingToNative :: [Test]
-testsComparingToNative = map nameToTest namesOfTestsComparingToNative
- where nameToTest name = createTest
- compareOdtToNative
- name
- (toOdtPath name)
- (toNativePath name)
- toOdtPath name = "odt/odt/" ++ name ++ ".odt"
- toNativePath name = "odt/native/" ++ name ++ ".native"
-
-
-newtype NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc}
- deriving ( Show )
-
-instance ToString NoNormPandoc where
- toString d = writeNative def{ writerTemplate = s } $ toPandoc d
- where s = case d of
- NoNormPandoc (Pandoc (Meta m) _)
- | M.null m -> Nothing
- | otherwise -> Just "" -- need this for Meta output
-
-instance ToPandoc NoNormPandoc where
- toPandoc = unNoNorm
-
-getNoNormVia :: (a -> Pandoc) -> String -> Either PandocError a -> NoNormPandoc
-getNoNormVia _ readerName (Left _) = error (readerName ++ " reader failed")
-getNoNormVia f _ (Right a) = NoNormPandoc (f a)
-
-type TestCreator = ReaderOptions
- -> FilePath -> FilePath
- -> IO (NoNormPandoc, NoNormPandoc)
-
-compareOdtToNative :: TestCreator
-compareOdtToNative opts odtPath nativePath = do
- nativeFile <- Prelude.readFile nativePath
- odtFile <- B.readFile odtPath
- let native = getNoNormVia id "native" $ readNative nativeFile
- let odt = getNoNormVia fst "odt" $ readOdt opts odtFile
- return (odt,native)
-
-compareOdtToMarkdown :: TestCreator
-compareOdtToMarkdown opts odtPath markdownPath = do
- markdownFile <- Prelude.readFile markdownPath
- odtFile <- B.readFile odtPath
- let markdown = getNoNormVia id "markdown" $ readMarkdown opts markdownFile
- let odt = getNoNormVia fst "odt" $ readOdt opts odtFile
- return (odt,markdown)
-
-
-createTest :: TestCreator
- -> TestName
- -> FilePath -> FilePath
- -> Test
-createTest creator name path1 path2 =
- buildTest $ liftM (test id name) (creator def path1 path2)
-
-{-
---
-
-getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString)
-getMedia archivePath mediaPath = do
- zf <- B.readFile archivePath >>= return . toArchive
- return $ findEntryByPath ("Pictures/" ++ mediaPath) zf >>= (Just . fromEntry)
-
-compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool
-compareMediaPathIO mediaPath mediaBag odtPath = do
- odtMedia <- getMedia odtPath mediaPath
- let mbBS = case lookupMedia mediaPath mediaBag of
- Just (_, bs) -> bs
- Nothing -> error ("couldn't find " ++
- mediaPath ++
- " in media bag")
- odtBS = case odtMedia of
- Just bs -> bs
- Nothing -> error ("couldn't find " ++
- mediaPath ++
- " in media bag")
- return $ mbBS == odtBS
-
-compareMediaBagIO :: FilePath -> IO Bool
-compareMediaBagIO odtFile = do
- df <- B.readFile odtFile
- let (_, mb) = readOdt def df
- bools <- mapM
- (\(fp, _, _) -> compareMediaPathIO fp mb odtFile)
- (mediaDirectory mb)
- return $ and bools
-
-testMediaBagIO :: String -> FilePath -> IO Test
-testMediaBagIO name odtFile = do
- outcome <- compareMediaBagIO odtFile
- return $ testCase name (assertBool
- ("Media didn't match media bag in file " ++ odtFile)
- outcome)
-
-testMediaBag :: String -> FilePath -> Test
-testMediaBag name odtFile = buildTest $ testMediaBagIO name odtFile
--}
---
-
-
-
-namesOfTestsComparingToMarkdown :: [ String ]
-namesOfTestsComparingToMarkdown = [ "bold"
--- , "citation"
- , "endnote"
- , "externalLink"
- , "footnote"
- , "headers"
--- , "horizontalRule"
- , "italic"
--- , "listBlocks"
- , "paragraph"
- , "strikeout"
--- , "trackedChanges"
- , "underlined"
- ]
-
-namesOfTestsComparingToNative :: [ String ]
-namesOfTestsComparingToNative = [ "blockquote"
- , "image"
- , "imageIndex"
- , "imageWithCaption"
- , "inlinedCode"
- , "orderedListMixed"
- , "orderedListRoman"
- , "orderedListSimple"
- , "referenceToChapter"
- , "referenceToListItem"
- , "referenceToText"
- , "simpleTable"
- , "simpleTableWithCaption"
--- , "table"
- , "textMixedStyles"
- , "tableWithContents"
- , "unicode"
- , "unorderedList"
- ]
diff --git a/tests/Tests/Readers/Org.hs b/tests/Tests/Readers/Org.hs
deleted file mode 100644
index 72b7e2601..000000000
--- a/tests/Tests/Readers/Org.hs
+++ /dev/null
@@ -1,1723 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Readers.Org (tests) where
-
-import Text.Pandoc.Definition
-import Test.Framework
-import Tests.Helpers
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Data.List (intersperse)
-
-org :: String -> Pandoc
-org = handleError . readOrg def
-
-orgSmart :: String -> Pandoc
-orgSmart = handleError . readOrg def { readerSmart = True }
-
-infix 4 =:
-(=:) :: ToString c
- => String -> (String, c) -> Test
-(=:) = test org
-
-spcSep :: [Inlines] -> Inlines
-spcSep = mconcat . intersperse space
-
-simpleTable' :: Int
- -> [Blocks]
- -> [[Blocks]]
- -> Blocks
-simpleTable' n = table "" (take n $ repeat (AlignDefault, 0.0))
-
-tests :: [Test]
-tests =
- [ testGroup "Inlines" $
- [ "Plain String" =:
- "Hello, World" =?>
- para (spcSep [ "Hello,", "World" ])
-
- , "Emphasis" =:
- "/Planet Punk/" =?>
- para (emph . spcSep $ ["Planet", "Punk"])
-
- , "Strong" =:
- "*Cider*" =?>
- para (strong "Cider")
-
- , "Strong Emphasis" =:
- "/*strength*/" =?>
- para (emph . strong $ "strength")
-
- , "Emphasized Strong preceded by space" =:
- " */super/*" =?>
- para (strong . emph $ "super")
-
- , "Strikeout" =:
- "+Kill Bill+" =?>
- para (strikeout . spcSep $ [ "Kill", "Bill" ])
-
- , "Verbatim" =:
- "=Robot.rock()=" =?>
- para (code "Robot.rock()")
-
- , "Code" =:
- "~word for word~" =?>
- para (code "word for word")
-
- , "Math $..$" =:
- "$E=mc^2$" =?>
- para (math "E=mc^2")
-
- , "Math $$..$$" =:
- "$$E=mc^2$$" =?>
- para (displayMath "E=mc^2")
-
- , "Math \\[..\\]" =:
- "\\[E=ℎν\\]" =?>
- para (displayMath "E=ℎν")
-
- , "Math \\(..\\)" =:
- "\\(σ_x σ_p ≥ \\frac{ℏ}{2}\\)" =?>
- para (math "σ_x σ_p ≥ \\frac{ℏ}{2}")
-
- , "Symbol" =:
- "A * symbol" =?>
- para (str "A" <> space <> str "*" <> space <> "symbol")
-
- , "Superscript simple expression" =:
- "2^-λ" =?>
- para (str "2" <> superscript "-λ")
-
- , "Superscript multi char" =:
- "2^{n-1}" =?>
- para (str "2" <> superscript "n-1")
-
- , "Subscript simple expression" =:
- "a_n" =?>
- para (str "a" <> subscript "n")
-
- , "Subscript multi char" =:
- "a_{n+1}" =?>
- para (str "a" <> subscript "n+1")
-
- , "Linebreak" =:
- "line \\\\ \nbreak" =?>
- para ("line" <> linebreak <> "break")
-
- , "Inline note" =:
- "[fn::Schreib mir eine E-Mail]" =?>
- para (note $ para "Schreib mir eine E-Mail")
-
- , "Markup-chars not occuring on word break are symbols" =:
- unlines [ "this+that+ +so+on"
- , "seven*eight* nine*"
- , "+not+funny+"
- ] =?>
- para ("this+that+ +so+on" <> softbreak <>
- "seven*eight* nine*" <> softbreak <>
- strikeout "not+funny")
-
- , "No empty markup" =:
- "// ** __ ++ == ~~ $$" =?>
- para (spcSep [ "//", "**", "__", "++", "==", "~~", "$$" ])
-
- , "Adherence to Org's rules for markup borders" =:
- "/t/& a/ / ./r/ (*l*) /e/! /b/." =?>
- para (spcSep [ emph $ "t/&" <> space <> "a"
- , "/"
- , "./r/"
- , "(" <> (strong "l") <> ")"
- , (emph "e") <> "!"
- , (emph "b") <> "."
- ])
-
- , "Quotes are forbidden border chars" =:
- "/'nope/ *nope\"*" =?>
- para ("/'nope/" <> space <> "*nope\"*")
-
- , "Commata are forbidden border chars" =:
- "/nada,/" =?>
- para "/nada,/"
-
- , "Markup should work properly after a blank line" =:
- unlines ["foo", "", "/bar/"] =?>
- (para $ text "foo") <> (para $ emph $ text "bar")
-
- , "Inline math must stay within three lines" =:
- unlines [ "$a", "b", "c$", "$d", "e", "f", "g$" ] =?>
- para ((math "a\nb\nc") <> softbreak <>
- "$d" <> softbreak <> "e" <> softbreak <>
- "f" <> softbreak <> "g$")
-
- , "Single-character math" =:
- "$a$ $b$! $c$?" =?>
- para (spcSep [ math "a"
- , "$b$!"
- , (math "c") <> "?"
- ])
-
- , "Markup may not span more than two lines" =:
- "/this *is +totally\nnice+ not*\nemph/" =?>
- para ("/this" <> space <>
- strong ("is" <> space <>
- strikeout ("totally" <>
- softbreak <> "nice") <>
- space <> "not") <>
- softbreak <> "emph/")
-
- , "Sub- and superscript expressions" =:
- unlines [ "a_(a(b)(c)d)"
- , "e^(f(g)h)"
- , "i_(jk)l)"
- , "m^()n"
- , "o_{p{q{}r}}"
- , "s^{t{u}v}"
- , "w_{xy}z}"
- , "1^{}2"
- , "3_{{}}"
- , "4^(a(*b(c*)d))"
- ] =?>
- para (mconcat $ intersperse softbreak
- [ "a" <> subscript "(a(b)(c)d)"
- , "e" <> superscript "(f(g)h)"
- , "i" <> (subscript "(jk)") <> "l)"
- , "m" <> (superscript "()") <> "n"
- , "o" <> subscript "p{q{}r}"
- , "s" <> superscript "t{u}v"
- , "w" <> (subscript "xy") <> "z}"
- , "1" <> (superscript "") <> "2"
- , "3" <> subscript "{}"
- , "4" <> superscript ("(a(" <> strong "b(c" <> ")d))")
- ])
- , "Verbatim text can contain equal signes (=)" =:
- "=is_subst = True=" =?>
- para (code "is_subst = True")
-
- , testGroup "Images"
- [ "Image" =:
- "[[./sunset.jpg]]" =?>
- (para $ image "./sunset.jpg" "" "")
-
- , "Image with explicit file: prefix" =:
- "[[file:sunrise.jpg]]" =?>
- (para $ image "sunrise.jpg" "" "")
-
- , "Multiple images within a paragraph" =:
- unlines [ "[[file:sunrise.jpg]]"
- , "[[file:sunset.jpg]]"
- ] =?>
- (para $ (image "sunrise.jpg" "" "")
- <> softbreak
- <> (image "sunset.jpg" "" ""))
-
- , "Image with html attributes" =:
- unlines [ "#+ATTR_HTML: :width 50%"
- , "[[file:guinea-pig.gif]]"
- ] =?>
- (para $ imageWith ("", [], [("width", "50%")]) "guinea-pig.gif" "" "")
- ]
-
- , "Explicit link" =:
- "[[http://zeitlens.com/][pseudo-random /nonsense/]]" =?>
- (para $ link "http://zeitlens.com/" ""
- ("pseudo-random" <> space <> emph "nonsense"))
-
- , "Self-link" =:
- "[[http://zeitlens.com/]]" =?>
- (para $ link "http://zeitlens.com/" "" "http://zeitlens.com/")
-
- , "Absolute file link" =:
- "[[/url][hi]]" =?>
- (para $ link "file:///url" "" "hi")
-
- , "Link to file in parent directory" =:
- "[[../file.txt][moin]]" =?>
- (para $ link "../file.txt" "" "moin")
-
- , "Empty link (for gitit interop)" =:
- "[[][New Link]]" =?>
- (para $ link "" "" "New Link")
-
- , "Image link" =:
- "[[sunset.png][file:dusk.svg]]" =?>
- (para $ link "sunset.png" "" (image "dusk.svg" "" ""))
-
- , "Image link with non-image target" =:
- "[[http://example.com][./logo.png]]" =?>
- (para $ link "http://example.com" "" (image "./logo.png" "" ""))
-
- , "Plain link" =:
- "Posts on http://zeitlens.com/ can be funny at times." =?>
- (para $ spcSep [ "Posts", "on"
- , link "http://zeitlens.com/" "" "http://zeitlens.com/"
- , "can", "be", "funny", "at", "times."
- ])
-
- , "Angle link" =:
- "Look at <http://moltkeplatz.de> for fnords." =?>
- (para $ spcSep [ "Look", "at"
- , link "http://moltkeplatz.de" "" "http://moltkeplatz.de"
- , "for", "fnords."
- ])
-
- , "Absolute file link" =:
- "[[file:///etc/passwd][passwd]]" =?>
- (para $ link "file:///etc/passwd" "" "passwd")
-
- , "File link" =:
- "[[file:target][title]]" =?>
- (para $ link "target" "" "title")
-
- , "Anchor" =:
- "<<anchor>> Link here later." =?>
- (para $ spanWith ("anchor", [], []) mempty <>
- "Link" <> space <> "here" <> space <> "later.")
-
- , "Inline code block" =:
- "src_emacs-lisp{(message \"Hello\")}" =?>
- (para $ codeWith ( ""
- , [ "commonlisp", "rundoc-block" ]
- , [ ("rundoc-language", "emacs-lisp") ])
- "(message \"Hello\")")
-
- , "Inline code block with arguments" =:
- "src_sh[:export both :results output]{echo 'Hello, World'}" =?>
- (para $ codeWith ( ""
- , [ "bash", "rundoc-block" ]
- , [ ("rundoc-language", "sh")
- , ("rundoc-export", "both")
- , ("rundoc-results", "output")
- ]
- )
- "echo 'Hello, World'")
-
- , "Inline code block with toggle" =:
- "src_sh[:toggle]{echo $HOME}" =?>
- (para $ codeWith ( ""
- , [ "bash", "rundoc-block" ]
- , [ ("rundoc-language", "sh")
- , ("rundoc-toggle", "yes")
- ]
- )
- "echo $HOME")
-
- , "Citation" =:
- "[@nonexistent]" =?>
- let citation = Citation
- { citationId = "nonexistent"
- , citationPrefix = []
- , citationSuffix = []
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0}
- in (para $ cite [citation] "[@nonexistent]")
-
- , "Citation containing text" =:
- "[see @item1 p. 34-35]" =?>
- let citation = Citation
- { citationId = "item1"
- , citationPrefix = [Str "see"]
- , citationSuffix = [Space ,Str "p.",Space,Str "34-35"]
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0}
- in (para $ cite [citation] "[see @item1 p. 34-35]")
-
- , "Org-ref simple citation" =:
- "cite:pandoc" =?>
- let citation = Citation
- { citationId = "pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "cite:pandoc")
-
- , "Org-ref simple citation succeeded by comma" =:
- "cite:pandoc," =?>
- let citation = Citation
- { citationId = "pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "cite:pandoc" <> str ",")
-
- , "Org-ref simple citep citation" =:
- "citep:pandoc" =?>
- let citation = Citation
- { citationId = "pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "citep:pandoc")
-
- , "Org-ref extended citation" =:
- "[[citep:Dominik201408][See page 20::, for example]]" =?>
- let citation = Citation
- { citationId = "Dominik201408"
- , citationPrefix = toList "See page 20"
- , citationSuffix = toList ", for example"
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "[[citep:Dominik201408][See page 20::, for example]]")
-
- , testGroup "Berkeley-style citations" $
- let pandocCite = Citation
- { citationId = "Pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
- pandocInText = pandocCite { citationMode = AuthorInText }
- dominikCite = Citation
- { citationId = "Dominik201408"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
- dominikInText = dominikCite { citationMode = AuthorInText }
- in [
- "Berkeley-style in-text citation" =:
- "See @Dominik201408." =?>
- (para $ "See "
- <> cite [dominikInText] "@Dominik201408"
- <> ".")
-
- , "Berkeley-style parenthetical citation list" =:
- "[(cite): see; @Dominik201408;also @Pandoc; and others]" =?>
- let pandocCite' = pandocCite {
- citationPrefix = toList "also"
- , citationSuffix = toList "and others"
- }
- dominikCite' = dominikCite {
- citationPrefix = toList "see"
- }
- in (para $ cite [dominikCite', pandocCite'] "")
-
- , "Berkeley-style plain citation list" =:
- "[cite: See; @Dominik201408; and @Pandoc; and others]" =?>
- let pandocCite' = pandocInText {
- citationPrefix = toList "and"
- }
- in (para $ "See "
- <> cite [dominikInText] ""
- <> "," <> space
- <> cite [pandocCite'] ""
- <> "," <> space <> "and others")
- ]
-
- , "Inline LaTeX symbol" =:
- "\\dots" =?>
- para "…"
-
- , "Inline LaTeX command" =:
- "\\textit{Emphasised}" =?>
- para (emph "Emphasised")
-
- , "Inline LaTeX command with spaces" =:
- "\\emph{Emphasis mine}" =?>
- para (emph "Emphasis mine")
-
- , "Inline LaTeX math symbol" =:
- "\\tau" =?>
- para (emph "τ")
-
- , "Unknown inline LaTeX command" =:
- "\\notacommand{foo}" =?>
- para (rawInline "latex" "\\notacommand{foo}")
-
- , "Export snippet" =:
- "@@html:<kbd>M-x org-agenda</kbd>@@" =?>
- para (rawInline "html" "<kbd>M-x org-agenda</kbd>")
-
- , "MathML symbol in LaTeX-style" =:
- "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: '\\nbsp')." =?>
- para ("There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: ' ').")
-
- , "MathML symbol in LaTeX-style, including braces" =:
- "\\Aacute{}stor" =?>
- para "Ástor"
-
- , "MathML copy sign" =:
- "\\copy" =?>
- para "©"
-
- , "MathML symbols, space separated" =:
- "\\ForAll \\Auml" =?>
- para "∀ Ä"
-
- , "LaTeX citation" =:
- "\\cite{Coffee}" =?>
- let citation = Citation
- { citationId = "Coffee"
- , citationPrefix = []
- , citationSuffix = []
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0}
- in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
- ]
-
- , testGroup "Meta Information" $
- [ "Comment" =:
- "# Nothing to see here" =?>
- (mempty::Blocks)
-
- , "Not a comment" =:
- "#-tag" =?>
- para "#-tag"
-
- , "Comment surrounded by Text" =:
- unlines [ "Before"
- , "# Comment"
- , "After"
- ] =?>
- mconcat [ para "Before"
- , para "After"
- ]
-
- , "Title" =:
- "#+TITLE: Hello, World" =?>
- let titleInline = toList $ "Hello," <> space <> "World"
- meta = setMeta "title" (MetaInlines titleInline) $ nullMeta
- in Pandoc meta mempty
-
- , "Author" =:
- "#+author: Albert /Emacs-Fanboy/ Krewinkel" =?>
- let author = toList . spcSep $ [ "Albert", emph "Emacs-Fanboy", "Krewinkel" ]
- meta = setMeta "author" (MetaList [MetaInlines author]) $ nullMeta
- in Pandoc meta mempty
-
- , "Multiple authors" =:
- "#+author: James Dewey Watson, Francis Harry Compton Crick " =?>
- let watson = MetaInlines $ toList "James Dewey Watson"
- crick = MetaInlines $ toList "Francis Harry Compton Crick"
- meta = setMeta "author" (MetaList [watson, crick]) $ nullMeta
- in Pandoc meta mempty
-
- , "Date" =:
- "#+Date: Feb. *28*, 2014" =?>
- let date = toList . spcSep $ [ "Feb.", (strong "28") <> ",", "2014" ]
- meta = setMeta "date" (MetaInlines date) $ nullMeta
- in Pandoc meta mempty
-
- , "Description" =:
- "#+DESCRIPTION: Explanatory text" =?>
- let description = "Explanatory text"
- meta = setMeta "description" (MetaString description) $ nullMeta
- in Pandoc meta mempty
-
- , "Properties drawer" =:
- unlines [ " :PROPERTIES:"
- , " :setting: foo"
- , " :END:"
- ] =?>
- (mempty::Blocks)
-
- , "LaTeX_headers options are translated to header-includes" =:
- "#+LaTeX_header: \\usepackage{tikz}" =?>
- let latexInlines = rawInline "latex" "\\usepackage{tikz}"
- inclList = MetaList [MetaInlines (toList latexInlines)]
- meta = setMeta "header-includes" inclList nullMeta
- in Pandoc meta mempty
-
- , "LaTeX_class option is translated to documentclass" =:
- "#+LATEX_CLASS: article" =?>
- let meta = setMeta "documentclass" (MetaString "article") nullMeta
- in Pandoc meta mempty
-
- , "LaTeX_class_options is translated to classoption" =:
- "#+LATEX_CLASS_OPTIONS: [a4paper]" =?>
- let meta = setMeta "classoption" (MetaString "a4paper") nullMeta
- in Pandoc meta mempty
-
- , "LaTeX_class_options is translated to classoption" =:
- "#+html_head: <meta/>" =?>
- let html = rawInline "html" "<meta/>"
- inclList = MetaList [MetaInlines (toList html)]
- meta = setMeta "header-includes" inclList nullMeta
- in Pandoc meta mempty
-
- , "later meta definitions take precedence" =:
- unlines [ "#+AUTHOR: this will not be used"
- , "#+author: Max"
- ] =?>
- let author = MetaInlines [Str "Max"]
- meta = setMeta "author" (MetaList [author]) $ nullMeta
- in Pandoc meta mempty
-
- , "Logbook drawer" =:
- unlines [ " :LogBook:"
- , " - State \"DONE\" from \"TODO\" [2014-03-03 Mon 11:00]"
- , " :END:"
- ] =?>
- (mempty::Blocks)
-
- , "Drawer surrounded by text" =:
- unlines [ "Before"
- , ":PROPERTIES:"
- , ":END:"
- , "After"
- ] =?>
- para "Before" <> para "After"
-
- , "Drawer markers must be the only text in the line" =:
- unlines [ " :LOGBOOK: foo"
- , " :END: bar"
- ] =?>
- para (":LOGBOOK: foo" <> softbreak <> ":END: bar")
-
- , "Drawers can be arbitrary" =:
- unlines [ ":FOO:"
- , "/bar/"
- , ":END:"
- ] =?>
- divWith (mempty, ["FOO", "drawer"], mempty) (para $ emph "bar")
-
- , "Anchor reference" =:
- unlines [ "<<link-here>> Target."
- , ""
- , "[[link-here][See here!]]"
- ] =?>
- (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
- para (link "#link-here" "" ("See" <> space <> "here!")))
-
- , "Search links are read as emph" =:
- "[[Wally][Where's Wally?]]" =?>
- (para (emph $ "Where's" <> space <> "Wally?"))
-
- , "Link to nonexistent anchor" =:
- unlines [ "<<link-here>> Target."
- , ""
- , "[[link$here][See here!]]"
- ] =?>
- (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
- para (emph ("See" <> space <> "here!")))
-
- , "Link abbreviation" =:
- unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
- , "[[wp:Org_mode][Wikipedia on Org-mode]]"
- ] =?>
- (para (link "https://en.wikipedia.org/wiki/Org_mode" ""
- ("Wikipedia" <> space <> "on" <> space <> "Org-mode")))
-
- , "Link abbreviation, defined after first use" =:
- unlines [ "[[zl:non-sense][Non-sense articles]]"
- , "#+LINK: zl http://zeitlens.com/tags/%s.html"
- ] =?>
- (para (link "http://zeitlens.com/tags/non-sense.html" ""
- ("Non-sense" <> space <> "articles")))
-
- , "Link abbreviation, URL encoded arguments" =:
- unlines [ "#+link: expl http://example.com/%h/foo"
- , "[[expl:Hello, World!][Moin!]]"
- ] =?>
- (para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!"))
-
- , "Link abbreviation, append arguments" =:
- unlines [ "#+link: expl http://example.com/"
- , "[[expl:foo][bar]]"
- ] =?>
- (para (link "http://example.com/foo" "" "bar"))
-
-
- , testGroup "export options"
-
- [ "disable simple sub/superscript syntax" =:
- unlines [ "#+OPTIONS: ^:nil"
- , "a^b"
- ] =?>
- para "a^b"
-
- , "directly select drawers to be exported" =:
- unlines [ "#+OPTIONS: d:(\"IMPORTANT\")"
- , ":IMPORTANT:"
- , "23"
- , ":END:"
- , ":BORING:"
- , "very boring"
- , ":END:"
- ] =?>
- divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "23")
-
- , "exclude drawers from being exported" =:
- unlines [ "#+OPTIONS: d:(not \"BORING\")"
- , ":IMPORTANT:"
- , "5"
- , ":END:"
- , ":BORING:"
- , "very boring"
- , ":END:"
- ] =?>
- divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "5")
-
- , "don't include archive trees" =:
- unlines [ "#+OPTIONS: arch:nil"
- , "* old :ARCHIVE:"
- ] =?>
- (mempty ::Blocks)
-
- , "include complete archive trees" =:
- unlines [ "#+OPTIONS: arch:t"
- , "* old :ARCHIVE:"
- , " boring"
- ] =?>
- let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
- in mconcat [ headerWith ("old", [], mempty) 1 ("old" <> tagSpan "ARCHIVE")
- , para "boring"
- ]
-
- , "include archive tree header only" =:
- unlines [ "#+OPTIONS: arch:headline"
- , "* old :ARCHIVE:"
- , " boring"
- ] =?>
- let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
- in headerWith ("old", [], mempty) 1 ("old" <> tagSpan "ARCHIVE")
-
- , "limit headline depth" =:
- unlines [ "#+OPTIONS: H:2"
- , "* section"
- , "** subsection"
- , "*** list item 1"
- , "*** list item 2"
- ] =?>
- mconcat [ headerWith ("section", [], []) 1 "section"
- , headerWith ("subsection", [], []) 2 "subsection"
- , orderedList [ para "list item 1", para "list item 2" ]
- ]
-
- , "disable author export" =:
- unlines [ "#+OPTIONS: author:nil"
- , "#+AUTHOR: ShyGuy"
- ] =?>
- Pandoc nullMeta mempty
-
- , "disable creator export" =:
- unlines [ "#+OPTIONS: creator:nil"
- , "#+creator: The Architect"
- ] =?>
- Pandoc nullMeta mempty
-
- , "disable email export" =:
- unlines [ "#+OPTIONS: email:nil"
- , "#+email: no-mail-please@example.com"
- ] =?>
- Pandoc nullMeta mempty
-
- , "disable inclusion of todo keywords" =:
- unlines [ "#+OPTIONS: todo:nil"
- , "** DONE todo export"
- ] =?>
- headerWith ("todo-export", [], []) 2 "todo export"
- ]
- ]
-
- , testGroup "Basic Blocks" $
- [ "Paragraph" =:
- "Paragraph\n" =?>
- para "Paragraph"
-
- , testGroup "headers" $
- [ "First Level Header" =:
- "* Headline\n" =?>
- headerWith ("headline", [], []) 1 "Headline"
-
- , "Third Level Header" =:
- "*** Third Level Headline\n" =?>
- headerWith ("third-level-headline", [], [])
- 3
- ("Third" <> space <> "Level" <> space <> "Headline")
-
- , "Compact Headers with Paragraph" =:
- unlines [ "* First Level"
- , "** Second Level"
- , " Text"
- ] =?>
- mconcat [ headerWith ("first-level", [], [])
- 1
- ("First" <> space <> "Level")
- , headerWith ("second-level", [], [])
- 2
- ("Second" <> space <> "Level")
- , para "Text"
- ]
-
- , "Separated Headers with Paragraph" =:
- unlines [ "* First Level"
- , ""
- , "** Second Level"
- , ""
- , " Text"
- ] =?>
- mconcat [ headerWith ("first-level", [], [])
- 1
- ("First" <> space <> "Level")
- , headerWith ("second-level", [], [])
- 2
- ("Second" <> space <> "Level")
- , para "Text"
- ]
-
- , "Headers not preceded by a blank line" =:
- unlines [ "** eat dinner"
- , "Spaghetti and meatballs tonight."
- , "** walk dog"
- ] =?>
- mconcat [ headerWith ("eat-dinner", [], [])
- 2
- ("eat" <> space <> "dinner")
- , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
- , headerWith ("walk-dog", [], [])
- 2
- ("walk" <> space <> "dog")
- ]
-
- , testGroup "Todo keywords"
- [ "Header with known todo keyword" =:
- "* TODO header" =?>
- let todoSpan = spanWith ("", ["todo", "TODO"], []) "TODO"
- in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
-
- , "Header marked as done" =:
- "* DONE header" =?>
- let todoSpan = spanWith ("", ["done", "DONE"], []) "DONE"
- in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
-
- , "Header with unknown todo keyword" =:
- "* WAITING header" =?>
- headerWith ("waiting-header", [], []) 1 "WAITING header"
-
- , "Custom todo keywords" =:
- unlines [ "#+TODO: WAITING CANCELLED"
- , "* WAITING compile"
- , "* CANCELLED lunch"
- ] =?>
- let todoSpan = spanWith ("", ["todo", "WAITING"], []) "WAITING"
- doneSpan = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
- in headerWith ("compile", [], []) 1 (todoSpan <> space <> "compile")
- <> headerWith ("lunch", [], []) 1 (doneSpan <> space <> "lunch")
-
- , "Custom todo keywords with multiple done-states" =:
- unlines [ "#+TODO: WAITING | DONE CANCELLED "
- , "* WAITING compile"
- , "* CANCELLED lunch"
- , "* DONE todo-feature"
- ] =?>
- let waiting = spanWith ("", ["todo", "WAITING"], []) "WAITING"
- cancelled = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
- done = spanWith ("", ["done", "DONE"], []) "DONE"
- in headerWith ("compile", [], []) 1 (waiting <> space <> "compile")
- <> headerWith ("lunch", [], []) 1 (cancelled <> space <> "lunch")
- <> headerWith ("todo-feature", [], []) 1 (done <> space <> "todo-feature")
- ]
-
- , "Tagged headers" =:
- unlines [ "* Personal :PERSONAL:"
- , "** Call Mom :@PHONE:"
- , "** Call John :@PHONE:JOHN: "
- ] =?>
- let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
- in mconcat [ headerWith ("personal", [], [])
- 1
- ("Personal" <> tagSpan "PERSONAL")
- , headerWith ("call-mom", [], [])
- 2
- ("Call Mom" <> tagSpan "@PHONE")
- , headerWith ("call-john", [], [])
- 2
- ("Call John" <> tagSpan "@PHONE" <> tagSpan "JOHN")
- ]
-
- , "Untagged header containing colons" =:
- "* This: is not: tagged" =?>
- headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged"
-
- , "Header starting with strokeout text" =:
- unlines [ "foo"
- , ""
- , "* +thing+ other thing"
- ] =?>
- mconcat [ para "foo"
- , headerWith ("thing-other-thing", [], [])
- 1
- ((strikeout "thing") <> " other thing")
- ]
-
- , "Comment Trees" =:
- unlines [ "* COMMENT A comment tree"
- , " Not much going on here"
- , "** This will be dropped"
- , "* Comment tree above"
- ] =?>
- headerWith ("comment-tree-above", [], []) 1 "Comment tree above"
-
- , "Nothing but a COMMENT header" =:
- "* COMMENT Test" =?>
- (mempty::Blocks)
-
- , "Tree with :noexport:" =:
- unlines [ "* Should be ignored :archive:noexport:old:"
- , "** Old stuff"
- , " This is not going to be exported"
- ] =?>
- (mempty::Blocks)
-
- , "Subtree with :noexport:" =:
- unlines [ "* Exported"
- , "** This isn't exported :noexport:"
- , "*** This neither"
- , "** But this is"
- ] =?>
- mconcat [ headerWith ("exported", [], []) 1 "Exported"
- , headerWith ("but-this-is", [], []) 2 "But this is"
- ]
-
- , "Preferences are treated as header attributes" =:
- unlines [ "* foo"
- , " :PROPERTIES:"
- , " :custom_id: fubar"
- , " :bar: baz"
- , " :END:"
- ] =?>
- headerWith ("fubar", [], [("bar", "baz")]) 1 "foo"
-
-
- , "Headers marked with a unnumbered property get a class of the same name" =:
- unlines [ "* Not numbered"
- , " :PROPERTIES:"
- , " :UNNUMBERED: t"
- , " :END:"
- ] =?>
- headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
- ]
- , "Paragraph starting with an asterisk" =:
- "*five" =?>
- para "*five"
-
- , "Paragraph containing asterisk at beginning of line" =:
- unlines [ "lucky"
- , "*star"
- ] =?>
- para ("lucky" <> softbreak <> "*star")
-
- , "Example block" =:
- unlines [ ": echo hello"
- , ": echo dear tester"
- ] =?>
- codeBlockWith ("", ["example"], []) "echo hello\necho dear tester\n"
-
- , "Example block surrounded by text" =:
- unlines [ "Greetings"
- , ": echo hello"
- , ": echo dear tester"
- , "Bye"
- ] =?>
- mconcat [ para "Greetings"
- , codeBlockWith ("", ["example"], [])
- "echo hello\necho dear tester\n"
- , para "Bye"
- ]
-
- , "Horizontal Rule" =:
- unlines [ "before"
- , "-----"
- , "after"
- ] =?>
- mconcat [ para "before"
- , horizontalRule
- , para "after"
- ]
-
- , "Not a Horizontal Rule" =:
- "----- five dashes" =?>
- (para $ spcSep [ "-----", "five", "dashes" ])
-
- , "Comment Block" =:
- unlines [ "#+BEGIN_COMMENT"
- , "stuff"
- , "bla"
- , "#+END_COMMENT"] =?>
- (mempty::Blocks)
-
- , testGroup "Figures" $
- [ "Figure" =:
- unlines [ "#+caption: A very courageous man."
- , "#+name: goodguy"
- , "[[file:edward.jpg]]"
- ] =?>
- para (image "edward.jpg" "fig:goodguy" "A very courageous man.")
-
- , "Figure with no name" =:
- unlines [ "#+caption: I've been through the desert on this"
- , "[[file:horse.png]]"
- ] =?>
- para (image "horse.png" "fig:" "I've been through the desert on this")
-
- , "Figure with `fig:` prefix in name" =:
- unlines [ "#+caption: Used as a metapher in evolutionary biology."
- , "#+name: fig:redqueen"
- , "[[./the-red-queen.jpg]]"
- ] =?>
- para (image "./the-red-queen.jpg" "fig:redqueen"
- "Used as a metapher in evolutionary biology.")
-
- , "Figure with HTML attributes" =:
- unlines [ "#+CAPTION: mah brain just explodid"
- , "#+NAME: lambdacat"
- , "#+ATTR_HTML: :style color: blue :role button"
- , "[[file:lambdacat.jpg]]"
- ] =?>
- let kv = [("style", "color: blue"), ("role", "button")]
- name = "fig:lambdacat"
- caption = "mah brain just explodid"
- in para (imageWith (mempty, mempty, kv) "lambdacat.jpg" name caption)
-
- , "Labelled figure" =:
- unlines [ "#+CAPTION: My figure"
- , "#+LABEL: fig:myfig"
- , "[[file:blub.png]]"
- ] =?>
- let attr = ("fig:myfig", mempty, mempty)
- in para (imageWith attr "blub.png" "fig:" "My figure")
-
- , "Figure with empty caption" =:
- unlines [ "#+CAPTION:"
- , "[[file:guess.jpg]]"
- ] =?>
- para (image "guess.jpg" "fig:" "")
- ]
-
- , "Footnote" =:
- unlines [ "A footnote[1]"
- , ""
- , "[1] First paragraph"
- , ""
- , "second paragraph"
- ] =?>
- para (mconcat
- [ "A", space, "footnote"
- , note $ mconcat [ para ("First" <> space <> "paragraph")
- , para ("second" <> space <> "paragraph")
- ]
- ])
-
- , "Two footnotes" =:
- unlines [ "Footnotes[fn:1][fn:2]"
- , ""
- , "[fn:1] First note."
- , ""
- , "[fn:2] Second note."
- ] =?>
- para (mconcat
- [ "Footnotes"
- , note $ para ("First" <> space <> "note.")
- , note $ para ("Second" <> space <> "note.")
- ])
-
- , "Footnote followed by header" =:
- unlines [ "Another note[fn:yay]"
- , ""
- , "[fn:yay] This is great!"
- , ""
- , "** Headline"
- ] =?>
- mconcat
- [ para (mconcat
- [ "Another", space, "note"
- , note $ para ("This" <> space <> "is" <> space <> "great!")
- ])
- , headerWith ("headline", [], []) 2 "Headline"
- ]
- ]
-
- , testGroup "Lists" $
- [ "Simple Bullet Lists" =:
- ("- Item1\n" ++
- "- Item2\n") =?>
- bulletList [ plain "Item1"
- , plain "Item2"
- ]
-
- , "Indented Bullet Lists" =:
- (" - Item1\n" ++
- " - Item2\n") =?>
- bulletList [ plain "Item1"
- , plain "Item2"
- ]
-
- , "Unindented *" =:
- ("- Item1\n" ++
- "* Item2\n") =?>
- bulletList [ plain "Item1"
- ] <>
- headerWith ("item2", [], []) 1 "Item2"
-
- , "Multi-line Bullet Lists" =:
- ("- *Fat\n" ++
- " Tony*\n" ++
- "- /Sideshow\n" ++
- " Bob/") =?>
- bulletList [ plain $ strong ("Fat" <> softbreak <> "Tony")
- , plain $ emph ("Sideshow" <> softbreak <> "Bob")
- ]
-
- , "Nested Bullet Lists" =:
- ("- Discovery\n" ++
- " + One More Time\n" ++
- " + Harder, Better, Faster, Stronger\n" ++
- "- Homework\n" ++
- " + Around the World\n"++
- "- Human After All\n" ++
- " + Technologic\n" ++
- " + Robot Rock\n") =?>
- bulletList [ mconcat
- [ plain "Discovery"
- , bulletList [ plain ("One" <> space <>
- "More" <> space <>
- "Time")
- , plain ("Harder," <> space <>
- "Better," <> space <>
- "Faster," <> space <>
- "Stronger")
- ]
- ]
- , mconcat
- [ plain "Homework"
- , bulletList [ plain ("Around" <> space <>
- "the" <> space <>
- "World")
- ]
- ]
- , mconcat
- [ plain ("Human" <> space <> "After" <> space <> "All")
- , bulletList [ plain "Technologic"
- , plain ("Robot" <> space <> "Rock")
- ]
- ]
- ]
-
- , "Bullet List with Decreasing Indent" =:
- (" - Discovery\n\
- \ - Human After All\n") =?>
- mconcat [ bulletList [ plain "Discovery" ]
- , bulletList [ plain ("Human" <> space <> "After" <> space <> "All")]
- ]
-
- , "Header follows Bullet List" =:
- (" - Discovery\n\
- \ - Human After All\n\
- \* Homework") =?>
- mconcat [ bulletList [ plain "Discovery"
- , plain ("Human" <> space <> "After" <> space <> "All")
- ]
- , headerWith ("homework", [], []) 1 "Homework"
- ]
-
- , "Bullet List Unindented with trailing Header" =:
- ("- Discovery\n\
- \- Homework\n\
- \* NotValidListItem") =?>
- mconcat [ bulletList [ plain "Discovery"
- , plain "Homework"
- ]
- , headerWith ("notvalidlistitem", [], []) 1 "NotValidListItem"
- ]
-
- , "Simple Ordered List" =:
- ("1. Item1\n" ++
- "2. Item2\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ plain "Item1"
- , plain "Item2"
- ]
- in orderedListWith listStyle listStructure
-
- , "Simple Ordered List with Parens" =:
- ("1) Item1\n" ++
- "2) Item2\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ plain "Item1"
- , plain "Item2"
- ]
- in orderedListWith listStyle listStructure
-
- , "Indented Ordered List" =:
- (" 1. Item1\n" ++
- " 2. Item2\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ plain "Item1"
- , plain "Item2"
- ]
- in orderedListWith listStyle listStructure
-
- , "Nested Ordered Lists" =:
- ("1. One\n" ++
- " 1. One-One\n" ++
- " 2. One-Two\n" ++
- "2. Two\n" ++
- " 1. Two-One\n"++
- " 2. Two-Two\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ mconcat
- [ plain "One"
- , orderedList [ plain "One-One"
- , plain "One-Two"
- ]
- ]
- , mconcat
- [ plain "Two"
- , orderedList [ plain "Two-One"
- , plain "Two-Two"
- ]
- ]
- ]
- in orderedListWith listStyle listStructure
-
- , "Ordered List in Bullet List" =:
- ("- Emacs\n" ++
- " 1. Org\n") =?>
- bulletList [ (plain "Emacs") <>
- (orderedList [ plain "Org"])
- ]
-
- , "Bullet List in Ordered List" =:
- ("1. GNU\n" ++
- " - Freedom\n") =?>
- orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ]
-
- , "Definition List" =:
- unlines [ "- PLL :: phase-locked loop"
- , "- TTL ::"
- , " transistor-transistor logic"
- , "- PSK :: phase-shift keying"
- , ""
- , " a digital modulation scheme"
- ] =?>
- definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
- , ("TTL", [ plain $ "transistor-transistor" <> space <>
- "logic" ])
- , ("PSK", [ mconcat
- [ para $ "phase-shift" <> space <> "keying"
- , para $ spcSep [ "a", "digital"
- , "modulation", "scheme" ]
- ]
- ])
- ]
- , "Definition list with multi-word term" =:
- " - Elijah Wood :: He plays Frodo" =?>
- definitionList [ ("Elijah" <> space <> "Wood", [plain $ "He" <> space <> "plays" <> space <> "Frodo"])]
- , "Compact definition list" =:
- unlines [ "- ATP :: adenosine 5' triphosphate"
- , "- DNA :: deoxyribonucleic acid"
- , "- PCR :: polymerase chain reaction"
- , ""
- ] =?>
- definitionList
- [ ("ATP", [ plain $ spcSep [ "adenosine", "5'", "triphosphate" ] ])
- , ("DNA", [ plain $ spcSep [ "deoxyribonucleic", "acid" ] ])
- , ("PCR", [ plain $ spcSep [ "polymerase", "chain", "reaction" ] ])
- ]
-
- , "Definition List With Trailing Header" =:
- "- definition :: list\n\
- \- cool :: defs\n\
- \* header" =?>
- mconcat [ definitionList [ ("definition", [plain "list"])
- , ("cool", [plain "defs"])
- ]
- , headerWith ("header", [], []) 1 "header"
- ]
-
- , "Definition lists double-colon markers must be surrounded by whitespace" =:
- "- std::cout" =?>
- bulletList [ plain "std::cout" ]
-
- , "Loose bullet list" =:
- unlines [ "- apple"
- , ""
- , "- orange"
- , ""
- , "- peach"
- ] =?>
- bulletList [ para "apple"
- , para "orange"
- , para "peach"
- ]
-
- , "Recognize preceding paragraphs in non-list contexts" =:
- unlines [ "CLOSED: [2015-10-19 Mon 15:03]"
- , "- Note taken on [2015-10-19 Mon 13:24]"
- ] =?>
- mconcat [ para "CLOSED: [2015-10-19 Mon 15:03]"
- , bulletList [ plain "Note taken on [2015-10-19 Mon 13:24]" ]
- ]
- ]
-
- , testGroup "Tables"
- [ "Single cell table" =:
- "|Test|" =?>
- simpleTable' 1 mempty [[plain "Test"]]
-
- , "Multi cell table" =:
- "| One | Two |" =?>
- simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
-
- , "Multi line table" =:
- unlines [ "| One |"
- , "| Two |"
- , "| Three |"
- ] =?>
- simpleTable' 1 mempty
- [ [ plain "One" ]
- , [ plain "Two" ]
- , [ plain "Three" ]
- ]
-
- , "Empty table" =:
- "||" =?>
- simpleTable' 1 mempty [[mempty]]
-
- , "Glider Table" =:
- unlines [ "| 1 | 0 | 0 |"
- , "| 0 | 1 | 1 |"
- , "| 1 | 1 | 0 |"
- ] =?>
- simpleTable' 3 mempty
- [ [ plain "1", plain "0", plain "0" ]
- , [ plain "0", plain "1", plain "1" ]
- , [ plain "1", plain "1", plain "0" ]
- ]
-
- , "Table between Paragraphs" =:
- unlines [ "Before"
- , "| One | Two |"
- , "After"
- ] =?>
- mconcat [ para "Before"
- , simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
- , para "After"
- ]
-
- , "Table with Header" =:
- unlines [ "| Species | Status |"
- , "|--------------+--------------|"
- , "| cervisiae | domesticated |"
- , "| paradoxus | wild |"
- ] =?>
- simpleTable [ plain "Species", plain "Status" ]
- [ [ plain "cervisiae", plain "domesticated" ]
- , [ plain "paradoxus", plain "wild" ]
- ]
-
- , "Table with final hline" =:
- unlines [ "| cervisiae | domesticated |"
- , "| paradoxus | wild |"
- , "|--------------+--------------|"
- ] =?>
- simpleTable' 2 mempty
- [ [ plain "cervisiae", plain "domesticated" ]
- , [ plain "paradoxus", plain "wild" ]
- ]
-
- , "Table in a box" =:
- unlines [ "|---------|---------|"
- , "| static | Haskell |"
- , "| dynamic | Lisp |"
- , "|---------+---------|"
- ] =?>
- simpleTable' 2 mempty
- [ [ plain "static", plain "Haskell" ]
- , [ plain "dynamic", plain "Lisp" ]
- ]
-
- , "Table with empty cells" =:
- "|||c|" =?>
- simpleTable' 3 mempty [[mempty, mempty, plain "c"]]
-
- , "Table with empty rows" =:
- unlines [ "| first |"
- , "| |"
- , "| third |"
- ] =?>
- simpleTable' 1 mempty [[plain "first"], [mempty], [plain "third"]]
-
- , "Table with alignment row" =:
- unlines [ "| Numbers | Text | More |"
- , "| <c> | <r> | |"
- , "| 1 | One | foo |"
- , "| 2 | Two | bar |"
- ] =?>
- table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
- []
- [ [ plain "Numbers", plain "Text", plain "More" ]
- , [ plain "1" , plain "One" , plain "foo" ]
- , [ plain "2" , plain "Two" , plain "bar" ]
- ]
-
- , "Pipe within text doesn't start a table" =:
- "Ceci n'est pas une | pipe " =?>
- para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ])
-
- , "Missing pipe at end of row" =:
- "|incomplete-but-valid" =?>
- simpleTable' 1 mempty [ [ plain "incomplete-but-valid" ] ]
-
- , "Table with differing row lengths" =:
- unlines [ "| Numbers | Text "
- , "|-"
- , "| <c> | <r> |"
- , "| 1 | One | foo |"
- , "| 2"
- ] =?>
- table "" (zip [AlignCenter, AlignRight] [0, 0])
- [ plain "Numbers", plain "Text" ]
- [ [ plain "1" , plain "One" , plain "foo" ]
- , [ plain "2" ]
- ]
-
- , "Table with caption" =:
- unlines [ "#+CAPTION: Hitchhiker's Multiplication Table"
- , "| x | 6 |"
- , "| 9 | 42 |"
- ] =?>
- table "Hitchhiker's Multiplication Table"
- [(AlignDefault, 0), (AlignDefault, 0)]
- []
- [ [ plain "x", plain "6" ]
- , [ plain "9", plain "42" ]
- ]
- ]
-
- , testGroup "Blocks and fragments"
- [ "Source block" =:
- unlines [ " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"moin\""
- , " #+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" ++
- " where greeting = \"moin\"\n"
- in codeBlockWith attr' code'
-
- , "Source block with indented code" =:
- unlines [ " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"moin\""
- , " #+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" ++
- " where greeting = \"moin\"\n"
- in codeBlockWith attr' code'
-
- , "Source block with tab-indented code" =:
- unlines [ "\t#+BEGIN_SRC haskell"
- , "\tmain = putStrLn greeting"
- , "\t where greeting = \"moin\""
- , "\t#+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" ++
- " where greeting = \"moin\"\n"
- in codeBlockWith attr' code'
-
- , "Empty source block" =:
- unlines [ " #+BEGIN_SRC haskell"
- , " #+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = ""
- in codeBlockWith attr' code'
-
- , "Source block between paragraphs" =:
- unlines [ "Low German greeting"
- , " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"Moin!\""
- , " #+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" ++
- " where greeting = \"Moin!\"\n"
- in mconcat [ para $ spcSep [ "Low", "German", "greeting" ]
- , codeBlockWith attr' code'
- ]
- , "Source block with rundoc/babel arguments" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC" ] =?>
- let classes = [ "commonlisp" -- as kate doesn't know emacs-lisp syntax
- , "rundoc-block"
- ]
- params = [ ("rundoc-language", "emacs-lisp")
- , ("rundoc-exports", "both")
- ]
- code' = unlines [ "(progn (message \"Hello, World!\")"
- , " (+ 23 42))" ]
- in codeBlockWith ("", classes, params) code'
-
- , "Source block with results and :exports both" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65"] =?>
- let classes = [ "commonlisp" -- as kate doesn't know emacs-lisp syntax
- , "rundoc-block"
- ]
- params = [ ("rundoc-language", "emacs-lisp")
- , ("rundoc-exports", "both")
- ]
- code' = unlines [ "(progn (message \"Hello, World!\")"
- , " (+ 23 42))" ]
- results' = "65\n"
- in codeBlockWith ("", classes, params) code'
- <>
- codeBlockWith ("", ["example"], []) results'
-
- , "Source block with results and :exports code" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports code"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
- let classes = [ "commonlisp" -- as kate doesn't know emacs-lisp syntax
- , "rundoc-block"
- ]
- params = [ ("rundoc-language", "emacs-lisp")
- , ("rundoc-exports", "code")
- ]
- code' = unlines [ "(progn (message \"Hello, World!\")"
- , " (+ 23 42))" ]
- in codeBlockWith ("", classes, params) code'
-
- , "Source block with results and :exports results" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports results"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
- let results' = "65\n"
- in codeBlockWith ("", ["example"], []) results'
-
- , "Source block with results and :exports none" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports none"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
- rawBlock "html" ""
-
- , "Source block with toggling header arguments" =:
- unlines [ "#+BEGIN_SRC sh :noeval"
- , "echo $HOME"
- , "#+END_SRC"
- ] =?>
- let classes = [ "bash", "rundoc-block" ]
- params = [ ("rundoc-language", "sh"), ("rundoc-noeval", "yes") ]
- in codeBlockWith ("", classes, params) "echo $HOME\n"
-
- , "Example block" =:
- unlines [ "#+begin_example"
- , "A chosen representation of"
- , "a rule."
- , "#+eND_exAMPle"
- ] =?>
- codeBlockWith ("", ["example"], [])
- "A chosen representation of\na rule.\n"
-
- , "HTML block" =:
- unlines [ "#+BEGIN_HTML"
- , "<aside>HTML5 is pretty nice.</aside>"
- , "#+END_HTML"
- ] =?>
- rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
-
- , "Quote block" =:
- unlines [ "#+BEGIN_QUOTE"
- , "/Niemand/ hat die Absicht, eine Mauer zu errichten!"
- , "#+END_QUOTE"
- ] =?>
- blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
- , "eine", "Mauer", "zu", "errichten!"
- ]))
-
- , "Verse block" =:
- unlines [ "The first lines of Goethe's /Faust/:"
- , "#+begin_verse"
- , "Habe nun, ach! Philosophie,"
- , "Juristerei und Medizin,"
- , "Und leider auch Theologie!"
- , "Durchaus studiert, mit heißem Bemühn."
- , "#+end_verse"
- ] =?>
- mconcat
- [ para $ spcSep [ "The", "first", "lines", "of"
- , "Goethe's", emph "Faust" <> ":"]
- , lineBlock
- [ "Habe nun, ach! Philosophie,"
- , "Juristerei und Medizin,"
- , "Und leider auch Theologie!"
- , "Durchaus studiert, mit heißem Bemühn."
- ]
- ]
-
- , "Verse block with blank lines" =:
- unlines [ "#+BEGIN_VERSE"
- , "foo"
- , ""
- , "bar"
- , "#+END_VERSE"
- ] =?>
- lineBlock [ "foo", mempty, "bar" ]
-
- , "Verse block with varying indentation" =:
- unlines [ "#+BEGIN_VERSE"
- , " hello darkness"
- , "my old friend"
- , "#+END_VERSE"
- ] =?>
- lineBlock [ "\160\160hello darkness", "my old friend" ]
-
- , "Raw block LaTeX" =:
- unlines [ "#+BEGIN_LaTeX"
- , "The category $\\cat{Set}$ is adhesive."
- , "#+END_LaTeX"
- ] =?>
- rawBlock "latex" "The category $\\cat{Set}$ is adhesive.\n"
-
- , "Raw LaTeX line" =:
- "#+LATEX: \\let\\foo\\bar" =?>
- rawBlock "latex" "\\let\\foo\\bar"
-
- , "Raw Beamer line" =:
- "#+beamer: \\pause" =?>
- rawBlock "beamer" "\\pause"
-
- , "Raw HTML line" =:
- "#+HTML: <aside>not important</aside>" =?>
- rawBlock "html" "<aside>not important</aside>"
-
- , "Export block HTML" =:
- unlines [ "#+BEGIN_export html"
- , "<samp>Hello, World!</samp>"
- , "#+END_export"
- ] =?>
- rawBlock "html" "<samp>Hello, World!</samp>\n"
-
- , "LaTeX fragment" =:
- unlines [ "\\begin{equation}"
- , "X_i = \\begin{cases}"
- , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) = \\alpha(i)\\\\"
- , " C_{\\alpha(i)} & \\text{otherwise}"
- , " \\end{cases}"
- , "\\end{equation}"
- ] =?>
- rawBlock "latex"
- (unlines [ "\\begin{equation}"
- , "X_i = \\begin{cases}"
- , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" ++
- " \\alpha(i)\\\\"
- , " C_{\\alpha(i)} & \\text{otherwise}"
- , " \\end{cases}"
- , "\\end{equation}"
- ])
-
- , "Code block with caption" =:
- unlines [ "#+CAPTION: Functor laws in Haskell"
- , "#+NAME: functor-laws"
- , "#+BEGIN_SRC haskell"
- , "fmap id = id"
- , "fmap (p . q) = (fmap p) . (fmap q)"
- , "#+END_SRC"
- ] =?>
- divWith
- nullAttr
- (mappend
- (plain $ spanWith ("", ["label"], [])
- (spcSep [ "Functor", "laws", "in", "Haskell" ]))
- (codeBlockWith ("functor-laws", ["haskell"], [])
- (unlines [ "fmap id = id"
- , "fmap (p . q) = (fmap p) . (fmap q)"
- ])))
-
- , "Convert blank lines in blocks to single newlines" =:
- unlines [ "#+begin_html"
- , ""
- , "<span>boring</span>"
- , ""
- , "#+end_html"
- ] =?>
- rawBlock "html" "\n<span>boring</span>\n\n"
-
- , "Accept `ATTR_HTML` attributes for generic block" =:
- unlines [ "#+ATTR_HTML: :title hello, world :id test :class fun code"
- , "#+BEGIN_TEST"
- , "nonsense"
- , "#+END_TEST"
- ] =?>
- let attr = ("test", ["fun", "code", "TEST"], [("title", "hello, world")])
- in divWith attr (para "nonsense")
-
- , "Non-letter chars in source block parameters" =:
- unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich"
- , "code body"
- , "#+END_SRC"
- ] =?>
- let classes = [ "c", "rundoc-block" ]
- params = [ ("rundoc-language", "C")
- , ("rundoc-tangle", "xxxx.c")
- , ("rundoc-city", "Zürich")
- ]
- in codeBlockWith ( "", classes, params) "code body\n"
- ]
-
- , testGroup "Smart punctuation"
- [ test orgSmart "quote before ellipses"
- ("'...hi'"
- =?> para (singleQuoted "…hi"))
-
- , test orgSmart "apostrophe before emph"
- ("D'oh! A l'/aide/!"
- =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
-
- , test orgSmart "apostrophe in French"
- ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
- =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
-
- , test orgSmart "Quotes cannot occur at the end of emphasized text"
- ("/say \"yes\"/" =?>
- para ("/say" <> space <> doubleQuoted "yes" <> "/"))
-
- , test orgSmart "Dashes are allowed at the borders of emphasis'"
- ("/foo---/" =?>
- para (emph "foo—"))
-
- , test orgSmart "Single quotes can be followed by emphasized text"
- ("Singles on the '/meat market/'" =?>
- para ("Singles on the " <> (singleQuoted $ emph "meat market")))
-
- , test orgSmart "Double quotes can be followed by emphasized text"
- ("Double income, no kids: \"/DINK/\"" =?>
- para ("Double income, no kids: " <> (doubleQuoted $ emph "DINK")))
- ]
- ]
diff --git a/tests/Tests/Readers/RST.hs b/tests/Tests/Readers/RST.hs
deleted file mode 100644
index 9ecbb7af7..000000000
--- a/tests/Tests/Readers/RST.hs
+++ /dev/null
@@ -1,174 +0,0 @@
-{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
-module Tests.Readers.RST (tests) where
-
-import Text.Pandoc.Definition
-import Test.Framework
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-import Text.Pandoc.Builder
-import Text.Pandoc
-
-rst :: String -> Pandoc
-rst = handleError . readRST def{ readerStandalone = True }
-
-infix 4 =:
-(=:) :: ToString c
- => String -> (String, c) -> Test
-(=:) = test rst
-
-tests :: [Test]
-tests = [ "line block with blank line" =:
- "| a\n|\n| b" =?> lineBlock [ "a", mempty, "\160b" ]
- , testGroup "field list"
- [ "general" =: unlines
- [ "para"
- , ""
- , ":Hostname: media08"
- , ":IP address: 10.0.0.19"
- , ":Size: 3ru"
- , ":Version: 1"
- , ":Indentation: Since the field marker may be quite long, the second"
- , " and subsequent lines of the field body do not have to line up"
- , " with the first line, but they must be indented relative to the"
- , " field name marker, and they must line up with each other."
- , ":Parameter i: integer"
- , ":Final: item"
- , " on two lines" ]
- =?> ( doc
- $ para "para" <>
- definitionList [ (str "Hostname", [para "media08"])
- , (text "IP address", [para "10.0.0.19"])
- , (str "Size", [para "3ru"])
- , (str "Version", [para "1"])
- , (str "Indentation", [para "Since the field marker may be quite long, the second\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."])
- , (text "Parameter i", [para "integer"])
- , (str "Final", [para "item\non two lines"])
- ])
- , "metadata" =: unlines
- [ "====="
- , "Title"
- , "====="
- , "--------"
- , "Subtitle"
- , "--------"
- , ""
- , ":Version: 1"
- ]
- =?> ( setMeta "version" (para "1")
- $ setMeta "title" ("Title" :: Inlines)
- $ setMeta "subtitle" ("Subtitle" :: Inlines)
- $ doc mempty )
- , "with inline markup" =: unlines
- [ ":*Date*: today"
- , ""
- , ".."
- , ""
- , ":*one*: emphasis"
- , ":two_: reference"
- , ":`three`_: another one"
- , ":``four``: literal"
- , ""
- , ".. _two: http://example.com"
- , ".. _three: http://example.org"
- ]
- =?> ( setMeta "date" (str "today")
- $ doc
- $ definitionList [ (emph "one", [para "emphasis"])
- , (link "http://example.com" "" "two", [para "reference"])
- , (link "http://example.org" "" "three", [para "another one"])
- , (code "four", [para "literal"])
- ])
- ]
- , "URLs with following punctuation" =:
- ("http://google.com, http://yahoo.com; http://foo.bar.baz.\n" ++
- "http://foo.bar/baz_(bam) (http://foo.bar)") =?>
- para (link "http://google.com" "" "http://google.com" <> ", " <>
- link "http://yahoo.com" "" "http://yahoo.com" <> "; " <>
- link "http://foo.bar.baz" "" "http://foo.bar.baz" <> ". " <>
- softbreak <>
- link "http://foo.bar/baz_(bam)" "" "http://foo.bar/baz_(bam)"
- <> " (" <> link "http://foo.bar" "" "http://foo.bar" <> ")")
- , "Reference names with special characters" =:
- ("A-1-B_2_C:3:D+4+E.5.F_\n\n" ++
- ".. _A-1-B_2_C:3:D+4+E.5.F: https://example.com\n") =?>
- para (link "https://example.com" "" "A-1-B_2_C:3:D+4+E.5.F")
- , "Code directive with class and number-lines" =: unlines
- [ ".. code::python"
- , " :number-lines: 34"
- , " :class: class1 class2 class3"
- , ""
- , " def func(x):"
- , " return y"
- ] =?>
- ( doc $ codeBlockWith
- ( ""
- , ["sourceCode", "python", "numberLines", "class1", "class2", "class3"]
- , [ ("startFrom", "34") ]
- )
- "def func(x):\n return y"
- )
- , "Code directive with number-lines, no line specified" =: unlines
- [ ".. code::python"
- , " :number-lines: "
- , ""
- , " def func(x):"
- , " return y"
- ] =?>
- ( doc $ codeBlockWith
- ( ""
- , ["sourceCode", "python", "numberLines"]
- , [ ("startFrom", "") ]
- )
- "def func(x):\n return y"
- )
- , testGroup "literal / line / code blocks"
- [ "indented literal block" =: unlines
- [ "::"
- , ""
- , " block quotes"
- , ""
- , " can go on for many lines"
- , "but must stop here"]
- =?> (doc $
- codeBlock "block quotes\n\ncan go on for many lines" <>
- para "but must stop here")
- , "line block with 3 lines" =: "| a\n| b\n| c"
- =?> lineBlock ["a", "b", "c"]
- , "quoted literal block using >" =: "::\n\n> quoted\n> block\n\nOrdinary paragraph"
- =?> codeBlock "> quoted\n> block" <> para "Ordinary paragraph"
- , "quoted literal block using | (not a line block)" =: "::\n\n| quoted\n| block\n\nOrdinary paragraph"
- =?> codeBlock "| quoted\n| block" <> para "Ordinary paragraph"
- , "class directive with single paragraph" =: ".. class:: special\n\nThis is a \"special\" paragraph."
- =?> divWith ("", ["special"], []) (para "This is a \"special\" paragraph.")
- , "class directive with two paragraphs" =: ".. class:: exceptional remarkable\n\n First paragraph.\n\n Second paragraph."
- =?> divWith ("", ["exceptional", "remarkable"], []) (para "First paragraph." <> para "Second paragraph.")
- , "class directive around literal block" =: ".. class:: classy\n\n::\n\n a\n b"
- =?> divWith ("", ["classy"], []) (codeBlock "a\nb")]
- , testGroup "interpreted text roles"
- [ "literal role prefix" =: ":literal:`a`" =?> para (code "a")
- , "literal role postfix" =: "`a`:literal:" =?> para (code "a")
- , "literal text" =: "``text``" =?> para (code "text")
- , "code role" =: ":code:`a`" =?> para (codeWith ("", ["sourceCode"], []) "a")
- , "inherited code role" =: ".. role:: codeLike(code)\n\n:codeLike:`a`"
- =?> para (codeWith ("", ["codeLike", "sourceCode"], []) "a")
- , "custom code role with language field"
- =: ".. role:: lhs(code)\n :language: haskell\n\n:lhs:`a`"
- =?> para (codeWith ("", ["lhs", "haskell","sourceCode"], []) "a")
- , "custom role with unspecified parent role"
- =: ".. role:: classy\n\n:classy:`text`"
- =?> para (spanWith ("", ["classy"], []) "text")
- , "role with recursive inheritance"
- =: ".. role:: haskell(code)\n.. role:: lhs(haskell)\n\n:lhs:`text`"
- =?> para (codeWith ("", ["lhs", "haskell", "sourceCode"], []) "text")
- , "unknown role" =: ":unknown:`text`" =?> para (str "text")
- ]
- , testGroup "footnotes"
- [ "remove space before note" =: unlines
- [ "foo [1]_"
- , ""
- , ".. [1]"
- , " bar"
- ] =?>
- (para $ "foo" <> (note $ para "bar"))
- ]
- ]
diff --git a/tests/Tests/Readers/Txt2Tags.hs b/tests/Tests/Readers/Txt2Tags.hs
deleted file mode 100644
index 1bda32a49..000000000
--- a/tests/Tests/Readers/Txt2Tags.hs
+++ /dev/null
@@ -1,429 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Readers.Txt2Tags (tests) where
-
-import Text.Pandoc.Definition
-import Test.Framework
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Data.List (intersperse)
-import Text.Pandoc.Readers.Txt2Tags
-
-t2t :: String -> Pandoc
-t2t = handleError . readTxt2Tags (T2TMeta "date" "mtime" "in" "out") def
-
-infix 4 =:
-(=:) :: ToString c
- => String -> (String, c) -> Test
-(=:) = test t2t
-
-spcSep :: [Inlines] -> Inlines
-spcSep = mconcat . intersperse space
-
-simpleTable' :: Int
- -> [Blocks]
- -> [[Blocks]]
- -> Blocks
-simpleTable' n = table "" (take n $ repeat (AlignCenter, 0.0))
-
-tests :: [Test]
-tests =
- [ testGroup "Inlines" $
- [ "Plain String" =:
- "Hello, World" =?>
- para (spcSep [ "Hello,", "World" ])
-
- , "Emphasis" =:
- "//Planet Punk//" =?>
- para (emph . spcSep $ ["Planet", "Punk"])
-
- , "Strong" =:
- "**Cider**" =?>
- para (strong "Cider")
-
- , "Strong Emphasis" =:
- "//**strength**//" =?>
- para (emph . strong $ "strength")
-
- , "Strikeout" =:
- "--Kill Bill--" =?>
- para (strikeout . spcSep $ [ "Kill", "Bill" ])
-
- , "Verbatim" =:
- "``Robot.rock()``" =?>
- para (code "Robot.rock()")
-
- , "Symbol" =:
- "A * symbol" =?>
- para (str "A" <> space <> str "*" <> space <> "symbol")
-
- , "No empty markup" =:
- "//// **** ____ ---- ```` \"\"\"\" ''''" =?>
- para (spcSep [ "////", "****", "____", "----", "````", "\"\"\"\"", "''''" ])
-
- , "Inline markup is greedy" =:
- "***** ///// _____ ----- ````` \"\"\"\"\" '''''" =?>
- para (spcSep [strong "*", emph "/", emph "_"
- , strikeout "-", code "`", text "\""
- , rawInline "html" "'"])
- , "Markup must be greedy" =:
- "********** ////////// __________ ---------- `````````` \"\"\"\"\"\"\"\"\"\" ''''''''''" =?>
- para (spcSep [strong "******", emph "//////", emph "______"
- , strikeout "------", code "``````", text "\"\"\"\"\"\""
- , rawInline "html" "''''''"])
- , "Inlines must be glued" =:
- "** a** **a ** ** a **" =?>
- para (text "** a** **a ** ** a **")
-
- , "Macros: Date" =:
- "%%date" =?>
- para "date"
- , "Macros: Mod Time" =:
- "%%mtime" =?>
- para "mtime"
- , "Macros: Infile" =:
- "%%infile" =?>
- para "in"
- , "Macros: Outfile" =:
- "%%outfile" =?>
- para "out"
- , "Autolink" =:
- "http://www.google.com" =?>
- para (link "http://www.google.com" "" (str "http://www.google.com"))
- , "Image" =:
- "[image.jpg]" =?>
- para (image "image.jpg" "" mempty)
-
- , "Link" =:
- "[title http://google.com]" =?>
- para (link "http://google.com" "" (str "title"))
-
- , "Image link" =:
- "[[image.jpg] abc]" =?>
- para (link "abc" "" (image "image.jpg" "" mempty))
- , "Invalid link: No trailing space" =:
- "[title invalid ]" =?>
- para (text "[title invalid ]")
-
-
- ]
-
- , testGroup "Basic Blocks" $
- ["Paragraph, lines grouped together" =:
- "A paragraph\n A blank line ends the \n current paragraph\n"
- =?> para "A paragraph\n A blank line ends the\n current paragraph"
- , "Paragraph, ignore leading and trailing spaces" =:
- " Leading and trailing spaces are ignored. \n" =?>
- para "Leading and trailing spaces are ignored."
- , "Comment line in paragraph" =:
- "A comment line can be placed inside a paragraph.\n% this comment will be ignored \nIt will not affect it.\n"
- =?> para "A comment line can be placed inside a paragraph.\nIt will not affect it."
- , "Paragraph" =:
- "Paragraph\n" =?>
- para "Paragraph"
-
- , "First Level Header" =:
- "+ Headline +\n" =?>
- header 1 "Headline"
-
- , "Third Level Header" =:
- "=== Third Level Headline ===\n" =?>
- header 3 ("Third" <> space <>
- "Level" <> space <>
- "Headline")
-
- , "Header with label" =:
- "= header =[label]" =?>
- headerWith ("label", [], []) 1 ("header")
-
- , "Invalid header, mismatched delimiters" =:
- "== header =" =?>
- para (text "== header =")
-
- , "Invalid header, spaces in label" =:
- "== header ==[ haha ]" =?>
- para (text "== header ==[ haha ]")
-
- , "Invalid header, invalid label character" =:
- "== header ==[lab/el]" =?>
- para (text "== header ==[lab/el]")
- , "Headers not preceded by a blank line" =:
- unlines [ "++ eat dinner ++"
- , "Spaghetti and meatballs tonight."
- , "== walk dog =="
- ] =?>
- mconcat [ header 2 ("eat" <> space <> "dinner")
- , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
- , header 2 ("walk" <> space <> "dog")
- ]
-
- , "Paragraph starting with an equals" =:
- "=five" =?>
- para "=five"
-
- , "Paragraph containing asterisk at beginning of line" =:
- unlines [ "lucky"
- , "*star"
- ] =?>
- para ("lucky" <> softbreak <> "*star")
-
- , "Horizontal Rule" =:
- unlines [ "before"
- , replicate 20 '-'
- , replicate 20 '='
- , replicate 20 '_'
- , "after"
- ] =?>
- mconcat [ para "before"
- , horizontalRule
- , horizontalRule
- , horizontalRule
- , para "after"
- ]
-
- , "Comment Block" =:
- unlines [ "%%%"
- , "stuff"
- , "bla"
- , "%%%"] =?>
- (mempty::Blocks)
-
-
- ]
-
- , testGroup "Lists" $
- [ "Simple Bullet Lists" =:
- ("- Item1\n" ++
- "- Item2\n") =?>
- bulletList [ plain "Item1"
- , plain "Item2"
- ]
-
- , "Indented Bullet Lists" =:
- (" - Item1\n" ++
- " - Item2\n") =?>
- bulletList [ plain "Item1"
- , plain "Item2"
- ]
-
-
-
- , "Nested Bullet Lists" =:
- ("- Discovery\n" ++
- " + One More Time\n" ++
- " + Harder, Better, Faster, Stronger\n" ++
- "- Homework\n" ++
- " + Around the World\n"++
- "- Human After All\n" ++
- " + Technologic\n" ++
- " + Robot Rock\n") =?>
- bulletList [ mconcat
- [ plain "Discovery"
- , orderedList [ plain ("One" <> space <>
- "More" <> space <>
- "Time")
- , plain ("Harder," <> space <>
- "Better," <> space <>
- "Faster," <> space <>
- "Stronger")
- ]
- ]
- , mconcat
- [ plain "Homework"
- , orderedList [ plain ("Around" <> space <>
- "the" <> space <>
- "World")
- ]
- ]
- , mconcat
- [ plain ("Human" <> space <> "After" <> space <> "All")
- , orderedList [ plain "Technologic"
- , plain ("Robot" <> space <> "Rock")
- ]
- ]
- ]
-
- , "Simple Ordered List" =:
- ("+ Item1\n" ++
- "+ Item2\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ plain "Item1"
- , plain "Item2"
- ]
- in orderedListWith listStyle listStructure
-
-
- , "Indented Ordered List" =:
- (" + Item1\n" ++
- " + Item2\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ plain "Item1"
- , plain "Item2"
- ]
- in orderedListWith listStyle listStructure
-
- , "Nested Ordered Lists" =:
- ("+ One\n" ++
- " + One-One\n" ++
- " + One-Two\n" ++
- "+ Two\n" ++
- " + Two-One\n"++
- " + Two-Two\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ mconcat
- [ plain "One"
- , orderedList [ plain "One-One"
- , plain "One-Two"
- ]
- ]
- , mconcat
- [ plain "Two"
- , orderedList [ plain "Two-One"
- , plain "Two-Two"
- ]
- ]
- ]
- in orderedListWith listStyle listStructure
-
- , "Ordered List in Bullet List" =:
- ("- Emacs\n" ++
- " + Org\n") =?>
- bulletList [ (plain "Emacs") <>
- (orderedList [ plain "Org"])
- ]
-
- , "Bullet List in Ordered List" =:
- ("+ GNU\n" ++
- " - Freedom\n") =?>
- orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ]
-
- , "Definition List" =:
- unlines [ ": PLL"
- , " phase-locked loop"
- , ": TTL"
- , " transistor-transistor logic"
- , ": PSK"
- , " a digital"
- ] =?>
- definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
- , ("TTL", [ plain $ "transistor-transistor" <> space <> "logic" ])
- , ("PSK", [ plain $ "a" <> space <> "digital" ])
- ]
-
-
- , "Loose bullet list" =:
- unlines [ "- apple"
- , ""
- , "- orange"
- , ""
- , "- peach"
- ] =?>
- bulletList [ para "apple"
- , para "orange"
- , para "peach"
- ]
- ]
-
- , testGroup "Tables"
- [ "Single cell table" =:
- "| Test " =?>
- simpleTable' 1 mempty [[plain "Test"]]
-
- , "Multi cell table" =:
- "| One | Two |" =?>
- simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
-
- , "Multi line table" =:
- unlines [ "| One |"
- , "| Two |"
- , "| Three |"
- ] =?>
- simpleTable' 1 mempty
- [ [ plain "One" ]
- , [ plain "Two" ]
- , [ plain "Three" ]
- ]
-
- , "Empty table" =:
- "| |" =?>
- simpleTable' 1 mempty [[mempty]]
-
- , "Glider Table" =:
- unlines [ "| 1 | 0 | 0 |"
- , "| 0 | 1 | 1 |"
- , "| 1 | 1 | 0 |"
- ] =?>
- simpleTable' 3 mempty
- [ [ plain "1", plain "0", plain "0" ]
- , [ plain "0", plain "1", plain "1" ]
- , [ plain "1", plain "1", plain "0" ]
- ]
-
-
- , "Table with Header" =:
- unlines [ "|| Species | Status |"
- , "| cervisiae | domesticated |"
- , "| paradoxus | wild |"
- ] =?>
- simpleTable [ plain "Species", plain "Status" ]
- [ [ plain "cervisiae", plain "domesticated" ]
- , [ plain "paradoxus", plain "wild" ]
- ]
-
- , "Table alignment determined by spacing" =:
- unlines [ "| Numbers | Text | More |"
- , "| 1 | One | foo |"
- , "| 2 | Two | bar |"
- ] =?>
- table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
- []
- [ [ plain "Numbers", plain "Text", plain "More" ]
- , [ plain "1" , plain "One" , plain "foo" ]
- , [ plain "2" , plain "Two" , plain "bar" ]
- ]
-
- , "Pipe within text doesn't start a table" =:
- "Ceci n'est pas une | pipe " =?>
- para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ])
-
-
- , "Table with differing row lengths" =:
- unlines [ "|| Numbers | Text "
- , "| 1 | One | foo |"
- , "| 2 "
- ] =?>
- table "" (zip [AlignCenter, AlignLeft, AlignLeft] [0, 0, 0])
- [ plain "Numbers", plain "Text" , plain mempty ]
- [ [ plain "1" , plain "One" , plain "foo" ]
- , [ plain "2" , plain mempty , plain mempty ]
- ]
-
- ]
-
- , testGroup "Blocks and fragments"
- [ "Source block" =:
- unlines [ "```"
- , "main = putStrLn greeting"
- , " where greeting = \"moin\""
- , "```" ] =?>
- let code' = "main = putStrLn greeting\n" ++
- " where greeting = \"moin\"\n"
- in codeBlock code'
-
- , "tagged block" =:
- unlines [ "'''"
- , "<aside>HTML5 is pretty nice.</aside>"
- , "'''"
- ] =?>
- rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
-
- , "Quote block" =:
- unlines ["\t//Niemand// hat die Absicht, eine Mauer zu errichten!"
- ] =?>
- blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
- , "eine", "Mauer", "zu", "errichten!"
- ]))
-
- ]
- ]
diff --git a/tests/Tests/Shared.hs b/tests/Tests/Shared.hs
deleted file mode 100644
index 55f520433..000000000
--- a/tests/Tests/Shared.hs
+++ /dev/null
@@ -1,60 +0,0 @@
-module Tests.Shared (tests) where
-
-import Text.Pandoc.Definition
-import Text.Pandoc.Shared
-import Test.Framework
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-import Test.Framework.Providers.HUnit
-import Test.HUnit ( assertBool, (@?=) )
-import Text.Pandoc.Builder
-import System.FilePath.Posix (joinPath)
-
-tests :: [Test]
-tests = [ testGroup "normalize"
- [ property "p_normalize_blocks_rt" p_normalize_blocks_rt
- , property "p_normalize_inlines_rt" p_normalize_inlines_rt
- , property "p_normalize_no_trailing_spaces"
- p_normalize_no_trailing_spaces
- ]
- , testGroup "compactify'DL"
- [ testCase "compactify'DL with empty def" $
- assertBool "compactify'DL"
- (let x = [(str "word", [para (str "def"), mempty])]
- in compactify'DL x == x)
- ]
- , testGroup "collapseFilePath" testCollapse
- ]
-
-p_normalize_blocks_rt :: [Block] -> Bool
-p_normalize_blocks_rt bs =
- normalizeBlocks bs == normalizeBlocks (normalizeBlocks bs)
-
-p_normalize_inlines_rt :: [Inline] -> Bool
-p_normalize_inlines_rt ils =
- normalizeInlines ils == normalizeInlines (normalizeInlines ils)
-
-p_normalize_no_trailing_spaces :: [Inline] -> Bool
-p_normalize_no_trailing_spaces ils = null ils' || last ils' /= Space
- where ils' = normalizeInlines $ ils ++ [Space]
-
-testCollapse :: [Test]
-testCollapse = map (testCase "collapse")
- [ (collapseFilePath (joinPath [ ""]) @?= (joinPath [ ""]))
- , (collapseFilePath (joinPath [ ".","foo"]) @?= (joinPath [ "foo"]))
- , (collapseFilePath (joinPath [ ".",".","..","foo"]) @?= (joinPath [ joinPath ["..", "foo"]]))
- , (collapseFilePath (joinPath [ "..","foo"]) @?= (joinPath [ "..","foo"]))
- , (collapseFilePath (joinPath [ "","bar","..","baz"]) @?= (joinPath [ "","baz"]))
- , (collapseFilePath (joinPath [ "","..","baz"]) @?= (joinPath [ "","..","baz"]))
- , (collapseFilePath (joinPath [ ".","foo","..",".","bar","..",".",".","baz"]) @?= (joinPath [ "baz"]))
- , (collapseFilePath (joinPath [ ".",""]) @?= (joinPath [ ""]))
- , (collapseFilePath (joinPath [ ".",".",""]) @?= (joinPath [ ""]))
- , (collapseFilePath (joinPath [ "..",""]) @?= (joinPath [ ".."]))
- , (collapseFilePath (joinPath [ "..",".",""]) @?= (joinPath [ ".."]))
- , (collapseFilePath (joinPath [ ".","..",""]) @?= (joinPath [ ".."]))
- , (collapseFilePath (joinPath [ "..","..",""]) @?= (joinPath [ "..",".."]))
- , (collapseFilePath (joinPath [ "parent","foo","baz","..","bar"]) @?= (joinPath [ "parent","foo","bar"]))
- , (collapseFilePath (joinPath [ "parent","foo","baz","..","..","bar"]) @?= (joinPath [ "parent","bar"]))
- , (collapseFilePath (joinPath [ "parent","foo",".."]) @?= (joinPath [ "parent"]))
- , (collapseFilePath (joinPath [ "","parent","foo","..","..","bar"]) @?= (joinPath [ "","bar"]))
- , (collapseFilePath (joinPath [ "",".","parent","foo"]) @?= (joinPath [ "","parent","foo"]))]
diff --git a/tests/Tests/Walk.hs b/tests/Tests/Walk.hs
deleted file mode 100644
index 876d75e30..000000000
--- a/tests/Tests/Walk.hs
+++ /dev/null
@@ -1,46 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables, FlexibleContexts #-}
-module Tests.Walk (tests) where
-
-import Text.Pandoc.Definition
-import Text.Pandoc.Walk
-import Test.Framework
-import Tests.Helpers
-import Data.Char (toUpper)
-import Text.Pandoc.Arbitrary()
-import Data.Generics
-
-tests :: [Test]
-tests = [ testGroup "Walk"
- [ property "p_walk inlineTrans" (p_walk inlineTrans)
- , property "p_walk blockTrans" (p_walk blockTrans)
- , property "p_query inlineQuery" (p_query inlineQuery)
- , property "p_query blockQuery" (p_query blockQuery)
- ]
- ]
-
-p_walk :: (Typeable a, Walkable a Pandoc)
- => (a -> a) -> Pandoc -> Bool
-p_walk f d = everywhere (mkT f) d == walk f d
-
-p_query :: (Eq a, Typeable a1, Monoid a, Walkable a1 Pandoc)
- => (a1 -> a) -> Pandoc -> Bool
-p_query f d = everything mappend (mempty `mkQ` f) d == query f d
-
-inlineTrans :: Inline -> Inline
-inlineTrans (Str xs) = Str $ map toUpper xs
-inlineTrans (Emph xs) = Strong xs
-inlineTrans x = x
-
-blockTrans :: Block -> Block
-blockTrans (Plain xs) = Para xs
-blockTrans (BlockQuote xs) = Div ("",["special"],[]) xs
-blockTrans x = x
-
-inlineQuery :: Inline -> String
-inlineQuery (Str xs) = xs
-inlineQuery _ = ""
-
-blockQuery :: Block -> [Int]
-blockQuery (Header lev _ _) = [lev]
-blockQuery _ = []
-
diff --git a/tests/Tests/Writers/AsciiDoc.hs b/tests/Tests/Writers/AsciiDoc.hs
deleted file mode 100644
index 8ab216753..000000000
--- a/tests/Tests/Writers/AsciiDoc.hs
+++ /dev/null
@@ -1,55 +0,0 @@
-module Tests.Writers.AsciiDoc (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-asciidoc :: (ToPandoc a) => a -> String
-asciidoc = writeAsciiDoc def{ writerWrapText = WrapNone } . toPandoc
-
-tests :: [Test]
-tests = [ testGroup "emphasis"
- [ test asciidoc "emph word before" $
- para (text "foo" <> emph (text "bar")) =?>
- "foo__bar__"
- , test asciidoc "emph word after" $
- para (emph (text "foo") <> text "bar") =?>
- "__foo__bar"
- , test asciidoc "emph quoted" $
- para (doubleQuoted (emph (text "foo"))) =?>
- "``__foo__''"
- , test asciidoc "strong word before" $
- para (text "foo" <> strong (text "bar")) =?>
- "foo**bar**"
- , test asciidoc "strong word after" $
- para (strong (text "foo") <> text "bar") =?>
- "**foo**bar"
- , test asciidoc "strong quoted" $
- para (singleQuoted (strong (text "foo"))) =?>
- "`**foo**'"
- ]
- , testGroup "tables"
- [ test asciidoc "empty cells" $
- simpleTable [] [[mempty],[mempty]] =?> unlines
- [ "[cols=\"\",]"
- , "|===="
- , "|"
- , "|"
- , "|===="
- ]
- , test asciidoc "multiblock cells" $
- simpleTable [] [[para (text "Para 1") <> para (text "Para 2")]]
- =?> unlines
- [ "[cols=\"\",]"
- , "|====="
- , "a|"
- , "Para 1"
- , ""
- , "Para 2"
- , ""
- , "|====="
- ]
- ]
- ]
diff --git a/tests/Tests/Writers/ConTeXt.hs b/tests/Tests/Writers/ConTeXt.hs
deleted file mode 100644
index 629e58b8f..000000000
--- a/tests/Tests/Writers/ConTeXt.hs
+++ /dev/null
@@ -1,70 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Writers.ConTeXt (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-context :: (ToPandoc a) => a -> String
-context = writeConTeXt def . toPandoc
-
-context' :: (ToPandoc a) => a -> String
-context' = writeConTeXt def{ writerWrapText = WrapNone } . toPandoc
-
-{-
- "my test" =: X =?> Y
-
-is shorthand for
-
- test context "my test" $ X =?> Y
-
-which is in turn shorthand for
-
- test context "my test" (X,Y)
--}
-
-infix 4 =:
-(=:) :: (ToString a, ToPandoc a)
- => String -> (a, String) -> Test
-(=:) = test context
-
-tests :: [Test]
-tests = [ testGroup "inline code"
- [ "with '}'" =: code "}" =?> "\\mono{\\}}"
- , "without '}'" =: code "]" =?> "\\type{]}"
- , property "code property" $ \s -> null s ||
- if '{' `elem` s || '}' `elem` s
- then (context' $ code s) == "\\mono{" ++
- (context' $ str s) ++ "}"
- else (context' $ code s) == "\\type{" ++ s ++ "}"
- ]
- , testGroup "headers"
- [ "level 1" =:
- headerWith ("my-header",[],[]) 1 "My header" =?> "\\section[my-header]{My header}"
- ]
- , testGroup "bullet lists"
- [ "nested" =:
- bulletList [
- plain (text "top")
- <> bulletList [
- plain (text "next")
- <> bulletList [plain (text "bot")]
- ]
- ] =?> unlines
- [ "\\startitemize[packed]"
- , "\\item"
- , " top"
- , " \\startitemize[packed]"
- , " \\item"
- , " next"
- , " \\startitemize[packed]"
- , " \\item"
- , " bot"
- , " \\stopitemize"
- , " \\stopitemize"
- , "\\stopitemize" ]
- ]
- ]
-
diff --git a/tests/Tests/Writers/Docbook.hs b/tests/Tests/Writers/Docbook.hs
deleted file mode 100644
index a288242dc..000000000
--- a/tests/Tests/Writers/Docbook.hs
+++ /dev/null
@@ -1,302 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Writers.Docbook (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-docbook :: (ToPandoc a) => a -> String
-docbook = docbookWithOpts def{ writerWrapText = WrapNone }
-
-docbookWithOpts :: ToPandoc a => WriterOptions -> a -> String
-docbookWithOpts opts = writeDocbook opts . toPandoc
-
-{-
- "my test" =: X =?> Y
-
-is shorthand for
-
- test docbook "my test" $ X =?> Y
-
-which is in turn shorthand for
-
- test docbook "my test" (X,Y)
--}
-
-infix 4 =:
-(=:) :: (ToString a, ToPandoc a)
- => String -> (a, String) -> Test
-(=:) = test docbook
-
-lineblock :: Blocks
-lineblock = para ("some text" <> linebreak <>
- "and more lines" <> linebreak <>
- "and again")
-lineblock_out :: [String]
-lineblock_out = [ "<literallayout>some text"
- , "and more lines"
- , "and again</literallayout>"
- ]
-
-tests :: [Test]
-tests = [ testGroup "line blocks"
- [ "none" =: para "This is a test"
- =?> unlines
- [ "<para>"
- , " This is a test"
- , "</para>"
- ]
- , "basic" =: lineblock
- =?> unlines lineblock_out
- , "blockquote" =: blockQuote lineblock
- =?> unlines
- ( [ "<blockquote>" ] ++
- lineblock_out ++
- [ "</blockquote>" ]
- )
- , "footnote" =: para ("This is a test" <>
- note lineblock <>
- " of footnotes")
- =?> unlines
- ( [ "<para>"
- , " This is a test<footnote>" ] ++
- lineblock_out ++
- [ " </footnote> of footnotes"
- , "</para>" ]
- )
- ]
- , testGroup "compact lists"
- [ testGroup "bullet"
- [ "compact" =: bulletList [plain "a", plain "b", plain "c"]
- =?> unlines
- [ "<itemizedlist spacing=\"compact\">"
- , " <listitem>"
- , " <para>"
- , " a"
- , " </para>"
- , " </listitem>"
- , " <listitem>"
- , " <para>"
- , " b"
- , " </para>"
- , " </listitem>"
- , " <listitem>"
- , " <para>"
- , " c"
- , " </para>"
- , " </listitem>"
- , "</itemizedlist>"
- ]
- , "loose" =: bulletList [para "a", para "b", para "c"]
- =?> unlines
- [ "<itemizedlist>"
- , " <listitem>"
- , " <para>"
- , " a"
- , " </para>"
- , " </listitem>"
- , " <listitem>"
- , " <para>"
- , " b"
- , " </para>"
- , " </listitem>"
- , " <listitem>"
- , " <para>"
- , " c"
- , " </para>"
- , " </listitem>"
- , "</itemizedlist>"
- ]
- ]
- , testGroup "ordered"
- [ "compact" =: orderedList [plain "a", plain "b", plain "c"]
- =?> unlines
- [ "<orderedlist spacing=\"compact\">"
- , " <listitem>"
- , " <para>"
- , " a"
- , " </para>"
- , " </listitem>"
- , " <listitem>"
- , " <para>"
- , " b"
- , " </para>"
- , " </listitem>"
- , " <listitem>"
- , " <para>"
- , " c"
- , " </para>"
- , " </listitem>"
- , "</orderedlist>"
- ]
- , "loose" =: orderedList [para "a", para "b", para "c"]
- =?> unlines
- [ "<orderedlist>"
- , " <listitem>"
- , " <para>"
- , " a"
- , " </para>"
- , " </listitem>"
- , " <listitem>"
- , " <para>"
- , " b"
- , " </para>"
- , " </listitem>"
- , " <listitem>"
- , " <para>"
- , " c"
- , " </para>"
- , " </listitem>"
- , "</orderedlist>"
- ]
- ]
- , testGroup "definition"
- [ "compact" =: definitionList [ ("an", [plain "apple" ])
- , ("a", [plain "banana"])
- , ("an", [plain "orange"])]
- =?> unlines
- [ "<variablelist spacing=\"compact\">"
- , " <varlistentry>"
- , " <term>"
- , " an"
- , " </term>"
- , " <listitem>"
- , " <para>"
- , " apple"
- , " </para>"
- , " </listitem>"
- , " </varlistentry>"
- , " <varlistentry>"
- , " <term>"
- , " a"
- , " </term>"
- , " <listitem>"
- , " <para>"
- , " banana"
- , " </para>"
- , " </listitem>"
- , " </varlistentry>"
- , " <varlistentry>"
- , " <term>"
- , " an"
- , " </term>"
- , " <listitem>"
- , " <para>"
- , " orange"
- , " </para>"
- , " </listitem>"
- , " </varlistentry>"
- , "</variablelist>"
- ]
- , "loose" =: definitionList [ ("an", [para "apple" ])
- , ("a", [para "banana"])
- , ("an", [para "orange"])]
- =?> unlines
- [ "<variablelist>"
- , " <varlistentry>"
- , " <term>"
- , " an"
- , " </term>"
- , " <listitem>"
- , " <para>"
- , " apple"
- , " </para>"
- , " </listitem>"
- , " </varlistentry>"
- , " <varlistentry>"
- , " <term>"
- , " a"
- , " </term>"
- , " <listitem>"
- , " <para>"
- , " banana"
- , " </para>"
- , " </listitem>"
- , " </varlistentry>"
- , " <varlistentry>"
- , " <term>"
- , " an"
- , " </term>"
- , " <listitem>"
- , " <para>"
- , " orange"
- , " </para>"
- , " </listitem>"
- , " </varlistentry>"
- , "</variablelist>"
- ]
- ]
- ]
- , testGroup "writer options" $
- [ testGroup "top-level division" $
- let
- headers = header 1 (text "header1")
- <> header 2 (text "header2")
- <> header 3 (text "header3")
-
- docbookTopLevelDiv :: (ToPandoc a)
- => TopLevelDivision -> a -> String
- docbookTopLevelDiv division =
- docbookWithOpts def{ writerTopLevelDivision = division }
- in
- [ test (docbookTopLevelDiv TopLevelSection) "sections as top-level" $
- headers =?>
- unlines [ "<sect1>"
- , " <title>header1</title>"
- , " <sect2>"
- , " <title>header2</title>"
- , " <sect3>"
- , " <title>header3</title>"
- , " <para>"
- , " </para>"
- , " </sect3>"
- , " </sect2>"
- , "</sect1>"
- ]
- , test (docbookTopLevelDiv TopLevelChapter) "chapters as top-level" $
- headers =?>
- unlines [ "<chapter>"
- , " <title>header1</title>"
- , " <sect1>"
- , " <title>header2</title>"
- , " <sect2>"
- , " <title>header3</title>"
- , " <para>"
- , " </para>"
- , " </sect2>"
- , " </sect1>"
- , "</chapter>"
- ]
- , test (docbookTopLevelDiv TopLevelPart) "parts as top-level" $
- headers =?>
- unlines [ "<part>"
- , " <title>header1</title>"
- , " <chapter>"
- , " <title>header2</title>"
- , " <sect1>"
- , " <title>header3</title>"
- , " <para>"
- , " </para>"
- , " </sect1>"
- , " </chapter>"
- , "</part>"
- ]
- , test (docbookTopLevelDiv TopLevelDefault) "default top-level" $
- headers =?>
- unlines [ "<sect1>"
- , " <title>header1</title>"
- , " <sect2>"
- , " <title>header2</title>"
- , " <sect3>"
- , " <title>header3</title>"
- , " <para>"
- , " </para>"
- , " </sect3>"
- , " </sect2>"
- , "</sect1>"
- ]
- ]
- ]
- ]
diff --git a/tests/Tests/Writers/Docx.hs b/tests/Tests/Writers/Docx.hs
deleted file mode 100644
index 31fc3a47b..000000000
--- a/tests/Tests/Writers/Docx.hs
+++ /dev/null
@@ -1,149 +0,0 @@
-module Tests.Writers.Docx (tests) where
-
-import Text.Pandoc.Options
-import Text.Pandoc.Readers.Native
-import Text.Pandoc.Definition
-import Tests.Helpers
-import Test.Framework
-import Text.Pandoc.Readers.Docx
-import Text.Pandoc.Writers.Docx
-import Text.Pandoc.Error
-import System.FilePath ((</>))
-
-type Options = (WriterOptions, ReaderOptions)
-
-compareOutput :: Options
- -> FilePath
- -> FilePath
- -> IO (Pandoc, Pandoc)
-compareOutput opts nativeFileIn nativeFileOut = do
- nf <- Prelude.readFile nativeFileIn
- nf' <- Prelude.readFile nativeFileOut
- let wopts = fst opts
- df <- writeDocx wopts{writerUserDataDir = Just (".." </> "data")}
- (handleError $ readNative nf)
- let (p, _) = handleError $ readDocx (snd opts) df
- return (p, handleError $ readNative nf')
-
-testCompareWithOptsIO :: Options -> String -> FilePath -> FilePath -> IO Test
-testCompareWithOptsIO opts name nativeFileIn nativeFileOut = do
- (dp, np) <- compareOutput opts nativeFileIn nativeFileOut
- return $ test id name (dp, np)
-
-testCompareWithOpts :: Options -> String -> FilePath -> FilePath -> Test
-testCompareWithOpts opts name nativeFileIn nativeFileOut =
- buildTest $ testCompareWithOptsIO opts name nativeFileIn nativeFileOut
-
-roundTripCompareWithOpts :: Options -> String -> FilePath -> Test
-roundTripCompareWithOpts opts name nativeFile =
- testCompareWithOpts opts name nativeFile nativeFile
-
--- testCompare :: String -> FilePath -> FilePath -> Test
--- testCompare = testCompareWithOpts def
-
-roundTripCompare :: String -> FilePath -> Test
-roundTripCompare = roundTripCompareWithOpts def
-
-tests :: [Test]
-tests = [ testGroup "inlines"
- [ roundTripCompare
- "font formatting"
- "docx/inline_formatting_writer.native"
- , roundTripCompare
- "font formatting with character styles"
- "docx/char_styles.native"
- , roundTripCompare
- "hyperlinks"
- "docx/links_writer.native"
- , roundTripCompare
- "inline image"
- "docx/image_no_embed_writer.native"
- , roundTripCompare
- "inline image in links"
- "docx/inline_images_writer.native"
- , roundTripCompare
- "handling unicode input"
- "docx/unicode.native"
- , roundTripCompare
- "literal tabs"
- "docx/tabs.native"
- , roundTripCompare
- "normalizing inlines"
- "docx/normalize.native"
- , roundTripCompare
- "normalizing inlines deep inside blocks"
- "docx/deep_normalize.native"
- , roundTripCompare
- "move trailing spaces outside of formatting"
- "docx/trailing_spaces_in_formatting.native"
- , roundTripCompare
- "inline code (with VerbatimChar style)"
- "docx/inline_code.native"
- , roundTripCompare
- "inline code in subscript and superscript"
- "docx/verbatim_subsuper.native"
- ]
- , testGroup "blocks"
- [ roundTripCompare
- "headers"
- "docx/headers.native"
- , roundTripCompare
- "headers already having auto identifiers"
- "docx/already_auto_ident.native"
- , roundTripCompare
- "numbered headers automatically made into list"
- "docx/numbered_header.native"
- , roundTripCompare
- "i18n blocks (headers and blockquotes)"
- "docx/i18n_blocks.native"
- -- Continuation does not survive round-trip
- , roundTripCompare
- "lists"
- "docx/lists_writer.native"
- , roundTripCompare
- "definition lists"
- "docx/definition_list.native"
- , roundTripCompare
- "custom defined lists in styles"
- "docx/german_styled_lists.native"
- , roundTripCompare
- "footnotes and endnotes"
- "docx/notes.native"
- , roundTripCompare
- "blockquotes (parsing indent as blockquote)"
- "docx/block_quotes_parse_indent.native"
- , roundTripCompare
- "hanging indents"
- "docx/hanging_indent.native"
- -- tables headers do not survive round-trip, should look into that
- , roundTripCompare
- "tables"
- "docx/tables.native"
- , roundTripCompare
- "tables with lists in cells"
- "docx/table_with_list_cell.native"
- , roundTripCompare
- "code block"
- "docx/codeblock.native"
- , roundTripCompare
- "dropcap paragraphs"
- "docx/drop_cap.native"
- ]
- , testGroup "metadata"
- [ roundTripCompareWithOpts (def,def{readerStandalone=True})
- "metadata fields"
- "docx/metadata.native"
- , roundTripCompareWithOpts (def,def{readerStandalone=True})
- "stop recording metadata with normal text"
- "docx/metadata_after_normal.native"
- ]
- , testGroup "customized styles"
- [ testCompareWithOpts
- ( def{writerReferenceDocx=Just "docx/custom-style-reference.docx"}
- , def)
- "simple customized blocks and inlines"
- "docx/custom-style-roundtrip-start.native"
- "docx/custom-style-roundtrip-end.native"
- ]
-
- ]
diff --git a/tests/Tests/Writers/HTML.hs b/tests/Tests/Writers/HTML.hs
deleted file mode 100644
index 5bea99f71..000000000
--- a/tests/Tests/Writers/HTML.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Writers.HTML (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-html :: (ToPandoc a) => a -> String
-html = writeHtmlString def{ writerWrapText = WrapNone } . toPandoc
-
-{-
- "my test" =: X =?> Y
-
-is shorthand for
-
- test html "my test" $ X =?> Y
-
-which is in turn shorthand for
-
- test html "my test" (X,Y)
--}
-
-infix 4 =:
-(=:) :: (ToString a, ToPandoc a)
- => String -> (a, String) -> Test
-(=:) = test html
-
-tests :: [Test]
-tests = [ testGroup "inline code"
- [ "basic" =: code "@&" =?> "<code>@&amp;</code>"
- , "haskell" =: codeWith ("",["haskell"],[]) ">>="
- =?> "<code class=\"haskell\">&gt;&gt;=</code>"
- , "nolanguage" =: codeWith ("",["nolanguage"],[]) ">>="
- =?> "<code class=\"nolanguage\">&gt;&gt;=</code>"
- ]
- , testGroup "images"
- [ "alt with formatting" =:
- image "/url" "title" ("my " <> emph "image")
- =?> "<img src=\"/url\" title=\"title\" alt=\"my image\" />"
- ]
- ]
diff --git a/tests/Tests/Writers/LaTeX.hs b/tests/Tests/Writers/LaTeX.hs
deleted file mode 100644
index f140cc2dd..000000000
--- a/tests/Tests/Writers/LaTeX.hs
+++ /dev/null
@@ -1,173 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Writers.LaTeX (tests) where
-
-import Test.Framework
-import Tests.Helpers
-import Text.Pandoc
-import Text.Pandoc.Arbitrary ()
-import Text.Pandoc.Builder
-
-latex :: (ToPandoc a) => a -> String
-latex = latexWithOpts def{ writerHighlight = True }
-
-latexListing :: (ToPandoc a) => a -> String
-latexListing = latexWithOpts def{ writerListings = True }
-
-latexWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
-latexWithOpts opts = writeLaTeX opts . toPandoc
-
-{-
- "my test" =: X =?> Y
-
-is shorthand for
-
- test latex "my test" $ X =?> Y
-
-which is in turn shorthand for
-
- test latex "my test" (X,Y)
--}
-
-infix 4 =:
-(=:) :: (ToString a, ToPandoc a)
- => String -> (a, String) -> Test
-(=:) = test latex
-
-tests :: [Test]
-tests = [ testGroup "code blocks"
- [ "in footnotes" =: note (para "hi" <> codeBlock "hi") =?>
- "\\footnote{hi\n\n\\begin{Verbatim}\nhi\n\\end{Verbatim}\n}"
- , test latexListing "identifier" $ codeBlockWith ("id",[],[]) "hi" =?>
- ("\\begin{lstlisting}[label=id]\nhi\n\\end{lstlisting}" :: String)
- , test latexListing "no identifier" $ codeBlock "hi" =?>
- ("\\begin{lstlisting}\nhi\n\\end{lstlisting}" :: String)
- ]
- , testGroup "definition lists"
- [ "with internal link" =: definitionList [(link "#go" "" (str "testing"),
- [plain (text "hi there")])] =?>
- "\\begin{description}\n\\tightlist\n\\item[{\\protect\\hyperlink{go}{testing}}]\nhi there\n\\end{description}"
- ]
- , testGroup "math"
- [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
- "\\(\\sigma|_{\\{x\\}}\\)"
- ]
- , testGroup "headers"
- [ "unnumbered header" =:
- headerWith ("foo",["unnumbered"],[]) 1
- (text "Header 1" <> note (plain $ text "note")) =?>
- "\\section*{\\texorpdfstring{Header 1\\footnote{note}}{Header 1}}\\label{foo}\n\\addcontentsline{toc}{section}{Header 1}\n"
- , "in list item" =:
- bulletList [header 2 (text "foo")] =?>
- "\\begin{itemize}\n\\item ~\n \\subsection{foo}\n\\end{itemize}"
- , "in definition list item" =:
- definitionList [(text "foo", [header 2 (text "bar"),
- para $ text "baz"])] =?>
- "\\begin{description}\n\\item[foo] ~ \n\\subsection{bar}\n\nbaz\n\\end{description}"
- , "containing image" =:
- header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?>
- "\\section{\\texorpdfstring{\\protect\\includegraphics{imgs/foo.jpg}}{Alt text}}"
- ]
- , testGroup "inline code"
- [ "struck out and highlighted" =:
- strikeout (codeWith ("",["haskell"],[]) "foo" <> space
- <> str "bar") =?>
- "\\sout{\\mbox{\\VERB|\\NormalTok{foo}|} bar}"
- , "struck out and not highlighted" =:
- strikeout (code "foo" <> space
- <> str "bar") =?>
- "\\sout{\\texttt{foo} bar}"
- , "single quotes" =:
- code "dog's" =?> "\\texttt{dog\\textquotesingle{}s}"
- , "backtick" =:
- code "`nu?`" =?> "\\texttt{\\textasciigrave{}nu?\\textasciigrave{}}"
- ]
- , testGroup "writer options"
- [ testGroup "top-level division" $
- let
- headers = header 1 (text "header1")
- <> header 2 (text "header2")
- <> header 3 (text "header3")
-
- latexTopLevelDiv :: (ToPandoc a) => TopLevelDivision -> a -> String
- latexTopLevelDiv division =
- latexWithOpts def{ writerTopLevelDivision = division }
-
- beamerTopLevelDiv :: (ToPandoc a)
- => TopLevelDivision -> a -> String
- beamerTopLevelDiv division =
- latexWithOpts def { writerTopLevelDivision = division
- , writerBeamer = True }
- in
- [ test (latexTopLevelDiv TopLevelSection)
- "sections as top-level" $ headers =?>
- unlines [ "\\section{header1}\n"
- , "\\subsection{header2}\n"
- , "\\subsubsection{header3}"
- ]
- , test (latexTopLevelDiv TopLevelChapter)
- "chapters as top-level" $ headers =?>
- unlines [ "\\chapter{header1}\n"
- , "\\section{header2}\n"
- , "\\subsection{header3}"
- ]
- , test (latexTopLevelDiv TopLevelPart)
- "parts as top-level" $ headers =?>
- unlines [ "\\part{header1}\n"
- , "\\chapter{header2}\n"
- , "\\section{header3}"
- ]
- , test (latexTopLevelDiv TopLevelDefault)
- "default top-level" $ headers =?>
- unlines [ "\\section{header1}\n"
- , "\\subsection{header2}\n"
- , "\\subsubsection{header3}"
- ]
- , test (beamerTopLevelDiv TopLevelSection)
- "sections as top-level in beamer" $ headers =?>
- unlines [ "\\section{header1}\n"
- , "\\subsection{header2}\n"
- , "\\subsubsection{header3}"
- ]
- , test (beamerTopLevelDiv TopLevelChapter)
- "chapters are as part in beamer" $ headers =?>
- unlines [ "\\part{header1}\n"
- , "\\section{header2}\n"
- , "\\subsection{header3}"
- ]
- , test (beamerTopLevelDiv TopLevelPart)
- "parts as top-level in beamer" $ headers =?>
- unlines [ "\\part{header1}\n"
- , "\\section{header2}\n"
- , "\\subsection{header3}"
- ]
- , test (beamerTopLevelDiv TopLevelDefault)
- "default top-level in beamer" $ headers =?>
- unlines [ "\\section{header1}\n"
- , "\\subsection{header2}\n"
- , "\\subsubsection{header3}"
- ]
- , test (latexTopLevelDiv TopLevelPart)
- "part top-level, section not in toc" $
- ( headerWith ("", ["unnumbered"], []) 1 (text "header1")
- <> headerWith ("", ["unnumbered"], []) 2 (text "header2")
- <> headerWith ("", ["unnumbered"], []) 3 (text "header3")
- <> headerWith ("", ["unnumbered"], []) 4 (text "header4")
- <> headerWith ("", ["unnumbered"], []) 5 (text "header5")
- <> headerWith ("", ["unnumbered"], []) 6 (text "header6"))
- =?>
- unlines [ "\\part*{header1}"
- , "\\addcontentsline{toc}{part}{header1}\n"
- , "\\chapter*{header2}"
- , "\\addcontentsline{toc}{chapter}{header2}\n"
- , "\\section*{header3}"
- , "\\addcontentsline{toc}{section}{header3}\n"
- , "\\subsection*{header4}"
- , "\\addcontentsline{toc}{subsection}{header4}\n"
- , "\\subsubsection*{header5}"
- , "\\addcontentsline{toc}{subsubsection}{header5}\n"
- , "\\paragraph{header6}"
- , "\\addcontentsline{toc}{paragraph}{header6}"
- ]
- ]
- ]
- ]
diff --git a/tests/Tests/Writers/Markdown.hs b/tests/Tests/Writers/Markdown.hs
deleted file mode 100644
index aab916b38..000000000
--- a/tests/Tests/Writers/Markdown.hs
+++ /dev/null
@@ -1,263 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
-module Tests.Writers.Markdown (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-markdown :: (ToPandoc a) => a -> String
-markdown = writeMarkdown def . toPandoc
-
-markdownWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
-markdownWithOpts opts x = writeMarkdown opts $ toPandoc x
-
-{-
- "my test" =: X =?> Y
-
-is shorthand for
-
- test markdown "my test" $ X =?> Y
-
-which is in turn shorthand for
-
- test markdown "my test" (X,Y)
--}
-
-infix 4 =:
-(=:) :: (ToString a, ToPandoc a)
- => String -> (a, String) -> Test
-(=:) = test markdown
-
-tests :: [Test]
-tests = [ "indented code after list"
- =: (orderedList [ para "one" <> para "two" ] <> codeBlock "test")
- =?> "1. one\n\n two\n\n<!-- -->\n\n test"
- , "list with tight sublist"
- =: bulletList [ plain "foo" <> bulletList [ plain "bar" ],
- plain "baz" ]
- =?> "- foo\n - bar\n- baz\n"
- ] ++ [noteTests] ++ [shortcutLinkRefsTests]
-
-{-
-
-Testing with the following text:
-
-First Header
-============
-
-This is a footnote.[^1] And this is a [link](https://www.google.com).
-
-> A note inside a block quote.[^2]
->
-> A second paragraph.
-
-Second Header
-=============
-
-Some more text.
-
-
-[^1]: Down here.
-
-[^2]: The second note.
-
--}
-
-noteTestDoc :: Blocks
-noteTestDoc =
- header 1 "First Header" <>
- para ("This is a footnote." <>
- note (para "Down here.") <>
- " And this is a " <>
- link "https://www.google.com" "" "link" <>
- ".") <>
- blockQuote (para ("A note inside a block quote." <>
- note (para "The second note.")) <>
- para ("A second paragraph.")) <>
- header 1 "Second Header" <>
- para "Some more text."
-
-
-
-noteTests :: Test
-noteTests = testGroup "note and reference location"
- [ test (markdownWithOpts def)
- "footnotes at the end of a document" $
- noteTestDoc =?>
- (unlines $ [ "First Header"
- , "============"
- , ""
- , "This is a footnote.[^1] And this is a [link](https://www.google.com)."
- , ""
- , "> A note inside a block quote.[^2]"
- , ">"
- , "> A second paragraph."
- , ""
- , "Second Header"
- , "============="
- , ""
- , "Some more text."
- , ""
- , "[^1]: Down here."
- , ""
- , "[^2]: The second note."
- ])
- , test (markdownWithOpts def{writerReferenceLocation=EndOfBlock})
- "footnotes at the end of blocks" $
- noteTestDoc =?>
- (unlines $ [ "First Header"
- , "============"
- , ""
- , "This is a footnote.[^1] And this is a [link](https://www.google.com)."
- , ""
- , "[^1]: Down here."
- , ""
- , "> A note inside a block quote.[^2]"
- , ">"
- , "> A second paragraph."
- , ""
- , "[^2]: The second note."
- , ""
- , "Second Header"
- , "============="
- , ""
- , "Some more text."
- ])
- , test (markdownWithOpts def{writerReferenceLocation=EndOfBlock, writerReferenceLinks=True})
- "footnotes and reference links at the end of blocks" $
- noteTestDoc =?>
- (unlines $ [ "First Header"
- , "============"
- , ""
- , "This is a footnote.[^1] And this is a [link]."
- , ""
- , "[^1]: Down here."
- , ""
- , " [link]: https://www.google.com"
- , ""
- , "> A note inside a block quote.[^2]"
- , ">"
- , "> A second paragraph."
- , ""
- , "[^2]: The second note."
- , ""
- , "Second Header"
- , "============="
- , ""
- , "Some more text."
- ])
- , test (markdownWithOpts def{writerReferenceLocation=EndOfSection})
- "footnotes at the end of section" $
- noteTestDoc =?>
- (unlines $ [ "First Header"
- , "============"
- , ""
- , "This is a footnote.[^1] And this is a [link](https://www.google.com)."
- , ""
- , "> A note inside a block quote.[^2]"
- , ">"
- , "> A second paragraph."
- , ""
- , "[^1]: Down here."
- , ""
- , "[^2]: The second note."
- , ""
- , "Second Header"
- , "============="
- , ""
- , "Some more text."
- ])
-
- ]
-
-shortcutLinkRefsTests :: Test
-shortcutLinkRefsTests =
- let infix 4 =:
- (=:) :: (ToString a, ToPandoc a)
-
- => String -> (a, String) -> Test
- (=:) = test (writeMarkdown (def {writerReferenceLinks = True}) . toPandoc)
- in testGroup "Shortcut reference links"
- [ "Simple link (shortcutable)"
- =: (para (link "/url" "title" "foo"))
- =?> "[foo]\n\n [foo]: /url \"title\""
- , "Followed by another link (unshortcutable)"
- =: (para ((link "/url1" "title1" "first")
- <> (link "/url2" "title2" "second")))
- =?> unlines [ "[first][][second]"
- , ""
- , " [first]: /url1 \"title1\""
- , " [second]: /url2 \"title2\""
- ]
- , "Followed by space and another link (unshortcutable)"
- =: (para ((link "/url1" "title1" "first") <> " "
- <> (link "/url2" "title2" "second")))
- =?> unlines [ "[first][] [second]"
- , ""
- , " [first]: /url1 \"title1\""
- , " [second]: /url2 \"title2\""
- ]
- , "Reference link is used multiple times (unshortcutable)"
- =: (para ((link "/url1" "" "foo") <> (link "/url2" "" "foo")
- <> (link "/url3" "" "foo")))
- =?> unlines [ "[foo][][foo][1][foo][2]"
- , ""
- , " [foo]: /url1"
- , " [1]: /url2"
- , " [2]: /url3"
- ]
- , "Reference link is used multiple times (unshortcutable)"
- =: (para ((link "/url1" "" "foo") <> " " <> (link "/url2" "" "foo")
- <> " " <> (link "/url3" "" "foo")))
- =?> unlines [ "[foo][] [foo][1] [foo][2]"
- , ""
- , " [foo]: /url1"
- , " [1]: /url2"
- , " [2]: /url3"
- ]
- , "Reference link is followed by text in brackets"
- =: (para ((link "/url" "" "link") <> "[text in brackets]"))
- =?> unlines [ "[link][]\\[text in brackets\\]"
- , ""
- , " [link]: /url"
- ]
- , "Reference link is followed by space and text in brackets"
- =: (para ((link "/url" "" "link") <> " [text in brackets]"))
- =?> unlines [ "[link][] \\[text in brackets\\]"
- , ""
- , " [link]: /url"
- ]
- , "Reference link is followed by RawInline"
- =: (para ((link "/url" "" "link") <> rawInline "markdown" "[rawText]"))
- =?> unlines [ "[link][][rawText]"
- , ""
- , " [link]: /url"
- ]
- , "Reference link is followed by space and RawInline"
- =: (para ((link "/url" "" "link") <> space <> rawInline "markdown" "[rawText]"))
- =?> unlines [ "[link][] [rawText]"
- , ""
- , " [link]: /url"
- ]
- , "Reference link is followed by RawInline with space"
- =: (para ((link "/url" "" "link") <> rawInline "markdown" " [rawText]"))
- =?> unlines [ "[link][] [rawText]"
- , ""
- , " [link]: /url"
- ]
- , "Reference link is followed by citation"
- =: (para ((link "/url" "" "link") <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]")))
- =?> unlines [ "[link][][@author]"
- , ""
- , " [link]: /url"
- ]
- , "Reference link is followed by space and citation"
- =: (para ((link "/url" "" "link") <> space <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]")))
- =?> unlines [ "[link][] [@author]"
- , ""
- , " [link]: /url"
- ]
- ]
diff --git a/tests/Tests/Writers/Native.hs b/tests/Tests/Writers/Native.hs
deleted file mode 100644
index 7ec43b339..000000000
--- a/tests/Tests/Writers/Native.hs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Tests.Writers.Native (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-p_write_rt :: Pandoc -> Bool
-p_write_rt d =
- read (writeNative def{ writerTemplate = Just "" } d) == d
-
-p_write_blocks_rt :: [Block] -> Bool
-p_write_blocks_rt bs = length bs > 20 ||
- read (writeNative def (Pandoc nullMeta bs)) ==
- bs
-
-tests :: [Test]
-tests = [ property "p_write_rt" p_write_rt
- , property "p_write_blocks_rt" p_write_blocks_rt
- ]
diff --git a/tests/Tests/Writers/Plain.hs b/tests/Tests/Writers/Plain.hs
deleted file mode 100644
index 42f77e3ec..000000000
--- a/tests/Tests/Writers/Plain.hs
+++ /dev/null
@@ -1,21 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Writers.Plain (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-
-infix 4 =:
-(=:) :: (ToString a, ToPandoc a)
- => String -> (a, String) -> Test
-(=:) = test (writePlain def . toPandoc)
-
-
-tests :: [Test]
-tests = [ "strongly emphasized text to uppercase"
- =: strong "Straße"
- =?> "STRASSE"
- ]
diff --git a/tests/Tests/Writers/RST.hs b/tests/Tests/Writers/RST.hs
deleted file mode 100644
index 77dafeb4c..000000000
--- a/tests/Tests/Writers/RST.hs
+++ /dev/null
@@ -1,107 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Writers.RST (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-infix 4 =:
-(=:) :: (ToString a, ToPandoc a)
- => String -> (a, String) -> Test
-(=:) = test (writeRST def{ writerHighlight = True } . toPandoc)
-
-tests :: [Test]
-tests = [ testGroup "rubrics"
- [ "in list item" =:
- bulletList [header 2 (text "foo")] =?>
- "- .. rubric:: foo"
- , "in definition list item" =:
- definitionList [(text "foo", [header 2 (text "bar"),
- para $ text "baz"])] =?>
- unlines
- [ "foo"
- , " .. rubric:: bar"
- , ""
- , " baz"]
- , "in block quote" =:
- blockQuote (header 1 (text "bar")) =?>
- " .. rubric:: bar"
- , "with id" =:
- blockQuote (headerWith ("foo",[],[]) 1 (text "bar")) =?>
- unlines
- [ " .. rubric:: bar"
- , " :name: foo"]
- , "with id class" =:
- blockQuote (headerWith ("foo",["baz"],[]) 1 (text "bar")) =?>
- unlines
- [ " .. rubric:: bar"
- , " :name: foo"
- , " :class: baz"]
- ]
- , testGroup "headings"
- [ "normal heading" =:
- header 1 (text "foo") =?>
- unlines
- [ "foo"
- , "==="]
- -- note: heading normalization is only done in standalone mode
- , test (writeRST def{ writerTemplate = Just "$body$\n" } . toPandoc)
- "heading levels" $
- header 1 (text "Header 1") <>
- header 3 (text "Header 2") <>
- header 2 (text "Header 2") <>
- header 1 (text "Header 1") <>
- header 4 (text "Header 2") <>
- header 5 (text "Header 3") <>
- header 3 (text "Header 2") =?>
- unlines
- [ "Header 1"
- , "========"
- , ""
- , "Header 2"
- , "--------"
- , ""
- , "Header 2"
- , "--------"
- , ""
- , "Header 1"
- , "========"
- , ""
- , "Header 2"
- , "--------"
- , ""
- , "Header 3"
- , "~~~~~~~~"
- , ""
- , "Header 2"
- , "--------"]
- , test (writeRST def{ writerTemplate = Just "$body$\n" } . toPandoc)
- "minimal heading levels" $
- header 2 (text "Header 1") <>
- header 3 (text "Header 2") <>
- header 2 (text "Header 1") <>
- header 4 (text "Header 2") <>
- header 5 (text "Header 3") <>
- header 3 (text "Header 2") =?>
- unlines
- [ "Header 1"
- , "========"
- , ""
- , "Header 2"
- , "--------"
- , ""
- , "Header 1"
- , "========"
- , ""
- , "Header 2"
- , "--------"
- , ""
- , "Header 3"
- , "~~~~~~~~"
- , ""
- , "Header 2"
- , "--------"]
- ]
- ]
diff --git a/tests/Tests/Writers/TEI.hs b/tests/Tests/Writers/TEI.hs
deleted file mode 100644
index 3eb8478b7..000000000
--- a/tests/Tests/Writers/TEI.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Tests.Writers.TEI (tests) where
-
-import Test.Framework
-import Text.Pandoc.Builder
-import Text.Pandoc
-import Tests.Helpers
-import Text.Pandoc.Arbitrary()
-
-{-
- "my test" =: X =?> Y
-
-is shorthand for
-
- test html "my test" $ X =?> Y
-
-which is in turn shorthand for
-
- test html "my test" (X,Y)
--}
-
-infix 4 =:
-(=:) :: (ToString a, ToPandoc a)
- => String -> (a, String) -> Test
-(=:) = test (writeTEI def . toPandoc)
-
-tests :: [Test]
-tests = [ testGroup "block elements"
- ["para" =: para "Lorem ipsum cetera."
- =?> "<p>Lorem ipsum cetera.</p>"
- ]
- , testGroup "inlines"
- [
- "Emphasis" =: emph ("emphasized")
- =?> "<p><hi rendition=\"simple:italic\">emphasized</hi></p>"
- ,"SingleQuoted" =: singleQuoted (text "quoted material")
- =?> "<p><quote>quoted material</quote></p>"
- ,"DoubleQuoted" =: doubleQuoted (text "quoted material")
- =?> "<p><quote>quoted material</quote></p>"
- ,"NestedQuoted" =: doubleQuoted (singleQuoted (text "quoted material"))
- =?> "<p><quote><quote>quoted material</quote></quote></p>"
- ]
- ]
diff --git a/tests/docx/adjacent_links.docx b/tests/docx/adjacent_links.docx
deleted file mode 100644
index 86b1c2a14..000000000
--- a/tests/docx/adjacent_links.docx
+++ /dev/null
Binary files differ
diff --git a/tests/docx/adjacent_links.native b/tests/docx/adjacent_links.native
deleted file mode 100644
index cca861890..000000000
--- a/tests/docx/adjacent_links.native
+++ /dev/null
@@ -1 +0,0 @@
-[Para [Str "Le",Space,Str "plus",Space,Str "int\233ressant",Space,Str "\233tant",Space,Str "sans",Space,Str "doute",Space,Str "le",Space,Str "Marsan,",Space,Str "propos\233",Space,Str "par",Space,Str "Claude",Space,Str "Marsan",Space,Str "en",Space,Str "1976",Space,Str "qui",Space,Str "avait",Space,Str "m\234me",Space,Str "fait",Space,Str "l'objet",Space,Str "d'une",Space,Str "norme,",Space,Str "mais",Space,Str "qui",Space,Str "n'a",Space,Str "pas",Space,Str "du",Space,Str "tout",Space,Str "\233t\233",Space,Str "adopt\233",Space,Str "\224",Space,Str "cause",Space,Str "des",Space,Str "habitudes",Space,Str "trop",Space,Str "ancr\233es",Space,Str "et",Space,Str "qui",Space,Str "a",Space,Str "fini",Space,Str "par",Space,Str "tomber",Space,Str "dans",Space,Str "l'oubli,",Space,Str "gros",Space,Str "clin",Space,Str "d'\339il",Space,Str "\224",Space,Str "cela",Space,Str "d'ailleurs",Space,Str "dans",Space,Str "le",Space,Str "film",Space,Link ("",[],[]) [Emph [Str "\"Le",Space,Str "nom",Space,Str "des",Space,Str "gens\""]] ("http://www.allocine.fr/film/fichefilm_gen_cfilm=172167.html",""),Str ".",Space,Str "D\8217ailleurs",Space,Str "l\8217\233tat,",Space,Str "bien",Space,Str "conscient",Space,Str "que",Space,Str "tous",Space,Str "les",Space,Str "fran\231ais",Space,Str "\233crivent",Space,Str "sur",Space,Str "des",Space,Str "claviers",Space,Str "compl\232tement",Space,Str "inadapt\233s,",Space,Link ("",[],[]) [Emph [Str "tente",Space,Str "encore",Space,Str "une",Space,Str "fois",Space,Str "de",Space,Str "faire",Space,Str "une",Space,Str "norme",Space,Str "en",Space,Str "ce",Space,Str "moment",Space,Str "m\234me"]] ("http://www.appy-geek.com/Web/ArticleWeb.aspx?regionid=2&articleid=56103389&source=messenger",""),Str "."]]
diff --git a/tests/docx/inline_formatting.native b/tests/docx/inline_formatting.native
deleted file mode 100644
index 22d8f79e8..000000000
--- a/tests/docx/inline_formatting.native
+++ /dev/null
@@ -1,5 +0,0 @@
-[Para [Str "Regular",Space,Str "text",Space,Emph [Str "italics"],Space,Strong [Str "bold",Space,Emph [Str "bold",Space,Str "italics"]],Str "."]
-,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "Small",Space,Str "Caps"],Str ",",Space,Str "and",Space,Str "this",Space,Str "is",Space,Strikeout [Str "strikethrough"],Str "."]
-,Para [Str "Some",Space,Str "people",Space,Str "use",Space,Emph [Str "single",Space,Str "underlines",Space,Str "for",Space,Emph [Str "emphasis"]],Str "."]
-,Para [Str "Above",Space,Str "the",Space,Str "line",Space,Str "is",Space,Superscript [Str "superscript"],Space,Str "and",Space,Str "below",Space,Str "the",Space,Str "line",Space,Str "is",Space,Subscript [Str "subscript"],Str "."]
-,Para [Str "A",Space,Str "line",LineBreak,Str "break."]]
diff --git a/tests/docx/nested_anchors_in_header.native b/tests/docx/nested_anchors_in_header.native
deleted file mode 100644
index e2b6eb1ef..000000000
--- a/tests/docx/nested_anchors_in_header.native
+++ /dev/null
@@ -1,10 +0,0 @@
-[Header 1 ("short-instructions",[],[]) [Str "Short",Space,Str "instructions"]
-,Para [Link ("",[],[]) [Str "Open",Space,Str "remote",Space,Str "folder"] ("#remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-opening","")]
-,Para [Str "Do",Space,Str "staff"]
-,Para [Link ("",[],[]) [Str "Close",Space,Str "remote",Space,Str "folder"] ("#remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-closing","")]
-,Header 1 ("some-instructions",[],[]) [Str "Some",Space,Str "instructions"]
-,Para [Str "Lines"]
-,Header 2 ("remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-opening",[],[]) [Str "Remote",Space,Str "folder",Space,Str "or",Space,Str "longlonglonglonglong",Space,Str "file",Space,Str "with",Space,Str "manymanymanymany",Space,Str "letters",Space,Str "inside",Space,Str "opening"]
-,Para [Str "Open",Space,Str "folder"]
-,Header 2 ("remote-folder-or-longlonglonglonglong-file-with-manymanymanymany-letters-inside-closing",[],[]) [Str "Remote",Space,Str "folder",Space,Str "or",Space,Str "longlonglonglonglong",Space,Str "file",Space,Str "with",Space,Str "manymanymanymany",Space,Str "letters",Space,Str "inside",Space,Str "closing"]
-,Para [Str "Close",Space,Str "folder"]]
diff --git a/tests/epub/features.native b/tests/epub/features.native
deleted file mode 100644
index 60f3a58ba..000000000
--- a/tests/epub/features.native
+++ /dev/null
@@ -1,93 +0,0 @@
-[Para [Span ("front.xhtml",[],[]) []]
-,Div ("",["section"],[])
- [Header 1 ("",[],[]) [Str "Reflowable",Space,Str "EPUB",Space,Str "3",Space,Str "Conformance",Space,Str "Test",Space,Str "Document:",Space,Str "0100"]
- ,Div ("",["section"],[])
- [Header 2 ("",[],[]) [Str "Status",Space,Str "of",Space,Str "this",Space,Str "Document"]
- ,Para [Str "This",Space,Str "publication",Space,Str "is",Space,Str "currently",Space,Str "considered",Space,Span ("",["status"],[]) [Str "[UNDER",Space,Str "DEVELOPMENT]"],Space,Str "by",Space,Str "the",Space,Str "IDPF."]
- ,Para [Str "This",Space,Str "publication",Space,Str "is",Space,Str "part",Space,Str "of",Space,Str "version",Space,Span ("",["version"],[]) [Str "X.X"],Space,Str "of",Space,Str "the",Space,Str "EPUB",Space,Str "3.0",Space,Str "Compliance",Space,Str "Test",Space,Str "Suite",Space,Str "released",SoftBreak,Str "on",Space,RawInline (Format "html") "<time class=\"release\">",Str "TBD",RawInline (Format "html") "</time>",Str "."]
- ,Para [Str "Before",Space,Str "using",Space,Str "this",Space,Str "publication",Space,Str "to",Space,Str "evaluate",Space,Str "reading",Space,Str "systems,",Space,Str "testers",Space,Str "are",Space,Str "strongly",Space,Str "encouraged",Space,Str "to",SoftBreak,Str "verify",Space,Str "that",Space,Str "they",Space,Str "have",Space,Str "the",Space,Str "latest",Space,Str "release",Space,Str "by",Space,Str "checking",Space,Str "the",Space,Str "current",Space,Str "release",Space,Str "version",Space,Str "and",Space,Str "date",Space,Str "of",SoftBreak,Str "the",Space,Str "test",Space,Str "suite",Space,Str "at",Space,Link ("",[],[]) [Str "TBD"] ("http://idpf.org/","")]
- ,Para [Str "This",Space,Str "publication",Space,Str "is",Space,Str "one",Space,Str "of",Space,Str "several",Space,Str "that",Space,Str "currently",Space,Str "comprise",Space,Str "the",Space,Str "EPUB",Space,Str "3",Space,Str "conformance",Space,Str "test",Space,Str "suite",SoftBreak,Str "for",Space,Str "reflowable",Space,Str "content.",Space,Str "The",Space,Str "complete",Space,Str "test",Space,Str "suite",Space,Str "includes",Space,Str "all",Space,Str "of",Space,Str "the",Space,Str "following",Space,Str "publications:"]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "."]]]]
- ,Div ("",["section"],[])
- [Header 2 ("",[],[]) [Str "About",Space,Str "this",Space,Str "Document"]
- ,Para [Str "This",Space,Str "document",Space,Str "focuses",Space,Str "on",Space,Str "human-evaluated",Space,Str "binary",Space,Str "(pass/fail)",Space,Str "tests",Space,Str "in",Space,Str "a",SoftBreak,Str "reflowable",Space,Str "context.",Space,Str "Tests",Space,Str "for",Space,Str "fixed-layout",Space,Str "content",Space,Str "and",Space,Str "other",Space,Str "individual",Space,Str "tests",Space,Str "that",SoftBreak,Str "require",Space,Str "a",Space,Str "dedicated",Space,Str "epub",Space,Str "file",Space,Str "are",Space,Str "available",Space,Str "in",Space,Str "additional",Space,Str "sibling",Space,Str "documents;",Space,Str "refer",Space,Str "to",SoftBreak,Str "the",Space,Link ("",[],[]) [Str "test",Space,Str "suite",SoftBreak,Str "wiki"] ("https://github.com/mgylling/epub-testsuite/wiki/Overview",""),Space,Str "(",Code ("",[],[]) "https://github.com/mgylling/epub-testsuite/wiki/Overview",Str ")",Space,Str "for",Space,Str "additional",SoftBreak,Str "information."]]
- ,Div ("",["section"],[])
- [Header 2 ("",[],[]) [Str "Conventions"]
- ,Para [Str "The",Space,Str "following",Space,Str "conventions",Space,Str "are",Space,Str "used",Space,Str "throughout",Space,Str "the",Space,Str "document:"]
- ,DefinitionList
- [([Str "1.",Space,Str "Locating",Space,Str "a",Space,Str "test"],
- [[Div ("",["ctest"],[])
- [Para [Str "Tests",Space,Str "for",Space,Emph [Str "required"],Space,Str "Reading",Space,Str "System",Space,Str "functionality",Space,Str "are",SoftBreak,Str "preceded",Space,Str "by",Space,Str "the",Space,Str "label:",Space,Span ("",["nature"],[("style","display: inline; font-size: 100%")]) [Str "[REQUIRED]"]]]
- ,Div ("",["otest"],[])
- [Para [Str "Tests",Space,Str "for",Space,Emph [Str "optional"],Space,Str "Reading",Space,Str "System",Space,Str "functionality",Space,Str "are",SoftBreak,Str "preceded",Space,Str "by",Space,Str "the",Space,Str "label:",Space,Span ("",["nature"],[("style","display: inline; font-size: 100%")]) [Str "[OPTIONAL]"]]]]])
- ,([Str "2.",Space,Str "Performing",Space,Str "the",Space,Str "test"],
- [[Plain [Str "Each",Space,Str "test",Space,Str "includes",Space,Str "a",Space,Str "description",Space,Str "of",Space,Str "its",Space,Str "purpose",Space,Str "followed",Space,Str "by",Space,Str "the",Space,Str "actual",Space,Strong [Str "test",Space,Str "statement,",SoftBreak,Str "which",Space,Str "can",Space,Str "always",Space,Str "be",Space,Str "evaluated",Space,Str "to",Space,Str "true",Space,Str "or",Space,Str "false"],Str ".",Space,Str "These",Space,Str "statements",Space,Str "typically",Space,Str "have",Space,Str "the",Space,Str "form:",SoftBreak,Str "\"If",Space,Str "[some",Space,Str "condition],",Space,Str "the",Space,Str "test",Space,Str "passes\"."]]])
- ,([Str "3.",Space,Str "Scoring",Space,Str "in",Space,Str "the",Space,Str "results",Space,Str "form"],
- [[Plain [Str "@@@TODO",Space,Str "provide",Space,Str "info",Space,Str "on",Space,Str "where",Space,Str "to",Space,Str "get",Space,Str "the",Space,Str "results",Space,Str "form"]]])]]]
-,Para [Span ("content-mathml-001.xhtml",[],[]) []]
-,Div ("",["section"],[])
- [Header 2 ("content-mathml-001.xhtml#mathml",[],[]) [Str "MathML"]
- ,Div ("content-mathml-001.xhtml#mathml-010",["section","ctest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-010"],Space,Str "Rendering"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "MathML",Space,Str "equation",Space,Str "rendering",Space,Str "is",Space,Str "supported."]
- ,Plain [Math DisplayMath "\\int_{- \\infty}^{\\infty}e^{- x^{2}}\\, dx = \\sqrt{\\pi}",SoftBreak,Math DisplayMath "\\sum\\limits_{n = 1}^{\\infty}\\frac{1}{n^{2}} = \\frac{\\pi^{2}}{6}",SoftBreak,Math DisplayMath "x = \\frac{- b \\pm \\sqrt{b^{2} - 4ac}}{2a}"]
- ,Para [Str "If",Space,Str "the",Space,Str "preceding",Space,Str "equations",Space,Str "are",Space,Str "not",Space,Str "presented",Space,Str "as",Space,Str "linear",Space,Str "text",Space,Str "(e.g.,",Space,Str "x=-b\177b2-4ac2a),",SoftBreak,Str "the",Space,Str "test",Space,Str "passes."]]
- ,Div ("content-mathml-001.xhtml#mathml-020",["section","otest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-020"],Space,Str "CSS",Space,Str "Styling",Space,Str "of",Space,Str "the",Space,Code ("",[],[]) "math",Space,Str "element"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "basic",Space,Str "CSS",Space,Str "styling",Space,Str "of",Space,Str "MathML",Space,Str "is",Space,Str "supported",Space,Str "on",Space,Str "the",Space,Code ("",[],[]) "math",Space,Str "element."]
- ,Plain [Math InlineMath "{2x}{+ y - z}"]
- ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "equation",Space,Str "has",Space,Str "a",Space,Str "yellow",Space,Str "background",Space,Str "and",Space,Str "a",Space,Str "dashed",Space,Str "border."]
- ,Para [Str "If",Space,Str "the",Space,Str "reading",Space,Str "system",Space,Str "does",Space,Str "not",Space,Str "have",Space,Str "a",Space,Str "viewport,",Space,Str "or",Space,Str "does",Space,Str "not",Space,Str "support",SoftBreak,Str "CSS",Space,Str "styles,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]
- ,Div ("content-mathml-001.xhtml#mathml-021",["section","otest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-021"],Space,Str "CSS",Space,Str "Styling",Space,Str "of",Space,Str "the",Space,Code ("",[],[]) "mo",Space,Str "element"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "basic",Space,Str "CSS",Space,Str "styling",Space,Str "of",Space,Str "MathML",Space,Str "is",Space,Str "supported",Space,Str "on",Space,Str "the",Space,Code ("",[],[]) "mo",Space,Str "element."]
- ,Plain [Math InlineMath "{2x}{+ y - z}"]
- ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "operators",Space,Str "are",Space,Str "enlarged",Space,Str "relative",Space,Str "to",Space,Str "the",Space,Str "other",Space,Str "symbols",Space,Str "and",Space,Str "numbers."]
- ,Para [Str "If",Space,Str "the",Space,Str "reading",Space,Str "system",Space,Str "does",Space,Str "not",Space,Str "have",Space,Str "a",Space,Str "viewport,",Space,Str "or",Space,Str "does",Space,Str "not",Space,Str "support",SoftBreak,Str "CSS",Space,Str "styles,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]
- ,Div ("content-mathml-001.xhtml#mathml-022",["section","otest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-022"],Space,Str "CSS",Space,Str "Styling",Space,Str "of",Space,Str "the",Space,Code ("",[],[]) "mi",Space,Str "element"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "basic",Space,Str "CSS",Space,Str "styling",Space,Str "of",Space,Str "MathML",Space,Str "is",Space,Str "supported",Space,Str "on",Space,Str "the",Space,Code ("",[],[]) "mi",Space,Str "element."]
- ,Plain [Math InlineMath "{2x}{+ y - z}"]
- ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "identifiers",Space,Str "are",Space,Str "bolded",Space,Str "and",Space,Str "blue."]
- ,Para [Str "If",Space,Str "the",Space,Str "reading",Space,Str "system",Space,Str "does",Space,Str "not",Space,Str "have",Space,Str "a",Space,Str "viewport,",Space,Str "or",Space,Str "does",Space,Str "not",Space,Str "support",SoftBreak,Str "CSS",Space,Str "styles,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]
- ,Div ("content-mathml-001.xhtml#mathml-023",["section","otest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-023"],Space,Str "CSS",Space,Str "Styling",Space,Str "of",Space,Str "the",Space,Code ("",[],[]) "mn",Space,Str "element"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "basic",Space,Str "CSS",Space,Str "styling",Space,Str "of",Space,Str "MathML",Space,Str "is",Space,Str "supported",Space,Str "on",Space,Str "the",Space,Code ("",[],[]) "mn",Space,Str "element."]
- ,Plain [Math InlineMath "{2x}{+ y - z}"]
- ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "number",Space,Str "2",Space,Str "is",Space,Str "italicized",Space,Str "and",Space,Str "blue."]
- ,Para [Str "If",Space,Str "the",Space,Str "reading",Space,Str "system",Space,Str "does",Space,Str "not",Space,Str "have",Space,Str "a",Space,Str "viewport,",Space,Str "or",Space,Str "does",Space,Str "not",Space,Str "support",SoftBreak,Str "CSS",Space,Str "styles,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]
- ,Div ("content-mathml-001.xhtml#mathml-024",["section","ctest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-024"],Str "Horizontal",Space,Str "stretch,",Space,Code ("",[],[]) "mover",Str ",",Space,Code ("",[],[]) "munder",Str ",",Space,Str "and",Space,Code ("",[],[]) "mspace",Space,Str "elements"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "horizontal",Space,Str "stretch,",Space,Code ("",[],[]) "mover",Str ",",Space,Code ("",[],[]) "munder",Str ",",Space,Code ("",[],[]) "mspace",Space,Str "elements",Space,Str "are",Space,Str "supported."]
- ,Plain [Math DisplayMath "c = \\overset{\\text{complex\\ number}}{\\overbrace{\\underset{\\text{real}}{\\underbrace{\\mspace{20mu} a\\mspace{20mu}}} + \\underset{\\text{imaginary}}{\\underbrace{\\quad b{\\mathbb{i}}\\quad}}}}"]
- ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "rendering",Space,Str "looks",Space,Str "like",Space,Str "."]]
- ,Div ("content-mathml-001.xhtml#mathml-025",["section","ctest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-025"],Str "Testing",Space,Code ("",[],[]) "mtable",Space,Str "with",Space,Code ("",[],[]) "colspan",Space,Str "and",Space,Code ("",[],[]) "rowspan",Space,Str "attributes,",Space,Str "Hebrew",Space,Str "and",Space,Str "Script",Space,Str "fonts"]
- ,Para [Str "Tests",Space,Str "whether",Space,Code ("",[],[]) "mtable",Space,Str "with",Space,Code ("",[],[]) "colspan",Space,Str "and",Space,Code ("",[],[]) "mspace",Space,Str "attributes",Space,Str "(colum",Space,Str "and",Space,Str "row",Space,Str "spanning)",Space,Str "are",Space,Str "supported;",Space,Str "uses",Space,Str "Hebrew",Space,Str "and",Space,Str "Script",Space,Str "alphabets."]
- ,Plain [Math DisplayMath "\\begin{array}{llllllllll}\n & {\\operatorname{cov}\\left( \\mathcal{L} \\right)} & \\longrightarrow & {\\operatorname{non}\\left( \\mathcal{K} \\right)} & \\longrightarrow & {\\operatorname{cof}\\left( \\mathcal{K} \\right)} & \\longrightarrow & {\\operatorname{cof}\\left( \\mathcal{L} \\right)} & \\longrightarrow & 2^{\\aleph_{0}} \\\\\n & \\uparrow & & \\uparrow & & \\uparrow & & \\uparrow & & \\\\\n & {\\mathfrak{b}} & \\longrightarrow & {\\mathfrak{d}} & & & & & & \\\\\n & \\uparrow & & \\uparrow & & & & & & \\\\\n\\aleph_{1} & \\longrightarrow & {\\operatorname{add}\\left( \\mathcal{L} \\right)} & \\longrightarrow & {\\operatorname{add}\\left( \\mathcal{K} \\right)} & \\longrightarrow & {\\operatorname{cov}\\left( \\mathcal{K} \\right)} & \\longrightarrow & {\\operatorname{non}\\left( \\mathcal{L} \\right)} & \\\\\n\\end{array}"]
- ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "rendering",Space,Str "looks",Space,Str "like",Space,Link ("",[],[]) [Str "Cicho\324's",Space,Str "Diagram"] ("http://en.wikipedia.org/wiki/Cicho%C5%84's_diagram",""),Str ":",Space,Str "."]]
- ,Div ("content-mathml-001.xhtml#mathml-026",["section","ctest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-026"],Str "BiDi,",Space,Str "RTL",Space,Str "and",Space,Str "Arabic",Space,Str "alphabets"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "right-to-left",Space,Str "and",Space,Str "Arabic",Space,Str "alphabets",Space,Str "are",Space,Str "supported."]
- ,Plain [Math DisplayMath "{d\\left( s \\right)} = \\begin{cases}\n{\\sum\\limits_{{\\lbrack?\\rbrack} = 1}^{S}s^{\\lbrack?\\rbrack}} & {\\text{\1573\1584\1575\1603\1575\1606}s > 0} \\\\\n{\\int_{1}^{S}{s^{\\lbrack?\\rbrack}s}} & {\\text{\1573\1584\1575\1603\1575\1606}s \\in m} \\\\\n{T\\pi} & {\\text{\1594\1610\1585\1584\1604\1603}\\left( \\text{\1605\1593}\\pi \\simeq 3,141 \\right)} \\\\\n\\end{cases}"]
- ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "rendering",Space,Str "looks",Space,Str "like",Space,Str "the",Space,Str "following",Space,Str "image:"]]
- ,Div ("content-mathml-001.xhtml#mathml-027",["section","ctest"],[])
- [Header 2 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],SoftBreak,Span ("",["test-id"],[]) [Str "mathml-027"],Str "Elementary",Space,Str "math:",Space,Str "long",Space,Str "division",Space,Str "notation"]
- ,Para [Str "Tests",Space,Str "whether",Space,Code ("",[],[]) "mlongdiv",Space,Str "elements",Space,Str "(from",Space,Str "elementary",Space,Str "math)",Space,Str "are",Space,Str "supported."]
- ,Plain [Span ("",["math"],[("xmlns","http://www.w3.org/1998/Math/MathML")]) [SoftBreak,Str "3",SoftBreak,Str "435.3",SoftBreak,Str "1306",SoftBreak,Str "12",SoftBreak,Str "10",SoftBreak,Str "9",SoftBreak,Str "16",SoftBreak,Str "15",SoftBreak,Str "1.0",SoftBreak,Str "9",SoftBreak,Str "1",SoftBreak]]
- ,Para [Str "The",Space,Str "test",Space,Str "passes",Space,Str "if",Space,Str "the",Space,Str "rendering",Space,Str "looks",Space,Str "like",Space,Str "the",Space,Str "following",Space,Str "image:",Space,Str "."]]]
-,Para [Span ("content-switch-001.xhtml",[],[]) []]
-,Div ("content-switch-001.xhtml#epub-switch",["section"],[])
- [Header 3 ("",[],[]) [Code ("",[],[]) "epub:switch"]
- ,Div ("content-switch-001.xhtml#switch-010",["section","ctest"],[])
- [Header 4 ("",[],[]) [Span ("",["nature"],[]) [Str "[REQUIRED]"],Space,Span ("",["test-id"],[]) [Str "switch-010"],Space,Str "Support"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "the",Space,Code ("",[],[]) "epub:switch",Space,Str "element",Space,Str "is",Space,Str "supported."]
- ,Para [Str "PASS"]
- ,Para [Str "If",Space,Str "only",Space,Str "the",Space,Str "word",Space,Str "\"PASS\"",Space,Str "is",Space,Str "rendered",Space,Str "before",Space,Str "this",Space,Str "paragraph,",Space,Str "the",Space,Str "test",Space,Str "passes.",Space,Str "If",Space,Str "both",Space,Str "\"PASS\"",Space,Str "and",Space,Str "\"FAIL\"",Space,Str "are",Space,Str "rendered,",Space,Str "or",Space,Str "neither",SoftBreak,Str "\"PASS\"",Space,Str "nor",Space,Str "\"FAIL\"",Space,Str "is",Space,Str "rendered,",Space,Str "the",Space,Str "test",Space,Str "fails."]]
- ,Div ("content-switch-001.xhtml#switch-020",["section","otest"],[])
- [Header 4 ("",[],[]) [Span ("",["nature"],[]) [Str "[OPTIONAL]"],SoftBreak,Span ("",["test-id"],[]) [Str "switch-020"],SoftBreak,Str "MathML",Space,Str "Embedding"]
- ,Para [Str "Tests",Space,Str "whether",Space,Str "the",Space,Str "MathML",Space,Str "namespace",Space,Str "is",Space,Str "recognized",Space,Str "when",Space,Str "used",Space,Str "in",Space,Str "an",Space,Code ("",[],[]) "epub:case",Space,Str "element."]
- ,Para [Math InlineMath "{2x}{+ y - z}"]
- ,Para [Str "If",Space,Str "a",Space,Str "MathML",Space,Str "equation",Space,Str "is",Space,Str "rendered",Space,Str "before",Space,Str "this",Space,Str "paragraph,",Space,Str "the",Space,Str "test",Space,Str "passes."]
- ,Para [Str "If",Space,Str "test",Space,Code ("",[],[]) "switch-010",Space,Str "did",Space,Str "not",Space,Str "pass,",Space,Str "this",Space,Str "test",Space,Str "should",Space,Str "be",Space,Str "marked",Space,Code ("",[],[]) "Not Supported",Str "."]]]]
diff --git a/tests/fb2/basic.fb2 b/tests/fb2/basic.fb2
deleted file mode 100644
index 14b03fbea..000000000
--- a/tests/fb2/basic.fb2
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info /><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><annotation><p></p></annotation><section><title><p>Top-level title</p></title><section><title><p>Section</p></title><section><title><p>Subsection</p></title><p>This <emphasis>emphasized</emphasis> <strong>strong</strong> <code>verbatim</code> markdown. See this link<a l:href="#l1" type="note"><sup>[1]</sup></a>.</p><p>Ordered list:</p><p> 1. one</p><p> 2. two</p><p> 3. three</p><cite><p>Blockquote is for citatons.</p></cite><empty-line /><p><code>Code</code></p><p><code>block</code></p><p><code>is</code></p><p><code>for</code></p><p><code>code.</code></p><empty-line /><p><strikethrough>Strikeout</strikethrough> is Pandoc&#39;s extension. Superscript and subscripts too: H<sub>2</sub>O is a liquid<a l:href="#n2" type="note"><sup>[2]</sup></a>. 2<sup>10</sup> is 1024.</p><p>Math is another Pandoc extension: <code>E = m c^2</code>.</p></section></section></section></body><body name="notes"><section id="l1"><title><p>1</p></title><p><code>http://example.com/</code></p></section><section id="n2"><title><p>2</p></title><p>Sometimes.</p></section></body></FictionBook> \ No newline at end of file
diff --git a/tests/fb2/images-embedded.fb2 b/tests/fb2/images-embedded.fb2
deleted file mode 100644
index 8c22efad3..000000000
--- a/tests/fb2/images-embedded.fb2
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info /><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><annotation><p></p></annotation><section><image l:href="#image1" l:type="inlineImageType" alt="This image was embedded using data URI scheme" /><p>This image was embedded using data URI scheme</p></section></body><binary id="image1" content-type="image/png">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</binary></FictionBook>
diff --git a/tests/fb2/images.fb2 b/tests/fb2/images.fb2
deleted file mode 100644
index 8b783edf5..000000000
--- a/tests/fb2/images.fb2
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info /><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><annotation><p></p></annotation><section><p>This example test if Pandoc correctly embeds images into FictionBook.</p><p>Small inline image: <image l:href="#image1" l:type="inlineImageType" alt="alt text a small PNG image" />.</p><p>Paragraph image:</p><image l:href="#image2" l:type="imageType" alt="alt text of a big JPEG image" title="image title text" /><p>alt text of a big missing image</p><p>A missing image inline: alt text of missing image.</p></section></body><binary id="image2" content-type="image/jpeg">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</binary><binary id="image1" content-type="image/png">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</binary></FictionBook> \ No newline at end of file
diff --git a/tests/fb2/math.fb2 b/tests/fb2/math.fb2
deleted file mode 100644
index 5a69556c1..000000000
--- a/tests/fb2/math.fb2
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info /><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><annotation><p></p></annotation><section><p>List math:</p><p>• <code>E = m c^2</code></p><p>• <code>A = \pi r^2</code></p><p>Inline math: <code>x=\frac{-b \pm \sqrt {b^2-4ac}}{2a}</code>.</p><p>Display math:</p><code>\int_a^b \! f(x)\,dx = F(b) - F(a).</code></section></body></FictionBook> \ No newline at end of file
diff --git a/tests/fb2/titles.fb2 b/tests/fb2/titles.fb2
deleted file mode 100644
index d8fc1e424..000000000
--- a/tests/fb2/titles.fb2
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info /><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><annotation><p></p></annotation><section><title><p>Simple title</p></title><p>This example tests if Pandoc doesn&#39;t insert forbidden elements in FictionBook titles.</p></section><section><title><p>Emphasized Strong Title</p></title></section><section><title><p>Title with</p><empty-line /><p>line break</p></title></section></body></FictionBook> \ No newline at end of file
diff --git a/tests/fb2/titles.markdown b/tests/fb2/titles.markdown
deleted file mode 100644
index cc3d0e0d0..000000000
--- a/tests/fb2/titles.markdown
+++ /dev/null
@@ -1,10 +0,0 @@
-# Simple title
-
-This example tests if Pandoc doesn't insert forbidden elements in FictionBook titles.
-
-# *Emphasized* **Strong** Title
-
-# Title with\
-line break
-
-
diff --git a/tests/html-reader.html b/tests/html-reader.html
deleted file mode 100644
index 3bd5e4ce3..000000000
--- a/tests/html-reader.html
+++ /dev/null
@@ -1,708 +0,0 @@
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<meta http-equiv="Content-Style-Type" content="text/css" />
-<meta name="generator" content="pandoc" />
-<style type="text/css">
-div.pandocNote { border-left: 1px solid grey; padding-left: 1em; }
-span.pandocNoteRef { vertical-align: super; font-size: 80%; }
-span.pandocNoteMarker { }
-</style>
-<title>Pandoc Test Suite</title>
-</head>
-<body>
-<h1 class="title">Pandoc Test Suite</h1>
-<p>This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.</p>
-<hr />
-<h1>Headers</h1>
-<h2>Level 2 with an <a href="/url">embedded link</a></h2>
-<h3>Level 3 with <em>emphasis</em></h3>
-<h4>Level 4</h4>
-<h5>Level 5</h5>
-<h1>Level 1</h1>
-<h2>Level 2 with <em>emphasis</em></h2>
-<h3>Level 3</h3>
-<p>with no blank line</p>
-<h2>Level 2</h2>
-<p>with no blank line</p>
-<hr />
-<h1>Paragraphs</h1>
-<p>Here's a regular paragraph.</p>
-<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p>
-<p>Here's one with a bullet. * criminey.</p>
-<p>There should be a hard line break<br />
- here.</p>
-<hr />
-<h1>Block Quotes</h1>
-<p>E-mail style:</p>
-<blockquote>
-<p>This is a block quote. It is pretty short.</p>
-</blockquote>
-<blockquote>
-<p>Code in a block quote:</p>
-<pre><code>sub status {
- print "working";
-}
-</code></pre>
-<p>A list:</p>
-<ol>
-<li>item one</li>
-<li>item two</li>
-</ol>
-<p>Nested block quotes:</p>
-<blockquote>
-<p>nested</p>
-</blockquote>
-<blockquote>
-<p>nested</p>
-</blockquote>
-</blockquote>
-<p>This should not be a block quote: 2 &gt; 1.</p>
-<p>Box-style:</p>
-<blockquote>
-<p>Example:</p>
-<pre><code>sub status {
- print "working";
-}
-</code></pre>
-</blockquote>
-<blockquote>
-<ol>
-<li>do laundry</li>
-<li>take out the trash</li>
-</ol>
-</blockquote>
-<p>Here's a nested one:</p>
-<blockquote>
-<p>Joe said:</p>
-<blockquote>
-<p>Don't quote me.</p>
-</blockquote>
-</blockquote>
-<p>And a following paragraph.</p>
-<hr />
-<h1>Code Blocks</h1>
-<p>Code:</p>
-<pre><code>---- (should be four hyphens)
-
-sub status {
- print "working";
-}
-
-this code block is indented by one tab
-</code></pre>
-<p>And:</p>
-<pre><code> this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \> \[ \{
-</code></pre>
-<hr />
-<h1>Lists</h1>
-<h2>Unordered</h2>
-<p>Asterisks tight:</p>
-<ul>
-<li>asterisk 1</li>
-<li>asterisk 2</li>
-<li>asterisk 3</li>
-</ul>
-<p>Asterisks loose:</p>
-<ul>
-<li><p>asterisk 1</p>
-</li>
-<li><p>asterisk 2</p>
-</li>
-<li><p>asterisk 3</p>
-</li>
-</ul>
-<p>Pluses tight:</p>
-<ul>
-<li>Plus 1</li>
-<li>Plus 2</li>
-<li>Plus 3</li>
-</ul>
-<p>Pluses loose:</p>
-<ul>
-<li><p>Plus 1</p>
-</li>
-<li><p>Plus 2</p>
-</li>
-<li><p>Plus 3</p>
-</li>
-</ul>
-<p>Minuses tight:</p>
-<ul>
-<li>Minus 1</li>
-<li>Minus 2</li>
-<li>Minus 3</li>
-</ul>
-<p>Minuses loose:</p>
-<ul>
-<li><p>Minus 1</p>
-</li>
-<li><p>Minus 2</p>
-</li>
-<li><p>Minus 3</p>
-</li>
-</ul>
-<h2>Ordered</h2>
-<p>Tight:</p>
-<ol>
-<li>First</li>
-<li>Second</li>
-<li>Third</li>
-</ol>
-<p>and:</p>
-<ol>
-<li>One</li>
-<li>Two</li>
-<li>Three</li>
-</ol>
-<p>Loose using tabs:</p>
-<ol>
-<li><p>First</p>
-</li>
-<li><p>Second</p>
-</li>
-<li><p>Third</p>
-</li>
-</ol>
-<p>and using spaces:</p>
-<ol>
-<li><p>One</p>
-</li>
-<li><p>Two</p>
-</li>
-<li><p>Three</p>
-</li>
-</ol>
-<p>Multiple paragraphs:</p>
-<ol>
-<li><p>Item 1, graf one.</p>
-<p>Item 1. graf two. The quick brown fox jumped over the lazy dog's back.</p>
-</li>
-<li><p>Item 2.</p>
-</li>
-<li><p>Item 3.</p>
-</li>
-</ol>
-<p>List styles:</p>
-<ol></ol>
-<ol type="i"></ol>
-<ol class="lower-roman"></ol>
-<ol style="lower-roman"></ol>
-<ol style="list-style: lower-roman;"></ol>
-<ol style="list-style-type: lower-roman;"></ol>
-<h2>Nested</h2>
-<ul>
-<li>Tab<ul>
-<li>Tab<ul>
-<li>Tab</li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-<p>Here's another:</p>
-<ol>
-<li>First</li>
-<li>Second:<ul>
-<li>Fee</li>
-<li>Fie</li>
-<li>Foe</li>
-</ul>
-</li>
-<li>Third</li>
-</ol>
-<p>Same thing but with paragraphs:</p>
-<ol>
-<li><p>First</p>
-</li>
-<li><p>Second:</p>
-<ul>
-<li>Fee</li>
-<li>Fie</li>
-<li>Foe</li>
-</ul>
-</li>
-<li><p>Third</p>
-</li>
-</ol>
-<h2>Tabs and spaces</h2>
-<ul>
-<li><p>this is a list item indented with tabs</p>
-</li>
-<li><p>this is a list item indented with spaces</p>
-<ul>
-<li><p>this is an example list item indented with tabs</p>
-</li>
-<li><p>this is an example list item indented with spaces</p>
-</li>
-</ul>
-</li>
-</ul>
-<h2 id="fancy-list-markers"
- >Fancy list markers</h2
- ><ol start="2" class="decimal"
- ><li
- >begins with 2</li
- ><li
- ><p
- >and now 3</p
- ><p
- >with a continuation</p
- ><ol start="4" class="lower-roman"
- ><li
- >sublist with roman numerals, starting with 4</li
- ><li
- >more items<ol class="upper-alpha"
- ><li
- >a subsublist</li
- ><li
- >a subsublist</li
- ></ol
- ></li
- ></ol
- ></li
- ></ol
- ><p
- >Nesting:</p
- ><ol type="A"
- ><li
- >Upper Alpha<ol class="upper-roman"
- ><li
- >Upper Roman.<ol start="6" class="decimal"
- ><li
- >Decimal start with 6<ol start="3" type="a"
- ><li
- >Lower alpha with paren</li
- ></ol
- ></li
- ></ol
- ></li
- ></ol
- ></li
- ></ol
- ><p
- >Autonumbering:</p
- ><ol
- ><li
- >Autonumber.</li
- ><li
- >More.<ol
- ><li
- >Nested.</li
- ></ol
- ></li
- ></ol
- ><hr
- />
-<h2>Definition</h2>
-<dl>
- <dt>Violin</dt>
- <dd>Stringed musical instrument.</dd>
- <dd>Torture device.</dd>
- <dt>Cello</dt>
- <dt>Violoncello</dt>
- <dd>Low-voiced stringed instrument.</dd>
-</dl>
-<hr />
-<h1>Inline Markup</h1>
-<p>This is <em>emphasized</em>, and so <em>is this</em>.</p>
-<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
-<p>Empty <strong></strong> and <em></em>.
-<p>An <em><a href="/url">emphasized link</a></em>.</p>
-<p><strong><em>This is strong and em.</em></strong></p>
-<p>So is <strong><em>this</em></strong> word.</p>
-<p><strong><em>This is strong and em.</em></strong></p>
-<p>So is <strong><em>this</em></strong> word.</p>
-<p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p>
-<p>This is <span style="font-variant: small-caps;">small caps</span>.</p>
-<hr />
-<h1>Smart quotes, ellipses, dashes</h1>
-<p>"Hello," said the spider. "'Shelob' is my name."</p>
-<p>'A', 'B', and 'C' are letters.</p>
-<p>'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'</p>
-<p>'He said, "I want to go."' Were you alive in the 70's?</p>
-<p>Here is some quoted '<code>code</code>' and a "<a href="http://example.com/?foo=1&amp;bar=2">quoted link</a>".</p>
-<p>Some dashes: one---two --- three--four -- five.</p>
-<p>Dashes between numbers: 5-7, 255-66, 1987-1999.</p>
-<p>Ellipses...and. . .and . . . .</p>
-<hr />
-<h1>LaTeX</h1>
-<ul>
-<li>\cite[22-23]{smith.1899}</li>
-<li>\doublespacing</li>
-<li>$2+2=4$</li>
-<li>$x \in y$</li>
-<li>$\alpha \wedge \omega$</li>
-<li>$223$</li>
-<li>$p$-Tree</li>
-<li>$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</li>
-<li>Here's one that has a line break in it: $\alpha + \omega \times x^2$.</li>
-</ul>
-<p>These shouldn't be math:</p>
-<ul>
-<li>To get the famous equation, write <code>$e = mc^2$</code>.</li>
-<li>$22,000 is a <em>lot</em> of money. So is $34,000. (It worked if "lot" is emphasized.)</li>
-<li>Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.</li>
-</ul>
-<p>Here's a LaTeX table:</p>
-<p>\begin{tabular}{|l|l|}\hline Animal &amp; Number \\ \hline Dog &amp; 2 \\ Cat &amp; 1 \\ \hline \end{tabular}</p>
-<hr />
-<h1>Special Characters</h1>
-<p>Here is some unicode:</p>
-<ul>
-<li>I hat: Î</li>
-<li>o umlaut: ö</li>
-<li>section: §</li>
-<li>set membership: ∈</li>
-<li>copyright: ©</li>
-</ul>
-<p>AT&amp;T has an ampersand in their name.</p>
-<p>AT&amp;T is another way to write it.</p>
-<p>This &amp; that.</p>
-<p>4 &lt; 5.</p>
-<p>6 &gt; 5.</p>
-<p>Backslash: \</p>
-<p>Backtick: `</p>
-<p>Asterisk: *</p>
-<p>Underscore: _</p>
-<p>Left brace: {</p>
-<p>Right brace: }</p>
-<p>Left bracket: [</p>
-<p>Right bracket: ]</p>
-<p>Left paren: (</p>
-<p>Right paren: )</p>
-<p>Greater-than: &gt;</p>
-<p>Hash: #</p>
-<p>Period: .</p>
-<p>Bang: !</p>
-<p>Plus: +</p>
-<p>Minus: -</p>
-<hr />
-<h1>Links</h1>
-<h2>Explicit</h2>
-<p>Just a <a href="/url/">URL</a>.</p>
-<p><a href="/url/" title="title">URL and title</a>.</p>
-<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
-<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
-<p><a href="/url/" title="title with &quot;quotes&quot; in it">URL and title</a></p>
-<p><a href="/url/" title="title with single quotes">URL and title</a></p>
-Email link (nobody [at] nowhere.net)<p><a href="">Empty</a>.</p>
-<h2>Reference</h2>
-<p>Foo <a href="/url/">bar</a>.</p>
-<p>Foo <a href="/url/">bar</a>.</p>
-<p>Foo <a href="/url/">bar</a>.</p>
-<p>With <a href="/url/">embedded [brackets]</a>.</p>
-<p><a href="/url/">b</a> by itself should be a link.</p>
-<p>Indented <a href="/url">once</a>.</p>
-<p>Indented <a href="/url">twice</a>.</p>
-<p>Indented <a href="/url">thrice</a>.</p>
-<p>This should [not] be a link.</p>
-<pre><code>[not]: /url
-</code></pre>
-<p>Foo <a href="/url/" title="Title with &quot;quotes&quot; inside">bar</a>.</p>
-<p>Foo <a href="/url/" title="Title with &quot;quote&quot; inside">biz</a>.</p>
-<h2>With ampersands</h2>
-<p>Here's a <a href="http://example.com/?foo=1&amp;bar=2">link with an ampersand in the URL</a>.</p>
-<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&amp;T</a>.</p>
-<p>Here's an <a href="/script?foo=1&amp;bar=2">inline link</a>.</p>
-<p>Here's an <a href="/script?foo=1&amp;bar=2">inline link in pointy braces</a>.</p>
-<h2>Autolinks</h2>
-<p>With an ampersand: <a href="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</a></p>
-<ul>
-<li>In a list?</li>
-<li><a href="http://example.com/">http://example.com/</a></li>
-<li>It should.</li>
-</ul>
-An e-mail address: nobody [at] nowhere.net<blockquote>
-<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>
-</blockquote>
-<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p>
-<pre><code>or here: &lt;http://example.com/&gt;
-</code></pre>
-<hr />
-<h1>Images</h1>
-<p>From "Voyage dans la Lune" by Georges Melies (1902):</p>
-<p><img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune"></p>
-<p>Here is a movie <img src="movie.jpg" alt="movie"> icon.</p>
-<hr />
-<h1>Footnotes</h1>
-<p>Here is a footnote reference<a href="#note_1">(1)</a>, and another<a href="#note_longnote">(longnote)</a>. This should <em>not</em> be a footnote reference, because it contains a space^(my note).</p>
-<p><a href="#ref_1">(1)</a> Here is the footnote. It can go anywhere in the document, not just at the end.</p>
-<p><a href="#ref_longnote">(longnote)</a> Here's the other note. This one contains multiple blocks.</p>
-<p>Caret characters are used to indicate that the blocks all belong to a single footnote (as with block quotes).</p>
-<pre><code> { &lt;code> }
-</code></pre>
-<p>If you want, you can use a caret at the beginning of every line, as with blockquotes, but all that you need is a caret at the beginning of the first line of the block and any preceding blank lines.</p>
-<p>text<em> Leading space</em></p>
-<p><em>Trailing space </em>text</p>
-<p>text<em> Leading spaces</em></p>
-<p><em>Trailing spaces </em>text</p>
-<h1>Tables</h1>
-<h2>Tables with Headers</h2>
-<table>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
-</table>
-<hr />
-<table>
- <thead>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
- </tbody>
-</table>
-<hr />
-<table>
- <thead>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th>1</th>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <th>4</th>
- <td>5</td>
- <td>6</td>
- </tr>
- </tbody>
-</table>
-<hr />
-<table>
- <thead>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th>1</th>
- <td>2</td>
- <td>3</td>
- </tr>
- </tbody>
- <tfoot>
- <tr>
- <th>4</th>
- <td>5</td>
- <td>6</td>
- </tr>
- </tfoot>
-</table>
-<hr />
-<table>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- <tr>
- <th>1</th>
- <th>2</th>
- <th>3</th>
- </tr>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
-</table>
-<hr />
-<table>
- <tbody>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
- </tbody>
-</table>
-<hr />
-<table>
- <thead>
- </thead>
- <tbody>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
- </tbody>
-</table>
-<hr />
-<table>
- <thead>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- </tbody>
- <tbody>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
- </tbody>
-</table>
-<hr />
-<table>
- <thead>
- <tr>
- <th>X</th>
- <th>Y</th>
- <th>Z</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>1</td>
- <td><p>2</p></td>
- <td>3</td>
- </tr>
- </tbody>
- <tbody>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
- </tbody>
-</table>
-<h2>Tables without Headers</h2>
-<table>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
- </tbody>
-</table>
-<hr />
-<table>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
-</table>
-<hr />
-<table>
- <thead>
- </thead>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
- </tbody>
-</table>
-<hr />
-<table>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- </tbody>
- <tfoot>
- <tr>
- <td>4</td>
- <td>5</td>
- <td>6</td>
- </tr>
- </tfoot>
-</table>
-<h2>Empty Tables</h2>
-<p>This section should be empty.</p>
-<table>
- <tbody>
- </tbody>
-</table>
-<table>
-</table>
-</body>
-</html>
diff --git a/tests/html-reader.native b/tests/html-reader.native
deleted file mode 100644
index 6b7799a88..000000000
--- a/tests/html-reader.native
+++ /dev/null
@@ -1,463 +0,0 @@
-Pandoc (Meta {unMeta = fromList [("generator",MetaInlines [Str "pandoc"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
-[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
-,HorizontalRule
-,Header 1 ("headers",[],[]) [Str "Headers"]
-,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
-,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
-,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
-,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
-,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
-,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
-,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,HorizontalRule
-,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
-,Para [Str "Here's",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
-,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
-,Para [Str "Here's",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
-,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
-,HorizontalRule
-,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
-,Para [Str "E-mail",Space,Str "style:"]
-,BlockQuote
- [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
-,BlockQuote
- [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
- ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
- ,Para [Str "A",Space,Str "list:"]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "item",Space,Str "one"]]
- ,[Plain [Str "item",Space,Str "two"]]]
- ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
- ,BlockQuote
- [Para [Str "nested"]]
- ,BlockQuote
- [Para [Str "nested"]]]
-,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1."]
-,Para [Str "Box-style:"]
-,BlockQuote
- [Para [Str "Example:"]
- ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"]
-,BlockQuote
- [OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "do",Space,Str "laundry"]]
- ,[Plain [Str "take",Space,Str "out",Space,Str "the",Space,Str "trash"]]]]
-,Para [Str "Here's",Space,Str "a",Space,Str "nested",Space,Str "one:"]
-,BlockQuote
- [Para [Str "Joe",Space,Str "said:"]
- ,BlockQuote
- [Para [Str "Don't",Space,Str "quote",Space,Str "me."]]]
-,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
-,HorizontalRule
-,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
-,Para [Str "And:"]
-,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
-,HorizontalRule
-,Header 1 ("lists",[],[]) [Str "Lists"]
-,Header 2 ("unordered",[],[]) [Str "Unordered"]
-,Para [Str "Asterisks",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "asterisk",Space,Str "1"]]
- ,[Plain [Str "asterisk",Space,Str "2"]]
- ,[Plain [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Asterisks",Space,Str "loose:"]
-,BulletList
- [[Para [Str "asterisk",Space,Str "1"]]
- ,[Para [Str "asterisk",Space,Str "2"]]
- ,[Para [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "Plus",Space,Str "1"]]
- ,[Plain [Str "Plus",Space,Str "2"]]
- ,[Plain [Str "Plus",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "loose:"]
-,BulletList
- [[Para [Str "Plus",Space,Str "1"]]
- ,[Para [Str "Plus",Space,Str "2"]]
- ,[Para [Str "Plus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "Minus",Space,Str "1"]]
- ,[Plain [Str "Minus",Space,Str "2"]]
- ,[Plain [Str "Minus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "loose:"]
-,BulletList
- [[Para [Str "Minus",Space,Str "1"]]
- ,[Para [Str "Minus",Space,Str "2"]]
- ,[Para [Str "Minus",Space,Str "3"]]]
-,Header 2 ("ordered",[],[]) [Str "Ordered"]
-,Para [Str "Tight:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second"]]
- ,[Plain [Str "Third"]]]
-,Para [Str "and:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "One"]]
- ,[Plain [Str "Two"]]
- ,[Plain [Str "Three"]]]
-,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Para [Str "First"]]
- ,[Para [Str "Second"]]
- ,[Para [Str "Third"]]]
-,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Para [Str "One"]]
- ,[Para [Str "Two"]]
- ,[Para [Str "Three"]]]
-,Para [Str "Multiple",Space,Str "paragraphs:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
- ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog's",Space,Str "back."]]
- ,[Para [Str "Item",Space,Str "2."]]
- ,[Para [Str "Item",Space,Str "3."]]]
-,Para [Str "List",Space,Str "styles:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- []
-,OrderedList (1,LowerRoman,DefaultDelim)
- []
-,OrderedList (1,LowerRoman,DefaultDelim)
- []
-,OrderedList (1,DefaultStyle,DefaultDelim)
- []
-,OrderedList (1,LowerRoman,DefaultDelim)
- []
-,OrderedList (1,LowerRoman,DefaultDelim)
- []
-,Header 2 ("nested",[],[]) [Str "Nested"]
-,BulletList
- [[Plain [Str "Tab"]
- ,BulletList
- [[Plain [Str "Tab"]
- ,BulletList
- [[Plain [Str "Tab"]]]]]]]
-,Para [Str "Here's",Space,Str "another:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second:"]
- ,BulletList
- [[Plain [Str "Fee"]]
- ,[Plain [Str "Fie"]]
- ,[Plain [Str "Foe"]]]]
- ,[Plain [Str "Third"]]]
-,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Para [Str "First"]]
- ,[Para [Str "Second:"]
- ,BulletList
- [[Plain [Str "Fee"]]
- ,[Plain [Str "Fie"]]
- ,[Plain [Str "Foe"]]]]
- ,[Para [Str "Third"]]]
-,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
-,BulletList
- [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
- ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
- ,BulletList
- [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
- ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
-,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
-,OrderedList (2,Decimal,DefaultDelim)
- [[Plain [Str "begins",Space,Str "with",Space,Str "2"]]
- ,[Para [Str "and",Space,Str "now",Space,Str "3"]
- ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
- ,OrderedList (4,LowerRoman,DefaultDelim)
- [[Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"]]
- ,[Plain [Str "more",Space,Str "items"]
- ,OrderedList (1,UpperAlpha,DefaultDelim)
- [[Plain [Str "a",Space,Str "subsublist"]]
- ,[Plain [Str "a",Space,Str "subsublist"]]]]]]]
-,Para [Str "Nesting:"]
-,OrderedList (1,UpperAlpha,DefaultDelim)
- [[Plain [Str "Upper",Space,Str "Alpha"]
- ,OrderedList (1,UpperRoman,DefaultDelim)
- [[Plain [Str "Upper",Space,Str "Roman."]
- ,OrderedList (6,Decimal,DefaultDelim)
- [[Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
- ,OrderedList (3,LowerAlpha,DefaultDelim)
- [[Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
-,Para [Str "Autonumbering:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "Autonumber."]]
- ,[Plain [Str "More."]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "Nested."]]]]]
-,HorizontalRule
-,Header 2 ("definition",[],[]) [Str "Definition"]
-,DefinitionList
- [([Str "Violin"],
- [[Plain [Str "Stringed",Space,Str "musical",Space,Str "instrument."]]
- ,[Plain [Str "Torture",Space,Str "device."]]])
- ,([Str "Cello",LineBreak,Str "Violoncello"],
- [[Plain [Str "Low-voiced",Space,Str "stringed",Space,Str "instrument."]]])]
-,HorizontalRule
-,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
-,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
-,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
-,Para [Str "Empty",Space,Strong [],Space,Str "and",Space,Emph [],Str "."]
-,Para [Str "An",Space,Emph [Link ("",[],[]) [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
-,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
-,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
-,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
-,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
-,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
-,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "small",Space,Str "caps"],Str "."]
-,HorizontalRule
-,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
-,Para [Str "\"Hello,\"",Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Str "\"'Shelob'",Space,Str "is",Space,Str "my",Space,Str "name.\""]
-,Para [Str "'A',",Space,Str "'B',",Space,Str "and",Space,Str "'C'",Space,Str "are",Space,Str "letters."]
-,Para [Str "'Oak,'",Space,Str "'elm,'",Space,Str "and",Space,Str "'beech'",Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Str "'pine.'"]
-,Para [Str "'He",Space,Str "said,",Space,Str "\"I",Space,Str "want",Space,Str "to",Space,Str "go.\"'",Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70's?"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Str "'",Code ("",[],[]) "code",Str "'",Space,Str "and",Space,Str "a",Space,Str "\"",Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2",""),Str "\"."]
-,Para [Str "Some",Space,Str "dashes:",Space,Str "one---two",Space,Str "---",Space,Str "three--four",Space,Str "--",Space,Str "five."]
-,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5-7,",Space,Str "255-66,",Space,Str "1987-1999."]
-,Para [Str "Ellipses...and.",Space,Str ".",Space,Str ".and",Space,Str ".",Space,Str ".",Space,Str ".",Space,Str "."]
-,HorizontalRule
-,Header 1 ("latex",[],[]) [Str "LaTeX"]
-,BulletList
- [[Plain [Str "\\cite[22-23]{smith.1899}"]]
- ,[Plain [Str "\\doublespacing"]]
- ,[Plain [Str "$2+2=4$"]]
- ,[Plain [Str "$x",Space,Str "\\in",Space,Str "y$"]]
- ,[Plain [Str "$\\alpha",Space,Str "\\wedge",Space,Str "\\omega$"]]
- ,[Plain [Str "$223$"]]
- ,[Plain [Str "$p$-Tree"]]
- ,[Plain [Str "$\\frac{d}{dx}f(x)=\\lim_{h\\to",Space,Str "0}\\frac{f(x+h)-f(x)}{h}$"]]
- ,[Plain [Str "Here's",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Str "$\\alpha",Space,Str "+",Space,Str "\\omega",Space,Str "\\times",Space,Str "x^2$."]]]
-,Para [Str "These",Space,Str "shouldn't",Space,Str "be",Space,Str "math:"]
-,BulletList
- [[Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code ("",[],[]) "$e = mc^2$",Str "."]]
- ,[Plain [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",Space,Str "(It",Space,Str "worked",Space,Str "if",Space,Str "\"lot\"",Space,Str "is",Space,Str "emphasized.)"]]
- ,[Plain [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]]
-,Para [Str "Here's",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
-,Para [Str "\\begin{tabular}{|l|l|}\\hline",Space,Str "Animal",Space,Str "&",Space,Str "Number",Space,Str "\\\\",Space,Str "\\hline",Space,Str "Dog",Space,Str "&",Space,Str "2",Space,Str "\\\\",Space,Str "Cat",Space,Str "&",Space,Str "1",Space,Str "\\\\",Space,Str "\\hline",Space,Str "\\end{tabular}"]
-,HorizontalRule
-,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
-,BulletList
- [[Plain [Str "I",Space,Str "hat:",Space,Str "\206"]]
- ,[Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
- ,[Plain [Str "section:",Space,Str "\167"]]
- ,[Plain [Str "set",Space,Str "membership:",Space,Str "\8712"]]
- ,[Plain [Str "copyright:",Space,Str "\169"]]]
-,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
-,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
-,Para [Str "This",Space,Str "&",Space,Str "that."]
-,Para [Str "4",Space,Str "<",Space,Str "5."]
-,Para [Str "6",Space,Str ">",Space,Str "5."]
-,Para [Str "Backslash:",Space,Str "\\"]
-,Para [Str "Backtick:",Space,Str "`"]
-,Para [Str "Asterisk:",Space,Str "*"]
-,Para [Str "Underscore:",Space,Str "_"]
-,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
-,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
-,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
-,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
-,Para [Str "Left",Space,Str "paren:",Space,Str "("]
-,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
-,Para [Str "Greater-than:",Space,Str ">"]
-,Para [Str "Hash:",Space,Str "#"]
-,Para [Str "Period:",Space,Str "."]
-,Para [Str "Bang:",Space,Str "!"]
-,Para [Str "Plus:",Space,Str "+"]
-,Para [Str "Minus:",Space,Str "-"]
-,HorizontalRule
-,Header 1 ("links",[],[]) [Str "Links"]
-,Header 2 ("explicit",[],[]) [Str "Explicit"]
-,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
-,Para [Str "Email",Space,Str "link",Space,Str "(nobody",Space,Str "[at]",Space,Str "nowhere.net)"]
-,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
-,Header 2 ("reference",[],[]) [Str "Reference"]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
-,Para [Str "This",Space,Str "should",Space,Str "[not]",Space,Str "be",Space,Str "a",Space,Str "link."]
-,CodeBlock ("",[],[]) "[not]: /url"
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
-,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
-,Para [Str "Here's",Space,Str "a",Space,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
-,Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link ("",[],[]) [Str "AT&T"] ("http://att.com/","AT&T"),Str "."]
-,Para [Str "Here's",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
-,Para [Str "Here's",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
-,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
-,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
-,BulletList
- [[Plain [Str "In",Space,Str "a",Space,Str "list?"]]
- ,[Plain [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
- ,[Plain [Str "It",Space,Str "should."]]]
-,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Str "nobody",Space,Str "[at]",Space,Str "nowhere.net"]
-,BlockQuote
- [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
-,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
-,CodeBlock ("",[],[]) "or here: <http://example.com/>"
-,HorizontalRule
-,Header 1 ("images",[],[]) [Str "Images"]
-,Para [Str "From",Space,Str "\"Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune\"",Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
-,Para [Image ("",[],[]) [Str "lalune"] ("lalune.jpg","Voyage dans la Lune")]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
-,HorizontalRule
-,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference",Link ("",[],[]) [Str "(1)"] ("#note_1",""),Str ",",Space,Str "and",Space,Str "another",Link ("",[],[]) [Str "(longnote)"] ("#note_longnote",""),Str ".",Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space^(my",Space,Str "note)."]
-,Para [Link ("",[],[]) [Str "(1)"] ("#ref_1",""),Space,Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "in",Space,Str "the",Space,Str "document,",Space,Str "not",Space,Str "just",Space,Str "at",Space,Str "the",Space,Str "end."]
-,Para [Link ("",[],[]) [Str "(longnote)"] ("#ref_longnote",""),Space,Str "Here's",Space,Str "the",Space,Str "other",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."]
-,Para [Str "Caret",Space,Str "characters",Space,Str "are",Space,Str "used",Space,Str "to",Space,Str "indicate",Space,Str "that",Space,Str "the",Space,Str "blocks",Space,Str "all",Space,Str "belong",Space,Str "to",Space,Str "a",Space,Str "single",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "block",Space,Str "quotes)."]
-,CodeBlock ("",[],[]) " { <code> }"
-,Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "use",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "every",Space,Str "line,",Space,Str "as",Space,Str "with",Space,Str "blockquotes,",Space,Str "but",Space,Str "all",Space,Str "that",Space,Str "you",Space,Str "need",Space,Str "is",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "the",Space,Str "block",Space,Str "and",Space,Str "any",Space,Str "preceding",Space,Str "blank",Space,Str "lines."]
-,Para [Str "text",Space,Emph [Str "Leading",Space,Str "space"]]
-,Para [Emph [Str "Trailing",Space,Str "space"],Space,Str "text"]
-,Para [Str "text",Space,Emph [Str "Leading",Space,Str "spaces"]]
-,Para [Emph [Str "Trailing",Space,Str "spaces"],Space,Str "text"]
-,Header 1 ("tables",[],[]) [Str "Tables"]
-,Header 2 ("tables-with-headers",[],[]) [Str "Tables",Space,Str "with",Space,Str "Headers"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.3333333333333333,0.3333333333333333,0.3333333333333333]
- [[Plain [Str "X"]]
- ,[Plain [Str "Y"]]
- ,[Plain [Str "Z"]]]
- [[[Plain [Str "1"]]
- ,[Para [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,Header 2 ("tables-without-headers",[],[]) [Str "Tables",Space,Str "without",Space,Str "Headers"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- []
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- []
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- []
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,HorizontalRule
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- []
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]
-,Header 2 ("empty-tables",[],[]) [Str "Empty",Space,Str "Tables"]
-,Para [Str "This",Space,Str "section",Space,Str "should",Space,Str "be",Space,Str "empty."]]
diff --git a/tests/latex-reader.latex b/tests/latex-reader.latex
deleted file mode 100644
index 2ebdfed99..000000000
--- a/tests/latex-reader.latex
+++ /dev/null
@@ -1,848 +0,0 @@
-\documentclass{article}
-\usepackage[mathletters]{ucs}
-\usepackage[utf8x]{inputenc}
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-
-\newcommand{\textsubscript}[1]{\ensuremath{_{\scriptsize\textrm{#1}}}}
-\usepackage[breaklinks=true,unicode=true]{hyperref}
-\usepackage[normalem]{ulem}
-% avoid problems with \sout in headers with hyperref:
-\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
-\usepackage{enumerate}
-\usepackage{fancyvrb}
-\usepackage{graphicx}
-\usepackage{url}
-
-\setcounter{secnumdepth}{0}
-\VerbatimFootnotes % allows verbatim text in footnotes
-\title{Pandoc Test Suite}
-\author{John MacFarlane \and Anonymous}
-\date{July 17, 2006}
-\begin{document}
-\maketitle
-
-This is a set of tests for pandoc. Most of them are adapted from
-John Gruber's markdown test suite.
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Headers}
-
-\subsection{Level 2 with an \href{/url}{embedded link}}
-
-\subsubsection{Level 3 with \emph{emphasis}}
-
-Level 4
-
-Level 5
-
-\section[alt title ignored]{Level 1}
-
-\subsection{Level 2 with \emph{emphasis}}
-
-\subsubsection{Level 3}
-
-with no blank line
-
-\subsection{Level 2}
-
-with no blank line
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Paragraphs}
-
-Here's a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a
-list item. Because a hard-wrapped line in the middle of a paragraph
-looked like a list item.
-
-Here's one with a bullet. * criminey.
-
-There should be a hard line break\\here.
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Block Quotes}
-
-E-mail style:
-
-\begin{quote}
-This is a block quote. It is pretty short.
-
-\end{quote}
-\begin {quote}
-Code in a block quote:
-
-\begin{verbatim}
-sub status {
- print "working";
-}
-\end{verbatim}
-A list:
-
-\begin{enumerate}[1.]
-\item
- item one
-\item
- item two
-\end{enumerate}
-Nested block quotes:
-
-\begin{quote}
-nested
-
-\end{quote}
-\begin{quote}
-nested
-
-\end{quote}
-\end{quote}
-This should not be a block quote: 2 \textgreater{} 1.
-
-Box-style:
-
-\begin{quote}
-Example:
-
-\begin{verbatim}
-sub status {
- print "working";
-}
-\end{verbatim}
-\end{quote}
-\begin{quote}
-\begin{enumerate}[1.]
-\item
- do laundry
-\item
- take out the trash
-\end{enumerate}
-\end{quote}
-Here's a nested one:
-
-\begin{quote}
-Joe said:
-
-\begin{quote}
-Don't quote me.
-
-\end{quote}
-\end{quote}
-And a following paragraph.
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Code Blocks}
-
-Code:
-
-\begin{verbatim}
----- (should be four hyphens)
-
-sub status {
- print "working";
-}
-
-this code block is indented by one tab
-\end{verbatim}
-And:
-
-\begin{verbatim}
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \> \[ \{
-\end{verbatim}
-
-\begin{obeylines}
-this has \emph{two
-lines}
-\end{obeylines}
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Lists}
-
-\subsection{Unordered}
-
-Asterisks tight:
-
-\begin{itemize}
-\item
- asterisk 1
-\item
- asterisk 2
-\item
- asterisk 3
-\end{itemize}
-Asterisks loose:
-
-\begin{itemize}
-\item
- asterisk 1
-
-\item
- asterisk 2
-
-\item
- asterisk 3
-
-\end{itemize}
-Pluses tight:
-
-\begin{itemize}
-\item
- Plus 1
-\item
- Plus 2
-\item
- Plus 3
-\end{itemize}
-Pluses loose:
-
-\begin{itemize}
-\item
- Plus 1
-
-\item
- Plus 2
-
-\item
- Plus 3
-
-\end{itemize}
-Minuses tight:
-
-\begin{itemize}
-\item
- Minus 1
-\item
- Minus 2
-\item
- Minus 3
-\end{itemize}
-Minuses loose:
-
-\begin{itemize}
-\item
- Minus 1
-
-\item
- Minus 2
-
-\item
- Minus 3
-
-\end{itemize}
-\subsection{Ordered}
-
-Tight:
-
-\begin{enumerate}[1.]
-\item
- First
-\item
- Second
-\item
- Third
-\end{enumerate}
-and:
-
-\begin{enumerate}[1.]
-\item
- One
-\item
- Two
-\item
- Three
-\end{enumerate}
-Loose using tabs:
-
-\begin{enumerate}[1.]
-\item
- First
-
-\item
- Second
-
-\item
- Third
-
-\end{enumerate}
-and using spaces:
-
-\begin{enumerate}[1.]
-\item
- One
-
-\item
- Two
-
-\item
- Three
-
-\end{enumerate}
-Multiple paragraphs:
-
-\begin{enumerate}[1.]
-\item
- Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog's
- back.
-
-\item
- Item 2.
-
-\item
- Item 3.
-
-\end{enumerate}
-\subsection{Nested}
-
-\begin{itemize}
-\item
- Tab
- \begin{itemize}
- \item
- Tab
- \begin{itemize}
- \item
- Tab
- \end{itemize}
- \end{itemize}
-\end{itemize}
-Here's another:
-
-\begin{enumerate}[1.]
-\item
- First
-\item
- Second:
- \begin{itemize}
- \item
- Fee
- \item
- Fie
- \item
- Foe
- \end{itemize}
-\item
- Third
-\end{enumerate}
-Same thing but with paragraphs:
-
-\begin{enumerate}[1.]
-\item
- First
-
-\item
- Second:
-
- \begin{itemize}
- \item
- Fee
- \item
- Fie
- \item
- Foe
- \end{itemize}
-\item
- Third
-
-\end{enumerate}
-\subsection{Tabs and spaces}
-
-\begin{itemize}
-\item
- this is a list item indented with tabs
-
-\item
- this is a list item indented with spaces
-
- \begin{itemize}
- \item
- this is an example list item indented with tabs
-
- \item
- this is an example list item indented with spaces
-
- \end{itemize}
-\end{itemize}
-\subsection{Fancy list markers}
-
-\begin{enumerate}[(1)]
-\setcounter{enumi}{1}
-\item
- begins with 2
-\item
- and now 3
-
- with a continuation
-
- \begin{enumerate}[i.]
- \setcounter{enumii}{3}
- \item
- sublist with roman numerals, starting with 4
- \item
- more items
- \begin{enumerate}[(A)]
- \item
- a subsublist
- \item
- a subsublist
- \end{enumerate}
- \end{enumerate}
-\end{enumerate}
-Nesting:
-
-\begin{enumerate}[A.]
-\item
- Upper Alpha
- \begin{enumerate}[I.]
- \item
- Upper Roman.
- \begin{enumerate}[(1)]
- \setcounter{enumiii}{5}
- \item
- Decimal start with 6
- \begin{enumerate}[a)]
- \setcounter{enumiv}{2}
- \item
- Lower alpha with paren
- \end{enumerate}
- \end{enumerate}
- \end{enumerate}
-\end{enumerate}
-Autonumbering:
-
-\begin{enumerate}
-\item
- Autonumber.
-\item
- More.
- \begin{enumerate}
- \item
- Nested.
- \end{enumerate}
-\end{enumerate}
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Definition Lists}
-
-Tight using spaces:
-
-\begin{description}
-\item[apple]
-red fruit
-\item[orange]
-orange fruit
-\item[banana]
-yellow fruit
-\end{description}
-Tight using tabs:
-
-\begin{description}
-\item[apple]
-red fruit
-\item[orange]
-orange fruit
-\item[banana]
-yellow fruit
-\end{description}
-Loose:
-
-\begin{description}
-\item[apple]
-red fruit
-
-\item[orange]
-orange fruit
-
-\item[banana]
-yellow fruit
-
-\end{description}
-Multiple blocks with italics:
-
-\begin{description}
-\item[\emph{apple}]
-red fruit
-
-contains seeds, crisp, pleasant to taste
-
-\item[\emph{orange}]
-orange fruit
-
-\begin{verbatim}
-{ orange code block }
-\end{verbatim}
-\begin{quote}
-orange block quote
-
-\end{quote}
-\end{description}
-\section{HTML Blocks}
-
-Simple block on one line:
-
-foo
-And nested without indentation:
-
-foo
-bar
-Interpreted markdown in a table:
-
-This is \emph{emphasized}
-And this is \textbf{strong}
-Here's a simple block:
-
-foo
-This should be a code block, though:
-
-\begin{verbatim}
-<div>
- foo
-</div>
-\end{verbatim}
-As should this:
-
-\begin{verbatim}
-<div>foo</div>
-\end{verbatim}
-Now, nested:
-
-foo
-This should just be an HTML comment:
-
-Multiline:
-
-Code block:
-
-\begin{verbatim}
-<!-- Comment -->
-\end{verbatim}
-Just plain comment, with trailing spaces on the line:
-
-Code:
-
-\begin{verbatim}
-<hr />
-\end{verbatim}
-Hr's:
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Inline Markup}
-
-This is \emph{emphasized}, and so \emph{is this}.
-
-This is \textbf{strong}, and so \textbf{is this}.
-
-An \emph{\href{/url}{emphasized link}}.
-
-\textbf{\emph{This is strong and em.}}
-
-So is \textbf{\emph{this}} word.
-
-\textbf{\emph{This is strong and em.}}
-
-So is \textbf{\emph{this}} word.
-
-This is code: \verb!>!, \verb!$!, \verb!\!, \verb!\$!,
-\verb!<html>!.
-
-\sout{This is \emph{strikeout}.}
-
-Superscripts: a\textsuperscript{bc}d
-a\textsuperscript{\emph{hello}} a\textsuperscript{hello there}.
-
-Subscripts: H\textsubscript{2}O, H\textsubscript{23}O,
-H\textsubscript{many of them}O.
-
-These should not be superscripts or subscripts, because of the
-unescaped spaces: a\^{}b c\^{}d, a\ensuremath{\sim}b
-c\ensuremath{\sim}d.
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Smart quotes, ellipses, dashes}
-
-``Hello,'' said the spider. ``\,`Shelob' is my name.''
-
-`A', `B', and `C' are letters.
-
-`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
-
-`He said, ``I want to go.''\,' Were you alive in the 70's?
-
-Here is some quoted `\verb!code!' and a
-``\href{http://example.com/?foo=1&bar=2}{quoted link}''.
-
-Some dashes: one---two---three---four---five.
-
-Dashes between numbers: 5--7, 255--66, 1987--1999.
-
-Ellipses\ldots{}and\ldots{}and\ldots{}.
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{LaTeX}
-
-\begin{itemize}
-\item
- \cite[22-23]{smith.1899}
-\item
- \doublespacing
-\item
- $2+2=4$
-\item
- $x \in y$
-\item
- $\alpha \wedge \omega$
-\item
- $223$
-\item
- $p$-Tree
-\item
- $\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$
-\item
- Here's one that has a line break in it:
- $\alpha + \omega \times x^2$.
-\end{itemize}
-These shouldn't be math:
-
-\begin{itemize}
-\item
- To get the famous equation, write \verb!$e = mc^2$!.
-\item
- \$22,000 is a \emph{lot} of money. So is \$34,000. (It worked if
- ``lot'' is emphasized.)
-\item
- Escaped \verb!$!: \$73 \emph{this should be emphasized} 23\$.
-\end{itemize}
-Here's a LaTeX table:
-
-\begin{tabular}{|l|l|}\hline
-Animal & Number \\ \hline
-Dog & 2 \\
-Cat & 1 \\ \hline
-\end{tabular}
-
-A table with one column:
-
-\begin{tabular}{c}
-Animal \\
-Vegetable
-\end{tabular}
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Special Characters}
-
-Here is some unicode:
-
-\begin{itemize}
-\item
- I hat: Î
-\item
- o umlaut: ö
-\item
- section: §
-\item
- set membership: ∈
-\item
- copyright: ©
-\end{itemize}
-AT\&T has an ampersand in their name.
-
-AT\&T is another way to write it.
-
-This \& that.
-
-4 \textless{} 5.
-
-6 \textgreater{} 5.
-
-Backslash: \textbackslash{}
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: \_
-
-Left brace: \{
-
-Right brace: \}
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: \textgreater{}
-
-Hash: \#
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Links}
-
-\subsection{Explicit}
-
-Just a \href{/url/}{URL}.
-
-\href{/url/}{URL and title}.
-
-\href{/url/}{URL and title}.
-
-\href{/url/}{URL and title}.
-
-\href{/url/}{URL and title}
-
-\href{/url/}{URL and title}
-
-\href{/url/with_underscore}{with\_underscore}
-
-\href{mailto:nobody@nowhere.net}{Email link}
-
-\href{}{Empty}.
-
-\subsection{Reference}
-
-Foo \href{/url/}{bar}.
-
-Foo \href{/url/}{bar}.
-
-Foo \href{/url/}{bar}.
-
-With \href{/url/}{embedded [brackets]}.
-
-\href{/url/}{b} by itself should be a link.
-
-Indented \href{/url}{once}.
-
-Indented \href{/url}{twice}.
-
-Indented \href{/url}{thrice}.
-
-This should [not][] be a link.
-
-\begin{verbatim}
-[not]: /url
-\end{verbatim}
-Foo \href{/url/}{bar}.
-
-Foo \href{/url/}{biz}.
-
-\subsection{With ampersands}
-
-Here's a
-\href{http://example.com/?foo=1&bar=2}{link with an ampersand in the URL}.
-
-Here's a link with an amersand in the link text:
-\href{http://att.com/}{AT\&T}.
-
-Here's an \href{/script?foo=1&bar=2}{inline link}.
-
-Here's an
-\href{/script?foo=1&bar=2}{inline link in pointy braces}.
-
-\subsection{Autolinks}
-
-With an ampersand: \url{http://example.com/?foo=1&bar=2}
-
-\begin{itemize}
-\item
- In a list?
-\item
- \url{http://example.com/}
-\item
- It should.
-\end{itemize}
-An e-mail address:
-\href{mailto:nobody@nowhere.net}{nobody@nowhere.net}
-
-\begin{quote}
-Blockquoted: \url{http://example.com/}
-
-\end{quote}
-Auto-links should not occur here: \verb!<http://example.com/>!
-
-\begin{verbatim}
-or here: <http://example.com/>
-\end{verbatim}
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Images}
-
-From ``Voyage dans la Lune'' by Georges Melies (1902):
-
-\includegraphics{lalune.jpg}
-
-Here is a movie \includegraphics{movie.jpg} icon.
-
-\begin{center}\rule{3in}{0.4pt}\end{center}
-
-\section{Footnotes}
-
-Here is a footnote
-reference,\footnote{ Here is the footnote. It can go anywhere after the footnote
-reference. It need not be placed at the end of the document.
-}
-and
-another.\footnote{ Here's the long note. This one contains multiple blocks.
-
-Subsequent blocks are indented to show that they belong to the
-footnote (as with list items).
-
-\begin{Verbatim}
- { <code> }
-\end{Verbatim}
-If you want, you can indent every line, but you can also be lazy
-and just indent the first line of each block.
-}
-This should \emph{not} be a footnote reference, because it contains
-a space.[\^{}my note] Here is an inline
-note.\footnote{ This is \emph{easier} to type. Inline notes may contain
-\href{http://google.com}{links} and \verb!]! verbatim characters,
-as well as [bracketed text].
-}
-
-\begin{quote}
-Notes can go in quotes.\footnote{ In quote.
-}
-
-\end{quote}
-\begin{enumerate}[1.]
-\item
- And in list items.\footnote{ In list.
-}
-\end{enumerate}
-This paragraph should not be part of the note, as it is not
-indented.
-
-\section{Escaped characters}
-
-\$ \% \& \# \_ \{ \}
-
-\end{document}
diff --git a/tests/latex-reader.native b/tests/latex-reader.native
deleted file mode 100644
index d1ff4c0a4..000000000
--- a/tests/latex-reader.native
+++ /dev/null
@@ -1,375 +0,0 @@
-Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
-[RawBlock (Format "latex") "\\maketitle"
-,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",SoftBreak,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
-,HorizontalRule
-,Header 1 ("headers",[],[]) [Str "Headers"]
-,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
-,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Para [Str "Level",Space,Str "4"]
-,Para [Str "Level",Space,Str "5"]
-,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
-,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
-,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
-,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,HorizontalRule
-,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
-,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",SoftBreak,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",SoftBreak,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
-,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
-,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
-,HorizontalRule
-,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
-,Para [Str "E-mail",Space,Str "style:"]
-,BlockQuote
- [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
-,BlockQuote
- [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
- ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
- ,Para [Str "A",Space,Str "list:"]
- ,OrderedList (1,Decimal,Period)
- [[Para [Str "item",Space,Str "one"]]
- ,[Para [Str "item",Space,Str "two"]]]
- ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
- ,BlockQuote
- [Para [Str "nested"]]
- ,BlockQuote
- [Para [Str "nested"]]]
-,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1."]
-,Para [Str "Box-style:"]
-,BlockQuote
- [Para [Str "Example:"]
- ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"]
-,BlockQuote
- [OrderedList (1,Decimal,Period)
- [[Para [Str "do",Space,Str "laundry"]]
- ,[Para [Str "take",Space,Str "out",Space,Str "the",Space,Str "trash"]]]]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "nested",Space,Str "one:"]
-,BlockQuote
- [Para [Str "Joe",Space,Str "said:"]
- ,BlockQuote
- [Para [Str "Don\8217t",Space,Str "quote",Space,Str "me."]]]
-,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
-,HorizontalRule
-,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
-,Para [Str "And:"]
-,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
-,Para [Str "this",Space,Str "has",Space,Emph [Str "two",LineBreak,Str "lines"]]
-,HorizontalRule
-,Header 1 ("lists",[],[]) [Str "Lists"]
-,Header 2 ("unordered",[],[]) [Str "Unordered"]
-,Para [Str "Asterisks",Space,Str "tight:"]
-,BulletList
- [[Para [Str "asterisk",Space,Str "1"]]
- ,[Para [Str "asterisk",Space,Str "2"]]
- ,[Para [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Asterisks",Space,Str "loose:"]
-,BulletList
- [[Para [Str "asterisk",Space,Str "1"]]
- ,[Para [Str "asterisk",Space,Str "2"]]
- ,[Para [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "tight:"]
-,BulletList
- [[Para [Str "Plus",Space,Str "1"]]
- ,[Para [Str "Plus",Space,Str "2"]]
- ,[Para [Str "Plus",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "loose:"]
-,BulletList
- [[Para [Str "Plus",Space,Str "1"]]
- ,[Para [Str "Plus",Space,Str "2"]]
- ,[Para [Str "Plus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "tight:"]
-,BulletList
- [[Para [Str "Minus",Space,Str "1"]]
- ,[Para [Str "Minus",Space,Str "2"]]
- ,[Para [Str "Minus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "loose:"]
-,BulletList
- [[Para [Str "Minus",Space,Str "1"]]
- ,[Para [Str "Minus",Space,Str "2"]]
- ,[Para [Str "Minus",Space,Str "3"]]]
-,Header 2 ("ordered",[],[]) [Str "Ordered"]
-,Para [Str "Tight:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "First"]]
- ,[Para [Str "Second"]]
- ,[Para [Str "Third"]]]
-,Para [Str "and:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "One"]]
- ,[Para [Str "Two"]]
- ,[Para [Str "Three"]]]
-,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "First"]]
- ,[Para [Str "Second"]]
- ,[Para [Str "Third"]]]
-,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "One"]]
- ,[Para [Str "Two"]]
- ,[Para [Str "Three"]]]
-,Para [Str "Multiple",Space,Str "paragraphs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
- ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",SoftBreak,Str "back."]]
- ,[Para [Str "Item",Space,Str "2."]]
- ,[Para [Str "Item",Space,Str "3."]]]
-,Header 2 ("nested",[],[]) [Str "Nested"]
-,BulletList
- [[Para [Str "Tab"]
- ,BulletList
- [[Para [Str "Tab"]
- ,BulletList
- [[Para [Str "Tab"]]]]]]]
-,Para [Str "Here\8217s",Space,Str "another:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "First"]]
- ,[Para [Str "Second:"]
- ,BulletList
- [[Para [Str "Fee"]]
- ,[Para [Str "Fie"]]
- ,[Para [Str "Foe"]]]]
- ,[Para [Str "Third"]]]
-,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "First"]]
- ,[Para [Str "Second:"]
- ,BulletList
- [[Para [Str "Fee"]]
- ,[Para [Str "Fie"]]
- ,[Para [Str "Foe"]]]]
- ,[Para [Str "Third"]]]
-,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
-,BulletList
- [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
- ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
- ,BulletList
- [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
- ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
-,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
-,OrderedList (2,Decimal,TwoParens)
- [[Para [Str "begins",Space,Str "with",Space,Str "2"]]
- ,[Para [Str "and",Space,Str "now",Space,Str "3"]
- ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
- ,OrderedList (4,LowerRoman,Period)
- [[Para [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"]]
- ,[Para [Str "more",Space,Str "items"]
- ,OrderedList (1,UpperAlpha,TwoParens)
- [[Para [Str "a",Space,Str "subsublist"]]
- ,[Para [Str "a",Space,Str "subsublist"]]]]]]]
-,Para [Str "Nesting:"]
-,OrderedList (1,UpperAlpha,Period)
- [[Para [Str "Upper",Space,Str "Alpha"]
- ,OrderedList (1,UpperRoman,Period)
- [[Para [Str "Upper",Space,Str "Roman."]
- ,OrderedList (6,Decimal,TwoParens)
- [[Para [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
- ,OrderedList (3,LowerAlpha,OneParen)
- [[Para [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
-,Para [Str "Autonumbering:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Para [Str "Autonumber."]]
- ,[Para [Str "More."]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Para [Str "Nested."]]]]]
-,Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
-,Para [Str "M.A.",Space,Str "2007"]
-,Para [Str "B.",Space,Str "Williams"]
-,HorizontalRule
-,Header 1 ("definition-lists",[],[]) [Str "Definition",Space,Str "Lists"]
-,Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Para [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Para [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Loose:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Para [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
-,DefinitionList
- [([Emph [Str "apple"]],
- [[Para [Str "red",Space,Str "fruit"]
- ,Para [Str "contains",Space,Str "seeds,",Space,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"]]])
- ,([Emph [Str "orange"]],
- [[Para [Str "orange",Space,Str "fruit"]
- ,CodeBlock ("",[],[]) "{ orange code block }"
- ,BlockQuote
- [Para [Str "orange",Space,Str "block",Space,Str "quote"]]]])]
-,Header 1 ("html-blocks",[],[]) [Str "HTML",Space,Str "Blocks"]
-,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
-,Para [Str "foo",SoftBreak,Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
-,Para [Str "foo",SoftBreak,Str "bar",SoftBreak,Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
-,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],SoftBreak,Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"],SoftBreak,Str "Here\8217s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
-,Para [Str "foo",SoftBreak,Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
-,CodeBlock ("",[],[]) "<div>\n foo\n</div>"
-,Para [Str "As",Space,Str "should",Space,Str "this:"]
-,CodeBlock ("",[],[]) "<div>foo</div>"
-,Para [Str "Now,",Space,Str "nested:"]
-,Para [Str "foo",SoftBreak,Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
-,Para [Str "Multiline:"]
-,Para [Str "Code",Space,Str "block:"]
-,CodeBlock ("",[],[]) "<!-- Comment -->"
-,Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) "<hr />"
-,Para [Str "Hr\8217s:"]
-,HorizontalRule
-,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
-,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
-,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
-,Para [Str "An",Space,Emph [Link ("",[],[]) [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
-,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
-,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
-,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
-,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
-,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",SoftBreak,Code ("",[],[]) "<html>",Str "."]
-,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
-,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",SoftBreak,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello",Space,Str "there"],Str "."]
-,Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",SoftBreak,Str "H",Subscript [Str "many",Space,Str "of",Space,Str "them"],Str "O."]
-,Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",Space,Str "because",Space,Str "of",Space,Str "the",SoftBreak,Str "unescaped",Space,Str "spaces:",Space,Str "a^b",Space,Str "c^d,",Space,Str "a",Math InlineMath "\\sim",Str "b",SoftBreak,Str "c",Math InlineMath "\\sim",Str "d."]
-,HorizontalRule
-,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
-,Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
-,Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
-,Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine."]]
-,Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70\8217s?"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code ("",[],[]) "code"],Space,Str "and",Space,Str "a",SoftBreak,Quoted DoubleQuote [Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
-,Para [Str "Some",Space,Str "dashes:",Space,Str "one\8212two\8212three\8212four\8212five."]
-,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5\8211\&7,",Space,Str "255\8211\&66,",Space,Str "1987\8211\&1999."]
-,Para [Str "Ellipses\8230and\8230and\8230."]
-,HorizontalRule
-,Header 1 ("latex",[],[]) [Str "LaTeX"]
-,BulletList
- [[Para [Cite [Citation {citationId = "smith.1899", citationPrefix = [], citationSuffix = [Str "22-23"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cite[22-23]{smith.1899}"]]]
- ,[Para [RawInline (Format "latex") "\\doublespacing"]]
- ,[Para [Math InlineMath "2+2=4"]]
- ,[Para [Math InlineMath "x \\in y"]]
- ,[Para [Math InlineMath "\\alpha \\wedge \\omega"]]
- ,[Para [Math InlineMath "223"]]
- ,[Para [Math InlineMath "p",Str "-Tree"]]
- ,[Para [Math InlineMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"]]
- ,[Para [Str "Here\8217s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",SoftBreak,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."]]]
-,Para [Str "These",Space,Str "shouldn\8217t",Space,Str "be",Space,Str "math:"]
-,BulletList
- [[Para [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code ("",[],[]) "$e = mc^2$",Str "."]]
- ,[Para [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",Space,Str "(It",Space,Str "worked",Space,Str "if",SoftBreak,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized.)"]]
- ,[Para [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
-,Table [] [AlignLeft,AlignLeft] [0.0,0.0]
- [[Plain [Str "Animal"]]
- ,[Plain [Str "Number"]]]
- [[[Plain [Str "Dog"]]
- ,[Plain [Str "2"]]]
- ,[[Plain [Str "Cat"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "A",Space,Str "table",Space,Str "with",Space,Str "one",Space,Str "column:"]
-,Table [] [AlignCenter] [0.0]
- [[]]
- [[[Plain [Str "Animal"]]]
- ,[[Plain [Str "Vegetable"]]]]
-,HorizontalRule
-,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
-,BulletList
- [[Para [Str "I",Space,Str "hat:",Space,Str "\206"]]
- ,[Para [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
- ,[Para [Str "section:",Space,Str "\167"]]
- ,[Para [Str "set",Space,Str "membership:",Space,Str "\8712"]]
- ,[Para [Str "copyright:",Space,Str "\169"]]]
-,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
-,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
-,Para [Str "This",Space,Str "&",Space,Str "that."]
-,Para [Str "4",Space,Str "<",Space,Str "5."]
-,Para [Str "6",Space,Str ">",Space,Str "5."]
-,Para [Str "Backslash:",Space,Str "\\"]
-,Para [Str "Backtick:",Space,Str "\8216"]
-,Para [Str "Asterisk:",Space,Str "*"]
-,Para [Str "Underscore:",Space,Str "_"]
-,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
-,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
-,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
-,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
-,Para [Str "Left",Space,Str "paren:",Space,Str "("]
-,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
-,Para [Str "Greater-than:",Space,Str ">"]
-,Para [Str "Hash:",Space,Str "#"]
-,Para [Str "Period:",Space,Str "."]
-,Para [Str "Bang:",Space,Str "!"]
-,Para [Str "Plus:",Space,Str "+"]
-,Para [Str "Minus:",Space,Str "-"]
-,HorizontalRule
-,Header 1 ("links",[],[]) [Str "Links"]
-,Header 2 ("explicit",[],[]) [Str "Explicit"]
-,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","")]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","")]
-,Para [Link ("",[],[]) [Str "with_underscore"] ("/url/with_underscore","")]
-,Para [Link ("",[],[]) [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
-,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
-,Header 2 ("reference",[],[]) [Str "Reference"]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
-,Para [Str "This",Space,Str "should",Space,Str "[not][]",Space,Str "be",Space,Str "a",Space,Str "link."]
-,CodeBlock ("",[],[]) "[not]: /url"
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "biz"] ("/url/",""),Str "."]
-,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
-,Para [Str "Here\8217s",Space,Str "a",SoftBreak,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",SoftBreak,Link ("",[],[]) [Str "AT&T"] ("http://att.com/",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "an",SoftBreak,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
-,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
-,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
-,BulletList
- [[Para [Str "In",Space,Str "a",Space,Str "list?"]]
- ,[Para [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
- ,[Para [Str "It",Space,Str "should."]]]
-,Para [Str "An",Space,Str "e-mail",Space,Str "address:",SoftBreak,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
-,BlockQuote
- [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
-,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
-,CodeBlock ("",[],[]) "or here: <http://example.com/>"
-,HorizontalRule
-,Header 1 ("images",[],[]) [Str "Images"]
-,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
-,Para [Image ("",[],[]) [Str "image"] ("lalune.jpg","")]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "image"] ("movie.jpg",""),Space,Str "icon."]
-,HorizontalRule
-,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",SoftBreak,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",SoftBreak,Str "reference.",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document."]],SoftBreak,Str "and",SoftBreak,Str "another.",Note [Para [Str "Here\8217s",Space,Str "the",Space,Str "long",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",SoftBreak,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",SoftBreak,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block."]],SoftBreak,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",SoftBreak,Str "a",Space,Str "space.[^my",Space,Str "note]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",SoftBreak,Str "note.",Note [Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type.",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",SoftBreak,Link ("",[],[]) [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code ("",[],[]) "]",Space,Str "verbatim",Space,Str "characters,",SoftBreak,Str "as",Space,Str "well",Space,Str "as",Space,Str "[bracketed",Space,Str "text]."]]]
-,BlockQuote
- [Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes.",Note [Para [Str "In",Space,Str "quote."]]]]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]]]]
-,Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",SoftBreak,Str "indented."]
-,Header 1 ("escaped-characters",[],[]) [Str "Escaped",Space,Str "characters"]
-,Para [Str "$",Space,Str "%",Space,Str "&",Space,Str "#",Space,Str "_",Space,Str "{",Space,Str "}"]]
diff --git a/tests/lhs-test.html b/tests/lhs-test.html
deleted file mode 100644
index e4a5b3868..000000000
--- a/tests/lhs-test.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="Content-Style-Type" content="text/css" />
- <meta name="generator" content="pandoc" />
- <title></title>
- <style type="text/css">code{white-space: pre;}</style>
- <style type="text/css">
-div.sourceCode { overflow-x: auto; }
-table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
- margin: 0; padding: 0; vertical-align: baseline; border: none; }
-table.sourceCode { width: 100%; line-height: 100%; }
-td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
-td.sourceCode { padding-left: 5px; }
-code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
-code > span.dt { color: #902000; } /* DataType */
-code > span.dv { color: #40a070; } /* DecVal */
-code > span.bn { color: #40a070; } /* BaseN */
-code > span.fl { color: #40a070; } /* Float */
-code > span.ch { color: #4070a0; } /* Char */
-code > span.st { color: #4070a0; } /* String */
-code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
-code > span.ot { color: #007020; } /* Other */
-code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
-code > span.fu { color: #06287e; } /* Function */
-code > span.er { color: #ff0000; font-weight: bold; } /* Error */
-code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
-code > span.cn { color: #880000; } /* Constant */
-code > span.sc { color: #4070a0; } /* SpecialChar */
-code > span.vs { color: #4070a0; } /* VerbatimString */
-code > span.ss { color: #bb6688; } /* SpecialString */
-code > span.im { } /* Import */
-code > span.va { color: #19177c; } /* Variable */
-code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
-code > span.op { color: #666666; } /* Operator */
-code > span.bu { } /* BuiltIn */
-code > span.ex { } /* Extension */
-code > span.pp { color: #bc7a00; } /* Preprocessor */
-code > span.at { color: #7d9029; } /* Attribute */
-code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
-code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
-code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
-code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
- </style>
-</head>
-<body>
-<h1 id="lhs-test">lhs test</h1>
-<p><code>unsplit</code> is an arrow that takes a pair of values and combines them to
-return a single value:</p>
-<div class="sourceCode"><pre class="sourceCode literate haskell"><code class="sourceCode haskell"><span class="ot">unsplit ::</span> (<span class="dt">Arrow</span> a) <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d) <span class="ot">-&gt;</span> a (b, c) d
-unsplit <span class="fu">=</span> arr <span class="fu">.</span> uncurry
- <span class="co">-- arr (\op (x,y) -&gt; x `op` y)</span></code></pre></div>
-<p><code>(***)</code> combines two arrows into a new arrow by running the two arrows on a
-pair of values (one arrow on the first item of the pair and one arrow on the
-second item of the pair).</p>
-<pre><code>f *** g = first f &gt;&gt;&gt; second g</code></pre>
-<p>Block quote:</p>
-<blockquote>
-<p>foo bar</p>
-</blockquote>
-</body>
-</html>
diff --git a/tests/lhs-test.html+lhs b/tests/lhs-test.html+lhs
deleted file mode 100644
index 41e9ca283..000000000
--- a/tests/lhs-test.html+lhs
+++ /dev/null
@@ -1,63 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="Content-Style-Type" content="text/css" />
- <meta name="generator" content="pandoc" />
- <title></title>
- <style type="text/css">code{white-space: pre;}</style>
- <style type="text/css">
-div.sourceCode { overflow-x: auto; }
-table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
- margin: 0; padding: 0; vertical-align: baseline; border: none; }
-table.sourceCode { width: 100%; line-height: 100%; }
-td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
-td.sourceCode { padding-left: 5px; }
-code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
-code > span.dt { color: #902000; } /* DataType */
-code > span.dv { color: #40a070; } /* DecVal */
-code > span.bn { color: #40a070; } /* BaseN */
-code > span.fl { color: #40a070; } /* Float */
-code > span.ch { color: #4070a0; } /* Char */
-code > span.st { color: #4070a0; } /* String */
-code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
-code > span.ot { color: #007020; } /* Other */
-code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
-code > span.fu { color: #06287e; } /* Function */
-code > span.er { color: #ff0000; font-weight: bold; } /* Error */
-code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
-code > span.cn { color: #880000; } /* Constant */
-code > span.sc { color: #4070a0; } /* SpecialChar */
-code > span.vs { color: #4070a0; } /* VerbatimString */
-code > span.ss { color: #bb6688; } /* SpecialString */
-code > span.im { } /* Import */
-code > span.va { color: #19177c; } /* Variable */
-code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
-code > span.op { color: #666666; } /* Operator */
-code > span.bu { } /* BuiltIn */
-code > span.ex { } /* Extension */
-code > span.pp { color: #bc7a00; } /* Preprocessor */
-code > span.at { color: #7d9029; } /* Attribute */
-code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
-code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
-code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
-code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
- </style>
-</head>
-<body>
-<h1 id="lhs-test">lhs test</h1>
-<p><code>unsplit</code> is an arrow that takes a pair of values and combines them to
-return a single value:</p>
-<div class="sourceCode"><pre class="sourceCode literate literatehaskell"><code class="sourceCode literatehaskell"><span class="ot">&gt; unsplit ::</span> (<span class="dt">Arrow</span> a) <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d) <span class="ot">-&gt;</span> a (b, c) d
-<span class="ot">&gt;</span> unsplit <span class="fu">=</span> arr <span class="fu">.</span> uncurry
-<span class="ot">&gt;</span> <span class="co">-- arr (\op (x,y) -&gt; x `op` y)</span></code></pre></div>
-<p><code>(***)</code> combines two arrows into a new arrow by running the two arrows on a
-pair of values (one arrow on the first item of the pair and one arrow on the
-second item of the pair).</p>
-<pre><code>f *** g = first f &gt;&gt;&gt; second g</code></pre>
-<p>Block quote:</p>
-<blockquote>
-<p>foo bar</p>
-</blockquote>
-</body>
-</html>
diff --git a/tests/lhs-test.latex b/tests/lhs-test.latex
deleted file mode 100644
index d1ad9db69..000000000
--- a/tests/lhs-test.latex
+++ /dev/null
@@ -1,125 +0,0 @@
-\documentclass[]{article}
-\usepackage{lmodern}
-\usepackage{amssymb,amsmath}
-\usepackage{ifxetex,ifluatex}
-\usepackage{fixltx2e} % provides \textsubscript
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[T1]{fontenc}
- \usepackage[utf8]{inputenc}
-\else % if luatex or xelatex
- \ifxetex
- \usepackage{mathspec}
- \else
- \usepackage{fontspec}
- \fi
- \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
-\fi
-% use upquote if available, for straight quotes in verbatim environments
-\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
-% use microtype if available
-\IfFileExists{microtype.sty}{%
-\usepackage[]{microtype}
-\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
-}{}
-\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
-\usepackage[unicode=true]{hyperref}
-\hypersetup{
- pdfborder={0 0 0},
- breaklinks=true}
-\urlstyle{same} % don't use monospace font for urls
-\usepackage{color}
-\usepackage{fancyvrb}
-\newcommand{\VerbBar}{|}
-\newcommand{\VERB}{\Verb[commandchars=\\\{\}]}
-\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
-% Add ',fontsize=\small' for more characters per line
-\newenvironment{Shaded}{}{}
-\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
-\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{#1}}
-\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
-\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
-\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
-\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{#1}}
-\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
-\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
-\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
-\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
-\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{#1}}
-\newcommand{\ImportTok}[1]{#1}
-\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{#1}}}
-\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{#1}}}
-\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
-\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
-\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{#1}}
-\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{#1}}
-\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{#1}}
-\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
-\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
-\newcommand{\BuiltInTok}[1]{#1}
-\newcommand{\ExtensionTok}[1]{#1}
-\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{#1}}
-\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{#1}}
-\newcommand{\RegionMarkerTok}[1]{#1}
-\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
-\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
-\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
-\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
-\newcommand{\NormalTok}[1]{#1}
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
-\setlength{\emergencystretch}{3em} % prevent overfull lines
-\providecommand{\tightlist}{%
- \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-\setcounter{secnumdepth}{0}
-% Redefines (sub)paragraphs to behave more like sections
-\ifx\paragraph\undefined\else
-\let\oldparagraph\paragraph
-\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
-\fi
-\ifx\subparagraph\undefined\else
-\let\oldsubparagraph\subparagraph
-\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
-\fi
-
-% set default figure placement to htbp
-\makeatletter
-\def\fps@figure{htbp}
-\makeatother
-
-
-\date{}
-
-\begin{document}
-
-\section{lhs test}\label{lhs-test}
-
-\texttt{unsplit} is an arrow that takes a pair of values and combines them to
-return a single value:
-
-\begin{Shaded}
-\begin{Highlighting}[]
-\OtherTok{unsplit ::}\NormalTok{ (}\DataTypeTok{Arrow}\NormalTok{ a) }\OtherTok{=>}\NormalTok{ (b }\OtherTok{->}\NormalTok{ c }\OtherTok{->}\NormalTok{ d) }\OtherTok{->}\NormalTok{ a (b, c) d}
-\NormalTok{unsplit }\FunctionTok{=}\NormalTok{ arr }\FunctionTok{.}\NormalTok{ uncurry}
- \CommentTok{-- arr (\textbackslash{}op (x,y) -> x `op` y)}
-\end{Highlighting}
-\end{Shaded}
-
-\texttt{(***)} combines two arrows into a new arrow by running the two arrows on a
-pair of values (one arrow on the first item of the pair and one arrow on the
-second item of the pair).
-
-\begin{verbatim}
-f *** g = first f >>> second g
-\end{verbatim}
-
-Block quote:
-
-\begin{quote}
-foo bar
-\end{quote}
-
-\end{document}
diff --git a/tests/lhs-test.latex+lhs b/tests/lhs-test.latex+lhs
deleted file mode 100644
index c781e79b3..000000000
--- a/tests/lhs-test.latex+lhs
+++ /dev/null
@@ -1,87 +0,0 @@
-\documentclass[]{article}
-\usepackage{lmodern}
-\usepackage{amssymb,amsmath}
-\usepackage{ifxetex,ifluatex}
-\usepackage{fixltx2e} % provides \textsubscript
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[T1]{fontenc}
- \usepackage[utf8]{inputenc}
-\else % if luatex or xelatex
- \ifxetex
- \usepackage{mathspec}
- \else
- \usepackage{fontspec}
- \fi
- \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
-\fi
-% use upquote if available, for straight quotes in verbatim environments
-\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
-% use microtype if available
-\IfFileExists{microtype.sty}{%
-\usepackage[]{microtype}
-\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
-}{}
-\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
-\usepackage[unicode=true]{hyperref}
-\hypersetup{
- pdfborder={0 0 0},
- breaklinks=true}
-\urlstyle{same} % don't use monospace font for urls
-\usepackage{listings}
-\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
-\setlength{\emergencystretch}{3em} % prevent overfull lines
-\providecommand{\tightlist}{%
- \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-\setcounter{secnumdepth}{0}
-% Redefines (sub)paragraphs to behave more like sections
-\ifx\paragraph\undefined\else
-\let\oldparagraph\paragraph
-\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
-\fi
-\ifx\subparagraph\undefined\else
-\let\oldsubparagraph\subparagraph
-\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
-\fi
-
-% set default figure placement to htbp
-\makeatletter
-\def\fps@figure{htbp}
-\makeatother
-
-
-\date{}
-
-\begin{document}
-
-\section{lhs test}\label{lhs-test}
-
-\texttt{unsplit} is an arrow that takes a pair of values and combines them to
-return a single value:
-
-\begin{code}
-unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d
-unsplit = arr . uncurry
- -- arr (\op (x,y) -> x `op` y)
-\end{code}
-
-\texttt{(***)} combines two arrows into a new arrow by running the two arrows on a
-pair of values (one arrow on the first item of the pair and one arrow on the
-second item of the pair).
-
-\begin{verbatim}
-f *** g = first f >>> second g
-\end{verbatim}
-
-Block quote:
-
-\begin{quote}
-foo bar
-\end{quote}
-
-\end{document}
diff --git a/tests/markdown-citations.native b/tests/markdown-citations.native
deleted file mode 100644
index d9738fb4f..000000000
--- a/tests/markdown-citations.native
+++ /dev/null
@@ -1,17 +0,0 @@
-[Header 1 ("pandoc-with-citeproc-hs",[],[]) [Str "Pandoc",Space,Str "with",Space,Str "citeproc-hs"]
-,BulletList
- [[Para [Cite [Citation {citationId = "nonexistent", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@nonexistent]"]]]
- ,[Para [Cite [Citation {citationId = "nonexistent", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@nonexistent"]]]
- ,[Para [Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@item1"],Space,Str "says",Space,Str "blah."]]
- ,[Para [Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [Str "p.",Space,Str "30"], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@item1",Space,Str "[p.",Space,Str "30]"],Space,Str "says",Space,Str "blah."]]
- ,[Para [Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [Str "p.",Space,Str "30,",Space,Str "with",Space,Str "suffix"], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@item1",Space,Str "[p.",Space,Str "30,",Space,Str "with",Space,Str "suffix]"],Space,Str "says",Space,Str "blah."]]
- ,[Para [Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0},Citation {citationId = "item2", citationPrefix = [], citationSuffix = [Space,Str "p.",Space,Str "30"], citationMode = SuppressAuthor, citationNoteNum = 0, citationHash = 0},Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [Str "see",Space,Str "also"], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "@item1",Space,Str "[-@item2",Space,Str "p.",Space,Str "30;",Space,Str "see",Space,Str "also",Space,Str "@\1087\1091\1085\1082\1090\&3]"],Space,Str "says",Space,Str "blah."]]
- ,[Para [Str "In",Space,Str "a",Space,Str "note.",Note [Para [Cite [Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [], citationSuffix = [Str "p.",Space,Str "12"], citationMode = AuthorInText, citationNoteNum = 0, citationHash = 0}] [Str "@\1087\1091\1085\1082\1090\&3",Space,Str "[p.",Space,Str "12]"],Space,Str "and",Space,Str "a",Space,Str "citation",Space,Str "without",Space,Str "locators",Space,Cite [Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@\1087\1091\1085\1082\1090\&3]"],Str "."]]]]
- ,[Para [Str "A",Space,Str "citation",Space,Str "group",Space,Cite [Citation {citationId = "item1", citationPrefix = [Str "see"], citationSuffix = [Space,Str "chap.",Space,Str "3"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [Str "also"], citationSuffix = [Space,Str "p.",Space,Str "34-35"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[see",Space,Str "@item1",Space,Str "chap.",Space,Str "3;",Space,Str "also",Space,Str "@\1087\1091\1085\1082\1090\&3",Space,Str "p.",Space,Str "34-35]"],Str "."]]
- ,[Para [Str "Another",Space,Str "one",Space,Cite [Citation {citationId = "item1", citationPrefix = [Str "see"], citationSuffix = [Space,Str "p.",Space,Str "34-35"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[see",Space,Str "@item1",Space,Str "p.",Space,Str "34-35]"],Str "."]]
- ,[Para [Str "And",Space,Str "another",Space,Str "one",Space,Str "in",Space,Str "a",Space,Str "note.",Note [Para [Str "Some",Space,Str "citations",Space,Cite [Citation {citationId = "item1", citationPrefix = [Str "see"], citationSuffix = [Space,Str "chap.",Space,Str "3"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "\1087\1091\1085\1082\1090\&3", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "item2", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[see",Space,Str "@item1",Space,Str "chap.",Space,Str "3;",Space,Str "@\1087\1091\1085\1082\1090\&3;",Space,Str "@item2]"],Str "."]]]]
- ,[Para [Str "Citation",Space,Str "with",Space,Str "a",Space,Str "suffix",Space,Str "and",Space,Str "locator",Space,Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [Space,Str "pp.",Space,Str "33,",Space,Str "35-37,",Space,Str "and",Space,Str "nowhere",Space,Str "else"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@item1",Space,Str "pp.",Space,Str "33,",Space,Str "35-37,",Space,Str "and",Space,Str "nowhere",Space,Str "else]"],Str "."]]
- ,[Para [Str "Citation",Space,Str "with",Space,Str "suffix",Space,Str "only",Space,Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [Space,Str "and",Space,Str "nowhere",Space,Str "else"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@item1",Space,Str "and",Space,Str "nowhere",Space,Str "else]"],Str "."]]
- ,[Para [Str "Now",Space,Str "some",Space,Str "modifiers.",Note [Para [Str "Like",Space,Str "a",Space,Str "citation",Space,Str "without",Space,Str "author:",Space,Cite [Citation {citationId = "item1", citationPrefix = [], citationSuffix = [], citationMode = SuppressAuthor, citationNoteNum = 0, citationHash = 0}] [Str "[-@item1]"],Str ",",Space,Str "and",Space,Str "now",Space,Str "Doe",Space,Str "with",Space,Str "a",Space,Str "locator",Space,Cite [Citation {citationId = "item2", citationPrefix = [], citationSuffix = [Space,Str "p.",Space,Str "44"], citationMode = SuppressAuthor, citationNoteNum = 0, citationHash = 0}] [Str "[-@item2",Space,Str "p.",Space,Str "44]"],Str "."]]]]
- ,[Para [Str "With",Space,Str "some",Space,Str "markup",Space,Cite [Citation {citationId = "item1", citationPrefix = [Emph [Str "see"]], citationSuffix = [Space,Str "p.",Space,Strong [Str "32"]], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[*see*",Space,Str "@item1",Space,Str "p.",Space,Str "**32**]"],Str "."]]]
-,Header 1 ("references",[],[]) [Str "References"]]
diff --git a/tests/markdown-reader-more.native b/tests/markdown-reader-more.native
deleted file mode 100644
index baafb5334..000000000
--- a/tests/markdown-reader-more.native
+++ /dev/null
@@ -1,198 +0,0 @@
-Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",Space,Str "One"],MetaInlines [Str "Author",Space,Str "Two"],MetaInlines [Str "Author",Space,Str "Three"],MetaInlines [Str "Author",Space,Str "Four"]]),("title",MetaInlines [Str "Title",SoftBreak,Str "spanning",Space,Str "multiple",Space,Str "lines"])]})
-[Header 1 ("additional-markdown-reader-tests",[],[]) [Str "Additional",Space,Str "markdown",Space,Str "reader",Space,Str "tests"]
-,Header 2 ("blank-line-before-url-in-link-reference",[],[]) [Str "Blank",Space,Str "line",Space,Str "before",Space,Str "URL",Space,Str "in",Space,Str "link",Space,Str "reference"]
-,Para [Link ("",[],[]) [Str "foo"] ("/url",""),Space,Str "and",Space,Link ("",[],[]) [Str "bar"] ("/url","title")]
-,Header 2 ("raw-context-environments",[],[]) [Str "Raw",Space,Str "ConTeXt",Space,Str "environments"]
-,Plain [RawInline (Format "tex") "\\placeformula "]
-,RawBlock (Format "context") "\\startformula\n L_{1} = L_{2}\n \\stopformula"
-,RawBlock (Format "context") "\\start[a2]\n\\start[a2]\n\\stop[a2]\n\\stop[a2]"
-,Header 2 ("raw-latex-environments",[],[]) [Str "Raw",Space,Str "LaTeX",Space,Str "environments"]
-,RawBlock (Format "latex") "\\begin{center}\n\\begin{tikzpicture}[baseline={([yshift=+-.5ex]current bounding box.center)}, level distance=24pt]\n\\Tree [.{S} [.NP John\\index{i} ] [.VP [.V likes ] [.NP himself\\index{i,*j} ]]]\n\\end{tikzpicture}\n\\end{center}"
-,Header 2 ("urls-with-spaces-and-punctuation",[],[]) [Str "URLs",Space,Str "with",Space,Str "spaces",Space,Str "and",Space,Str "punctuation"]
-,Para [Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("bar%20baz","title")]
-,Para [Link ("",[],[]) [Str "baz"] ("/foo%20foo",""),Space,Link ("",[],[]) [Str "bam"] ("/foo%20fee",""),Space,Link ("",[],[]) [Str "bork"] ("/foo/zee%20zob","title")]
-,Para [Link ("",[],[]) [Str "Ward\8217s",Space,Str "method."] ("http://en.wikipedia.org/wiki/Ward's_method","")]
-,Header 2 ("horizontal-rules-with-spaces-at-end",[],[]) [Str "Horizontal",Space,Str "rules",Space,Str "with",Space,Str "spaces",Space,Str "at",Space,Str "end"]
-,HorizontalRule
-,HorizontalRule
-,Header 2 ("raw-html-before-header",[],[]) [Str "Raw",Space,Str "HTML",Space,Str "before",Space,Str "header"]
-,Para [RawInline (Format "html") "<a>",RawInline (Format "html") "</a>"]
-,Header 3 ("my-header",[],[]) [Str "my",Space,Str "header"]
-,Header 2 ("in-math",[],[]) [Str "$",Space,Str "in",Space,Str "math"]
-,Para [Math InlineMath "\\$2 + \\$3"]
-,Para [Math InlineMath "x = \\text{the $n$th root of $y$}"]
-,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "math:"]
-,Para [Str "$PATH",Space,Str "90",Space,Str "$PATH"]
-,Header 2 ("commented-out-list-item",[],[]) [Str "Commented-out",Space,Str "list",Space,Str "item"]
-,BulletList
- [[Plain [Str "one",SoftBreak,RawInline (Format "html") "<!--\n- two\n-->"]]
- ,[Plain [Str "three"]]]
-,Header 2 ("indented-code-at-beginning-of-list",[],[]) [Str "Indented",Space,Str "code",Space,Str "at",Space,Str "beginning",Space,Str "of",Space,Str "list"]
-,BulletList
- [[CodeBlock ("",[],[]) "code\ncode"]]
-,OrderedList (1,Decimal,Period)
- [[CodeBlock ("",[],[]) "code\ncode"]
- ,[CodeBlock ("",[],[]) "code\ncode"]]
-,BulletList
- [[CodeBlock ("",[],[]) "code\ncode"]
- ,[Plain [Str "no",Space,Str "code"]]]
-,Header 2 ("backslash-newline",[],[]) [Str "Backslash",Space,Str "newline"]
-,Para [Str "hi",LineBreak,Str "there"]
-,Header 2 ("code-spans",[],[]) [Str "Code",Space,Str "spans"]
-,Para [Code ("",[],[]) "hi\\"]
-,Para [Code ("",[],[]) "hi there"]
-,Para [Code ("",[],[]) "hi````there"]
-,Para [Str "`hi"]
-,Para [Str "there`"]
-,Header 2 ("multilingual-urls",[],[]) [Str "Multilingual",Space,Str "URLs"]
-,Para [Link ("",[],[]) [Str "http://\27979.com?\27979=\27979"] ("http://\27979.com?\27979=\27979","")]
-,Para [Link ("",[],[]) [Str "foo"] ("/bar/\27979?x=\27979","title")]
-,Para [Link ("",[],[]) [Str "\27979@foo.\27979.baz"] ("mailto:\27979@foo.\27979.baz","")]
-,Header 2 ("numbered-examples",[],[]) [Str "Numbered",Space,Str "examples"]
-,OrderedList (1,Example,TwoParens)
- [[Plain [Str "First",Space,Str "example."]]
- ,[Plain [Str "Second",Space,Str "example."]]]
-,Para [Str "Explanation",Space,Str "of",Space,Str "examples",Space,Str "(2)",Space,Str "and",Space,Str "(3)."]
-,OrderedList (3,Example,TwoParens)
- [[Plain [Str "Third",Space,Str "example."]]]
-,Header 2 ("macros",[],[]) [Str "Macros"]
-,Para [Math InlineMath "{\\langle x,y \\rangle}"]
-,Header 2 ("case-insensitive-references",[],[]) [Str "Case-insensitive",Space,Str "references"]
-,Para [Link ("",[],[]) [Str "Fum"] ("/fum","")]
-,Para [Link ("",[],[]) [Str "FUM"] ("/fum","")]
-,Para [Link ("",[],[]) [Str "bat"] ("/bat","")]
-,Header 2 ("curly-smart-quotes",[],[]) [Str "Curly",Space,Str "smart",Space,Str "quotes"]
-,Para [Quoted DoubleQuote [Str "Hi"]]
-,Para [Quoted SingleQuote [Str "Hi"]]
-,Header 2 ("consecutive-lists",[],[]) [Str "Consecutive",Space,Str "lists"]
-,BulletList
- [[Plain [Str "one"]]
- ,[Plain [Str "two"]]]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "one"]]
- ,[Plain [Str "two"]]]
-,OrderedList (1,LowerAlpha,Period)
- [[Plain [Str "one"]]
- ,[Plain [Str "two"]]]
-,Header 2 ("implicit-header-references",[],[]) [Str "Implicit",Space,Str "header",Space,Str "references"]
-,Header 3 ("my-header-1",[],[]) [Str "My",Space,Str "header"]
-,Header 3 ("my-other-header",[],[]) [Str "My",Space,Str "other",Space,Str "header"]
-,Para [Str "A",Space,Str "link",Space,Str "to",Space,Link ("",[],[]) [Str "My",Space,Str "header"] ("#my-header-1",""),Str "."]
-,Para [Str "Another",Space,Str "link",Space,Str "to",Space,Link ("",[],[]) [Str "it"] ("#my-header-1",""),Str "."]
-,Para [Str "Should",Space,Str "be",Space,Link ("",[],[]) [Str "case",Space,Str "insensitive"] ("#my-header-1",""),Str "."]
-,Para [Str "Link",Space,Str "to",Space,Link ("",[],[]) [Str "Explicit",Space,Str "header",Space,Str "attributes"] ("#foobar",""),Str "."]
-,Para [Str "But",Space,Str "this",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "link",Space,Str "to",Space,Link ("",[],[]) [Str "My",Space,Str "other",Space,Str "header"] ("/foo",""),Str ",",Space,Str "since",Space,Str "the",Space,Str "reference",Space,Str "is",Space,Str "defined."]
-,Header 2 ("foobar",["baz"],[("key","val")]) [Str "Explicit",Space,Str "header",Space,Str "attributes"]
-,BlockQuote
- [Header 2 ("foobar",["baz"],[("key","val")]) [Str "Header",Space,Str "attributes",Space,Str "inside",Space,Str "block",Space,Str "quote"]]
-,Header 2 ("line-blocks",[],[]) [Str "Line",Space,Str "blocks"]
-,LineBlock
- [[Str "But",Space,Str "can",Space,Str "a",Space,Str "bee",Space,Str "be",Space,Str "said",Space,Str "to",Space,Str "be"]
- ,[Str "\160\160\160\160or",Space,Str "not",Space,Str "to",Space,Str "be",Space,Str "an",Space,Str "entire",Space,Str "bee,"]
- ,[Str "\160\160\160\160\160\160\160\160when",Space,Str "half",Space,Str "the",Space,Str "bee",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "bee,"]
- ,[Str "\160\160\160\160\160\160\160\160\160\160\160\160due",Space,Str "to",Space,Str "some",Space,Str "ancient",Space,Str "injury?"]
- ,[]
- ,[Str "Continuation",Space,Str "line"]
- ,[Str "\160\160and",Space,Str "another"]]
-,Header 2 ("grid-tables",[],[]) [Str "Grid",Space,Str "Tables"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
- [[Plain [Str "col",Space,Str "1"]]
- ,[Plain [Str "col",Space,Str "2"]]
- ,[Plain [Str "col",Space,Str "3"]]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
-,Para [Str "Headless"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
- [[]
- ,[]
- ,[]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
-,Para [Str "With",Space,Str "alignments"]
-,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
- [[Plain [Str "col",Space,Str "1"]]
- ,[Plain [Str "col",Space,Str "2"]]
- ,[Plain [Str "col",Space,Str "3"]]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
-,Para [Str "Headless",Space,Str "with",Space,Str "alignments"]
-,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
- [[]
- ,[]
- ,[]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
-,Para [Str "Spaces",Space,Str "at",Space,Str "ends",Space,Str "of",Space,Str "lines"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
- [[]
- ,[]
- ,[]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
-,Para [Str "Multiple",Space,Str "blocks",Space,Str "in",Space,Str "a",Space,Str "cell"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
- [[]
- ,[]
- ,[]]
- [[[Header 1 ("col-1",[],[]) [Str "col",Space,Str "1"]
- ,Para [Str "col",Space,Str "1"]]
- ,[Header 1 ("col-2",[],[]) [Str "col",Space,Str "2"]
- ,Para [Str "col",Space,Str "2"]]
- ,[Header 1 ("col-3",[],[]) [Str "col",Space,Str "3"]
- ,Para [Str "col",Space,Str "3"]]]
- ,[[Para [Str "r1",Space,Str "a"]
- ,Para [Str "r1",Space,Str "bis"]]
- ,[BulletList
- [[Plain [Str "b"]]
- ,[Plain [Str "b",Space,Str "2"]]
- ,[Plain [Str "b",Space,Str "2"]]]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]]
-,Para [Str "Empty",Space,Str "cells"]
-,Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2]
- [[]
- ,[]]
- [[[]
- ,[]]]
-,Header 2 ("entities-in-links-and-titles",[],[]) [Str "Entities",Space,Str "in",Space,Str "links",Space,Str "and",Space,Str "titles"]
-,Para [Link ("",[],[]) [Str "link"] ("/\252rl","\246\246!")]
-,Para [Link ("",[],[]) [Str "http://g\246\246gle.com"] ("http://g\246\246gle.com","")]
-,Para [Link ("",[],[]) [Str "me@ex\228mple.com"] ("mailto:me@ex\228mple.com","")]
-,Para [Link ("",[],[]) [Str "foobar"] ("/\252rl","\246\246!")]
-,Header 2 ("parentheses-in-urls",[],[]) [Str "Parentheses",Space,Str "in",Space,Str "URLs"]
-,Para [Link ("",[],[]) [Str "link"] ("/hi(there)","")]
-,Para [Link ("",[],[]) [Str "link"] ("/hithere)","")]
-,Para [Link ("",[],[]) [Str "linky"] ("hi_(there_(nested))","")]
-,Header 2 ("backslashes-in-link-references",[],[]) [Str "Backslashes",Space,Str "in",Space,Str "link",Space,Str "references"]
-,Para [Link ("",[],[]) [Str "*",RawInline (Format "tex") "\\a"] ("b","")]
-,Header 2 ("reference-link-fallbacks",[],[]) [Str "Reference",Space,Str "link",Space,Str "fallbacks"]
-,Para [Str "[",Emph [Str "not",Space,Str "a",Space,Str "link"],Str "]",Space,Str "[",Emph [Str "nope"],Str "]\8230"]
-,Header 2 ("reference-link-followed-by-a-citation",[],[]) [Str "Reference",Space,Str "link",Space,Str "followed",Space,Str "by",Space,Str "a",Space,Str "citation"]
-,Para [Str "MapReduce",Space,Str "is",Space,Str "a",Space,Str "paradigm",Space,Str "popularized",Space,Str "by",Space,Link ("",[],[]) [Str "Google"] ("http://google.com",""),Space,Cite [Citation {citationId = "mapreduce", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@mapreduce]"],Space,Str "as",Space,Str "its",SoftBreak,Str "most",Space,Str "vocal",Space,Str "proponent."]
-,Header 2 ("empty-reference-links",[],[]) [Str "Empty",Space,Str "reference",Space,Str "links"]
-,Para [Str "bar"]
-,Para [Link ("",[],[]) [Str "foo2"] ("","")]
-,Header 2 ("wrapping-shouldnt-introduce-new-list-items",[],[]) [Str "Wrapping",Space,Str "shouldn\8217t",Space,Str "introduce",Space,Str "new",Space,Str "list",Space,Str "items"]
-,BulletList
- [[Plain [Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "2015."]]]
-,Header 2 ("bracketed-spans",[],[]) [Str "Bracketed",Space,Str "spans"]
-,Para [Span ("id",["class"],[("key","val")]) [Emph [Str "foo"],Space,Str "bar",Space,Str "baz",Space,Link ("",[],[]) [Str "link"] ("url","")]]]
diff --git a/tests/markdown-reader-more.txt b/tests/markdown-reader-more.txt
deleted file mode 100644
index 73c9500a0..000000000
--- a/tests/markdown-reader-more.txt
+++ /dev/null
@@ -1,320 +0,0 @@
-% Title
- spanning multiple lines
-% Author One
- Author Two; Author Three;
- Author Four
-
-# Additional markdown reader tests
-
-## Blank line before URL in link reference
-
-[foo] and [bar]
-
-[foo]:
- /url
-
-[bar]:
-/url
-"title"
-
-## Raw ConTeXt environments
-
-\placeformula \startformula
- L_{1} = L_{2}
- \stopformula
-
-\start[a2]
-\start[a2]
-\stop[a2]
-\stop[a2]
-
-## Raw LaTeX environments
-
-\begin{center}
-\begin{tikzpicture}[baseline={([yshift=+-.5ex]current bounding box.center)}, level distance=24pt]
-\Tree [.{S} [.NP John\index{i} ] [.VP [.V likes ] [.NP himself\index{i,*j} ]]]
-\end{tikzpicture}
-\end{center}
-
-## URLs with spaces and punctuation
-
-[foo](/bar and baz)
-[foo](/bar
- and baz )
-[foo]( /bar and baz )
-[foo](bar baz "title" )
-
-[baz][] [bam][] [bork][]
-
-[baz]: /foo foo
-[bam]: /foo fee
-[bork]: /foo/zee zob (title)
-
-[Ward's method.](http://en.wikipedia.org/wiki/Ward's_method)
-
-## Horizontal rules with spaces at end
-
-* * * * *
-
--- - -- -- -
-
-## Raw HTML before header
-
-<a></a>
-
-### my header
-
-## $ in math
-
-$\$2 + \$3$
-
-$x = \text{the $n$th root of $y$}$
-
-This should not be math:
-
-$PATH 90 $PATH
-
-## Commented-out list item
-
-- one
-<!--
-- two
--->
-- three
-
-## Indented code at beginning of list
-
-- code
- code
-
- 1. code
- code
-
- 12345678. code
- code
-
- - code
- code
-
- - no code
-
-## Backslash newline
-
-hi\
-there
-
-## Code spans
-
-`hi\`
-
-`hi
-there`
-
-`` hi````there ``
-
-`hi
-
-there`
-
-## Multilingual URLs
-
-<http://测.com?测=测>
-
-[foo](/bar/测?x=测 "title")
-
-<测@foo.测.baz>
-
-## Numbered examples
-
-(@) First example.
-(@foo) Second example.
-
-Explanation of examples (@foo) and (@bar).
-
-(@bar) Third example.
-
-## Macros
-
-\newcommand{\tuple}[1]{\langle #1 \rangle}
-
-$\tuple{x,y}$
-
-## Case-insensitive references
-
-[Fum]
-
-[FUM]
-
-[bat]
-
-[fum]: /fum
-[BAT]: /bat
-
-## Curly smart quotes
-
-“Hi”
-
-‘Hi’
-
-## Consecutive lists
-
-- one
-- two
-1. one
-2. two
-
- a. one
- b. two
-
-## Implicit header references
-
-### My header
-
-### My other header
-
-A link to [My header].
-
-Another link to [it][My header].
-
-Should be [case insensitive][my header].
-
-Link to [Explicit header attributes].
-
-[my other header]: /foo
-
-But this is not a link to [My other header], since the reference is defined.
-
-## Explicit header attributes {#foobar .baz key="val"}
-
-> ## Header attributes inside block quote {#foobar .baz key="val"}
-
-## Line blocks
-
-| But can a bee be said to be
-| or not to be an entire bee,
-| when half the bee is not a bee,
-| due to some ancient injury?
-|
-| Continuation
- line
-| and
- another
-
-## Grid Tables
-
-+------------------+-----------+------------+
-| col 1 | col 2 | col 3 |
-+==================+===========+============+
-| r1 a | b | c |
-| r1 bis | b 2 | c 2 |
-+------------------+-----------+------------+
-| r2 d | e | f |
-+------------------+-----------+------------+
-
-Headless
-
-+------------------+-----------+------------+
-| r1 a | b | c |
-| r1 bis | b 2 | c 2 |
-+------------------+-----------+------------+
-| r2 d | e | f |
-+------------------+-----------+------------+
-
-With alignments
-
-+------------------+-----------+------------+
-| col 1 | col 2 | col 3 |
-+=================:+:==========+:==========:+
-| r1 a | b | c |
-| r1 bis | b 2 | c 2 |
-+------------------+-----------+------------+
-| r2 d | e | f |
-+------------------+-----------+------------+
-
-Headless with alignments
-
-+-----------------:+:----------+:----------:+
-| r1 a | b | c |
-| r1 bis | b 2 | c 2 |
-+------------------+-----------+------------+
-| r2 d | e | f |
-+------------------+-----------+------------+
-
-Spaces at ends of lines
-
-+------------------+-----------+------------+
-| r1 a | b | c |
-| r1 bis | b 2 | c 2 |
-+------------------+-----------+------------+
-| r2 d | e | f |
-+------------------+-----------+------------+
-
-Multiple blocks in a cell
-
-+------------------+-----------+------------+
-| # col 1 | # col 2 | # col 3 |
-| col 1 | col 2 | col 3 |
-+------------------+-----------+------------+
-| r1 a | - b | c |
-| | - b 2 | c 2 |
-| r1 bis | - b 2 | c 2 |
-+------------------+-----------+------------+
-
-Empty cells
-
-+---+---+
-| | |
-+---+---+
-
-## Entities in links and titles
-
-[link](/&uuml;rl "&ouml;&ouml;!")
-
-<http://g&ouml;&ouml;gle.com>
-
-<me@ex&auml;mple.com>
-
-[foobar]
-
-[foobar]: /&uuml;rl "&ouml;&ouml;!"
-
-## Parentheses in URLs
-
-[link](/hi(there))
-
-[link](/hithere\))
-
-[linky]
-
-[linky]: hi_(there_(nested))
-
-## Backslashes in link references
-
-[\*\a](b)
-
-## Reference link fallbacks
-
-[*not a link*] [*nope*]...
-
-## Reference link followed by a citation
-
-MapReduce is a paradigm popularized by [Google] [@mapreduce] as its
-most vocal proponent.
-
-[Google]: http://google.com
-
-## Empty reference links
-
-[foo2]:
-
-bar
-
-[foo2]
-
-## Wrapping shouldn't introduce new list items
-
-- blah blah blah blah blah blah blah blah blah blah blah blah blah blah 2015.
-
-## Bracketed spans
-
-[*foo* bar baz [link](url)]{.class #id key=val}
diff --git a/tests/pipe-tables.native b/tests/pipe-tables.native
deleted file mode 100644
index 63c2c17bc..000000000
--- a/tests/pipe-tables.native
+++ /dev/null
@@ -1,115 +0,0 @@
-[Para [Str "Simplest",Space,Str "table",Space,Str "without",Space,Str "caption:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "Default1"]]
- ,[Plain [Str "Default2"]]
- ,[Plain [Str "Default3"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"]
-,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignRight,AlignLeft,AlignDefault,AlignCenter] [0.0,0.0,0.0,0.0]
- [[Plain [Str "Right"]]
- ,[Plain [Str "Left"]]
- ,[Plain [Str "Default"]]
- ,[Plain [Str "Center"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Simple",Space,Str "table",Space,Str "without",Space,Str "caption:"]
-,Table [] [AlignRight,AlignLeft,AlignCenter] [0.0,0.0,0.0]
- [[Plain [Str "Right"]]
- ,[Plain [Str "Left"]]
- ,[Plain [Str "Center"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Headerless",Space,Str "table",Space,Str "without",Space,Str "caption:"]
-,Table [] [AlignRight,AlignLeft,AlignCenter] [0.0,0.0,0.0]
- [[]
- ,[]
- ,[]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Table",Space,Str "without",Space,Str "sides:"]
-,Table [] [AlignDefault,AlignRight] [0.0,0.0]
- [[Plain [Str "Fruit"]]
- ,[Plain [Str "Quantity"]]]
- [[[Plain [Str "apple"]]
- ,[Plain [Str "5"]]]
- ,[[Plain [Str "orange"]]
- ,[Plain [Str "17"]]]
- ,[[Plain [Str "pear"]]
- ,[Plain [Str "302"]]]]
-,Para [Str "One-column:"]
-,Table [] [AlignDefault] [0.0]
- [[Plain [Str "hi"]]]
- [[[Plain [Str "lo"]]]]
-,Para [Str "Header-less",Space,Str "one-column:"]
-,Table [] [AlignCenter] [0.0]
- [[]]
- [[[Plain [Str "hi"]]]]
-,Para [Str "Indented",Space,Str "left",Space,Str "column:"]
-,Table [] [AlignRight,AlignLeft] [0.0,0.0]
- [[Plain [Str "Number",Space,Str "of",Space,Str "siblings"]]
- ,[Plain [Str "Salary"]]]
- [[[Plain [Str "3"]]
- ,[Plain [Str "33"]]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "44"]]]]
-,Para [Str "Long",Space,Str "pipe",Space,Str "table",Space,Str "with",Space,Str "relative",Space,Str "widths:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.125,0.1375,0.5]
- [[Plain [Str "Default1"]]
- ,[Plain [Str "Default2"]]
- ,[Plain [Str "Default3"]]]
- [[[Plain [Str "123"]]
- ,[Plain [Str "this",Space,Str "is",Space,Str "a",Space,Str "table",Space,Str "cell"]]
- ,[Plain [Str "and",Space,Str "this",Space,Str "is",Space,Str "a",Space,Str "really",Space,Str "long",Space,Str "table",Space,Str "cell",Space,Str "that",Space,Str "will",Space,Str "probably",Space,Str "need",Space,Str "wrapping"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]]
-,Para [Str "Pipe",Space,Str "table",Space,Str "with",Space,Str "no",Space,Str "body:"]
-,Table [] [AlignDefault] [0.0]
- [[Plain [Str "Header"]]]
- []
-,Para [Str "Pipe",Space,Str "table",Space,Str "with",Space,Str "tricky",Space,Str "cell",Space,Str "contents",Space,Str "(see",Space,Str "#2765):"]
-,Table [] [AlignLeft,AlignRight,AlignRight] [0.0,0.0,0.0]
- [[]
- ,[Plain [Str "IP_gene8-_1st"]]
- ,[Plain [Str "IP_gene8+_1st"]]]
- [[[Plain [Str "IP_gene8-_1st"]]
- ,[Plain [Str "1.0000000"]]
- ,[Plain [Str "0.4357325"]]]
- ,[[Plain [Str "IP_gene8+_1st"]]
- ,[Plain [Str "0.4357325"]]
- ,[Plain [Str "1.0000000"]]]
- ,[[Plain [Str "foo",Code ("",[],[]) "bar|baz"]]
- ,[Plain [Str "and|escaped"]]
- ,[Plain [Str "3.0000000"]]]]]
diff --git a/tests/rst-reader.native b/tests/rst-reader.native
deleted file mode 100644
index 768a05c24..000000000
--- a/tests/rst-reader.native
+++ /dev/null
@@ -1,341 +0,0 @@
-Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("revision",MetaBlocks [Para [Str "3"]]),("subtitle",MetaInlines [Str "Subtitle"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
-[Header 1 ("level-one-header",[],[]) [Str "Level",Space,Str "one",Space,Str "header"]
-,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",SoftBreak,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
-,Header 2 ("level-two-header",[],[]) [Str "Level",Space,Str "two",Space,Str "header"]
-,Header 3 ("level-three",[],[]) [Str "Level",Space,Str "three"]
-,Header 4 ("level-four-with-emphasis",[],[]) [Str "Level",Space,Str "four",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 5 ("level-five",[],[]) [Str "Level",Space,Str "five"]
-,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
-,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",SoftBreak,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",SoftBreak,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",SoftBreak,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",SoftBreak,Str "list",Space,Str "item."]
-,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",SoftBreak,Str "*",Space,Str "criminey."]
-,Para [Str "Horizontal",Space,Str "rule:"]
-,HorizontalRule
-,Para [Str "Another:"]
-,HorizontalRule
-,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "block",Space,Str "quote:"]
-,BlockQuote
- [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",SoftBreak,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
-,Para [Str "Here\8217s",Space,Str "another,",Space,Str "differently",Space,Str "indented:"]
-,BlockQuote
- [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",SoftBreak,Str "It\8217s",Space,Str "indented",Space,Str "with",Space,Str "a",Space,Str "tab."]
- ,Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
- ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
- ,Para [Str "List",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
- ,OrderedList (1,Decimal,Period)
- [[Plain [Str "item",Space,Str "one"]]
- ,[Plain [Str "item",Space,Str "two"]]]
- ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
- ,BlockQuote
- [Para [Str "nested"]
- ,BlockQuote
- [Para [Str "nested"]]]]
-,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}"
-,CodeBlock ("",[],[]) "this code block is indented by one tab"
-,Para [Str "And:"]
-,CodeBlock ("",[],[]) "this block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
-,Para [Str "And:"]
-,CodeBlock ("",["sourceCode","python"],[]) "def my_function(x):\n return x + 1"
-,Header 1 ("lists",[],[]) [Str "Lists"]
-,Header 2 ("unordered",[],[]) [Str "Unordered"]
-,Para [Str "Asterisks",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "asterisk",Space,Str "1"]]
- ,[Plain [Str "asterisk",Space,Str "2"]]
- ,[Plain [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Asterisks",Space,Str "loose:"]
-,BulletList
- [[Plain [Str "asterisk",Space,Str "1"]]
- ,[Plain [Str "asterisk",Space,Str "2"]]
- ,[Plain [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "Plus",Space,Str "1"]]
- ,[Plain [Str "Plus",Space,Str "2"]]
- ,[Plain [Str "Plus",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "loose:"]
-,BulletList
- [[Plain [Str "Plus",Space,Str "1"]]
- ,[Plain [Str "Plus",Space,Str "2"]]
- ,[Plain [Str "Plus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "Minus",Space,Str "1"]]
- ,[Plain [Str "Minus",Space,Str "2"]]
- ,[Plain [Str "Minus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "loose:"]
-,BulletList
- [[Plain [Str "Minus",Space,Str "1"]]
- ,[Plain [Str "Minus",Space,Str "2"]]
- ,[Plain [Str "Minus",Space,Str "3"]]]
-,Header 2 ("ordered",[],[]) [Str "Ordered"]
-,Para [Str "Tight:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second"]]
- ,[Plain [Str "Third"]]]
-,Para [Str "and:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "One"]]
- ,[Plain [Str "Two"]]
- ,[Plain [Str "Three"]]]
-,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second"]]
- ,[Plain [Str "Third"]]]
-,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "One"]]
- ,[Plain [Str "Two"]]
- ,[Plain [Str "Three"]]]
-,Para [Str "Multiple",Space,Str "paragraphs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
- ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",SoftBreak,Str "back."]]
- ,[Plain [Str "Item",Space,Str "2."]]
- ,[Plain [Str "Item",Space,Str "3."]]]
-,Para [Str "Nested:"]
-,BulletList
- [[Plain [Str "Tab"]
- ,BulletList
- [[Plain [Str "Tab"]
- ,BulletList
- [[Plain [Str "Tab"]]]]]]]
-,Para [Str "Here\8217s",Space,Str "another:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "First"]]
- ,[Para [Str "Second:"]
- ,BlockQuote
- [BulletList
- [[Plain [Str "Fee"]]
- ,[Plain [Str "Fie"]]
- ,[Plain [Str "Foe"]]]]]
- ,[Plain [Str "Third"]]]
-,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
-,OrderedList (2,Decimal,TwoParens)
- [[Plain [Str "begins",Space,Str "with",Space,Str "2"]]
- ,[Para [Str "and",Space,Str "now",Space,Str "3"]
- ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
- ,OrderedList (4,LowerRoman,Period)
- [[Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",Space,Str "starting",Space,Str "with",Space,Str "4"]]
- ,[Plain [Str "more",Space,Str "items"]
- ,OrderedList (1,UpperAlpha,TwoParens)
- [[Plain [Str "a",Space,Str "subsublist"]]
- ,[Plain [Str "a",Space,Str "subsublist"]]]]]]]
-,Para [Str "Nesting:"]
-,OrderedList (1,UpperAlpha,Period)
- [[Plain [Str "Upper",Space,Str "Alpha"]
- ,OrderedList (1,UpperRoman,Period)
- [[Plain [Str "Upper",Space,Str "Roman."]
- ,OrderedList (6,Decimal,TwoParens)
- [[Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
- ,OrderedList (3,LowerAlpha,OneParen)
- [[Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
-,Para [Str "Autonumbering:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "Autonumber."]]
- ,[Plain [Str "More."]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "Nested."]]]]]
-,Para [Str "Autonumbering",Space,Str "with",Space,Str "explicit",Space,Str "start:"]
-,OrderedList (4,LowerAlpha,TwoParens)
- [[Plain [Str "item",Space,Str "1"]]
- ,[Plain [Str "item",Space,Str "2"]]]
-,Header 2 ("definition",[],[]) [Str "Definition"]
-,DefinitionList
- [([Str "term",Space,Str "1"],
- [[Para [Str "Definition",Space,Str "1."]]])
- ,([Str "term",Space,Str "2"],
- [[Para [Str "Definition",Space,Str "2,",Space,Str "paragraph",Space,Str "1."]
- ,Para [Str "Definition",Space,Str "2,",Space,Str "paragraph",Space,Str "2."]]])
- ,([Str "term",Space,Str "with",Space,Emph [Str "emphasis"]],
- [[Para [Str "Definition",Space,Str "3."]]])]
-,Header 1 ("field-lists",[],[]) [Str "Field",Space,Str "Lists"]
-,BlockQuote
- [DefinitionList
- [([Str "address"],
- [[Para [Str "61",Space,Str "Main",Space,Str "St."]]])
- ,([Str "city"],
- [[Para [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",SoftBreak,Str "USA"]]])
- ,([Str "phone"],
- [[Para [Str "123-4567"]]])]]
-,DefinitionList
- [([Str "address"],
- [[Para [Str "61",Space,Str "Main",Space,Str "St."]]])
- ,([Str "city"],
- [[Para [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",SoftBreak,Str "USA"]]])
- ,([Str "phone"],
- [[Para [Str "123-4567"]]])]
-,Header 1 ("html-blocks",[],[]) [Str "HTML",Space,Str "Blocks"]
-,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
-,RawBlock (Format "html") "<div>foo</div>"
-,Para [Str "Now,",Space,Str "nested:"]
-,RawBlock (Format "html") "<div>\n <div>\n <div>\n foo\n </div>\n </div>\n</div>"
-,Header 1 ("latex-block",[],[]) [Str "LaTeX",Space,Str "Block"]
-,RawBlock (Format "latex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"
-,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
-,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ".",Space,Str "This",Space,Str "is",Space,Strong [Str "strong"],Str "."]
-,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
-,Para [Str "This",Space,Str "is",Subscript [Str "subscripted"],Space,Str "and",Space,Str "this",Space,Str "is",Space,Superscript [Str "superscripted"],Str "."]
-,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
-,BulletList
- [[Plain [Str "I",Space,Str "hat:",Space,Str "\206"]]
- ,[Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
- ,[Plain [Str "section:",Space,Str "\167"]]
- ,[Plain [Str "set",Space,Str "membership:",Space,Str "\8712"]]
- ,[Plain [Str "copyright:",Space,Str "\169"]]]
-,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
-,Para [Str "This",Space,Str "&",Space,Str "that."]
-,Para [Str "4",Space,Str "<",Space,Str "5."]
-,Para [Str "6",Space,Str ">",Space,Str "5."]
-,Para [Str "Backslash:",Space,Str "\\"]
-,Para [Str "Backtick:",Space,Str "`"]
-,Para [Str "Asterisk:",Space,Str "*"]
-,Para [Str "Underscore:",Space,Str "_"]
-,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
-,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
-,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
-,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
-,Para [Str "Left",Space,Str "paren:",Space,Str "("]
-,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
-,Para [Str "Greater-than:",Space,Str ">"]
-,Para [Str "Hash:",Space,Str "#"]
-,Para [Str "Period:",Space,Str "."]
-,Para [Str "Bang:",Space,Str "!"]
-,Para [Str "Plus:",Space,Str "+"]
-,Para [Str "Minus:",Space,Str "-"]
-,Header 1 ("links",[],[]) [Str "Links"]
-,Para [Str "Explicit:",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
-,Para [Str "Explicit",Space,Str "with",Space,Str "no",Space,Str "label:",Space,Link ("",[],[]) [Str "foo"] ("foo",""),Str "."]
-,Para [Str "Two",Space,Str "anonymous",Space,Str "links:",Space,Link ("",[],[]) [Str "the",Space,Str "first"] ("/url1/",""),Space,Str "and",Space,Link ("",[],[]) [Str "the",Space,Str "second"] ("/url2/","")]
-,Para [Str "Reference",Space,Str "links:",Space,Link ("",[],[]) [Str "link1"] ("/url1/",""),Space,Str "and",Space,Link ("",[],[]) [Str "link2"] ("/url2/",""),Space,Str "and",Space,Link ("",[],[]) [Str "link1"] ("/url1/",""),Space,Str "again."]
-,Para [Str "Another",Space,Link ("",[],[]) [Str "style",Space,Str "of",Space,Str "reference",Space,Str "link"] ("/url1/",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "a",Space,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link ("",[],[]) [Str "AT&T"] ("/url/",""),Str "."]
-,Para [Str "Autolinks:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2",""),Space,Str "and",Space,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net",""),Str "."]
-,Para [Str "But",Space,Str "not",Space,Str "here:"]
-,CodeBlock ("",[],[]) "http://example.com/"
-,Header 1 ("images",[],[]) [Str "Images"]
-,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
-,Para [Image ("",[],[]) [Str "image"] ("lalune.jpg","")]
-,Para [Image ("",[],[("height","2343")]) [Str "Voyage dans la Lune"] ("lalune.jpg","")]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
-,Para [Str "And",Space,Str "an",Space,Link ("",[],[]) [Image ("",[],[]) [Str "A movie"] ("movie.jpg","")] ("/url",""),Str "."]
-,Header 1 ("comments",[],[]) [Str "Comments"]
-,Para [Str "First",Space,Str "paragraph"]
-,Para [Str "Another",Space,Str "paragraph"]
-,Para [Str "A",Space,Str "third",Space,Str "paragraph"]
-,Header 1 ("line-blocks",[],[]) [Str "Line",Space,Str "blocks"]
-,LineBlock
- [[Str "But",Space,Str "can",Space,Str "a",Space,Str "bee",Space,Str "be",Space,Str "said",Space,Str "to",Space,Str "be"]
- ,[Str "\160\160\160\160or",Space,Str "not",Space,Str "to",Space,Str "be",Space,Str "an",Space,Str "entire",Space,Str "bee,"]
- ,[Str "\160\160\160\160\160\160\160\160when",Space,Str "half",Space,Str "the",Space,Str "bee",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "bee,"]
- ,[Str "\160\160\160\160\160\160\160\160\160\160\160\160due",Space,Str "to",Space,Str "some",Space,Str "ancient",Space,Str "injury?"]
- ,[]
- ,[Str "Continuation",Space,Str "line"]
- ,[Str "\160\160and",Space,Str "another"]]
-,Header 1 ("simple-tables",[],[]) [Str "Simple",Space,Str "Tables"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "col",Space,Str "1"]]
- ,[Plain [Str "col",Space,Str "2"]]
- ,[Plain [Str "col",Space,Str "3"]]]
- [[[Plain [Str "r1",Space,Str "a"]]
- ,[Plain [Str "b"]]
- ,[Plain [Str "c"]]]
- ,[[Plain [Str "r2",Space,Str "d"]]
- ,[Plain [Str "e"]]
- ,[Plain [Str "f"]]]]
-,Para [Str "Headless"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[]
- ,[]
- ,[]]
- [[[Plain [Str "r1",Space,Str "a"]]
- ,[Plain [Str "b"]]
- ,[Plain [Str "c"]]]
- ,[[Plain [Str "r2",Space,Str "d"]]
- ,[Plain [Str "e"]]
- ,[Plain [Str "f"]]]]
-,Header 1 ("grid-tables",[],[]) [Str "Grid",Space,Str "Tables"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2375,0.15,0.1625]
- [[Plain [Str "col",Space,Str "1"]]
- ,[Plain [Str "col",Space,Str "2"]]
- ,[Plain [Str "col",Space,Str "3"]]]
- [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Plain [Str "r2",Space,Str "d"]]
- ,[Plain [Str "e"]]
- ,[Plain [Str "f"]]]]
-,Para [Str "Headless"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2375,0.15,0.1625]
- [[]
- ,[]
- ,[]]
- [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Plain [Str "r2",Space,Str "d"]]
- ,[Plain [Str "e"]]
- ,[Plain [Str "f"]]]]
-,Para [Str "Spaces",Space,Str "at",Space,Str "ends",Space,Str "of",Space,Str "lines"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2375,0.15,0.1625]
- [[]
- ,[]
- ,[]]
- [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Plain [Str "r2",Space,Str "d"]]
- ,[Plain [Str "e"]]
- ,[Plain [Str "f"]]]]
-,Para [Str "Multiple",Space,Str "blocks",Space,Str "in",Space,Str "a",Space,Str "cell"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2375,0.15,0.1625]
- [[]
- ,[]
- ,[]]
- [[[Para [Str "r1",Space,Str "a"]
- ,Para [Str "r1",Space,Str "bis"]]
- ,[BulletList
- [[Plain [Str "b"]]
- ,[Plain [Str "b",Space,Str "2"]]
- ,[Plain [Str "b",Space,Str "2"]]]]
- ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]]
-,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
-,Para [Note [Para [Str "Note",Space,Str "with",Space,Str "one",Space,Str "line."]]]
-,Para [Note [Para [Str "Note",Space,Str "with",SoftBreak,Str "continuation",Space,Str "line."]]]
-,Para [Note [Para [Str "Note",Space,Str "with"],Para [Str "continuation",Space,Str "block."]]]
-,Para [Note [Para [Str "Note",Space,Str "with",SoftBreak,Str "continuation",Space,Str "line"],Para [Str "and",Space,Str "a",Space,Str "second",Space,Str "para."]]]
-,Para [Str "Not",Space,Str "in",Space,Str "note."]
-,Header 1 ("math",[],[]) [Str "Math"]
-,Para [Str "Some",Space,Str "inline",Space,Str "math",Space,Math InlineMath "E=mc^2",Str ".",Space,Str "Now",Space,Str "some",SoftBreak,Str "display",Space,Str "math:"]
-,Para [Math DisplayMath "E=mc^2"]
-,Para [Math DisplayMath "E = mc^2"]
-,Para [Math DisplayMath "E = mc^2",Math DisplayMath "\\alpha = \\beta"]
-,Para [Math DisplayMath "E &= mc^2\\\\\nF &= \\pi E",Math DisplayMath "F &= \\gamma \\alpha^2"]
-,Para [Str "All",Space,Str "done."]
-,Header 1 ("default-role",[],[]) [Str "Default-Role"]
-,Para [Str "Try",Space,Str "changing",Space,Str "the",Space,Str "default",Space,Str "role",Space,Str "to",Space,Str "a",Space,Str "few",Space,Str "different",Space,Str "things."]
-,Header 2 ("doesnt-break-title-parsing",[],[]) [Str "Doesn\8217t",Space,Str "Break",Space,Str "Title",Space,Str "Parsing"]
-,Para [Str "Inline",Space,Str "math:",Space,Math InlineMath "E=mc^2",Space,Str "or",Space,Math InlineMath "E=mc^2",Space,Str "or",Space,Math InlineMath "E=mc^2",Str ".",SoftBreak,Str "Other",Space,Str "roles:",Space,Superscript [Str "super"],Str ",",Space,Subscript [Str "sub"],Str "."]
-,Para [Math DisplayMath "\\alpha = beta",Math DisplayMath "E = mc^2"]
-,Para [Str "Some",Space,Superscript [Str "of"],Space,Str "these",Space,Superscript [Str "words"],Space,Str "are",Space,Str "in",Space,Superscript [Str "superscript"],Str "."]
-,Para [Str "Reset",Space,Str "default-role",Space,Str "to",Space,Str "the",Space,Str "default",Space,Str "default."]
-,Para [Str "And",Space,Str "now",Space,Str "some-invalid-string-3231231",Space,Str "is",Space,Str "nonsense."]
-,Null
-,Para [Str "And",Space,Str "now",Space,Str "with",Space,RawInline (Format "html") "<b>inline</b> <span id=\"test\">HTML</span>",Str "."]
-,Null
-,Para [Str "And",Space,Str "some",Space,Str "inline",Space,Str "haskell",Space,Code ("",["haskell","sourceCode"],[]) "fmap id [1,2..10]",Str "."]
-,Null
-,Null
-,Para [Str "Indirect",Space,Str "python",Space,Str "role",Space,Code ("",["py","python","indirect","sourceCode"],[]) "[x*x for x in [1,2,3,4,5]]",Str "."]
-,Null
-,Null
-,Para [Str "Different",Space,Str "indirect",Space,Str "C",Space,Code ("",["c","different-indirect","sourceCode"],[]) "int x = 15;",Str "."]
-,Header 2 ("literal-symbols",[],[]) [Str "Literal",Space,Str "symbols"]
-,Para [Str "2*2",Space,Str "=",Space,Str "4*1"]]
diff --git a/tests/s5-basic.html b/tests/s5-basic.html
deleted file mode 100644
index 6fb57e4aa..000000000
--- a/tests/s5-basic.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="Content-Style-Type" content="text/css" />
- <meta name="generator" content="pandoc" />
- <meta name="version" content="S5 1.1" />
- <meta name="author" content="Sam Smith" />
- <meta name="version" content="S5 1.1" />
- <meta name="author" content="Jen Jones" />
- <meta name="date" content="2006-07-15" />
- <title>My S5 Document</title>
- <style type="text/css">code{white-space: pre;}</style>
- <!-- configuration parameters -->
- <meta name="defaultView" content="slideshow" />
- <meta name="controlVis" content="hidden" />
- <!-- style sheet links -->
- <link rel="stylesheet" href="s5/default/slides.css" type="text/css" media="projection" id="slideProj" />
- <link rel="stylesheet" href="s5/default/outline.css" type="text/css" media="screen" id="outlineStyle" />
- <link rel="stylesheet" href="s5/default/print.css" type="text/css" media="print" id="slidePrint" />
- <link rel="stylesheet" href="s5/default/opera.css" type="text/css" media="projection" id="operaFix" />
- <!-- S5 JS -->
- <script src="s5/default/slides.js" type="text/javascript"></script>
-</head>
-<body>
-<div class="layout">
-<div id="controls"></div>
-<div id="currentSlide"></div>
-<div id="header"></div>
-<div id="footer">
- <h1>July 15, 2006</h1>
- <h2>My S5 Document</h2>
-</div>
-</div>
-<div class="presentation">
-<div class="titleslide slide">
- <h1 class="title">My S5 Document</h1>
- <h3 class="author">Sam Smith<br/>Jen Jones</h3>
- <h4 class="date">July 15, 2006</h4>
-</div>
-<div id="first-slide" class="slide section level1">
-<h1>First slide</h1>
-<ul>
-<li>first bullet</li>
-<li>second bullet</li>
-</ul>
-</div>
-<div id="math" class="slide section level1">
-<h1>Math</h1>
-<ul>
-<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
-</ul>
-</div>
-</div>
-</body>
-</html>
diff --git a/tests/s5-inserts.html b/tests/s5-inserts.html
deleted file mode 100644
index 2feed4173..000000000
--- a/tests/s5-inserts.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="Content-Style-Type" content="text/css" />
- <meta name="generator" content="pandoc" />
- <meta name="author" content="Sam Smith" />
- <meta name="author" content="Jen Jones" />
- <meta name="date" content="2006-07-15" />
- <title>My S5 Document</title>
- <style type="text/css">code{white-space: pre;}</style>
- <link rel="stylesheet" href="main.css" type="text/css" />
- STUFF INSERTED
-</head>
-<body>
-STUFF INSERTED
-<div id="header">
-<h1 class="title">My S5 Document</h1>
-<h2 class="author">Sam Smith</h2>
-<h2 class="author">Jen Jones</h2>
-<h3 class="date">July 15, 2006</h3>
-</div>
-<h1 id="first-slide">First slide</h1>
-<ul>
-<li>first bullet</li>
-<li>second bullet</li>
-</ul>
-<h1 id="math">Math</h1>
-<ul>
-<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
-</ul>
-STUFF INSERTED
-</body>
-</html>
diff --git a/tests/tables-rstsubset.native b/tests/tables-rstsubset.native
deleted file mode 100644
index c98a95541..000000000
--- a/tests/tables-rstsubset.native
+++ /dev/null
@@ -1,117 +0,0 @@
-[Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.125,0.1125,0.1375,0.15]
- [[Plain [Str "Right"]]
- ,[Plain [Str "Left"]]
- ,[Plain [Str "Center"]]
- ,[Plain [Str "Default"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Table:",Space,Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."]
-,Para [Str "Simple",Space,Str "table",Space,Str "without",Space,Str "caption:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.125,0.1125,0.1375,0.15]
- [[Plain [Str "Right"]]
- ,[Plain [Str "Left"]]
- ,[Plain [Str "Center"]]
- ,[Plain [Str "Default"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Simple",Space,Str "table",Space,Str "indented",Space,Str "two",Space,Str "spaces:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.125,0.1125,0.1375,0.15]
- [[Plain [Str "Right"]]
- ,[Plain [Str "Left"]]
- ,[Plain [Str "Center"]]
- ,[Plain [Str "Default"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Table:",Space,Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."]
-,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.175,0.1625,0.1875,0.3625]
- [[Plain [Str "Centered",Space,Str "Header"]]
- ,[Plain [Str "Left",Space,Str "Aligned"]]
- ,[Plain [Str "Right",Space,Str "Aligned"]]
- ,[Plain [Str "Default",Space,Str "aligned"]]]
- [[[Plain [Str "First"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "12.0"]]
- ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",SoftBreak,Str "spans",Space,Str "multiple",Space,Str "lines."]]]
- ,[[Plain [Str "Second"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "5.0"]]
- ,[Plain [Str "Here's",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]]
-,Para [Str "Table:",Space,Str "Here's",Space,Str "the",Space,Str "caption.",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."]
-,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.175,0.1625,0.1875,0.3625]
- [[Plain [Str "Centered",Space,Str "Header"]]
- ,[Plain [Str "Left",Space,Str "Aligned"]]
- ,[Plain [Str "Right",Space,Str "Aligned"]]
- ,[Plain [Str "Default",Space,Str "aligned"]]]
- [[[Plain [Str "First"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "12.0"]]
- ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",SoftBreak,Str "spans",Space,Str "multiple",Space,Str "lines."]]]
- ,[[Plain [Str "Second"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "5.0"]]
- ,[Plain [Str "Here's",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]]
-,Para [Str "Table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1,0.1,0.1,0.1]
- [[]
- ,[]
- ,[]
- ,[]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.175,0.1625,0.1875,0.3625]
- [[]
- ,[]
- ,[]
- ,[]]
- [[[Plain [Str "First"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "12.0"]]
- ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",SoftBreak,Str "spans",Space,Str "multiple",Space,Str "lines."]]]
- ,[[Plain [Str "Second"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "5.0"]]
- ,[Plain [Str "Here's",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]]]
diff --git a/tests/tables.asciidoc b/tests/tables.asciidoc
deleted file mode 100644
index 2a24544a3..000000000
--- a/tests/tables.asciidoc
+++ /dev/null
@@ -1,67 +0,0 @@
-Simple table with caption:
-
-.Demonstration of simple table syntax.
-[cols=">,<,^,",options="header",]
-|============================
-|Right |Left |Center |Default
-|12 |12 |12 |12
-|123 |123 |123 |123
-|1 |1 |1 |1
-|============================
-
-Simple table without caption:
-
-[cols=">,<,^,",options="header",]
-|============================
-|Right |Left |Center |Default
-|12 |12 |12 |12
-|123 |123 |123 |123
-|1 |1 |1 |1
-|============================
-
-Simple table indented two spaces:
-
-.Demonstration of simple table syntax.
-[cols=">,<,^,",options="header",]
-|============================
-|Right |Left |Center |Default
-|12 |12 |12 |12
-|123 |123 |123 |123
-|1 |1 |1 |1
-|============================
-
-Multiline table with caption:
-
-.Here's the caption. It may span multiple lines.
-[width="78%",cols="^21%,<17%,>20%,<42%",options="header",]
-|=======================================================================
-|Centered Header |Left Aligned |Right Aligned |Default aligned
-|First |row |12.0 |Example of a row that spans multiple lines.
-|Second |row |5.0 |Here's another one. Note the blank line between rows.
-|=======================================================================
-
-Multiline table without caption:
-
-[width="78%",cols="^21%,<17%,>20%,<42%",options="header",]
-|=======================================================================
-|Centered Header |Left Aligned |Right Aligned |Default aligned
-|First |row |12.0 |Example of a row that spans multiple lines.
-|Second |row |5.0 |Here's another one. Note the blank line between rows.
-|=======================================================================
-
-Table without column headers:
-
-[cols=">,<,^,>",]
-|==================
-|12 |12 |12 |12
-|123 |123 |123 |123
-|1 |1 |1 |1
-|==================
-
-Multiline table without column headers:
-
-[width="78%",cols="^21%,<17%,>20%,42%",]
-|=======================================================================
-|First |row |12.0 |Example of a row that spans multiple lines.
-|Second |row |5.0 |Here's another one. Note the blank line between rows.
-|=======================================================================
diff --git a/tests/tables.context b/tests/tables.context
deleted file mode 100644
index 371e559e5..000000000
--- a/tests/tables.context
+++ /dev/null
@@ -1,175 +0,0 @@
-Simple table with caption:
-
-\placetable{Demonstration of simple table syntax.}
-\starttable[|r|l|c|l|]
-\HL
-\NC Right
-\NC Left
-\NC Center
-\NC Default
-\NC\AR
-\HL
-\NC 12
-\NC 12
-\NC 12
-\NC 12
-\NC\AR
-\NC 123
-\NC 123
-\NC 123
-\NC 123
-\NC\AR
-\NC 1
-\NC 1
-\NC 1
-\NC 1
-\NC\AR
-\HL
-\stoptable
-
-Simple table without caption:
-
-\placetable[none]{}
-\starttable[|r|l|c|l|]
-\HL
-\NC Right
-\NC Left
-\NC Center
-\NC Default
-\NC\AR
-\HL
-\NC 12
-\NC 12
-\NC 12
-\NC 12
-\NC\AR
-\NC 123
-\NC 123
-\NC 123
-\NC 123
-\NC\AR
-\NC 1
-\NC 1
-\NC 1
-\NC 1
-\NC\AR
-\HL
-\stoptable
-
-Simple table indented two spaces:
-
-\placetable{Demonstration of simple table syntax.}
-\starttable[|r|l|c|l|]
-\HL
-\NC Right
-\NC Left
-\NC Center
-\NC Default
-\NC\AR
-\HL
-\NC 12
-\NC 12
-\NC 12
-\NC 12
-\NC\AR
-\NC 123
-\NC 123
-\NC 123
-\NC 123
-\NC\AR
-\NC 1
-\NC 1
-\NC 1
-\NC 1
-\NC\AR
-\HL
-\stoptable
-
-Multiline table with caption:
-
-\placetable{Here's the caption. It may span multiple lines.}
-\starttable[|cp(0.15\textwidth)|lp(0.14\textwidth)|rp(0.16\textwidth)|lp(0.34\textwidth)|]
-\HL
-\NC Centered Header
-\NC Left Aligned
-\NC Right Aligned
-\NC Default aligned
-\NC\AR
-\HL
-\NC First
-\NC row
-\NC 12.0
-\NC Example of a row that spans multiple lines.
-\NC\AR
-\NC Second
-\NC row
-\NC 5.0
-\NC Here's another one. Note the blank line between rows.
-\NC\AR
-\HL
-\stoptable
-
-Multiline table without caption:
-
-\placetable[none]{}
-\starttable[|cp(0.15\textwidth)|lp(0.14\textwidth)|rp(0.16\textwidth)|lp(0.34\textwidth)|]
-\HL
-\NC Centered Header
-\NC Left Aligned
-\NC Right Aligned
-\NC Default aligned
-\NC\AR
-\HL
-\NC First
-\NC row
-\NC 12.0
-\NC Example of a row that spans multiple lines.
-\NC\AR
-\NC Second
-\NC row
-\NC 5.0
-\NC Here's another one. Note the blank line between rows.
-\NC\AR
-\HL
-\stoptable
-
-Table without column headers:
-
-\placetable[none]{}
-\starttable[|r|l|c|r|]
-\HL
-\NC 12
-\NC 12
-\NC 12
-\NC 12
-\NC\AR
-\NC 123
-\NC 123
-\NC 123
-\NC 123
-\NC\AR
-\NC 1
-\NC 1
-\NC 1
-\NC 1
-\NC\AR
-\HL
-\stoptable
-
-Multiline table without column headers:
-
-\placetable[none]{}
-\starttable[|cp(0.15\textwidth)|lp(0.14\textwidth)|rp(0.16\textwidth)|lp(0.34\textwidth)|]
-\HL
-\NC First
-\NC row
-\NC 12.0
-\NC Example of a row that spans multiple lines.
-\NC\AR
-\NC Second
-\NC row
-\NC 5.0
-\NC Here's another one. Note the blank line between rows.
-\NC\AR
-\HL
-\stoptable
diff --git a/tests/tables.docbook b/tests/tables.docbook
deleted file mode 100644
index 6224cf222..000000000
--- a/tests/tables.docbook
+++ /dev/null
@@ -1,432 +0,0 @@
-<para>
- Simple table with caption:
-</para>
-<table>
- <title>
- Demonstration of simple table syntax.
- </title>
- <tgroup cols="4">
- <colspec align="right" />
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="left" />
- <thead>
- <row>
- <entry>
- Right
- </entry>
- <entry>
- Left
- </entry>
- <entry>
- Center
- </entry>
- <entry>
- Default
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- </row>
- <row>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- </row>
- <row>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- </row>
- </tbody>
- </tgroup>
-</table>
-<para>
- Simple table without caption:
-</para>
-<informaltable>
- <tgroup cols="4">
- <colspec align="right" />
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="left" />
- <thead>
- <row>
- <entry>
- Right
- </entry>
- <entry>
- Left
- </entry>
- <entry>
- Center
- </entry>
- <entry>
- Default
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- </row>
- <row>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- </row>
- <row>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- </row>
- </tbody>
- </tgroup>
-</informaltable>
-<para>
- Simple table indented two spaces:
-</para>
-<table>
- <title>
- Demonstration of simple table syntax.
- </title>
- <tgroup cols="4">
- <colspec align="right" />
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="left" />
- <thead>
- <row>
- <entry>
- Right
- </entry>
- <entry>
- Left
- </entry>
- <entry>
- Center
- </entry>
- <entry>
- Default
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- </row>
- <row>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- </row>
- <row>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- </row>
- </tbody>
- </tgroup>
-</table>
-<para>
- Multiline table with caption:
-</para>
-<table>
- <title>
- Here's the caption. It may span multiple lines.
- </title>
- <tgroup cols="4">
- <colspec colwidth="15*" align="center" />
- <colspec colwidth="13*" align="left" />
- <colspec colwidth="16*" align="right" />
- <colspec colwidth="33*" align="left" />
- <thead>
- <row>
- <entry>
- Centered Header
- </entry>
- <entry>
- Left Aligned
- </entry>
- <entry>
- Right Aligned
- </entry>
- <entry>
- Default aligned
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- First
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 12.0
- </entry>
- <entry>
- Example of a row that spans multiple lines.
- </entry>
- </row>
- <row>
- <entry>
- Second
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 5.0
- </entry>
- <entry>
- Here's another one. Note the blank line between rows.
- </entry>
- </row>
- </tbody>
- </tgroup>
-</table>
-<para>
- Multiline table without caption:
-</para>
-<informaltable>
- <tgroup cols="4">
- <colspec colwidth="15*" align="center" />
- <colspec colwidth="13*" align="left" />
- <colspec colwidth="16*" align="right" />
- <colspec colwidth="33*" align="left" />
- <thead>
- <row>
- <entry>
- Centered Header
- </entry>
- <entry>
- Left Aligned
- </entry>
- <entry>
- Right Aligned
- </entry>
- <entry>
- Default aligned
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- First
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 12.0
- </entry>
- <entry>
- Example of a row that spans multiple lines.
- </entry>
- </row>
- <row>
- <entry>
- Second
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 5.0
- </entry>
- <entry>
- Here's another one. Note the blank line between rows.
- </entry>
- </row>
- </tbody>
- </tgroup>
-</informaltable>
-<para>
- Table without column headers:
-</para>
-<informaltable>
- <tgroup cols="4">
- <colspec align="right" />
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="right" />
- <tbody>
- <row>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- </row>
- <row>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- </row>
- <row>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- </row>
- </tbody>
- </tgroup>
-</informaltable>
-<para>
- Multiline table without column headers:
-</para>
-<informaltable>
- <tgroup cols="4">
- <colspec colwidth="15*" align="center" />
- <colspec colwidth="13*" align="left" />
- <colspec colwidth="16*" align="right" />
- <colspec colwidth="33*" align="left" />
- <tbody>
- <row>
- <entry>
- First
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 12.0
- </entry>
- <entry>
- Example of a row that spans multiple lines.
- </entry>
- </row>
- <row>
- <entry>
- Second
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 5.0
- </entry>
- <entry>
- Here's another one. Note the blank line between rows.
- </entry>
- </row>
- </tbody>
- </tgroup>
-</informaltable>
diff --git a/tests/tables.docbook5 b/tests/tables.docbook5
deleted file mode 100644
index 6224cf222..000000000
--- a/tests/tables.docbook5
+++ /dev/null
@@ -1,432 +0,0 @@
-<para>
- Simple table with caption:
-</para>
-<table>
- <title>
- Demonstration of simple table syntax.
- </title>
- <tgroup cols="4">
- <colspec align="right" />
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="left" />
- <thead>
- <row>
- <entry>
- Right
- </entry>
- <entry>
- Left
- </entry>
- <entry>
- Center
- </entry>
- <entry>
- Default
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- </row>
- <row>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- </row>
- <row>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- </row>
- </tbody>
- </tgroup>
-</table>
-<para>
- Simple table without caption:
-</para>
-<informaltable>
- <tgroup cols="4">
- <colspec align="right" />
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="left" />
- <thead>
- <row>
- <entry>
- Right
- </entry>
- <entry>
- Left
- </entry>
- <entry>
- Center
- </entry>
- <entry>
- Default
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- </row>
- <row>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- </row>
- <row>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- </row>
- </tbody>
- </tgroup>
-</informaltable>
-<para>
- Simple table indented two spaces:
-</para>
-<table>
- <title>
- Demonstration of simple table syntax.
- </title>
- <tgroup cols="4">
- <colspec align="right" />
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="left" />
- <thead>
- <row>
- <entry>
- Right
- </entry>
- <entry>
- Left
- </entry>
- <entry>
- Center
- </entry>
- <entry>
- Default
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- </row>
- <row>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- </row>
- <row>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- </row>
- </tbody>
- </tgroup>
-</table>
-<para>
- Multiline table with caption:
-</para>
-<table>
- <title>
- Here's the caption. It may span multiple lines.
- </title>
- <tgroup cols="4">
- <colspec colwidth="15*" align="center" />
- <colspec colwidth="13*" align="left" />
- <colspec colwidth="16*" align="right" />
- <colspec colwidth="33*" align="left" />
- <thead>
- <row>
- <entry>
- Centered Header
- </entry>
- <entry>
- Left Aligned
- </entry>
- <entry>
- Right Aligned
- </entry>
- <entry>
- Default aligned
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- First
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 12.0
- </entry>
- <entry>
- Example of a row that spans multiple lines.
- </entry>
- </row>
- <row>
- <entry>
- Second
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 5.0
- </entry>
- <entry>
- Here's another one. Note the blank line between rows.
- </entry>
- </row>
- </tbody>
- </tgroup>
-</table>
-<para>
- Multiline table without caption:
-</para>
-<informaltable>
- <tgroup cols="4">
- <colspec colwidth="15*" align="center" />
- <colspec colwidth="13*" align="left" />
- <colspec colwidth="16*" align="right" />
- <colspec colwidth="33*" align="left" />
- <thead>
- <row>
- <entry>
- Centered Header
- </entry>
- <entry>
- Left Aligned
- </entry>
- <entry>
- Right Aligned
- </entry>
- <entry>
- Default aligned
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- First
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 12.0
- </entry>
- <entry>
- Example of a row that spans multiple lines.
- </entry>
- </row>
- <row>
- <entry>
- Second
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 5.0
- </entry>
- <entry>
- Here's another one. Note the blank line between rows.
- </entry>
- </row>
- </tbody>
- </tgroup>
-</informaltable>
-<para>
- Table without column headers:
-</para>
-<informaltable>
- <tgroup cols="4">
- <colspec align="right" />
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="right" />
- <tbody>
- <row>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- <entry>
- 12
- </entry>
- </row>
- <row>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- <entry>
- 123
- </entry>
- </row>
- <row>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- <entry>
- 1
- </entry>
- </row>
- </tbody>
- </tgroup>
-</informaltable>
-<para>
- Multiline table without column headers:
-</para>
-<informaltable>
- <tgroup cols="4">
- <colspec colwidth="15*" align="center" />
- <colspec colwidth="13*" align="left" />
- <colspec colwidth="16*" align="right" />
- <colspec colwidth="33*" align="left" />
- <tbody>
- <row>
- <entry>
- First
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 12.0
- </entry>
- <entry>
- Example of a row that spans multiple lines.
- </entry>
- </row>
- <row>
- <entry>
- Second
- </entry>
- <entry>
- row
- </entry>
- <entry>
- 5.0
- </entry>
- <entry>
- Here's another one. Note the blank line between rows.
- </entry>
- </row>
- </tbody>
- </tgroup>
-</informaltable>
diff --git a/tests/tables.dokuwiki b/tests/tables.dokuwiki
deleted file mode 100644
index 21e61f656..000000000
--- a/tests/tables.dokuwiki
+++ /dev/null
@@ -1,47 +0,0 @@
-Simple table with caption:
-
-Demonstration of simple table syntax.
-^ Right^Left ^ Center ^Default^
-| 12|12 | 12 |12 |
-| 123|123 | 123 |123 |
-| 1|1 | 1 |1 |
-
-Simple table without caption:
-
-^ Right^Left ^ Center ^Default^
-| 12|12 | 12 |12 |
-| 123|123 | 123 |123 |
-| 1|1 | 1 |1 |
-
-Simple table indented two spaces:
-
-Demonstration of simple table syntax.
-^ Right^Left ^ Center ^Default^
-| 12|12 | 12 |12 |
-| 123|123 | 123 |123 |
-| 1|1 | 1 |1 |
-
-Multiline table with caption:
-
-Here's the caption. It may span multiple lines.
-^ Centered Header ^Left Aligned ^ Right Aligned^Default aligned ^
-| First |row | 12.0|Example of a row that spans multiple lines. |
-| Second |row | 5.0|Here's another one. Note the blank line between rows. |
-
-Multiline table without caption:
-
-^ Centered Header ^Left Aligned ^ Right Aligned^Default aligned ^
-| First |row | 12.0|Example of a row that spans multiple lines. |
-| Second |row | 5.0|Here's another one. Note the blank line between rows. |
-
-Table without column headers:
-
-| 12|12 | 12 | 12|
-| 123|123 | 123 | 123|
-| 1|1 | 1 | 1|
-
-Multiline table without column headers:
-
-| First |row | 12.0|Example of a row that spans multiple lines. |
-| Second |row | 5.0|Here's another one. Note the blank line between rows.|
-
diff --git a/tests/tables.fb2 b/tests/tables.fb2
deleted file mode 100644
index f636e9fd4..000000000
--- a/tests/tables.fb2
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info /><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><annotation><p></p></annotation><section><p>Simple table with caption:</p><table><tr><th align="right">Right</th><th align="left">Left</th><th align="center">Center</th><th align="left">Default</th></tr><tr><td align="right">12</td><td align="left">12</td><td align="center">12</td><td align="left">12</td></tr><tr><td align="right">123</td><td align="left">123</td><td align="center">123</td><td align="left">123</td></tr><tr><td align="right">1</td><td align="left">1</td><td align="center">1</td><td align="left">1</td></tr></table><p><emphasis>Demonstration of simple table syntax.</emphasis></p><p>Simple table without caption:</p><table><tr><th align="right">Right</th><th align="left">Left</th><th align="center">Center</th><th align="left">Default</th></tr><tr><td align="right">12</td><td align="left">12</td><td align="center">12</td><td align="left">12</td></tr><tr><td align="right">123</td><td align="left">123</td><td align="center">123</td><td align="left">123</td></tr><tr><td align="right">1</td><td align="left">1</td><td align="center">1</td><td align="left">1</td></tr></table><p><emphasis /></p><p>Simple table indented two spaces:</p><table><tr><th align="right">Right</th><th align="left">Left</th><th align="center">Center</th><th align="left">Default</th></tr><tr><td align="right">12</td><td align="left">12</td><td align="center">12</td><td align="left">12</td></tr><tr><td align="right">123</td><td align="left">123</td><td align="center">123</td><td align="left">123</td></tr><tr><td align="right">1</td><td align="left">1</td><td align="center">1</td><td align="left">1</td></tr></table><p><emphasis>Demonstration of simple table syntax.</emphasis></p><p>Multiline table with caption:</p><table><tr><th align="center">Centered Header</th><th align="left">Left Aligned</th><th align="right">Right Aligned</th><th align="left">Default aligned</th></tr><tr><td align="center">First</td><td align="left">row</td><td align="right">12.0</td><td align="left">Example of a row that spans multiple lines.</td></tr><tr><td align="center">Second</td><td align="left">row</td><td align="right">5.0</td><td align="left">Here&#39;s another one. Note the blank line between rows.</td></tr></table><p><emphasis>Here&#39;s the caption. It may span multiple lines.</emphasis></p><p>Multiline table without caption:</p><table><tr><th align="center">Centered Header</th><th align="left">Left Aligned</th><th align="right">Right Aligned</th><th align="left">Default aligned</th></tr><tr><td align="center">First</td><td align="left">row</td><td align="right">12.0</td><td align="left">Example of a row that spans multiple lines.</td></tr><tr><td align="center">Second</td><td align="left">row</td><td align="right">5.0</td><td align="left">Here&#39;s another one. Note the blank line between rows.</td></tr></table><p><emphasis /></p><p>Table without column headers:</p><table><tr><th align="right" /><th align="left" /><th align="center" /><th align="right" /></tr><tr><td align="right">12</td><td align="left">12</td><td align="center">12</td><td align="right">12</td></tr><tr><td align="right">123</td><td align="left">123</td><td align="center">123</td><td align="right">123</td></tr><tr><td align="right">1</td><td align="left">1</td><td align="center">1</td><td align="right">1</td></tr></table><p><emphasis /></p><p>Multiline table without column headers:</p><table><tr><th align="center" /><th align="left" /><th align="right" /><th align="left" /></tr><tr><td align="center">First</td><td align="left">row</td><td align="right">12.0</td><td align="left">Example of a row that spans multiple lines.</td></tr><tr><td align="center">Second</td><td align="left">row</td><td align="right">5.0</td><td align="left">Here&#39;s another one. Note the blank line between rows.</td></tr></table><p><emphasis /></p></section></body></FictionBook> \ No newline at end of file
diff --git a/tests/tables.haddock b/tests/tables.haddock
deleted file mode 100644
index f9efdc0de..000000000
--- a/tests/tables.haddock
+++ /dev/null
@@ -1,76 +0,0 @@
-Simple table with caption:
-
-> Right Left Center Default
-> ------- ------ -------- ---------
-> 12 12 12 12
-> 123 123 123 123
-> 1 1 1 1
->
-> Demonstration of simple table syntax.
-
-Simple table without caption:
-
-> Right Left Center Default
-> ------- ------ -------- ---------
-> 12 12 12 12
-> 123 123 123 123
-> 1 1 1 1
-
-Simple table indented two spaces:
-
-> Right Left Center Default
-> ------- ------ -------- ---------
-> 12 12 12 12
-> 123 123 123 123
-> 1 1 1 1
->
-> Demonstration of simple table syntax.
-
-Multiline table with caption:
-
-> --------------------------------------------------------------
-> Centered Left Right Default aligned
-> Header Aligned Aligned
-> ----------- ---------- ------------ --------------------------
-> First row 12.0 Example of a row that
-> spans multiple lines.
->
-> Second row 5.0 Here\'s another one. Note
-> the blank line between
-> rows.
-> --------------------------------------------------------------
->
-> Here\'s the caption. It may span multiple lines.
-
-Multiline table without caption:
-
-> --------------------------------------------------------------
-> Centered Left Right Default aligned
-> Header Aligned Aligned
-> ----------- ---------- ------------ --------------------------
-> First row 12.0 Example of a row that
-> spans multiple lines.
->
-> Second row 5.0 Here\'s another one. Note
-> the blank line between
-> rows.
-> --------------------------------------------------------------
-
-Table without column headers:
-
-> ----- ----- ----- -----
-> 12 12 12 12
-> 123 123 123 123
-> 1 1 1 1
-> ----- ----- ----- -----
-
-Multiline table without column headers:
-
-> ----------- ---------- ------------ --------------------------
-> First row 12.0 Example of a row that
-> spans multiple lines.
->
-> Second row 5.0 Here\'s another one. Note
-> the blank line between
-> rows.
-> ----------- ---------- ------------ --------------------------
diff --git a/tests/tables.html b/tests/tables.html
deleted file mode 100644
index 0a9ea413c..000000000
--- a/tests/tables.html
+++ /dev/null
@@ -1,204 +0,0 @@
-<p>Simple table with caption:</p>
-<table>
-<caption>Demonstration of simple table syntax.</caption>
-<thead>
-<tr class="header">
-<th align="right">Right</th>
-<th align="left">Left</th>
-<th align="center">Center</th>
-<th>Default</th>
-</tr>
-</thead>
-<tbody>
-<tr class="odd">
-<td align="right">12</td>
-<td align="left">12</td>
-<td align="center">12</td>
-<td>12</td>
-</tr>
-<tr class="even">
-<td align="right">123</td>
-<td align="left">123</td>
-<td align="center">123</td>
-<td>123</td>
-</tr>
-<tr class="odd">
-<td align="right">1</td>
-<td align="left">1</td>
-<td align="center">1</td>
-<td>1</td>
-</tr>
-</tbody>
-</table>
-<p>Simple table without caption:</p>
-<table>
-<thead>
-<tr class="header">
-<th align="right">Right</th>
-<th align="left">Left</th>
-<th align="center">Center</th>
-<th>Default</th>
-</tr>
-</thead>
-<tbody>
-<tr class="odd">
-<td align="right">12</td>
-<td align="left">12</td>
-<td align="center">12</td>
-<td>12</td>
-</tr>
-<tr class="even">
-<td align="right">123</td>
-<td align="left">123</td>
-<td align="center">123</td>
-<td>123</td>
-</tr>
-<tr class="odd">
-<td align="right">1</td>
-<td align="left">1</td>
-<td align="center">1</td>
-<td>1</td>
-</tr>
-</tbody>
-</table>
-<p>Simple table indented two spaces:</p>
-<table>
-<caption>Demonstration of simple table syntax.</caption>
-<thead>
-<tr class="header">
-<th align="right">Right</th>
-<th align="left">Left</th>
-<th align="center">Center</th>
-<th>Default</th>
-</tr>
-</thead>
-<tbody>
-<tr class="odd">
-<td align="right">12</td>
-<td align="left">12</td>
-<td align="center">12</td>
-<td>12</td>
-</tr>
-<tr class="even">
-<td align="right">123</td>
-<td align="left">123</td>
-<td align="center">123</td>
-<td>123</td>
-</tr>
-<tr class="odd">
-<td align="right">1</td>
-<td align="left">1</td>
-<td align="center">1</td>
-<td>1</td>
-</tr>
-</tbody>
-</table>
-<p>Multiline table with caption:</p>
-<table style="width:79%;">
-<caption>Here's the caption. It may span multiple lines.</caption>
-<colgroup>
-<col width="15%" />
-<col width="13%" />
-<col width="16%" />
-<col width="33%" />
-</colgroup>
-<thead>
-<tr class="header">
-<th align="center">Centered Header</th>
-<th align="left">Left Aligned</th>
-<th align="right">Right Aligned</th>
-<th align="left">Default aligned</th>
-</tr>
-</thead>
-<tbody>
-<tr class="odd">
-<td align="center">First</td>
-<td align="left">row</td>
-<td align="right">12.0</td>
-<td align="left">Example of a row that spans multiple lines.</td>
-</tr>
-<tr class="even">
-<td align="center">Second</td>
-<td align="left">row</td>
-<td align="right">5.0</td>
-<td align="left">Here's another one. Note the blank line between rows.</td>
-</tr>
-</tbody>
-</table>
-<p>Multiline table without caption:</p>
-<table style="width:79%;">
-<colgroup>
-<col width="15%" />
-<col width="13%" />
-<col width="16%" />
-<col width="33%" />
-</colgroup>
-<thead>
-<tr class="header">
-<th align="center">Centered Header</th>
-<th align="left">Left Aligned</th>
-<th align="right">Right Aligned</th>
-<th align="left">Default aligned</th>
-</tr>
-</thead>
-<tbody>
-<tr class="odd">
-<td align="center">First</td>
-<td align="left">row</td>
-<td align="right">12.0</td>
-<td align="left">Example of a row that spans multiple lines.</td>
-</tr>
-<tr class="even">
-<td align="center">Second</td>
-<td align="left">row</td>
-<td align="right">5.0</td>
-<td align="left">Here's another one. Note the blank line between rows.</td>
-</tr>
-</tbody>
-</table>
-<p>Table without column headers:</p>
-<table>
-<tbody>
-<tr class="odd">
-<td align="right">12</td>
-<td align="left">12</td>
-<td align="center">12</td>
-<td align="right">12</td>
-</tr>
-<tr class="even">
-<td align="right">123</td>
-<td align="left">123</td>
-<td align="center">123</td>
-<td align="right">123</td>
-</tr>
-<tr class="odd">
-<td align="right">1</td>
-<td align="left">1</td>
-<td align="center">1</td>
-<td align="right">1</td>
-</tr>
-</tbody>
-</table>
-<p>Multiline table without column headers:</p>
-<table style="width:79%;">
-<colgroup>
-<col width="15%" />
-<col width="13%" />
-<col width="16%" />
-<col width="33%" />
-</colgroup>
-<tbody>
-<tr class="odd">
-<td align="center">First</td>
-<td align="left">row</td>
-<td align="right">12.0</td>
-<td>Example of a row that spans multiple lines.</td>
-</tr>
-<tr class="even">
-<td align="center">Second</td>
-<td align="left">row</td>
-<td align="right">5.0</td>
-<td>Here's another one. Note the blank line between rows.</td>
-</tr>
-</tbody>
-</table>
diff --git a/tests/tables.icml b/tests/tables.icml
deleted file mode 100644
index 8ce645a2f..000000000
--- a/tests/tables.icml
+++ /dev/null
@@ -1,757 +0,0 @@
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Simple table with caption:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="3" ColumnCount="4">
- <Column Name="0" />
- <Column Name="1" />
- <Column Name="2" />
- <Column Name="3" />
- <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Right</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Left</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Center</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Default</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
-</Table>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Demonstration of simple table syntax.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Simple table without caption:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="3" ColumnCount="4">
- <Column Name="0" />
- <Column Name="1" />
- <Column Name="2" />
- <Column Name="3" />
- <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Right</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Left</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Center</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Default</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
-</Table>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Simple table indented two spaces:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="3" ColumnCount="4">
- <Column Name="0" />
- <Column Name="1" />
- <Column Name="2" />
- <Column Name="3" />
- <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Right</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Left</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Center</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Default</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:3" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
-</Table>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Demonstration of simple table syntax.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Multiline table with caption:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="2" ColumnCount="4">
- <Column Name="0" SingleColumnWidth="75.0" />
- <Column Name="1" SingleColumnWidth="68.75" />
- <Column Name="2" SingleColumnWidth="81.25" />
- <Column Name="3" SingleColumnWidth="168.75" />
- <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Centered Header</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Left Aligned</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Right Aligned</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Default aligned</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>First</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>row</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12.0</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Example of a row that spans multiple lines.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Second</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>row</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>5.0</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here's another one. Note the blank line between rows.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
-</Table>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here's the caption. It may span multiple lines.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Multiline table without caption:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="1" BodyRowCount="2" ColumnCount="4">
- <Column Name="0" SingleColumnWidth="75.0" />
- <Column Name="1" SingleColumnWidth="68.75" />
- <Column Name="2" SingleColumnWidth="81.25" />
- <Column Name="3" SingleColumnWidth="168.75" />
- <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Centered Header</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Left Aligned</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Right Aligned</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; TableHeader &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Default aligned</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>First</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>row</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12.0</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Example of a row that spans multiple lines.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Second</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>row</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>5.0</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here's another one. Note the blank line between rows.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
-</Table>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Table without column headers:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="0" BodyRowCount="3" ColumnCount="4">
- <Column Name="0" />
- <Column Name="1" />
- <Column Name="2" />
- <Column Name="3" />
- <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>123</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:2" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>1</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
-</Table>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Multiline table without column headers:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<Table AppliedTableStyle="TableStyle/Table" HeaderRowCount="0" BodyRowCount="2" ColumnCount="4">
- <Column Name="0" SingleColumnWidth="75.0" />
- <Column Name="1" SingleColumnWidth="68.75" />
- <Column Name="2" SingleColumnWidth="81.25" />
- <Column Name="3" SingleColumnWidth="168.75" />
- <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>First</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>row</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>12.0</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:0" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Example of a row that spans multiple lines.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="0:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; CenterAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Second</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="1:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; LeftAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>row</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="2:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar &gt; RightAlign">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>5.0</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
- <Cell Name="3:1" AppliedCellStyle="CellStyle/Cell">
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here's another one. Note the blank line between rows.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Cell>
-</Table>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TableCaption">
-</ParagraphStyleRange> \ No newline at end of file
diff --git a/tests/tables.latex b/tests/tables.latex
deleted file mode 100644
index 38d4d089e..000000000
--- a/tests/tables.latex
+++ /dev/null
@@ -1,168 +0,0 @@
-Simple table with caption:
-
-\begin{longtable}[]{@{}rlcl@{}}
-\caption{Demonstration of simple table syntax.}\tabularnewline
-\toprule
-Right & Left & Center & Default\tabularnewline
-\midrule
-\endfirsthead
-\toprule
-Right & Left & Center & Default\tabularnewline
-\midrule
-\endhead
-12 & 12 & 12 & 12\tabularnewline
-123 & 123 & 123 & 123\tabularnewline
-1 & 1 & 1 & 1\tabularnewline
-\bottomrule
-\end{longtable}
-
-Simple table without caption:
-
-\begin{longtable}[]{@{}rlcl@{}}
-\toprule
-Right & Left & Center & Default\tabularnewline
-\midrule
-\endhead
-12 & 12 & 12 & 12\tabularnewline
-123 & 123 & 123 & 123\tabularnewline
-1 & 1 & 1 & 1\tabularnewline
-\bottomrule
-\end{longtable}
-
-Simple table indented two spaces:
-
-\begin{longtable}[]{@{}rlcl@{}}
-\caption{Demonstration of simple table syntax.}\tabularnewline
-\toprule
-Right & Left & Center & Default\tabularnewline
-\midrule
-\endfirsthead
-\toprule
-Right & Left & Center & Default\tabularnewline
-\midrule
-\endhead
-12 & 12 & 12 & 12\tabularnewline
-123 & 123 & 123 & 123\tabularnewline
-1 & 1 & 1 & 1\tabularnewline
-\bottomrule
-\end{longtable}
-
-Multiline table with caption:
-
-\begin{longtable}[]{@{}clrl@{}}
-\caption{Here's the caption. It may span multiple lines.}\tabularnewline
-\toprule
-\begin{minipage}[b]{0.13\columnwidth}\centering\strut
-Centered Header\strut
-\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright\strut
-Left Aligned\strut
-\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft\strut
-Right Aligned\strut
-\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright\strut
-Default aligned\strut
-\end{minipage}\tabularnewline
-\midrule
-\endfirsthead
-\toprule
-\begin{minipage}[b]{0.13\columnwidth}\centering\strut
-Centered Header\strut
-\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright\strut
-Left Aligned\strut
-\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft\strut
-Right Aligned\strut
-\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright\strut
-Default aligned\strut
-\end{minipage}\tabularnewline
-\midrule
-\endhead
-\begin{minipage}[t]{0.13\columnwidth}\centering\strut
-First\strut
-\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright\strut
-row\strut
-\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft\strut
-12.0\strut
-\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright\strut
-Example of a row that spans multiple lines.\strut
-\end{minipage}\tabularnewline
-\begin{minipage}[t]{0.13\columnwidth}\centering\strut
-Second\strut
-\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright\strut
-row\strut
-\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft\strut
-5.0\strut
-\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright\strut
-Here's another one. Note the blank line between rows.\strut
-\end{minipage}\tabularnewline
-\bottomrule
-\end{longtable}
-
-Multiline table without caption:
-
-\begin{longtable}[]{@{}clrl@{}}
-\toprule
-\begin{minipage}[b]{0.13\columnwidth}\centering\strut
-Centered Header\strut
-\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright\strut
-Left Aligned\strut
-\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft\strut
-Right Aligned\strut
-\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright\strut
-Default aligned\strut
-\end{minipage}\tabularnewline
-\midrule
-\endhead
-\begin{minipage}[t]{0.13\columnwidth}\centering\strut
-First\strut
-\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright\strut
-row\strut
-\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft\strut
-12.0\strut
-\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright\strut
-Example of a row that spans multiple lines.\strut
-\end{minipage}\tabularnewline
-\begin{minipage}[t]{0.13\columnwidth}\centering\strut
-Second\strut
-\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright\strut
-row\strut
-\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft\strut
-5.0\strut
-\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright\strut
-Here's another one. Note the blank line between rows.\strut
-\end{minipage}\tabularnewline
-\bottomrule
-\end{longtable}
-
-Table without column headers:
-
-\begin{longtable}[]{@{}rlcr@{}}
-\toprule
-12 & 12 & 12 & 12\tabularnewline
-123 & 123 & 123 & 123\tabularnewline
-1 & 1 & 1 & 1\tabularnewline
-\bottomrule
-\end{longtable}
-
-Multiline table without column headers:
-
-\begin{longtable}[]{@{}clrl@{}}
-\toprule
-\begin{minipage}[t]{0.13\columnwidth}\centering\strut
-First\strut
-\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright\strut
-row\strut
-\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft\strut
-12.0\strut
-\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright\strut
-Example of a row that spans multiple lines.\strut
-\end{minipage}\tabularnewline
-\begin{minipage}[t]{0.13\columnwidth}\centering\strut
-Second\strut
-\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright\strut
-row\strut
-\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft\strut
-5.0\strut
-\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright\strut
-Here's another one. Note the blank line between rows.\strut
-\end{minipage}\tabularnewline
-\bottomrule
-\end{longtable}
diff --git a/tests/tables.man b/tests/tables.man
deleted file mode 100644
index 788b2199d..000000000
--- a/tests/tables.man
+++ /dev/null
@@ -1,267 +0,0 @@
-.PP
-Simple table with caption:
-.PP
-Demonstration of simple table syntax.
-.TS
-tab(@);
-r l c l.
-T{
-Right
-T}@T{
-Left
-T}@T{
-Center
-T}@T{
-Default
-T}
-_
-T{
-12
-T}@T{
-12
-T}@T{
-12
-T}@T{
-12
-T}
-T{
-123
-T}@T{
-123
-T}@T{
-123
-T}@T{
-123
-T}
-T{
-1
-T}@T{
-1
-T}@T{
-1
-T}@T{
-1
-T}
-.TE
-.PP
-Simple table without caption:
-.PP
-.TS
-tab(@);
-r l c l.
-T{
-Right
-T}@T{
-Left
-T}@T{
-Center
-T}@T{
-Default
-T}
-_
-T{
-12
-T}@T{
-12
-T}@T{
-12
-T}@T{
-12
-T}
-T{
-123
-T}@T{
-123
-T}@T{
-123
-T}@T{
-123
-T}
-T{
-1
-T}@T{
-1
-T}@T{
-1
-T}@T{
-1
-T}
-.TE
-.PP
-Simple table indented two spaces:
-.PP
-Demonstration of simple table syntax.
-.TS
-tab(@);
-r l c l.
-T{
-Right
-T}@T{
-Left
-T}@T{
-Center
-T}@T{
-Default
-T}
-_
-T{
-12
-T}@T{
-12
-T}@T{
-12
-T}@T{
-12
-T}
-T{
-123
-T}@T{
-123
-T}@T{
-123
-T}@T{
-123
-T}
-T{
-1
-T}@T{
-1
-T}@T{
-1
-T}@T{
-1
-T}
-.TE
-.PP
-Multiline table with caption:
-.PP
-Here\[aq]s the caption. It may span multiple lines.
-.TS
-tab(@);
-cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
-T{
-Centered Header
-T}@T{
-Left Aligned
-T}@T{
-Right Aligned
-T}@T{
-Default aligned
-T}
-_
-T{
-First
-T}@T{
-row
-T}@T{
-12.0
-T}@T{
-Example of a row that spans multiple lines.
-T}
-T{
-Second
-T}@T{
-row
-T}@T{
-5.0
-T}@T{
-Here\[aq]s another one.
-Note the blank line between rows.
-T}
-.TE
-.PP
-Multiline table without caption:
-.PP
-.TS
-tab(@);
-cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
-T{
-Centered Header
-T}@T{
-Left Aligned
-T}@T{
-Right Aligned
-T}@T{
-Default aligned
-T}
-_
-T{
-First
-T}@T{
-row
-T}@T{
-12.0
-T}@T{
-Example of a row that spans multiple lines.
-T}
-T{
-Second
-T}@T{
-row
-T}@T{
-5.0
-T}@T{
-Here\[aq]s another one.
-Note the blank line between rows.
-T}
-.TE
-.PP
-Table without column headers:
-.PP
-.TS
-tab(@);
-r l c r.
-T{
-12
-T}@T{
-12
-T}@T{
-12
-T}@T{
-12
-T}
-T{
-123
-T}@T{
-123
-T}@T{
-123
-T}@T{
-123
-T}
-T{
-1
-T}@T{
-1
-T}@T{
-1
-T}@T{
-1
-T}
-.TE
-.PP
-Multiline table without column headers:
-.PP
-.TS
-tab(@);
-cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n).
-T{
-First
-T}@T{
-row
-T}@T{
-12.0
-T}@T{
-Example of a row that spans multiple lines.
-T}
-T{
-Second
-T}@T{
-row
-T}@T{
-5.0
-T}@T{
-Here\[aq]s another one.
-Note the blank line between rows.
-T}
-.TE
diff --git a/tests/tables.markdown b/tests/tables.markdown
deleted file mode 100644
index 4b5754cf9..000000000
--- a/tests/tables.markdown
+++ /dev/null
@@ -1,78 +0,0 @@
-Simple table with caption:
-
- Right Left Center Default
- ------- ------ -------- ---------
- 12 12 12 12
- 123 123 123 123
- 1 1 1 1
-
- : Demonstration of simple table syntax.
-
-Simple table without caption:
-
- Right Left Center Default
- ------- ------ -------- ---------
- 12 12 12 12
- 123 123 123 123
- 1 1 1 1
-
-Simple table indented two spaces:
-
- Right Left Center Default
- ------- ------ -------- ---------
- 12 12 12 12
- 123 123 123 123
- 1 1 1 1
-
- : Demonstration of simple table syntax.
-
-Multiline table with caption:
-
- --------------------------------------------------------------
- Centered Left Right Default aligned
- Header Aligned Aligned
- ----------- ---------- ------------ --------------------------
- First row 12.0 Example of a row that
- spans multiple lines.
-
- Second row 5.0 Here's another one. Note
- the blank line between
- rows.
- --------------------------------------------------------------
-
- : Here's the caption. It may span multiple lines.
-
-Multiline table without caption:
-
- --------------------------------------------------------------
- Centered Left Right Default aligned
- Header Aligned Aligned
- ----------- ---------- ------------ --------------------------
- First row 12.0 Example of a row that
- spans multiple lines.
-
- Second row 5.0 Here's another one. Note
- the blank line between
- rows.
- --------------------------------------------------------------
-
-Table without column headers:
-
- ----- ----- ----- -----
- 12 12 12 12
- 123 123 123 123
- 1 1 1 1
- ----- ----- ----- -----
-
-Multiline table without column headers:
-
- ----------- ---------- ------------ --------------------------
- First row 12.0 Example of a row that
- spans multiple lines.
-
- Second row 5.0 Here's another one. Note
- the blank line between
- rows.
- ----------- ---------- ------------ --------------------------
-
-
diff --git a/tests/tables.mediawiki b/tests/tables.mediawiki
deleted file mode 100644
index 614c3eea1..000000000
--- a/tests/tables.mediawiki
+++ /dev/null
@@ -1,146 +0,0 @@
-Simple table with caption:
-
-{|
-|+ Demonstration of simple table syntax.
-!align="right"| Right
-! Left
-!align="center"| Center
-! Default
-|-
-|align="right"| 12
-| 12
-|align="center"| 12
-| 12
-|-
-|align="right"| 123
-| 123
-|align="center"| 123
-| 123
-|-
-|align="right"| 1
-| 1
-|align="center"| 1
-| 1
-|}
-
-Simple table without caption:
-
-{|
-!align="right"| Right
-! Left
-!align="center"| Center
-! Default
-|-
-|align="right"| 12
-| 12
-|align="center"| 12
-| 12
-|-
-|align="right"| 123
-| 123
-|align="center"| 123
-| 123
-|-
-|align="right"| 1
-| 1
-|align="center"| 1
-| 1
-|}
-
-Simple table indented two spaces:
-
-{|
-|+ Demonstration of simple table syntax.
-!align="right"| Right
-! Left
-!align="center"| Center
-! Default
-|-
-|align="right"| 12
-| 12
-|align="center"| 12
-| 12
-|-
-|align="right"| 123
-| 123
-|align="center"| 123
-| 123
-|-
-|align="right"| 1
-| 1
-|align="center"| 1
-| 1
-|}
-
-Multiline table with caption:
-
-{|
-|+ Here's the caption. It may span multiple lines.
-!align="center" width="15%"| Centered Header
-!width="13%"| Left Aligned
-!align="right" width="16%"| Right Aligned
-!width="33%"| Default aligned
-|-
-|align="center"| First
-| row
-|align="right"| 12.0
-| Example of a row that spans multiple lines.
-|-
-|align="center"| Second
-| row
-|align="right"| 5.0
-| Here's another one. Note the blank line between rows.
-|}
-
-Multiline table without caption:
-
-{|
-!align="center" width="15%"| Centered Header
-!width="13%"| Left Aligned
-!align="right" width="16%"| Right Aligned
-!width="33%"| Default aligned
-|-
-|align="center"| First
-| row
-|align="right"| 12.0
-| Example of a row that spans multiple lines.
-|-
-|align="center"| Second
-| row
-|align="right"| 5.0
-| Here's another one. Note the blank line between rows.
-|}
-
-Table without column headers:
-
-{|
-|align="right"| 12
-| 12
-|align="center"| 12
-|align="right"| 12
-|-
-|align="right"| 123
-| 123
-|align="center"| 123
-|align="right"| 123
-|-
-|align="right"| 1
-| 1
-|align="center"| 1
-|align="right"| 1
-|}
-
-Multiline table without column headers:
-
-{|
-|align="center" width="15%"| First
-|width="13%"| row
-|align="right" width="16%"| 12.0
-|width="33%"| Example of a row that spans multiple lines.
-|-
-|align="center"| Second
-| row
-|align="right"| 5.0
-| Here's another one. Note the blank line between rows.
-|}
-
diff --git a/tests/tables.native b/tests/tables.native
deleted file mode 100644
index a7f4fdcf1..000000000
--- a/tests/tables.native
+++ /dev/null
@@ -1,114 +0,0 @@
-[Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"]
-,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
- [[Plain [Str "Right"]]
- ,[Plain [Str "Left"]]
- ,[Plain [Str "Center"]]
- ,[Plain [Str "Default"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Simple",Space,Str "table",Space,Str "without",Space,Str "caption:"]
-,Table [] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
- [[Plain [Str "Right"]]
- ,[Plain [Str "Left"]]
- ,[Plain [Str "Center"]]
- ,[Plain [Str "Default"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Simple",Space,Str "table",Space,Str "indented",Space,Str "two",Space,Str "spaces:"]
-,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignRight,AlignLeft,AlignCenter,AlignDefault] [0.0,0.0,0.0,0.0]
- [[Plain [Str "Right"]]
- ,[Plain [Str "Left"]]
- ,[Plain [Str "Center"]]
- ,[Plain [Str "Default"]]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"]
-,Table [Str "Here's",Space,Str "the",Space,Str "caption.",SoftBreak,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.3375]
- [[Plain [Str "Centered",SoftBreak,Str "Header"]]
- ,[Plain [Str "Left",SoftBreak,Str "Aligned"]]
- ,[Plain [Str "Right",SoftBreak,Str "Aligned"]]
- ,[Plain [Str "Default",Space,Str "aligned"]]]
- [[[Plain [Str "First"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "12.0"]]
- ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",Space,Str "spans",SoftBreak,Str "multiple",Space,Str "lines."]]]
- ,[[Plain [Str "Second"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "5.0"]]
- ,[Plain [Str "Here's",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows."]]]]
-,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"]
-,Table [] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.3375]
- [[Plain [Str "Centered",SoftBreak,Str "Header"]]
- ,[Plain [Str "Left",SoftBreak,Str "Aligned"]]
- ,[Plain [Str "Right",SoftBreak,Str "Aligned"]]
- ,[Plain [Str "Default",Space,Str "aligned"]]]
- [[[Plain [Str "First"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "12.0"]]
- ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",Space,Str "spans",SoftBreak,Str "multiple",Space,Str "lines."]]]
- ,[[Plain [Str "Second"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "5.0"]]
- ,[Plain [Str "Here's",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows."]]]]
-,Para [Str "Table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
-,Table [] [AlignRight,AlignLeft,AlignCenter,AlignRight] [0.0,0.0,0.0,0.0]
- [[]
- ,[]
- ,[]
- ,[]]
- [[[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]
- ,[Plain [Str "12"]]]
- ,[[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]
- ,[Plain [Str "123"]]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "1"]]]]
-,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
-,Table [] [AlignCenter,AlignLeft,AlignRight,AlignDefault] [0.15,0.1375,0.1625,0.3375]
- [[]
- ,[]
- ,[]
- ,[]]
- [[[Plain [Str "First"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "12.0"]]
- ,[Plain [Str "Example",Space,Str "of",Space,Str "a",Space,Str "row",Space,Str "that",Space,Str "spans",SoftBreak,Str "multiple",Space,Str "lines."]]]
- ,[[Plain [Str "Second"]]
- ,[Plain [Str "row"]]
- ,[Plain [Str "5.0"]]
- ,[Plain [Str "Here's",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows."]]]]]
diff --git a/tests/tables.opendocument b/tests/tables.opendocument
deleted file mode 100644
index 0765bb783..000000000
--- a/tests/tables.opendocument
+++ /dev/null
@@ -1,397 +0,0 @@
-<text:p text:style-name="Text_20_body">Simple table with caption:</text:p>
-<table:table table:name="Table1" table:style-name="Table1">
- <table:table-column table:style-name="Table1.A" />
- <table:table-column table:style-name="Table1.B" />
- <table:table-column table:style-name="Table1.C" />
- <table:table-column table:style-name="Table1.D" />
- <table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="P1">Right</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Left</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="P2">Center</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Default</text:p>
- </table:table-cell>
- </table:table-row>
- </table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="P3">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="P4">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">12</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="P3">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="P4">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">123</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="P3">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="P4">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table1.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">1</text:p>
- </table:table-cell>
- </table:table-row>
-</table:table>
-<text:p text:style-name="Table">Demonstration of simple table syntax.</text:p>
-<text:p text:style-name="First_20_paragraph">Simple table without
-caption:</text:p>
-<table:table table:name="Table2" table:style-name="Table2">
- <table:table-column table:style-name="Table2.A" />
- <table:table-column table:style-name="Table2.B" />
- <table:table-column table:style-name="Table2.C" />
- <table:table-column table:style-name="Table2.D" />
- <table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="P5">Right</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Left</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="P6">Center</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Default</text:p>
- </table:table-cell>
- </table:table-row>
- </table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="P7">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="P8">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">12</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="P7">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="P8">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">123</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="P7">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="P8">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table2.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">1</text:p>
- </table:table-cell>
- </table:table-row>
-</table:table>
-<text:p text:style-name="First_20_paragraph">Simple table indented two
-spaces:</text:p>
-<table:table table:name="Table3" table:style-name="Table3">
- <table:table-column table:style-name="Table3.A" />
- <table:table-column table:style-name="Table3.B" />
- <table:table-column table:style-name="Table3.C" />
- <table:table-column table:style-name="Table3.D" />
- <table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="P9">Right</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Left</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="P10">Center</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Default</text:p>
- </table:table-cell>
- </table:table-row>
- </table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="P11">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="P12">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">12</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="P11">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="P12">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">123</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="P11">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="P12">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table3.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">1</text:p>
- </table:table-cell>
- </table:table-row>
-</table:table>
-<text:p text:style-name="Table">Demonstration of simple table syntax.</text:p>
-<text:p text:style-name="First_20_paragraph">Multiline table with
-caption:</text:p>
-<table:table table:name="Table4" table:style-name="Table4">
- <table:table-column table:style-name="Table4.A" />
- <table:table-column table:style-name="Table4.B" />
- <table:table-column table:style-name="Table4.C" />
- <table:table-column table:style-name="Table4.D" />
- <table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="P13">Centered Header</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Left Aligned</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="P14">Right Aligned</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Default aligned</text:p>
- </table:table-cell>
- </table:table-row>
- </table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="P15">First</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">row</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="P16">12.0</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">Example of a row that spans
- multiple lines.</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="P15">Second</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">row</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="P16">5.0</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table4.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">Here's another one. Note the
- blank line between rows.</text:p>
- </table:table-cell>
- </table:table-row>
-</table:table>
-<text:p text:style-name="Table">Here's the caption. It may span multiple
-lines.</text:p>
-<text:p text:style-name="First_20_paragraph">Multiline table without
-caption:</text:p>
-<table:table table:name="Table5" table:style-name="Table5">
- <table:table-column table:style-name="Table5.A" />
- <table:table-column table:style-name="Table5.B" />
- <table:table-column table:style-name="Table5.C" />
- <table:table-column table:style-name="Table5.D" />
- <table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="P17">Centered Header</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Left Aligned</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="P18">Right Aligned</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Heading">Default aligned</text:p>
- </table:table-cell>
- </table:table-row>
- </table:table-header-rows>
- <table:table-row>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="P19">First</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">row</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="P20">12.0</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">Example of a row that spans
- multiple lines.</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="P19">Second</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">row</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="P20">5.0</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table5.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">Here's another one. Note the
- blank line between rows.</text:p>
- </table:table-cell>
- </table:table-row>
-</table:table>
-<text:p text:style-name="First_20_paragraph">Table without column
-headers:</text:p>
-<table:table table:name="Table6" table:style-name="Table6">
- <table:table-column table:style-name="Table6.A" />
- <table:table-column table:style-name="Table6.B" />
- <table:table-column table:style-name="Table6.C" />
- <table:table-column table:style-name="Table6.D" />
- <table:table-row>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P24">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P25">12</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P26">12</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P24">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P25">123</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P26">123</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P24">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P25">1</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table6.A1" office:value-type="string">
- <text:p text:style-name="P26">1</text:p>
- </table:table-cell>
- </table:table-row>
-</table:table>
-<text:p text:style-name="First_20_paragraph">Multiline table without column
-headers:</text:p>
-<table:table table:name="Table7" table:style-name="Table7">
- <table:table-column table:style-name="Table7.A" />
- <table:table-column table:style-name="Table7.B" />
- <table:table-column table:style-name="Table7.C" />
- <table:table-column table:style-name="Table7.D" />
- <table:table-row>
- <table:table-cell table:style-name="Table7.A1" office:value-type="string">
- <text:p text:style-name="P29">First</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table7.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">row</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table7.A1" office:value-type="string">
- <text:p text:style-name="P30">12.0</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table7.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">Example of a row that spans
- multiple lines.</text:p>
- </table:table-cell>
- </table:table-row>
- <table:table-row>
- <table:table-cell table:style-name="Table7.A1" office:value-type="string">
- <text:p text:style-name="P29">Second</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table7.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">row</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table7.A1" office:value-type="string">
- <text:p text:style-name="P30">5.0</text:p>
- </table:table-cell>
- <table:table-cell table:style-name="Table7.A1" office:value-type="string">
- <text:p text:style-name="Table_20_Contents">Here's another one. Note the
- blank line between rows.</text:p>
- </table:table-cell>
- </table:table-row>
-</table:table>
diff --git a/tests/tables.plain b/tests/tables.plain
deleted file mode 100644
index 4b5754cf9..000000000
--- a/tests/tables.plain
+++ /dev/null
@@ -1,78 +0,0 @@
-Simple table with caption:
-
- Right Left Center Default
- ------- ------ -------- ---------
- 12 12 12 12
- 123 123 123 123
- 1 1 1 1
-
- : Demonstration of simple table syntax.
-
-Simple table without caption:
-
- Right Left Center Default
- ------- ------ -------- ---------
- 12 12 12 12
- 123 123 123 123
- 1 1 1 1
-
-Simple table indented two spaces:
-
- Right Left Center Default
- ------- ------ -------- ---------
- 12 12 12 12
- 123 123 123 123
- 1 1 1 1
-
- : Demonstration of simple table syntax.
-
-Multiline table with caption:
-
- --------------------------------------------------------------
- Centered Left Right Default aligned
- Header Aligned Aligned
- ----------- ---------- ------------ --------------------------
- First row 12.0 Example of a row that
- spans multiple lines.
-
- Second row 5.0 Here's another one. Note
- the blank line between
- rows.
- --------------------------------------------------------------
-
- : Here's the caption. It may span multiple lines.
-
-Multiline table without caption:
-
- --------------------------------------------------------------
- Centered Left Right Default aligned
- Header Aligned Aligned
- ----------- ---------- ------------ --------------------------
- First row 12.0 Example of a row that
- spans multiple lines.
-
- Second row 5.0 Here's another one. Note
- the blank line between
- rows.
- --------------------------------------------------------------
-
-Table without column headers:
-
- ----- ----- ----- -----
- 12 12 12 12
- 123 123 123 123
- 1 1 1 1
- ----- ----- ----- -----
-
-Multiline table without column headers:
-
- ----------- ---------- ------------ --------------------------
- First row 12.0 Example of a row that
- spans multiple lines.
-
- Second row 5.0 Here's another one. Note
- the blank line between
- rows.
- ----------- ---------- ------------ --------------------------
-
-
diff --git a/tests/tables.rst b/tests/tables.rst
deleted file mode 100644
index 25d5932ea..000000000
--- a/tests/tables.rst
+++ /dev/null
@@ -1,90 +0,0 @@
-Simple table with caption:
-
-+---------+--------+----------+-----------+
-| Right | Left | Center | Default |
-+=========+========+==========+===========+
-| 12 | 12 | 12 | 12 |
-+---------+--------+----------+-----------+
-| 123 | 123 | 123 | 123 |
-+---------+--------+----------+-----------+
-| 1 | 1 | 1 | 1 |
-+---------+--------+----------+-----------+
-
-Table: Demonstration of simple table syntax.
-
-Simple table without caption:
-
-+---------+--------+----------+-----------+
-| Right | Left | Center | Default |
-+=========+========+==========+===========+
-| 12 | 12 | 12 | 12 |
-+---------+--------+----------+-----------+
-| 123 | 123 | 123 | 123 |
-+---------+--------+----------+-----------+
-| 1 | 1 | 1 | 1 |
-+---------+--------+----------+-----------+
-
-Simple table indented two spaces:
-
-+---------+--------+----------+-----------+
-| Right | Left | Center | Default |
-+=========+========+==========+===========+
-| 12 | 12 | 12 | 12 |
-+---------+--------+----------+-----------+
-| 123 | 123 | 123 | 123 |
-+---------+--------+----------+-----------+
-| 1 | 1 | 1 | 1 |
-+---------+--------+----------+-----------+
-
-Table: Demonstration of simple table syntax.
-
-Multiline table with caption:
-
-+-------------+------------+--------------+----------------------------+
-| Centered | Left | Right | Default aligned |
-| Header | Aligned | Aligned | |
-+=============+============+==============+============================+
-| First | row | 12.0 | Example of a row that |
-| | | | spans multiple lines. |
-+-------------+------------+--------------+----------------------------+
-| Second | row | 5.0 | Here's another one. Note |
-| | | | the blank line between |
-| | | | rows. |
-+-------------+------------+--------------+----------------------------+
-
-Table: Here's the caption. It may span multiple lines.
-
-Multiline table without caption:
-
-+-------------+------------+--------------+----------------------------+
-| Centered | Left | Right | Default aligned |
-| Header | Aligned | Aligned | |
-+=============+============+==============+============================+
-| First | row | 12.0 | Example of a row that |
-| | | | spans multiple lines. |
-+-------------+------------+--------------+----------------------------+
-| Second | row | 5.0 | Here's another one. Note |
-| | | | the blank line between |
-| | | | rows. |
-+-------------+------------+--------------+----------------------------+
-
-Table without column headers:
-
-+-------+-------+-------+-------+
-| 12 | 12 | 12 | 12 |
-+-------+-------+-------+-------+
-| 123 | 123 | 123 | 123 |
-+-------+-------+-------+-------+
-| 1 | 1 | 1 | 1 |
-+-------+-------+-------+-------+
-
-Multiline table without column headers:
-
-+-------------+------------+--------------+----------------------------+
-| First | row | 12.0 | Example of a row that |
-| | | | spans multiple lines. |
-+-------------+------------+--------------+----------------------------+
-| Second | row | 5.0 | Here's another one. Note |
-| | | | the blank line between |
-| | | | rows. |
-+-------------+------------+--------------+----------------------------+
diff --git a/tests/tables.rtf b/tests/tables.rtf
deleted file mode 100644
index e1fe4aab1..000000000
--- a/tests/tables.rtf
+++ /dev/null
@@ -1,359 +0,0 @@
-{\pard \ql \f0 \sa180 \li0 \fi0 Simple table with caption:\par}
-{
-\trowd \trgaph120
-\clbrdrb\brdrs\cellx2160\clbrdrb\brdrs\cellx4320\clbrdrb\brdrs\cellx6480\clbrdrb\brdrs\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Center\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-}
-\intbl\row}
-{\pard \ql \f0 \sa180 \li0 \fi0 Demonstration of simple table syntax.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Simple table without caption:\par}
-{
-\trowd \trgaph120
-\clbrdrb\brdrs\cellx2160\clbrdrb\brdrs\cellx4320\clbrdrb\brdrs\cellx6480\clbrdrb\brdrs\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Center\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-}
-\intbl\row}
-{\pard \ql \f0 \sa180 \li0 \fi0 \par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Simple table indented two spaces:\par}
-{
-\trowd \trgaph120
-\clbrdrb\brdrs\cellx2160\clbrdrb\brdrs\cellx4320\clbrdrb\brdrs\cellx6480\clbrdrb\brdrs\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Center\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-}
-\intbl\row}
-{\pard \ql \f0 \sa180 \li0 \fi0 Demonstration of simple table syntax.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Multiline table with caption:\par}
-{
-\trowd \trgaph120
-\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6804
-\trkeep\intbl
-{
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Centered Header\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left Aligned\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right Aligned\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default aligned\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx1296\cellx2484\cellx3888\cellx6804
-\trkeep\intbl
-{
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12.0\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Example of a row that spans multiple lines.\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx1296\cellx2484\cellx3888\cellx6804
-\trkeep\intbl
-{
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 5.0\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Here's another one. Note the blank line between rows.\par}
-\cell}
-}
-\intbl\row}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here's the caption. It may span multiple lines.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Multiline table without caption:\par}
-{
-\trowd \trgaph120
-\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6804
-\trkeep\intbl
-{
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Centered Header\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Left Aligned\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 Right Aligned\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Default aligned\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx1296\cellx2484\cellx3888\cellx6804
-\trkeep\intbl
-{
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12.0\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Example of a row that spans multiple lines.\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx1296\cellx2484\cellx3888\cellx6804
-\trkeep\intbl
-{
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 5.0\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Here's another one. Note the blank line between rows.\par}
-\cell}
-}
-\intbl\row}
-{\pard \ql \f0 \sa180 \li0 \fi0 \par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Table without column headers:\par}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 123\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx2160\cellx4320\cellx6480\cellx8640
-\trkeep\intbl
-{
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 1\par}
-\cell}
-}
-\intbl\row}
-{\pard \ql \f0 \sa180 \li0 \fi0 \par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Multiline table without column headers:\par}
-{
-\trowd \trgaph120
-\cellx1296\cellx2484\cellx3888\cellx6804
-\trkeep\intbl
-{
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 12.0\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Example of a row that spans multiple lines.\par}
-\cell}
-}
-\intbl\row}
-{
-\trowd \trgaph120
-\cellx1296\cellx2484\cellx3888\cellx6804
-\trkeep\intbl
-{
-{{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 row\par}
-\cell}
-{{\pard\intbl \qr \f0 \sa0 \li0 \fi0 5.0\par}
-\cell}
-{{\pard\intbl \ql \f0 \sa0 \li0 \fi0 Here's another one. Note the blank line between rows.\par}
-\cell}
-}
-\intbl\row}
-{\pard \ql \f0 \sa180 \li0 \fi0 \par}
diff --git a/tests/tables.tei b/tests/tables.tei
deleted file mode 100644
index 45b88b1cb..000000000
--- a/tests/tables.tei
+++ /dev/null
@@ -1,171 +0,0 @@
-<p>Simple table with caption:</p>
-<table>
- <row role="label">
- <cell><p>Right</p></cell>
- <cell><p>Left</p></cell>
- <cell><p>Center</p></cell>
- <cell><p>Default</p></cell>
- </row>
- <row>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- </row>
- <row>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- </row>
- <row>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- </row>
-</table>
-<p>Simple table without caption:</p>
-<table>
- <row role="label">
- <cell><p>Right</p></cell>
- <cell><p>Left</p></cell>
- <cell><p>Center</p></cell>
- <cell><p>Default</p></cell>
- </row>
- <row>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- </row>
- <row>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- </row>
- <row>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- </row>
-</table>
-<p>Simple table indented two spaces:</p>
-<table>
- <row role="label">
- <cell><p>Right</p></cell>
- <cell><p>Left</p></cell>
- <cell><p>Center</p></cell>
- <cell><p>Default</p></cell>
- </row>
- <row>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- </row>
- <row>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- </row>
- <row>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- </row>
-</table>
-<p>Multiline table with caption:</p>
-<table>
- <row role="label">
- <cell><p>Centered Header</p></cell>
- <cell><p>Left Aligned</p></cell>
- <cell><p>Right Aligned</p></cell>
- <cell><p>Default aligned</p></cell>
- </row>
- <row>
- <cell><p>First</p></cell>
- <cell><p>row</p></cell>
- <cell><p>12.0</p></cell>
- <cell><p>Example of a row that spans multiple lines.</p></cell>
- </row>
- <row>
- <cell><p>Second</p></cell>
- <cell><p>row</p></cell>
- <cell><p>5.0</p></cell>
- <cell><p>Here's another one. Note the blank line between rows.</p></cell>
- </row>
-</table>
-<p>Multiline table without caption:</p>
-<table>
- <row role="label">
- <cell><p>Centered Header</p></cell>
- <cell><p>Left Aligned</p></cell>
- <cell><p>Right Aligned</p></cell>
- <cell><p>Default aligned</p></cell>
- </row>
- <row>
- <cell><p>First</p></cell>
- <cell><p>row</p></cell>
- <cell><p>12.0</p></cell>
- <cell><p>Example of a row that spans multiple lines.</p></cell>
- </row>
- <row>
- <cell><p>Second</p></cell>
- <cell><p>row</p></cell>
- <cell><p>5.0</p></cell>
- <cell><p>Here's another one. Note the blank line between rows.</p></cell>
- </row>
-</table>
-<p>Table without column headers:</p>
-<table>
- <row role="label">
- <cell></cell>
- <cell></cell>
- <cell></cell>
- <cell></cell>
- </row>
- <row>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- <cell><p>12</p></cell>
- </row>
- <row>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- <cell><p>123</p></cell>
- </row>
- <row>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- <cell><p>1</p></cell>
- </row>
-</table>
-<p>Multiline table without column headers:</p>
-<table>
- <row role="label">
- <cell></cell>
- <cell></cell>
- <cell></cell>
- <cell></cell>
- </row>
- <row>
- <cell><p>First</p></cell>
- <cell><p>row</p></cell>
- <cell><p>12.0</p></cell>
- <cell><p>Example of a row that spans multiple lines.</p></cell>
- </row>
- <row>
- <cell><p>Second</p></cell>
- <cell><p>row</p></cell>
- <cell><p>5.0</p></cell>
- <cell><p>Here's another one. Note the blank line between rows.</p></cell>
- </row>
-</table>
diff --git a/tests/tables.zimwiki b/tests/tables.zimwiki
deleted file mode 100644
index 1f02c9908..000000000
--- a/tests/tables.zimwiki
+++ /dev/null
@@ -1,56 +0,0 @@
-Simple table with caption:
-
-Demonstration of simple table syntax.
-| Right|Left | Center |Default|
-|------:|:-----|:--------:|-------|
-| 12|12 | 12 |12 |
-| 123|123 | 123 |123 |
-| 1|1 | 1 |1 |
-
-Simple table without caption:
-
-| Right|Left | Center |Default|
-|------:|:-----|:--------:|-------|
-| 12|12 | 12 |12 |
-| 123|123 | 123 |123 |
-| 1|1 | 1 |1 |
-
-Simple table indented two spaces:
-
-Demonstration of simple table syntax.
-| Right|Left | Center |Default|
-|------:|:-----|:--------:|-------|
-| 12|12 | 12 |12 |
-| 123|123 | 123 |123 |
-| 1|1 | 1 |1 |
-
-Multiline table with caption:
-
-Here's the caption. It may span multiple lines.
-| Centered Header |Left Aligned | Right Aligned|Default aligned |
-|:-----------------:|:-------------|--------------:|:------------------------------------------------------|
-| First |row | 12.0|Example of a row that spans multiple lines. |
-| Second |row | 5.0|Here's another one. Note the blank line between rows. |
-
-Multiline table without caption:
-
-| Centered Header |Left Aligned | Right Aligned|Default aligned |
-|:-----------------:|:-------------|--------------:|:------------------------------------------------------|
-| First |row | 12.0|Example of a row that spans multiple lines. |
-| Second |row | 5.0|Here's another one. Note the blank line between rows. |
-
-Table without column headers:
-
-| 12|12 | 12 | 12|
-|----:|:----|:-----:|----:|
-| 12|12 | 12 | 12|
-| 123|123 | 123 | 123|
-| 1|1 | 1 | 1|
-
-Multiline table without column headers:
-
-| First |row | 12.0|Example of a row that spans multiple lines. |
-|:--------:|:----|-----:|-----------------------------------------------------|
-| First |row | 12.0|Example of a row that spans multiple lines. |
-| Second |row | 5.0|Here's another one. Note the blank line between rows.|
-
diff --git a/tests/test-pandoc.hs b/tests/test-pandoc.hs
deleted file mode 100644
index 2488917cb..000000000
--- a/tests/test-pandoc.hs
+++ /dev/null
@@ -1,67 +0,0 @@
-{-# OPTIONS_GHC -Wall #-}
-
-module Main where
-
-import Test.Framework
-import GHC.IO.Encoding
-import qualified Tests.Old
-import qualified Tests.Readers.LaTeX
-import qualified Tests.Readers.Markdown
-import qualified Tests.Readers.Org
-import qualified Tests.Readers.HTML
-import qualified Tests.Readers.RST
-import qualified Tests.Readers.Docx
-import qualified Tests.Readers.Odt
-import qualified Tests.Readers.Txt2Tags
-import qualified Tests.Readers.EPUB
-import qualified Tests.Writers.ConTeXt
-import qualified Tests.Writers.LaTeX
-import qualified Tests.Writers.HTML
-import qualified Tests.Writers.Docbook
-import qualified Tests.Writers.Native
-import qualified Tests.Writers.Markdown
-import qualified Tests.Writers.Plain
-import qualified Tests.Writers.AsciiDoc
-import qualified Tests.Writers.Docx
-import qualified Tests.Writers.RST
-import qualified Tests.Writers.TEI
-import qualified Tests.Shared
-import qualified Tests.Walk
-import Text.Pandoc.Shared (inDirectory)
-import System.Environment (getArgs)
-
-tests :: [Test]
-tests = [ testGroup "Old" Tests.Old.tests
- , testGroup "Shared" Tests.Shared.tests
- , testGroup "Walk" Tests.Walk.tests
- , testGroup "Writers"
- [ testGroup "Native" Tests.Writers.Native.tests
- , testGroup "ConTeXt" Tests.Writers.ConTeXt.tests
- , testGroup "LaTeX" Tests.Writers.LaTeX.tests
- , testGroup "HTML" Tests.Writers.HTML.tests
- , testGroup "Docbook" Tests.Writers.Docbook.tests
- , testGroup "Markdown" Tests.Writers.Markdown.tests
- , testGroup "Plain" Tests.Writers.Plain.tests
- , testGroup "AsciiDoc" Tests.Writers.AsciiDoc.tests
- , testGroup "Docx" Tests.Writers.Docx.tests
- , testGroup "RST" Tests.Writers.RST.tests
- , testGroup "TEI" Tests.Writers.TEI.tests
- ]
- , testGroup "Readers"
- [ testGroup "LaTeX" Tests.Readers.LaTeX.tests
- , testGroup "Markdown" Tests.Readers.Markdown.tests
- , testGroup "HTML" Tests.Readers.HTML.tests
- , testGroup "Org" Tests.Readers.Org.tests
- , testGroup "RST" Tests.Readers.RST.tests
- , testGroup "Docx" Tests.Readers.Docx.tests
- , testGroup "Odt" Tests.Readers.Odt.tests
- , testGroup "Txt2Tags" Tests.Readers.Txt2Tags.tests
- , testGroup "EPUB" Tests.Readers.EPUB.tests
- ]
- ]
-
-main :: IO ()
-main = do
- setLocaleEncoding utf8
- args <- getArgs
- inDirectory "tests" $ defaultMainWithArgs tests args
diff --git a/tests/testsuite.native b/tests/testsuite.native
deleted file mode 100644
index fa234dfc2..000000000
--- a/tests/testsuite.native
+++ /dev/null
@@ -1,411 +0,0 @@
-Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
-[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",SoftBreak,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
-,HorizontalRule
-,Header 1 ("headers",[],[]) [Str "Headers"]
-,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
-,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
-,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
-,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
-,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
-,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
-,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,HorizontalRule
-,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
-,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",SoftBreak,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",SoftBreak,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",SoftBreak,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",SoftBreak,Str "list",Space,Str "item."]
-,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",SoftBreak,Str "*",Space,Str "criminey."]
-,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
-,HorizontalRule
-,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
-,Para [Str "E-mail",Space,Str "style:"]
-,BlockQuote
- [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",SoftBreak,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
-,BlockQuote
- [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
- ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
- ,Para [Str "A",Space,Str "list:"]
- ,OrderedList (1,Decimal,Period)
- [[Plain [Str "item",Space,Str "one"]]
- ,[Plain [Str "item",Space,Str "two"]]]
- ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
- ,BlockQuote
- [Para [Str "nested"]]
- ,BlockQuote
- [Para [Str "nested"]]]
-,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",SoftBreak,Str ">",Space,Str "1."]
-,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
-,HorizontalRule
-,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
-,Para [Str "And:"]
-,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
-,HorizontalRule
-,Header 1 ("lists",[],[]) [Str "Lists"]
-,Header 2 ("unordered",[],[]) [Str "Unordered"]
-,Para [Str "Asterisks",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "asterisk",Space,Str "1"]]
- ,[Plain [Str "asterisk",Space,Str "2"]]
- ,[Plain [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Asterisks",Space,Str "loose:"]
-,BulletList
- [[Para [Str "asterisk",Space,Str "1"]]
- ,[Para [Str "asterisk",Space,Str "2"]]
- ,[Para [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "Plus",Space,Str "1"]]
- ,[Plain [Str "Plus",Space,Str "2"]]
- ,[Plain [Str "Plus",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "loose:"]
-,BulletList
- [[Para [Str "Plus",Space,Str "1"]]
- ,[Para [Str "Plus",Space,Str "2"]]
- ,[Para [Str "Plus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "Minus",Space,Str "1"]]
- ,[Plain [Str "Minus",Space,Str "2"]]
- ,[Plain [Str "Minus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "loose:"]
-,BulletList
- [[Para [Str "Minus",Space,Str "1"]]
- ,[Para [Str "Minus",Space,Str "2"]]
- ,[Para [Str "Minus",Space,Str "3"]]]
-,Header 2 ("ordered",[],[]) [Str "Ordered"]
-,Para [Str "Tight:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second"]]
- ,[Plain [Str "Third"]]]
-,Para [Str "and:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "One"]]
- ,[Plain [Str "Two"]]
- ,[Plain [Str "Three"]]]
-,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "First"]]
- ,[Para [Str "Second"]]
- ,[Para [Str "Third"]]]
-,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "One"]]
- ,[Para [Str "Two"]]
- ,[Para [Str "Three"]]]
-,Para [Str "Multiple",Space,Str "paragraphs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
- ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",SoftBreak,Str "back."]]
- ,[Para [Str "Item",Space,Str "2."]]
- ,[Para [Str "Item",Space,Str "3."]]]
-,Header 2 ("nested",[],[]) [Str "Nested"]
-,BulletList
- [[Plain [Str "Tab"]
- ,BulletList
- [[Plain [Str "Tab"]
- ,BulletList
- [[Plain [Str "Tab"]]]]]]]
-,Para [Str "Here\8217s",Space,Str "another:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second:"]
- ,BulletList
- [[Plain [Str "Fee"]]
- ,[Plain [Str "Fie"]]
- ,[Plain [Str "Foe"]]]]
- ,[Plain [Str "Third"]]]
-,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "First"]]
- ,[Para [Str "Second:"]
- ,BulletList
- [[Plain [Str "Fee"]]
- ,[Plain [Str "Fie"]]
- ,[Plain [Str "Foe"]]]]
- ,[Para [Str "Third"]]]
-,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
-,BulletList
- [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "tabs"]]
- ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "spaces"]
- ,BulletList
- [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "tabs"]]
- ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
-,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
-,OrderedList (2,Decimal,TwoParens)
- [[Plain [Str "begins",Space,Str "with",Space,Str "2"]]
- ,[Para [Str "and",Space,Str "now",Space,Str "3"]
- ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
- ,OrderedList (4,LowerRoman,Period)
- [[Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",SoftBreak,Str "starting",Space,Str "with",Space,Str "4"]]
- ,[Plain [Str "more",Space,Str "items"]
- ,OrderedList (1,UpperAlpha,TwoParens)
- [[Plain [Str "a",Space,Str "subsublist"]]
- ,[Plain [Str "a",Space,Str "subsublist"]]]]]]]
-,Para [Str "Nesting:"]
-,OrderedList (1,UpperAlpha,Period)
- [[Plain [Str "Upper",Space,Str "Alpha"]
- ,OrderedList (1,UpperRoman,Period)
- [[Plain [Str "Upper",Space,Str "Roman."]
- ,OrderedList (6,Decimal,TwoParens)
- [[Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
- ,OrderedList (3,LowerAlpha,OneParen)
- [[Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
-,Para [Str "Autonumbering:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "Autonumber."]]
- ,[Plain [Str "More."]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "Nested."]]]]]
-,Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
-,Para [Str "M.A.\160\&2007"]
-,Para [Str "B.",Space,Str "Williams"]
-,HorizontalRule
-,Header 1 ("definition-lists",[],[]) [Str "Definition",Space,Str "Lists"]
-,Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
-,DefinitionList
- [([Str "apple"],
- [[Plain [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Plain [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Plain [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
-,DefinitionList
- [([Str "apple"],
- [[Plain [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Plain [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Plain [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Loose:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Para [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
-,DefinitionList
- [([Emph [Str "apple"]],
- [[Para [Str "red",Space,Str "fruit"]
- ,Para [Str "contains",Space,Str "seeds,",SoftBreak,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"]]])
- ,([Emph [Str "orange"]],
- [[Para [Str "orange",Space,Str "fruit"]
- ,CodeBlock ("",[],[]) "{ orange code block }"
- ,BlockQuote
- [Para [Str "orange",Space,Str "block",Space,Str "quote"]]]])]
-,Para [Str "Multiple",Space,Str "definitions,",Space,Str "tight:"]
-,DefinitionList
- [([Str "apple"],
- [[Plain [Str "red",Space,Str "fruit"]]
- ,[Plain [Str "computer"]]])
- ,([Str "orange"],
- [[Plain [Str "orange",Space,Str "fruit"]]
- ,[Plain [Str "bank"]]])]
-,Para [Str "Multiple",Space,Str "definitions,",Space,Str "loose:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]
- ,[Para [Str "computer"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]]
- ,[Para [Str "bank"]]])]
-,Para [Str "Blank",Space,Str "line",Space,Str "after",Space,Str "term,",Space,Str "indented",Space,Str "marker,",Space,Str "alternate",Space,Str "markers:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]
- ,[Para [Str "computer"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]
- ,OrderedList (1,Decimal,Period)
- [[Plain [Str "sublist"]]
- ,[Plain [Str "sublist"]]]]])]
-,Header 1 ("html-blocks",[],[]) [Str "HTML",Space,Str "Blocks"]
-,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
-,Div ("",[],[])
- [Plain [Str "foo"]]
-,Para [Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
-,Div ("",[],[])
- [Div ("",[],[])
- [Div ("",[],[])
- [Para [Str "foo"]]]
- ,Div ("",[],[])
- [Plain [Str "bar"]]]
-,Para [Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
-,RawBlock (Format "html") "<table>"
-,RawBlock (Format "html") "<tr>"
-,RawBlock (Format "html") "<td>"
-,Plain [Str "This",Space,Str "is",Space,Emph [Str "emphasized"]]
-,RawBlock (Format "html") "</td>"
-,RawBlock (Format "html") "<td>"
-,Plain [Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"]]
-,RawBlock (Format "html") "</td>"
-,RawBlock (Format "html") "</tr>"
-,RawBlock (Format "html") "</table>"
-,RawBlock (Format "html") "<script type=\"text/javascript\">document.write('This *should not* be interpreted as markdown');</script>"
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
-,Div ("",[],[])
- [Para [Str "foo"]]
-,Para [Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
-,CodeBlock ("",[],[]) "<div>\n foo\n</div>"
-,Para [Str "As",Space,Str "should",Space,Str "this:"]
-,CodeBlock ("",[],[]) "<div>foo</div>"
-,Para [Str "Now,",Space,Str "nested:"]
-,Div ("",[],[])
- [Div ("",[],[])
- [Div ("",[],[])
- [Plain [Str "foo"]]]]
-,Para [Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
-,RawBlock (Format "html") "<!-- Comment -->"
-,Para [Str "Multiline:"]
-,RawBlock (Format "html") "<!--\nBlah\nBlah\n-->"
-,RawBlock (Format "html") "<!--\n This is another comment.\n-->"
-,Para [Str "Code",Space,Str "block:"]
-,CodeBlock ("",[],[]) "<!-- Comment -->"
-,Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
-,RawBlock (Format "html") "<!-- foo -->"
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) "<hr />"
-,Para [Str "Hr\8217s:"]
-,RawBlock (Format "html") "<hr>"
-,RawBlock (Format "html") "<hr />"
-,RawBlock (Format "html") "<hr />"
-,RawBlock (Format "html") "<hr>"
-,RawBlock (Format "html") "<hr />"
-,RawBlock (Format "html") "<hr />"
-,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\" />"
-,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\" />"
-,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\">"
-,HorizontalRule
-,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
-,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
-,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
-,Para [Str "An",Space,Emph [Link ("",[],[]) [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
-,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
-,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
-,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
-,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
-,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
-,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
-,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello\160there"],Str "."]
-,Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",Space,Str "H",Subscript [Str "many\160of\160them"],Str "O."]
-,Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",SoftBreak,Str "because",Space,Str "of",Space,Str "the",Space,Str "unescaped",Space,Str "spaces:",Space,Str "a^b",Space,Str "c^d,",Space,Str "a~b",Space,Str "c~d."]
-,HorizontalRule
-,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
-,Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
-,Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
-,Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",SoftBreak,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine."]]
-,Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",SoftBreak,Str "70\8217s?"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code ("",[],[]) "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
-,Para [Str "Some",Space,Str "dashes:",Space,Str "one\8212two",Space,Str "\8212",Space,Str "three\8212four",Space,Str "\8212",Space,Str "five."]
-,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5\8211\&7,",Space,Str "255\8211\&66,",Space,Str "1987\8211\&1999."]
-,Para [Str "Ellipses\8230and\8230and\8230."]
-,HorizontalRule
-,Header 1 ("latex",[],[]) [Str "LaTeX"]
-,BulletList
- [[Plain [RawInline (Format "tex") "\\cite[22-23]{smith.1899}"]]
- ,[Plain [Math InlineMath "2+2=4"]]
- ,[Plain [Math InlineMath "x \\in y"]]
- ,[Plain [Math InlineMath "\\alpha \\wedge \\omega"]]
- ,[Plain [Math InlineMath "223"]]
- ,[Plain [Math InlineMath "p",Str "-Tree"]]
- ,[Plain [Str "Here\8217s",Space,Str "some",Space,Str "display",Space,Str "math:",SoftBreak,Math DisplayMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"]]
- ,[Plain [Str "Here\8217s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."]]]
-,Para [Str "These",Space,Str "shouldn\8217t",Space,Str "be",Space,Str "math:"]
-,BulletList
- [[Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code ("",[],[]) "$e = mc^2$",Str "."]]
- ,[Plain [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",SoftBreak,Str "(It",Space,Str "worked",Space,Str "if",Space,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized.)"]]
- ,[Plain [Str "Shoes",Space,Str "($20)",Space,Str "and",Space,Str "socks",Space,Str "($5)."]]
- ,[Plain [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
-,RawBlock (Format "latex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"
-,HorizontalRule
-,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
-,BulletList
- [[Plain [Str "I",Space,Str "hat:",Space,Str "\206"]]
- ,[Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
- ,[Plain [Str "section:",Space,Str "\167"]]
- ,[Plain [Str "set",Space,Str "membership:",Space,Str "\8712"]]
- ,[Plain [Str "copyright:",Space,Str "\169"]]]
-,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
-,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
-,Para [Str "This",Space,Str "&",Space,Str "that."]
-,Para [Str "4",Space,Str "<",Space,Str "5."]
-,Para [Str "6",Space,Str ">",Space,Str "5."]
-,Para [Str "Backslash:",Space,Str "\\"]
-,Para [Str "Backtick:",Space,Str "`"]
-,Para [Str "Asterisk:",Space,Str "*"]
-,Para [Str "Underscore:",Space,Str "_"]
-,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
-,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
-,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
-,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
-,Para [Str "Left",Space,Str "paren:",Space,Str "("]
-,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
-,Para [Str "Greater-than:",Space,Str ">"]
-,Para [Str "Hash:",Space,Str "#"]
-,Para [Str "Period:",Space,Str "."]
-,Para [Str "Bang:",Space,Str "!"]
-,Para [Str "Plus:",Space,Str "+"]
-,Para [Str "Minus:",Space,Str "-"]
-,HorizontalRule
-,Header 1 ("links",[],[]) [Str "Links"]
-,Header 2 ("explicit",[],[]) [Str "Explicit"]
-,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
-,Para [Link ("",[],[]) [Str "with_underscore"] ("/url/with_underscore","")]
-,Para [Link ("",[],[]) [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
-,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
-,Header 2 ("reference",[],[]) [Str "Reference"]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
-,Para [Str "This",Space,Str "should",Space,Str "[not][]",Space,Str "be",Space,Str "a",Space,Str "link."]
-,CodeBlock ("",[],[]) "[not]: /url"
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
-,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
-,Para [Str "Here\8217s",Space,Str "a",Space,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link ("",[],[]) [Str "AT&T"] ("http://att.com/","AT&T"),Str "."]
-,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
-,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
-,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
-,BulletList
- [[Plain [Str "In",Space,Str "a",Space,Str "list?"]]
- ,[Plain [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
- ,[Plain [Str "It",Space,Str "should."]]]
-,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
-,BlockQuote
- [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
-,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
-,CodeBlock ("",[],[]) "or here: <http://example.com/>"
-,HorizontalRule
-,Header 1 ("images",[],[]) [Str "Images"]
-,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
-,Para [Image ("",[],[]) [Str "lalune"] ("lalune.jpg","fig:Voyage dans la Lune")]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
-,HorizontalRule
-,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",SoftBreak,Str "reference.",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document."]],Space,Str "and",Space,Str "another.",Note [Para [Str "Here\8217s",Space,Str "the",Space,Str "long",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",SoftBreak,Str "blocks."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",SoftBreak,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",SoftBreak,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block."]],SoftBreak,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",SoftBreak,Str "contains",Space,Str "a",Space,Str "space.[^my",Space,Str "note]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note.",Note [Para [Str "This",SoftBreak,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type.",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",SoftBreak,Link ("",[],[]) [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code ("",[],[]) "]",Space,Str "verbatim",Space,Str "characters,",SoftBreak,Str "as",Space,Str "well",Space,Str "as",Space,Str "[bracketed",Space,Str "text]."]]]
-,BlockQuote
- [Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes.",Note [Para [Str "In",Space,Str "quote."]]]]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]]]]
-,Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented."]]
diff --git a/tests/testsuite.txt b/tests/testsuite.txt
deleted file mode 100644
index f6b0a7c95..000000000
--- a/tests/testsuite.txt
+++ /dev/null
@@ -1,730 +0,0 @@
-% Pandoc Test Suite
-% John MacFarlane; Anonymous
-% July 17, 2006
-
-This is a set of tests for pandoc. Most of them are adapted from
-John Gruber's markdown test suite.
-
------
-
-# Headers
-
-## Level 2 with an [embedded link](/url)
-
-### Level 3 with *emphasis*
-
-#### Level 4
-
-##### Level 5
-
-Level 1
-=======
-
-Level 2 with *emphasis*
------------------------
-
-### Level 3
-with no blank line
-
-Level 2
--------
-with no blank line
-
-----------
-
-# Paragraphs
-
-Here's a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version
-8. This line turns into a list item.
-Because a hard-wrapped line in the
-middle of a paragraph looked like a
-list item.
-
-Here's one with a bullet.
-* criminey.
-
-There should be a hard line break
-here.
-
----
-
-# Block Quotes
-
-E-mail style:
-
-> This is a block quote.
-> It is pretty short.
-
-> Code in a block quote:
->
-> sub status {
-> print "working";
-> }
->
-> A list:
->
-> 1. item one
-> 2. item two
->
-> Nested block quotes:
->
-> > nested
->
->> nested
->
-
-This should not be a block quote: 2
-> 1.
-
-And a following paragraph.
-
-* * * *
-
-# Code Blocks
-
-Code:
-
- ---- (should be four hyphens)
-
- sub status {
- print "working";
- }
-
- this code block is indented by one tab
-
-And:
-
- this code block is indented by two tabs
-
- These should not be escaped: \$ \\ \> \[ \{
-
-___________
-
-# Lists
-
-## Unordered
-
-Asterisks tight:
-
-* asterisk 1
-* asterisk 2
-* asterisk 3
-
-Asterisks loose:
-
-* asterisk 1
-
-* asterisk 2
-
-* asterisk 3
-
-Pluses tight:
-
-+ Plus 1
-+ Plus 2
-+ Plus 3
-
-Pluses loose:
-
-+ Plus 1
-
-+ Plus 2
-
-+ Plus 3
-
-Minuses tight:
-
-- Minus 1
-- Minus 2
-- Minus 3
-
-Minuses loose:
-
-- Minus 1
-
-- Minus 2
-
-- Minus 3
-
-## Ordered
-
-Tight:
-
-1. First
-2. Second
-3. Third
-
-and:
-
-1. One
-2. Two
-3. Three
-
-Loose using tabs:
-
-1. First
-
-2. Second
-
-3. Third
-
-and using spaces:
-
-1. One
-
-2. Two
-
-3. Three
-
-Multiple paragraphs:
-
-1. Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog's
- back.
-
-2. Item 2.
-
-3. Item 3.
-
-## Nested
-
-* Tab
- * Tab
- * Tab
-
-Here's another:
-
-1. First
-2. Second:
- * Fee
- * Fie
- * Foe
-3. Third
-
-Same thing but with paragraphs:
-
-1. First
-
-2. Second:
-
- * Fee
- * Fie
- * Foe
-
-3. Third
-
-## Tabs and spaces
-
-+ this is a list item
- indented with tabs
-
-+ this is a list item
- indented with spaces
-
- + this is an example list item
- indented with tabs
-
- + this is an example list item
- indented with spaces
-
-## Fancy list markers
-
-(2) begins with 2
-(3) and now 3
-
- with a continuation
-
- iv. sublist with roman numerals,
- starting with 4
- v. more items
- (A) a subsublist
- (B) a subsublist
-
-Nesting:
-
-A. Upper Alpha
- I. Upper Roman.
- (6) Decimal start with 6
- c) Lower alpha with paren
-
-Autonumbering:
-
- #. Autonumber.
- #. More.
- #. Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
- * * * * *
-
-# Definition Lists
-
-Tight using spaces:
-
-apple
-: red fruit
-
-orange
-: orange fruit
-
-banana
-: yellow fruit
-
-Tight using tabs:
-
-apple
-: red fruit
-
-orange
-: orange fruit
-
-banana
-: yellow fruit
-
-Loose:
-
-apple
-
-: red fruit
-
-orange
-
-: orange fruit
-
-banana
-
-: yellow fruit
-
-Multiple blocks with italics:
-
-*apple*
-
-: red fruit
-
- contains seeds,
- crisp, pleasant to taste
-
-*orange*
-
-: orange fruit
-
- { orange code block }
-
- > orange block quote
-
-Multiple definitions, tight:
-
-apple
-: red fruit
-: computer
-
-orange
-: orange fruit
-: bank
-
-Multiple definitions, loose:
-
-apple
-
-: red fruit
-
-: computer
-
-orange
-
-: orange fruit
-
-: bank
-
-Blank line after term, indented marker, alternate markers:
-
-apple
-
- ~ red fruit
-
- ~ computer
-
-orange
-
- ~ orange fruit
-
- 1. sublist
- 2. sublist
-
-# HTML Blocks
-
-Simple block on one line:
-
-<div>foo</div>
-
-And nested without indentation:
-
-<div>
-<div>
-<div>
-foo
-</div>
-</div>
-<div>bar</div>
-</div>
-
-Interpreted markdown in a table:
-
-<table>
-<tr>
-<td>This is *emphasized*</td>
-<td>And this is **strong**</td>
-</tr>
-</table>
-
-<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
-
-Here's a simple block:
-
-<div>
-foo
-</div>
-
-This should be a code block, though:
-
- <div>
- foo
- </div>
-
-As should this:
-
- <div>foo</div>
-
-Now, nested:
-
-<div>
- <div>
- <div>
- foo
- </div>
- </div>
-</div>
-
-This should just be an HTML comment:
-
-<!-- Comment -->
-
-Multiline:
-
-<!--
-Blah
-Blah
--->
-
-<!--
- This is another comment.
--->
-
-Code block:
-
- <!-- Comment -->
-
-Just plain comment, with trailing spaces on the line:
-
-<!-- foo -->
-
-Code:
-
- <hr />
-
-Hr's:
-
-<hr>
-
-<hr />
-
-<hr />
-
-<hr>
-
-<hr />
-
-<hr />
-
-<hr class="foo" id="bar" />
-
-<hr class="foo" id="bar" />
-
-<hr class="foo" id="bar">
-
------
-
-# Inline Markup
-
-This is *emphasized*, and so _is this_.
-
-This is **strong**, and so __is this__.
-
-An *[emphasized link](/url)*.
-
-***This is strong and em.***
-
-So is ***this*** word.
-
-___This is strong and em.___
-
-So is ___this___ word.
-
-This is code: `>`, `$`, `\`, `\$`, `<html>`.
-
-~~This is *strikeout*.~~
-
-Superscripts: a^bc^d a^*hello*^ a^hello\ there^.
-
-Subscripts: H~2~O, H~23~O, H~many\ of\ them~O.
-
-These should not be superscripts or subscripts,
-because of the unescaped spaces: a^b c^d, a~b c~d.
-
------
-
-# Smart quotes, ellipses, dashes
-
-"Hello," said the spider. "'Shelob' is my name."
-
-'A', 'B', and 'C' are letters.
-
-'Oak,' 'elm,' and 'beech' are names of trees.
-So is 'pine.'
-
-'He said, "I want to go."' Were you alive in the
-70's?
-
-Here is some quoted '`code`' and a "[quoted link][1]".
-
-Some dashes: one---two --- three---four --- five.
-
-Dashes between numbers: 5--7, 255--66, 1987--1999.
-
-Ellipses...and...and....
-
------
-
-# LaTeX
-
-- \cite[22-23]{smith.1899}
-- $2+2=4$
-- $x \in y$
-- $\alpha \wedge \omega$
-- $223$
-- $p$-Tree
-- Here's some display math:
- $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
-- Here's one that has a line break in it: $\alpha + \omega \times
-x^2$.
-
-These shouldn't be math:
-
-- To get the famous equation, write `$e = mc^2$`.
-- $22,000 is a *lot* of money. So is $34,000.
- (It worked if "lot" is emphasized.)
-- Shoes ($20) and socks ($5).
-- Escaped `$`: $73 *this should be emphasized* 23\$.
-
-Here's a LaTeX table:
-
-\begin{tabular}{|l|l|}\hline
-Animal & Number \\ \hline
-Dog & 2 \\
-Cat & 1 \\ \hline
-\end{tabular}
-
-* * * * *
-
-# Special Characters
-
-Here is some unicode:
-
-- I hat: Î
-- o umlaut: ö
-- section: §
-- set membership: ∈
-- copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&amp;T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \\
-
-Backtick: \`
-
-Asterisk: \*
-
-Underscore: \_
-
-Left brace: \{
-
-Right brace: \}
-
-Left bracket: \[
-
-Right bracket: \]
-
-Left paren: \(
-
-Right paren: \)
-
-Greater-than: \>
-
-Hash: \#
-
-Period: \.
-
-Bang: \!
-
-Plus: \+
-
-Minus: \-
-
-- - - - - - - - - - - - -
-
-# Links
-
-## Explicit
-
-Just a [URL](/url/).
-
-[URL and title](/url/ "title").
-
-[URL and title](/url/ "title preceded by two spaces").
-
-[URL and title](/url/ "title preceded by a tab").
-
-[URL and title](/url/ "title with "quotes" in it")
-
-[URL and title](/url/ 'title with single quotes')
-
-[with\_underscore](/url/with_underscore)
-
-[Email link](mailto:nobody@nowhere.net)
-
-[Empty]().
-
-## Reference
-
-Foo [bar] [a].
-
-Foo [bar][a].
-
-Foo [bar]
-[a].
-
-[a]: /url/
-
-With [embedded [brackets]] [b].
-
-[b] by itself should be a link.
-
-Indented [once][].
-
-Indented [twice][].
-
-Indented [thrice][].
-
-This should [not][] be a link.
-
- [once]: /url
- [twice]: /url
-
- [thrice]: /url
-
- [not]: /url
-
-[b]: /url/
-
-Foo [bar][].
-
-Foo [biz](/url/ "Title with "quote" inside").
-
- [bar]: /url/ "Title with "quotes" inside"
-
-## With ampersands
-
-Here's a [link with an ampersand in the URL] [1].
-
-Here's a link with an amersand in the link text: [AT&T] [2].
-
-Here's an [inline link](/script?foo=1&bar=2).
-
-Here's an [inline link in pointy braces](</script?foo=1&bar=2>).
-
-[1]: http://example.com/?foo=1&bar=2
-[2]: http://att.com/ "AT&T"
-
-## Autolinks
-
-With an ampersand: <http://example.com/?foo=1&bar=2>
-
-* In a list?
-* <http://example.com/>
-* It should.
-
-An e-mail address: <nobody@nowhere.net>
-
-> Blockquoted: <http://example.com/>
-
-Auto-links should not occur here: `<http://example.com/>`
-
- or here: <http://example.com/>
-
-----
-
-# Images
-
-From "Voyage dans la Lune" by Georges Melies (1902):
-
-![lalune][]
-
- [lalune]: lalune.jpg "Voyage dans la Lune"
-
-Here is a movie ![movie](movie.jpg) icon.
-
-----
-
-# Footnotes
-
-Here is a footnote reference,[^1] and another.[^longnote]
-This should *not* be a footnote reference, because it
-contains a space.[^my note] Here is an inline note.^[This
-is *easier* to type. Inline notes may contain
-[links](http://google.com) and `]` verbatim characters,
-as well as [bracketed text].]
-
-> Notes can go in quotes.^[In quote.]
-
-1. And in list items.^[In list.]
-
-[^longnote]: Here's the long note. This one contains multiple
-blocks.
-
- Subsequent blocks are indented to show that they belong to the
-footnote (as with list items).
-
- { <code> }
-
- If you want, you can indent every line, but you can also be
- lazy and just indent the first line of each block.
-
-This paragraph should not be part of the note, as it is not indented.
-
- [^1]: Here is the footnote. It can go anywhere after the footnote
- reference. It need not be placed at the end of the document.
diff --git a/tests/textile-reader.native b/tests/textile-reader.native
deleted file mode 100644
index c617a53f5..000000000
--- a/tests/textile-reader.native
+++ /dev/null
@@ -1,176 +0,0 @@
-Pandoc (Meta {unMeta = fromList []})
-[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc",Space,Str "Textile",Space,Str "Reader.",Space,Str "Part",Space,Str "of",Space,Str "it",Space,Str "comes",LineBreak,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
-,HorizontalRule
-,Header 1 ("headers",[],[]) [Str "Headers"]
-,Header 2 ("level-2-with-an-embeded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embeded",Space,Str "link"] ("http://www.example.com","")]
-,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Strong [Str "emphasis"]]
-,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
-,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
-,Header 6 ("level-6",[],[]) [Str "Level",Space,Str "6"]
-,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
-,Para [Str "Here's",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
-,Para [Str "Line",Space,Str "breaks",Space,Str "are",Space,Str "preserved",Space,Str "in",Space,Str "textile,",Space,Str "so",Space,Str "you",Space,Str "can",Space,Str "not",Space,Str "wrap",Space,Str "your",Space,Str "very",LineBreak,Str "long",Space,Str "paragraph",Space,Str "with",Space,Str "your",Space,Str "favourite",Space,Str "text",Space,Str "editor",Space,Str "and",Space,Str "have",Space,Str "it",Space,Str "rendered",LineBreak,Str "with",Space,Str "no",Space,Str "break."]
-,Para [Str "Here's",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet."]
-,BulletList
- [[Plain [Str "criminey."]]]
-,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "paragraph",Space,Str "break",Space,Str "between",Space,Str "here"]
-,Para [Str "and",Space,Str "here."]
-,Para [Str "pandoc",Space,Str "converts",Space,Str "textile."]
-,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
-,BlockQuote
- [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "famous",Space,Str "quote",Space,Str "from",Space,Str "somebody.",Space,Str "He",Space,Str "had",Space,Str "a",Space,Str "lot",Space,Str "of",Space,Str "things",Space,Str "to",LineBreak,Str "say,",Space,Str "so",Space,Str "the",Space,Str "text",Space,Str "is",Space,Str "really",Space,Str "really",Space,Str "long",Space,Str "and",Space,Str "spans",Space,Str "on",Space,Str "multiple",Space,Str "lines."]]
-,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
-,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) " ---- (should be four hyphens)\n\n sub status {\n print \"working\";\n }\n\n this code block is indented by one tab"
-,Para [Str "And:"]
-,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\n These should not be escaped: \\$ \\\\ \\> \\[ \\{"
-,CodeBlock ("",[],[]) "Code block with .bc\n continued\n @</\\"
-,CodeBlock ("",[],[]) "extended code block\n\n continued"
-,Para [Str "ended",Space,Str "by",Space,Str "paragraph"]
-,Para [Str "Inline",Space,Str "code:",Space,Code ("",[],[]) "<tt>",Str ",",Space,Code ("",[],[]) "@",Str "."]
-,Header 1 ("notextile",[],[]) [Str "Notextile"]
-,Para [Str "A",Space,Str "block",Space,Str "of",Space,Str "text",Space,Str "can",Space,Str "be",Space,Str "protected",Space,Str "with",Space,Str "notextile",Space,Str ":"]
-,Para [Str "\nNo *bold* and\n* no bullet\n"]
-,Para [Str "and",Space,Str "inlines",Space,Str "can",Space,Str "be",Space,Str "protected",Space,Str "with",Space,Str "double *equals (=)* markup."]
-,Header 1 ("lists",[],[]) [Str "Lists"]
-,Header 2 ("unordered",[],[]) [Str "Unordered"]
-,Para [Str "Asterisks",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "asterisk",Space,Str "1"]]
- ,[Plain [Str "asterisk",Space,Str "2"]]
- ,[Plain [Str "asterisk",Space,Str "3"]]]
-,Para [Str "With",Space,Str "line",Space,Str "breaks:"]
-,BulletList
- [[Plain [Str "asterisk",Space,Str "1",LineBreak,Str "newline"]]
- ,[Plain [Str "asterisk",Space,Str "2"]]]
-,Header 2 ("ordered",[],[]) [Str "Ordered"]
-,Para [Str "Tight:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second"]]
- ,[Plain [Str "Third"]]]
-,Header 2 ("nested",[],[]) [Str "Nested"]
-,BulletList
- [[Plain [Str "ui",Space,Str "1"]
- ,BulletList
- [[Plain [Str "ui",Space,Str "1.1"]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "oi",Space,Str "1.1.1"]]
- ,[Plain [Str "oi",Space,Str "1.1.2"]]]]
- ,[Plain [Str "ui",Space,Str "1.2"]]]]
- ,[Plain [Str "ui",Space,Str "2"]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "oi",Space,Str "2.1"]
- ,BulletList
- [[Plain [Str "ui",Space,Str "2.1.1"]]
- ,[Plain [Str "ui",Space,Str "2.1.2"]]]]]]]
-,Header 2 ("issue-1500",[],[]) [Str "Issue",Space,Str "#1500"]
-,BulletList
- [[Plain [Str "one"]]
- ,[Plain [Str "two",LineBreak,Str "->",Space,Str "and",Space,Str "more"]]]
-,Header 2 ("issue-1513",[],[]) [Str "Issue",Space,Str "#1513"]
-,Para [Str "List:"]
-,BulletList
- [[Plain [Str "one"]]
- ,[Plain [Str "two"]]]
-,Header 2 ("definition-list",[],[]) [Str "Definition",Space,Str "List"]
-,DefinitionList
- [([Str "coffee"],
- [[Plain [Str "Hot",Space,Str "and",Space,Str "black"]]])
- ,([Str "tea"],
- [[Plain [Str "Also",Space,Str "hot,",Space,Str "but",Space,Str "a",Space,Str "little",Space,Str "less",Space,Str "black"]]])
- ,([Str "milk"],
- [[Para [Str "Nourishing",Space,Str "beverage",Space,Str "for",Space,Str "baby",Space,Str "cows."]
- ,Para [Str "Cold",Space,Str "drink",Space,Str "that",Space,Str "goes",Space,Str "great",Space,Str "with",Space,Str "cookies."]]])
- ,([Str "beer"],
- [[Plain [Str "fresh",Space,Str "and",Space,Str "bitter"]]])]
-,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
-,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str ".",LineBreak,Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str ".",LineBreak,Str "Hyphenated-words-are-ok,",Space,Str "as",Space,Str "well",Space,Str "as",Space,Str "strange_underscore_notation.",LineBreak,Str "A",Space,Link ("",[],[]) [Strong [Str "strong",Space,Str "link"]] ("http://www.foobar.com",""),Str "."]
-,Para [Emph [Strong [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]],LineBreak,Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word",Space,Str "and",Space,Emph [Strong [Str "that",Space,Str "one"]],Str ".",LineBreak,Strikeout [Str "This",Space,Str "is",Space,Str "strikeout",Space,Str "and",Space,Strong [Str "strong"]]]
-,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Space,Superscript [Strong [Str "hello"]],Space,Str "a",Superscript [Str "hello",Space,Str "there"],Str ".",LineBreak,Str "Subscripts:",Space,Subscript [Str "here"],Space,Str "H",Space,Subscript [Str "2"],Str "O,",Space,Str "H",Space,Subscript [Str "23"],Str "O,",Space,Str "H",Space,Subscript [Str "many",Space,Str "of",Space,Str "them"],Str "O."]
-,Para [Str "Dashes",Space,Str ":",Space,Str "How",Space,Str "cool",Space,Str "--",Space,Str "automatic",Space,Str "dashes."]
-,Para [Str "Elipses",Space,Str ":",Space,Str "He",Space,Str "thought",Space,Str "and",Space,Str "thought",Space,Str "...",Space,Str "and",Space,Str "then",Space,Str "thought",Space,Str "some",Space,Str "more."]
-,Para [Str "Quotes",Space,Str "and",Space,Str "apostrophes",Space,Str ":",Space,Str "\"I'd",Space,Str "like",Space,Str "to",Space,Str "thank",Space,Str "you\"",Space,Str "for",Space,Str "example."]
-,Header 1 ("links",[],[]) [Str "Links"]
-,Header 2 ("explicit",[],[]) [Str "Explicit"]
-,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "url"] ("http://www.url.com","")]
-,Para [Link ("",[],[]) [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
-,Para [Str "\"not",Space,Str "a",Space,Str "link\":",Space,Str "foo"]
-,Para [Str "Automatic",Space,Str "linking",Space,Str "to",Space,Link ("",[],[]) [Str "http://www.example.com"] ("http://www.example.com",""),Str "."]
-,Para [Link ("",[],[]) [Str "Example"] ("http://www.example.com/",""),Str ":",Space,Str "Example",Space,Str "of",Space,Str "a",Space,Str "link",Space,Str "followed",Space,Str "by",Space,Str "a",Space,Str "colon."]
-,Para [Str "A",Space,Str "link",Link ("",[],[]) [Str "with",Space,Str "brackets"] ("http://www.example.com",""),Str "and",Space,Str "no",Space,Str "spaces."]
-,Header 1 ("tables",[],[]) [Str "Tables"]
-,Para [Str "Textile",Space,Str "allows",Space,Str "tables",Space,Str "with",Space,Str "and",Space,Str "without",Space,Str "headers",Space,Str ":"]
-,Header 2 ("without-headers",[],[]) [Str "Without",Space,Str "headers"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- []
- [[[Plain [Str "name"]]
- ,[Plain [Str "age"]]
- ,[Plain [Str "sex"]]]
- ,[[Plain [Str "joan"]]
- ,[Plain [Str "24"]]
- ,[Plain [Str "f"]]]
- ,[[Plain [Str "archie"]]
- ,[Plain [Str "29"]]
- ,[Plain [Str "m"]]]
- ,[[Plain [Str "bella"]]
- ,[Plain [Str "45"]]
- ,[Plain [Str "f"]]]]
-,Para [Str "and",Space,Str "some",Space,Str "text",Space,Str "following",Space,Str "..."]
-,Header 2 ("with-headers",[],[]) [Str "With",Space,Str "headers"]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "name"]]
- ,[Plain [Str "age"]]
- ,[Plain [Str "sex"]]]
- [[[Plain [Str "joan"]]
- ,[Plain [Str "24"]]
- ,[Plain [Str "f"]]]
- ,[[Plain [Str "archie"]]
- ,[Plain [Str "29"]]
- ,[Plain [Str "m"]]]
- ,[[Plain [Str "bella"]]
- ,[Plain [Str "45"]]
- ,[Plain [Str "f"]]]]
-,Header 1 ("images",[],[]) [Str "Images"]
-,Para [Str "Textile",Space,Str "inline",Space,Str "image",Space,Str "syntax,",Space,Str "like",LineBreak,Str "here",Space,Image ("",[],[]) [Str "this is the alt text"] ("this_is_an_image.png","this is the alt text"),LineBreak,Str "and",Space,Str "here",Space,Image ("",[],[]) [Str ""] ("this_is_an_image.png",""),Str "."]
-,Header 1 ("attributes",[],[]) [Str "Attributes"]
-,Header 2 ("ident",["bar","foo"],[("style","color:red;"),("lang","en")]) [Str "HTML",Space,Str "and",Space,Str "CSS",Space,Str "attributes",Space,Str "are",Space,Str "parsed",Space,Str "in",Space,Str "headers."]
-,Header 2 ("centered",[],[("style","text-align:center;")]) [Str "Centered"]
-,Header 2 ("right",[],[("style","text-align:right;")]) [Str "Right"]
-,Header 2 ("justified",[],[("lang","en"),("style","color:blue;text-align:justify;")]) [Str "Justified"]
-,Para [Str "as",Space,Str "well",Space,Str "as",Space,Strong [Span ("",["foo"],[]) [Str "inline",Space,Str "attributes"]],Space,Str "of",Space,Span ("",[],[("style","color:red;")]) [Str "all",Space,Str "kind"]]
-,Para [Str "and",Space,Str "paragraph",Space,Str "attributes,",Space,Str "and",Space,Str "table",Space,Str "attributes."]
-,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
- []
- [[[Plain [Str "name"]]
- ,[Plain [Str "age"]]
- ,[Plain [Str "sex"]]]
- ,[[Plain [Str "joan"]]
- ,[Plain [Str "24"]]
- ,[Plain [Str "f"]]]]
-,Para [Emph [Str "(class#id)",Space,Str "emph"]]
-,Para [Emph [Str "(no",Space,Str "class#id)",Space,Str "emph"]]
-,Header 1 ("entities",[],[]) [Str "Entities"]
-,Para [Str "*",LineBreak,Str "&"]
-,Header 1 ("raw-html",[],[]) [Str "Raw",Space,Str "HTML"]
-,Para [Str "However,",Space,RawInline (Format "html") "<strong>",Space,Str "raw",Space,Str "HTML",Space,Str "inlines",Space,RawInline (Format "html") "</strong>",Space,Str "are",Space,Str "accepted,",Space,Str "as",Space,Str "well",Space,Str "as",Space,Str ":"]
-,RawBlock (Format "html") "<div class=\"foobar\">"
-,Para [Str "any",Space,Strong [Str "Raw",Space,Str "HTML",Space,Str "Block"],Space,Str "with",Space,Str "bold"]
-,RawBlock (Format "html") "</div>"
-,Para [Str "Html",Space,Str "blocks",Space,Str "can"]
-,RawBlock (Format "html") "<div>"
-,Para [Str "interrupt",Space,Str "paragraphs"]
-,RawBlock (Format "html") "</div>"
-,Para [Str "as",Space,Str "well."]
-,Para [Str "Can",Space,Str "you",Space,Str "prove",Space,Str "that",Space,Str "2",Space,Str "<",Space,Str "3",Space,Str "?"]
-,Header 1 ("acronyms-and-marks",[],[]) [Str "Acronyms",Space,Str "and",Space,Str "marks"]
-,Para [Str "PBS (Public Broadcasting System)"]
-,Para [Str "Hi\8482"]
-,Para [Str "Hi",Space,Str "\8482"]
-,Para [Str "\174",Space,Str "Hi\174"]
-,Para [Str "Hi\169\&2008",Space,Str "\169",Space,Str "2008"]
-,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
-,Para [Str "A",Space,Str "note.",Note [Para [Str "The",Space,Str "note",LineBreak,Str "is",Space,Str "here!"]],Space,Str "Another",Space,Str "note",Note [Para [Str "Other",Space,Str "note."]],Str "."]
-,Header 1 ("comment-blocks",[],[]) [Str "Comment",Space,Str "blocks"]
-,Para [Str "not",Space,Str "a",Space,Str "comment."]]
diff --git a/tests/textile-reader.textile b/tests/textile-reader.textile
deleted file mode 100644
index cb9a68313..000000000
--- a/tests/textile-reader.textile
+++ /dev/null
@@ -1,278 +0,0 @@
-This is a set of tests for pandoc Textile Reader. Part of it comes
-from John Gruber's markdown test suite.
-
------
-
-h1. Headers
-
-h2. Level 2 with an "embeded link":http://www.example.com
-
-h3. Level 3 with *emphasis*
-
-h4. Level 4
-
-h5. Level 5
-
-h6. Level 6
-
-
-h1. Paragraphs
-
-Here's a regular paragraph.
-
-Line breaks are preserved in textile, so you can not wrap your very
-long paragraph with your favourite text editor and have it rendered
-with no break.
-
-
-Here's one with a bullet.
-
-* criminey.
-
-There should be a paragraph break between here
-
-and here.
-
-pandoc converts textile.
-
-h1. Block Quotes
-
-bq. This is a famous quote from somebody. He had a lot of things to
-say, so the text is really really long and spans on multiple lines.
-
-And a following paragraph.
-
-h1. Code Blocks
-
-Code:
-
-<pre>
- ---- (should be four hyphens)
-
- sub status {
- print "working";
- }
-
- this code block is indented by one tab
-</pre>
-
-And:
-
-<pre>
- this code block is indented by two tabs
-
- These should not be escaped: \$ \\ \> \[ \{
-</pre>
-
-bc. Code block with .bc
- continued
- @</\
-
-bc.. extended code block
-
- continued
-p. ended by paragraph
-
-Inline code: @<tt>@, <tt>@</tt>.
-
-h1. Notextile
-
-A block of text can be protected with notextile :
-
-<notextile>
-No *bold* and
-* no bullet
-</notextile>
-
-and inlines can be protected with ==double *equals (=)* markup==.
-
-h1. Lists
-
-h2. Unordered
-
-Asterisks tight:
-
-* asterisk 1
-* asterisk 2
-* asterisk 3
-
-With line breaks:
-
-* asterisk 1
-newline
-* asterisk 2
-
-h2. Ordered
-
-Tight:
-
-# First
-# Second
-# Third
-
-h2. Nested
-
-* ui 1
-** ui 1.1
-### oi 1.1.1
-### oi 1.1.2
-** ui 1.2
-* ui 2
-## oi 2.1
-*** ui 2.1.1
-*** ui 2.1.2
-
-h2. Issue #1500
-
-* one
-* two
--> and more
-
-h2. Issue #1513
-
-List:
-* one
-* two
-
-h2. Definition List
-
-- coffee := Hot and black
-- tea := Also hot, but a little less black
-- milk :=
-Nourishing beverage for baby cows.
-
-Cold drink that goes great with cookies.=:
-- beer := fresh and bitter
-
-
-h1. Inline Markup
-
-This is _emphasized_, and so __is this__.
-This is *strong*, and so **is this**.
-Hyphenated-words-are-ok, as well as strange_underscore_notation.
-A "*strong link*":http://www.foobar.com.
-
-_*This is strong and em.*_
-So is *_this_* word and __**that one**__.
--This is strikeout and *strong*-
-
-Superscripts: a[^bc^]d a ^*hello*^ a[^hello there^].
-Subscripts: ~here~ H[ ~2~]O, H[ ~23~]O, H[ ~many of them~]O.
-
-Dashes : How cool -- automatic dashes.
-
-Elipses : He thought and thought ... and then thought some more.
-
-Quotes and apostrophes : "I'd like to thank you" for example.
-
-
-h1. Links
-
-h2. Explicit
-
-Just a "url":http://www.url.com
-
-"Email link":mailto:nobody@nowhere.net
-
-"not a link": foo
-
-Automatic linking to "$":http://www.example.com.
-
-"Example":http://www.example.com/: Example of a link followed by a colon.
-
-A link["with brackets":http://www.example.com]and no spaces.
-
-h1. Tables
-
-Textile allows tables with and without headers :
-
-h2. Without headers
-
-| name | age | sex |
-| joan | 24 | f |
-| archie | 29 | m |
-| bella | 45 | f |
-
-and some text following ...
-
-h2. With headers
-
-|_. name |_. age |_. sex |
-| joan | 24 | f |
-| archie | 29 | m |
-| bella | 45 | f |
-
-
-
-h1. Images
-
-Textile inline image syntax, like
-here !this_is_an_image.png(this is the alt text)!
-and here !this_is_an_image.png!.
-
-h1. Attributes
-
-h2[en]{color:red}(foo bar #ident). HTML and CSS attributes are parsed in headers.
-
-h2=. Centered
-
-h2>. Right
-
-h2<>{color:blue}[en]. Justified
-
-as well as *(foo)inline attributes* of %{color:red}all kind%
-
-p{color:green}. and paragraph attributes, and table attributes.
-
-table{foo:bar}.
-| name | age | sex |
-| joan | 24 | f |
-
-_(class#id) emph_
-
-_(no class#id) emph_
-
-h1. Entities
-
-&#42;
-&amp;
-
-h1. Raw HTML
-
-However, <strong> raw HTML inlines </strong> are accepted, as well as :
-
-<div class="foobar">
- any *Raw HTML Block* with bold
-</div>
-
-Html blocks can <div>interrupt paragraphs</div> as well.
-
-Can you prove that 2 < 3 ?
-
-h1. Acronyms and marks
-
-PBS(Public Broadcasting System)
-
-Hi(tm)
-
-Hi (TM)
-
-(r) Hi(r)
-
-Hi(c)2008 (C) 2008
-
-h1. Footnotes
-
-A note.[1] Another note[2].
-
-fn1. The note
-is here!
-
-fn2. Other note.
-
-h1. Comment blocks
-
-###. my comment
-is here.
-
-not a comment.
diff --git a/tests/txt2tags.native b/tests/txt2tags.native
deleted file mode 100644
index 2eb795fde..000000000
--- a/tests/txt2tags.native
+++ /dev/null
@@ -1,552 +0,0 @@
-Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "author"]]),("date",MetaInlines [Str "date"]),("includeconf",MetaString "rules.conf"),("title",MetaInlines [Str "Txt2tags",Space,Str "Markup",Space,Str "Rules"])]})
-[Para [Str "This",Space,Str "document",Space,Str "describes",Space,Str "all",Space,Str "the",Space,Str "details",Space,Str "about",Space,Str "each",Space,Str "txt2tags",Space,Str "mark.",SoftBreak,Str "The",Space,Str "target",Space,Str "audience",Space,Str "are",Space,Strong [Str "experienced"],Space,Str "users.",Space,Str "You",Space,Str "may",Space,Str "find",Space,Str "it",SoftBreak,Str "useful",Space,Str "if",Space,Str "you",Space,Str "want",Space,Str "to",Space,Str "master",Space,Str "the",Space,Str "marks",Space,Str "or",Space,Str "solve",Space,Str "a",Space,Str "specific",Space,Str "problem",SoftBreak,Str "about",Space,Str "a",Space,Str "mark."]
-,Para [Str "If",Space,Str "you",Space,Str "are",Space,Str "new",Space,Str "to",Space,Str "txt2tags",Space,Str "or",Space,Str "just",Space,Str "want",Space,Str "to",Space,Str "know",Space,Str "which",Space,Str "are",Space,Str "the",SoftBreak,Str "available",Space,Str "marks,",Space,Str "please",Space,Str "read",Space,Str "the",Space,Link ("",[],[]) [Str "Markup",Space,Str "Demo"] ("MARKUPDEMO",""),Str "."]
-,Para [Str "Note",Space,Str "1:",Space,Str "This",Space,Str "document",Space,Str "is",Space,Str "generated",Space,Str "directly",Space,Str "from",Space,Str "the",Space,Str "txt2tags",SoftBreak,Str "test-suite.",Space,Str "All",Space,Str "the",Space,Str "rules",Space,Str "mentioned",Space,Str "here",Space,Str "are",Space,Str "100%",Space,Str "in",Space,Str "sync",Space,Str "with",Space,Str "the",SoftBreak,Str "current",Space,Str "program",Space,Str "code."]
-,Para [Str "Note",Space,Str "2:",Space,Str "A",Space,Str "good",Space,Str "practice",Space,Str "is",Space,Str "to",Space,Str "consult",Space,Link ("",[],[]) [Str "the",Space,Str "sources"] ("rules.t2t",""),Space,Str "when",SoftBreak,Str "reading,",Space,Str "to",Space,Str "see",Space,Str "how",Space,Str "the",Space,Str "texts",Space,Str "were",Space,Str "made."]
-,Para [Str "Table",Space,Str "of",Space,Str "Contents:"]
-,HorizontalRule
-,Header 1 ("paragraph",[],[]) [Str "Paragraph"]
-,Para [Str "A",Space,Str "paragraph",Space,Str "is",Space,Str "composed",Space,Str "by",Space,Str "one",Space,Str "or",Space,Str "more",Space,Str "lines.",SoftBreak,Str "A",Space,Str "blank",Space,Str "line",Space,Str "(or",Space,Str "a",Space,Str "table,",Space,Str "or",Space,Str "a",Space,Str "list)",Space,Str "ends",Space,Str "the",SoftBreak,Str "current",Space,Str "paragraph."]
-,Para [Str "Leading",Space,Str "and",Space,Str "trailing",Space,Str "spaces",Space,Str "are",Space,Str "ignored."]
-,Para [Str "A",Space,Str "comment",Space,Str "line",Space,Str "can",Space,Str "be",Space,Str "placed",Space,Str "inside",Space,Str "a",Space,Str "paragraph.",SoftBreak,Str "It",Space,Str "will",Space,Str "not",Space,Str "affect",Space,Str "it."]
-,Para [Str "The",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "file",Space,Str "(EOF)",Space,Str "closes",Space,Str "the",SoftBreak,Str "currently",Space,Str "open",Space,Str "paragraph."]
-,Header 1 ("comment",[],[]) [Str "Comment"]
-,Para [Str "%",Space,Str "not",Space,Str "on",Space,Str "the",Space,Str "line",Space,Str "beginning",Space,Str "(at",Space,Str "column",Space,Str "2)"]
-,Para [Str "some",Space,Str "text",Space,Str "%",Space,Str "half",Space,Str "line",Space,Str "comments",Space,Str "are",Space,Str "not",Space,Str "allowed"]
-,Header 1 ("line",[],[]) [Str "Line"]
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,HorizontalRule
-,Para [Strikeout [Str "-----"],SoftBreak,Strikeout [Str "-------",Space,Str "--------"]]
-,Para [Strikeout [Str "-------+--------"]]
-,Para [Str "(",Space,Strikeout [Str "----------------"],Space,Str ")"]
-,Header 1 ("inline",[],[]) [Str "Inline"]
-,Para [Str "i)",Space,Strong [Str "b"],Space,Emph [Str "i"],Space,Emph [Str "u"],Space,Strikeout [Str "s"],Space,Code ("",[],[]) "m",Space,Str "r",Space,RawInline (Format "html") "t",SoftBreak,Str "i)",Space,Strong [Str "bo"],Space,Emph [Str "it"],Space,Emph [Str "un"],Space,Strikeout [Str "st"],Space,Code ("",[],[]) "mo",Space,Str "ra",Space,RawInline (Format "html") "tg",SoftBreak,Str "i)",Space,Strong [Str "bold"],Space,Emph [Str "ital"],Space,Emph [Str "undr"],Space,Strikeout [Str "strk"],Space,Code ("",[],[]) "mono",Space,Str "raw",Space,RawInline (Format "html") "tggd",SoftBreak,Str "i)",Space,Strong [Str "bo",Space,Str "ld"],Space,Emph [Str "it",Space,Str "al"],Space,Emph [Str "un",Space,Str "dr"],Space,Strikeout [Str "st",Space,Str "rk"],Space,Code ("",[],[]) "mo no",Space,Str "r",Space,Str "aw",Space,RawInline (Format "html") "tg gd",SoftBreak,Str "i)",Space,Strong [Str "bo",Space,Str "*",Space,Str "ld"],Space,Emph [Str "it",Space,Str "/",Space,Str "al"],Space,Emph [Str "un",Space,Str "_",Space,Str "dr"],Space,Strikeout [Str "st",Space,Str "-",Space,Str "rk"],Space,Code ("",[],[]) "mo ` no",Space,Str "r",Space,Str "\"",Space,Str "aw",Space,RawInline (Format "html") "tg ' gd",SoftBreak,Str "i)",Space,Strong [Str "bo",Space,Str "**ld"],Space,Emph [Str "it",Space,Str "//al"],Space,Emph [Str "un",Space,Str "__dr"],Space,Strikeout [Str "st",Space,Str "--rk"],Space,Code ("",[],[]) "mo ``no",Space,Str "r",Space,Str "\"\"aw",Space,RawInline (Format "html") "tg ''gd",SoftBreak,Str "i)",Space,Strong [Str "bo",Space,Str "**",Space,Str "ld"],Space,Emph [Str "it",Space,Str "//",Space,Str "al"],Space,Emph [Str "un",Space,Str "__",Space,Str "dr"],Space,Strikeout [Str "st",Space,Str "--",Space,Str "rk"],Space,Code ("",[],[]) "mo `` no",Space,Str "r",Space,Str "\"\"",Space,Str "aw",Space,RawInline (Format "html") "tg '' gd",SoftBreak,Str "i)",Space,Strong [Str "**bold**"],Space,Emph [Str "//ital//"],Space,Emph [Str "__undr__"],Space,Strikeout [Str "--strk--"],Space,Code ("",[],[]) "``mono``",Space,Str "\"\"raw\"\"",Space,RawInline (Format "html") "''tggd''",SoftBreak,Str "i)",Space,Strong [Str "*bold*"],Space,Emph [Str "/ital/"],Space,Emph [Str "_undr_"],Space,Strikeout [Str "-strk-"],Space,Code ("",[],[]) "`mono`",Space,Str "\"raw\"",Space,RawInline (Format "html") "'tggd'"]
-,Para [Str "i)",Space,Strong [Str "*"],Space,Emph [Str "/"],Space,Emph [Str "_"],Space,Strikeout [Str "-"],Space,Code ("",[],[]) "`",Space,Str "\"",Space,RawInline (Format "html") "'",SoftBreak,Str "i)",Space,Strong [Str "**"],Space,Emph [Str "//"],Space,Emph [Str "__"],Space,Strikeout [Str "--"],Space,Code ("",[],[]) "``",Space,Str "\"\"",Space,RawInline (Format "html") "''",SoftBreak,Str "i)",Space,Strong [Str "***"],Space,Emph [Str "///"],Space,Emph [Str "___"],Space,Strikeout [Str "---"],Space,Code ("",[],[]) "```",Space,Str "\"\"\"",Space,RawInline (Format "html") "'''",SoftBreak,Str "i)",Space,Strong [Str "****"],Space,Emph [Str "////"],Space,Emph [Str "____"],Space,Strikeout [Str "----"],Space,Code ("",[],[]) "````",Space,Str "\"\"\"\"",Space,RawInline (Format "html") "''''",SoftBreak,Str "i)",Space,Strong [Str "*****"],Space,Emph [Str "/////"],Space,Emph [Str "_____"],Space,Strikeout [Str "-----"],Space,Code ("",[],[]) "`````",Space,Str "\"\"\"\"\"",Space,RawInline (Format "html") "'''''",SoftBreak,Str "i)",Space,Strong [Str "******"],Space,Emph [Str "//////"],Space,Emph [Str "______"],Space,Strikeout [Str "------"],Space,Code ("",[],[]) "``````",Space,Str "\"\"\"\"\"\"",Space,RawInline (Format "html") "''''''"]
-,Para [Str "i)",Space,Str "****",Space,Str "////",Space,Str "____",Space,Str "----",Space,Str "````",Space,Str "\"\"\"\"",Space,Str "''''",SoftBreak,Str "i)",Space,Str "**",Space,Str "**",Space,Str "//",Space,Str "//",Space,Str "__",Space,Str "__",Space,Str "--",Space,Str "--",Space,Str "``",Space,Str "``",Space,Str "\"\"",Space,Str "\"\"",Space,Str "''",Space,Str "''"]
-,Para [Str "i)",Space,Str "**",Space,Str "bold**",Space,Str "//",Space,Str "ital//",Space,Str "__",Space,Str "undr__",Space,Str "--",Space,Str "strk--",Space,Str "``",Space,Str "mono``",Space,Str "\"\"",Space,Str "raw\"\"",Space,Str "''",Space,Str "tggd''",SoftBreak,Str "i)",Space,Str "**bold",Space,Str "**",Space,Str "//ital",Space,Str "//",Space,Str "__undr",Space,Str "__",Space,Str "--strk",Space,Str "--",Space,Str "``mono",Space,Str "``",Space,Str "\"\"raw",Space,Str "\"\"",Space,Str "''tggd",Space,Str "''",SoftBreak,Str "i)",Space,Str "**",Space,Str "bold",Space,Str "**",Space,Str "//",Space,Str "ital",Space,Str "//",Space,Str "__",Space,Str "undr",Space,Str "__",Space,Str "--",Space,Str "strk",Space,Str "--",Space,Str "``",Space,Str "mono",Space,Str "``",Space,Str "\"\"",Space,Str "raw",Space,Str "\"\"",Space,Str "''",Space,Str "tggd",Space,Str "''"]
-,Header 1 ("link",[],[]) [Str "Link"]
-,Para [Link ("",[],[]) [Str "mailto:user@domain.com"] ("user@domain.com",""),SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com"] ("user@domain.com",""),Str ".",SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com"] ("user@domain.com",""),Str ".",Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "mailto:user@domain.com"] ("user@domain.com",""),Str ".",Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "label"] ("user@domain.com",""),SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla"] ("user@domain.com?subject=bla",""),SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla"] ("user@domain.com?subject=bla",""),Str ".",SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla"] ("user@domain.com?subject=bla",""),Str ",",SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla&cc=otheruser@domain.com"] ("user@domain.com?subject=bla&cc=otheruser@domain.com",""),SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla&cc=otheruser@domain.com"] ("user@domain.com?subject=bla&cc=otheruser@domain.com",""),Str ".",SoftBreak,Link ("",[],[]) [Str "mailto:user@domain.com?subject=bla&cc=otheruser@domain.com"] ("user@domain.com?subject=bla&cc=otheruser@domain.com",""),Str ",",SoftBreak,Link ("",[],[]) [Str "label"] ("user@domain.com?subject=bla&cc=otheruser@domain.com",""),Str ".",SoftBreak,Link ("",[],[]) [Str "label"] ("user@domain.com?subject=bla&cc=otheruser@domain.com.",""),Str ".",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com"] ("http://www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/"] ("http://www.domain.com/dir/",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir///"] ("http://www.domain.com/dir///",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com."] ("http://www.domain.com.",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com,"] ("http://www.domain.com,",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com."] ("http://www.domain.com.",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com,"] ("http://www.domain.com,",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/."] ("http://www.domain.com/dir/.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com."] ("http://www.domain.com.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/."] ("http://www.domain.com/dir/.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html."] ("http://www.domain.com/dir/index.html.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html,"] ("http://www.domain.com/dir/index.html,",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/#anchor"] ("http://www.domain.com/dir/#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html#anchor"] ("http://www.domain.com/dir/index.html#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html#anchor."] ("http://www.domain.com/dir/index.html#anchor.",""),SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/#anchor."] ("http://www.domain.com/dir/#anchor.",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html#anchor."] ("http://www.domain.com/dir/index.html#anchor.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/#anchor."] ("http://www.domain.com/dir/#anchor.",""),Space,Str "any",Space,Str "text.",SoftBreak,Str "any",Space,Str "text:",Space,Link ("",[],[]) [Str "http://www.domain.com/dir/index.html#anchor."] ("http://www.domain.com/dir/index.html#anchor.",""),Space,Str "any",Space,Str "text.",SoftBreak,Link ("",[],[]) [Str "http://domain.com?a=a@a.a&b=a+b+c."] ("http://domain.com?a=a@a.a&b=a+b+c.",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com?a=a@a.a&b=a+b+c,"] ("http://domain.com?a=a@a.a&b=a+b+c,",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com/bla.cgi?a=a@a.a&b=a+b+c."] ("http://domain.com/bla.cgi?a=a@a.a&b=a+b+c.",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com/bla.cgi?a=a@a.a&b=a+b+c@."] ("http://domain.com/bla.cgi?a=a@a.a&b=a+b+c@.",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com?a=a@a.a&b=a+b+c.#anchor"] ("http://domain.com?a=a@a.a&b=a+b+c.#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor"] ("http://domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com/bla.cgi?a=a@a.a&b=a+b+c@.#anchor"] ("http://domain.com/bla.cgi?a=a@a.a&b=a+b+c@.#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com/bla.html."] ("http://user:password@domain.com/bla.html.",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com/dir/."] ("http://user:password@domain.com/dir/.",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com."] ("http://user:password@domain.com.",""),SoftBreak,Link ("",[],[]) [Str "http://user:@domain.com."] ("http://user:@domain.com.",""),SoftBreak,Link ("",[],[]) [Str "http://user@domain.com."] ("http://user@domain.com.",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor"] ("http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor",""),SoftBreak,Link ("",[],[]) [Str "http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c@#anchor"] ("http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c@#anchor",""),SoftBreak,Link ("",[],[]) [Str "label"] ("www.domain.com",""),SoftBreak,Str "[",Space,Str "label",Space,Link ("",[],[]) [Str "www.domain.com"] ("www.domain.com",""),Str "]",SoftBreak,Link ("",[],[]) [Str "label",Space] ("www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "anchor",Space] ("http://www.domain.com/dir/index.html#anchor.",""),SoftBreak,Link ("",[],[]) [Str "login",Space] ("http://user:password@domain.com/bla.html",""),SoftBreak,Link ("",[],[]) [Str "form",Space] ("http://www.domain.com/bla.cgi?a=a@a.a&b=a+b+c.",""),SoftBreak,Link ("",[],[]) [Str "form",Space,Str "&",Space,Str "anchor"] ("http://www.domain.com/bla.cgi?a=a@a.a&b=a+b+c.#anchor",""),SoftBreak,Link ("",[],[]) [Str "login",Space,Str "&",Space,Str "form",Space] ("http://user:password@domain.com/bla.cgi?a=a@a.a&b=a+b+c.",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "up",Space] ("..",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "file",Space] ("bla.html",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "anchor",Space] ("#anchor",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "file/anchor"] ("bla.html#anchor",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "file/anchor"] ("bla.html#anchor.",""),SoftBreak,Link ("",[],[]) [Str "local",Space,Str "link",Space,Str "img",Space] ("abc.gif",""),SoftBreak,Link ("",[],[]) [Str "www.fake.com"] ("www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm"] ("http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-"] ("http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-",""),SoftBreak,Link ("",[],[]) [Str "http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-#anchor_"] ("http://domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-#anchor_",""),Str "-1%.",SoftBreak,Link ("",[],[]) [Str "http://foo._user-9:pass!#$%&*()+word@domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-#anchor_"] ("http://foo._user-9:pass!#$%&*()+word@domain.com:8080/~user/_st-r@a=n$g,e/index%20new.htm?a=/%22&b=+.@*_-#anchor_",""),Str "-1%.",SoftBreak,Link ("",[],[]) [Str "http://L1.com"] ("http://L1.com",""),Space,Str "!",Space,Link ("",[],[]) [Str "mailto:L2@www.com"] ("L2@www.com",""),Space,Str "!",Space,Link ("",[],[]) [Str "L3"] ("www.com",""),Space,Str "!",Space,Link ("",[],[]) [Str "L4"] ("w@ww.com",""),Space,Str "!",Space,Link ("",[],[]) [Str "www.L5.com"] ("www.L5.com",""),SoftBreak,Link ("",[],[]) [Str "www.domain.com"] ("www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "www2.domain.com"] ("www2.domain.com",""),SoftBreak,Link ("",[],[]) [Str "ftp.domain.com"] ("ftp.domain.com",""),SoftBreak,Link ("",[],[]) [Str "WWW.DOMAIN.COM"] ("WWW.DOMAIN.COM",""),SoftBreak,Link ("",[],[]) [Str "FTP.DOMAIN.COM"] ("FTP.DOMAIN.COM",""),SoftBreak,Link ("",[],[]) [Str "label"] ("www.domain.com",""),SoftBreak,Link ("",[],[]) [Str "label"] ("ftp.domain.com",""),SoftBreak,Link ("",[],[]) [Str "label"] ("WWW.DOMAIN.COM",""),SoftBreak,Link ("",[],[]) [Str "label"] ("FTP.DOMAIN.COM",""),SoftBreak,Str "[label",Space,Link ("",[],[]) [Str "www.domain.com"] ("www.domain.com",""),Space,Str "]",SoftBreak,Str "[label]",Space,Link ("",[],[]) [Str "www.domain.com"] ("www.domain.com",""),Str "]"]
-,Header 1 ("image",[],[]) [Str "Image"]
-,Para [Image ("",[],[]) [] ("img.png","")]
-,Para [Link ("",[],[]) [Image ("",[],[]) [] ("img.png","")] ("http://txt2tags.org","")]
-,Para [Image ("",[],[]) [] ("img.png",""),Space,Str "Image",Space,Str "at",Space,Str "the",Space,Str "line",Space,Str "beginning."]
-,Para [Str "Image",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Image ("",[],[]) [] ("img.png",""),Space,Str "of",Space,Str "the",Space,Str "line."]
-,Para [Str "Image",Space,Str "at",Space,Str "the",Space,Str "line",Space,Str "end.",Space,Image ("",[],[]) [] ("img.png","")]
-,Para [Image ("",[],[]) [] ("img.png",""),SoftBreak,Image ("",[],[]) [] ("img.png",""),SoftBreak,Image ("",[],[]) [] ("img.png","")]
-,Para [Image ("",[],[]) [] ("img.png",""),Image ("",[],[]) [] ("img.png","")]
-,Para [Str "Images",Space,Image ("",[],[]) [] ("img.png",""),Space,Str "mixed",Space,Image ("",[],[]) [] ("img.png",""),Space,Str "with",Space,Image ("",[],[]) [] ("img.png",""),Space,Str "text."]
-,Para [Str "Images",Space,Str "glued",Space,Str "together:",Space,Image ("",[],[]) [] ("img.png",""),Image ("",[],[]) [] ("img.png",""),Image ("",[],[]) [] ("img.png",""),Str "."]
-,Para [Str "[img.png",Space,Str "]"]
-,Para [Str "[",Space,Str "img.png]"]
-,Para [Str "[",Space,Str "img.png",Space,Str "]"]
-,Header 1 ("numtitle",[],[]) [Str "Numbered",Space,Str "Title"]
-,Header 1 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "1"]
-,Header 2 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "2"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 4 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "4"]
-,Header 5 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "5"]
-,Header 1 ("lab_el-1",[],[]) [Str "Title",Space,Str "Level",Space,Str "1"]
-,Header 2 ("lab_el-2",[],[]) [Str "Title",Space,Str "Level",Space,Str "2"]
-,Header 3 ("lab_el-3",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 4 ("lab_el-4",[],[]) [Str "Title",Space,Str "Level",Space,Str "4"]
-,Header 5 ("lab_el-5",[],[]) [Str "Title",Space,Str "Level",Space,Str "5"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("lab_el-9",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Para [Str "+Not",Space,Str "Title"]
-,Para [Str "++Not",Space,Str "Title+"]
-,Para [Str "+++Not",Space,Str "Title++++",SoftBreak,Str "++++++Not",Space,Str "Title",Space,Str "6++++++"]
-,Para [Str "+++++++Not",Space,Str "Title",Space,Str "7+++++++",SoftBreak,Str "+Not",Space,Str "Title+",Space,Str "[label1]",SoftBreak,Str "+Not",Space,Str "Title+[",Space,Str "label",Space,Str "]",SoftBreak,Str "+Not",Space,Str "Title+[la/bel]"]
-,Header 1 ("title",[],[]) [Str "Title"]
-,Header 1 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "1"]
-,Header 2 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "2"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 4 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "4"]
-,Header 5 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "5"]
-,Header 1 ("lab_el-1",[],[]) [Str "Title",Space,Str "Level",Space,Str "1"]
-,Header 2 ("lab_el-2",[],[]) [Str "Title",Space,Str "Level",Space,Str "2"]
-,Header 3 ("lab_el-3",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 4 ("lab_el-4",[],[]) [Str "Title",Space,Str "Level",Space,Str "4"]
-,Header 5 ("lab_el-5",[],[]) [Str "Title",Space,Str "Level",Space,Str "5"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Header 3 ("lab_el-9",[],[]) [Str "Title",Space,Str "Level",Space,Str "3"]
-,Para [Str "=Not",Space,Str "Title"]
-,Para [Str "==Not",Space,Str "Title="]
-,Para [Str "===Not",Space,Str "Title====",SoftBreak,Str "======Not",Space,Str "Title",Space,Str "6======"]
-,Para [Str "=======Not",Space,Str "Title",Space,Str "7=======",SoftBreak,Str "=Not",Space,Str "Title=",Space,Str "[label1]",SoftBreak,Str "=Not",Space,Str "Title=[",Space,Str "label",Space,Str "]",SoftBreak,Str "=Not",Space,Str "Title=[la/bel]"]
-,Header 1 ("quote",[],[]) [Str "Quote"]
-,BlockQuote
- [Para [Str "To",Space,Str "quote",Space,Str "a",Space,Str "paragraph,",Space,Str "just",Space,Str "prefix",Space,Str "it",Space,Str "by",Space,Str "a",Space,Str "TAB",SoftBreak,Str "character.",Space,Str "All",Space,Str "the",Space,Str "lines",Space,Str "of",Space,Str "the",Space,Str "paragraph",Space,Str "must",SoftBreak,Str "begin",Space,Str "with",Space,Str "a",Space,Str "TAB."]]
-,Para [Str "Any",Space,Str "non-tabbed",Space,Str "line",Space,Str "closes",Space,Str "the",Space,Str "quote",Space,Str "block."]
-,BlockQuote
- [Para [Str "The",Space,Str "number",Space,Str "of",Space,Str "leading",Space,Str "TABs",Space,Str "identifies",Space,Str "the",Space,Str "quote",SoftBreak,Str "block",Space,Str "depth.",Space,Str "This",Space,Str "is",Space,Str "quote",Space,Str "level",Space,Str "1."]
- ,BlockQuote
- [Para [Str "With",Space,Str "two",Space,Str "TABs,",Space,Str "we",Space,Str "are",Space,Str "on",Space,Str "the",Space,Str "quote",SoftBreak,Str "level",Space,Str "2."]
- ,BlockQuote
- [Para [Str "The",Space,Str "more",Space,Str "TABs,",Space,Str "more",Space,Str "deep",Space,Str "is",SoftBreak,Str "the",Space,Str "quote",Space,Str "level."]
- ,BlockQuote
- [Para [Str "There",Space,Str "isn't",Space,Str "a",Space,Str "limit."]]]]]
-,BlockQuote
- [BlockQuote
- [BlockQuote
- [BlockQuote
- [Para [Str "This",Space,Str "quote",Space,Str "starts",Space,Str "at",SoftBreak,Str "level",Space,Str "4."]]
- ,Para [Str "Then",Space,Str "its",Space,Str "depth",Space,Str "is",Space,Str "decreased."]]
- ,Para [Str "Counting",Space,Str "down,",Space,Str "one",Space,Str "by",Space,Str "one."]]
- ,Para [Str "Until",Space,Str "the",Space,Str "level",Space,Str "1."]]
-,BlockQuote
- [BlockQuote
- [BlockQuote
- [Para [Str "Unlike",Space,Str "lists,",Space,Str "any",Space,Str "quote",Space,Str "block",Space,Str "is",SoftBreak,Str "independent,",Space,Str "not",Space,Str "part",Space,Str "of",Space,Str "a",Space,Str "tree."]]]
- ,Para [Str "The",Space,Str "TAB",Space,Str "count",Space,Str "don't",Space,Str "need",Space,Str "to",Space,Str "be",Space,Str "incremental",SoftBreak,Str "by",Space,Str "one."]
- ,BlockQuote
- [BlockQuote
- [BlockQuote
- [Para [Str "The",Space,Str "nesting",Space,Str "don't",Space,Str "need",SoftBreak,Str "to",Space,Str "follow",Space,Str "any",Space,Str "rule."]]]
- ,Para [Str "Quotes",Space,Str "can",Space,Str "be",Space,Str "opened",Space,Str "and",Space,Str "closed",SoftBreak,Str "in",Space,Str "any",Space,Str "way."]
- ,BlockQuote
- [BlockQuote
- [BlockQuote
- [Para [Str "You",Space,Str "choose."]]]]]]
-,BlockQuote
- [Para [Str "Some",Space,Str "targets",Space,Str "(as",Space,Str "sgml)",Space,Str "don't",Space,Str "support",Space,Str "the",SoftBreak,Str "nesting",Space,Str "of",Space,Str "quotes.",Space,Str "There",Space,Str "is",Space,Str "only",Space,Str "one",Space,Str "quote",SoftBreak,Str "level."]
- ,BlockQuote
- [Para [Str "In",Space,Str "this",Space,Str "case,",Space,Str "no",Space,Str "matter",Space,Str "how",Space,Str "much",SoftBreak,Str "TABs",Space,Str "are",Space,Str "used",Space,Str "to",Space,Str "define",Space,Str "the",Space,Str "quote",SoftBreak,Str "block,",Space,Str "it",Space,Str "always",Space,Str "will",Space,Str "be",Space,Str "level",Space,Str "1."]]]
-,BlockQuote
- [Para [Str "Spaces",Space,Str "AFTER",Space,Str "the",Space,Str "TAB",Space,Str "character",Space,Str "are",Space,Str "allowed.",SoftBreak,Str "But",Space,Str "be",Space,Str "careful,",Space,Str "it",Space,Str "can",Space,Str "be",Space,Str "confusing."]]
-,Para [Str "Spaces",Space,Str "BEFORE",Space,Str "the",Space,Str "TAB",Space,Str "character",SoftBreak,Str "invalidate",Space,Str "the",Space,Str "mark.",Space,Str "It's",Space,Str "not",Space,Str "quote."]
-,BlockQuote
- [Para [Str "Paragraph",Space,Str "breaks",Space,Str "inside",Space,Str "a",Space,Str "quote",Space,Str "aren't",SoftBreak,Str "possible."]
- ,Para [Str "This",Space,Str "sample",Space,Str "are",Space,Str "two",Space,Str "separated",Space,Str "quoted",SoftBreak,Str "paragraphs,",Space,Str "not",Space,Str "a",Space,Str "quote",Space,Str "block",Space,Str "with",SoftBreak,Str "two",Space,Str "paragraphs",Space,Str "inside."]]
-,BlockQuote
- [Para [Str "The",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "file",Space,Str "(EOF)",Space,Str "closes",Space,Str "the",SoftBreak,Str "currently",Space,Str "open",Space,Str "quote",Space,Str "block."]]
-,Header 1 ("raw",[],[]) [Str "Raw"]
-,Para [Str "A raw line.\n"]
-,Para [Str " Another raw line, with leading spaces.\n"]
-,Para [Str "A raw area delimited\n by lines with marks.\n"]
-,Para [Str "Trailing spaces and TABs after the area marks\nare allowed, but not encouraged nor documented.\n"]
-,Para [Str "\"\"\"Not",Space,Str "a",Space,Str "raw",Space,Str "line,",Space,Str "need",Space,Str "one",Space,Str "space",Space,Str "after",Space,Str "mark."]
-,Para [Str "\"\"\"",SoftBreak,Str "Not",Space,Str "a",Space,Str "raw",Space,Str "area.",SoftBreak,Str "The",Space,Str "marks",Space,Str "must",Space,Str "be",Space,Str "at",Space,Str "the",Space,Str "line",Space,Str "beginning,",SoftBreak,Str "no",Space,Str "leading",Space,Str "spaces.",SoftBreak,Str "\"\"\""]
-,Para [Str "The end of the file (EOF) closes\nthe currently open raw area.\n"]
-,Header 1 ("verbatim",[],[]) [Str "Verbatim"]
-,CodeBlock ("",[],[]) "A verbatim line.\n"
-,CodeBlock ("",[],[]) " Another verbatim line, with leading spaces.\n"
-,CodeBlock ("",[],[]) "A verbatim area delimited\n by lines with marks.\n"
-,CodeBlock ("",[],[]) "Trailing spaces and TABs after the area marks\nare allowed, but not encouraged nor documented.\n"
-,Para [Str "```Not",Space,Str "a",Space,Str "verbatim",Space,Str "line,",Space,Str "need",Space,Str "one",Space,Str "space",Space,Str "after",Space,Str "mark."]
-,Para [Str "```",SoftBreak,Str "Not",Space,Str "a",Space,Str "verbatim",Space,Str "area.",SoftBreak,Str "The",Space,Str "marks",Space,Str "must",Space,Str "be",Space,Str "at",Space,Str "the",Space,Str "line",Space,Str "beginning,",SoftBreak,Str "no",Space,Str "leading",Space,Str "spaces.",SoftBreak,Str "```"]
-,CodeBlock ("",[],[]) "The end of the file (EOF) closes\nthe currently open verbatim area.\n"
-,Header 1 ("deflist",[],[]) [Str "Definition",Space,Str "List"]
-,DefinitionList
- [([Str "Definition",Space,Str "list"],
- [[Plain [Str "A",Space,Str "list",Space,Str "with",Space,Str "terms"]]])
- ,([Str "Start",Space,Str "term",Space,Str "with",Space,Str "colon"],
- [[Plain [Str "And",Space,Str "its",Space,Str "definition",Space,Str "follows"]]])]
-,Header 1 ("numlist",[],[]) [Str "Numbered",Space,Str "List"]
-,Para [Str "See",Space,Link ("",[],[]) [Str "List"] ("#list",""),Str ",",Space,Str "the",Space,Str "same",Space,Str "rules",Space,Str "apply."]
-,Header 1 ("list",[],[]) [Str "List"]
-,BulletList
- [[Plain [Str "Use",Space,Str "the",Space,Str "hyphen",Space,Str "to",Space,Str "prefix",Space,Str "list",Space,Str "items."]]
- ,[Plain [Str "There",Space,Str "must",Space,Str "be",Space,Str "one",Space,Str "space",Space,Str "after",Space,Str "the",Space,Str "hyphen."]]
- ,[Plain [Str "The",Space,Str "list",Space,Str "is",Space,Str "closed",Space,Str "by",Space,Str "two",Space,Str "consecutive",Space,Str "blank",Space,Str "lines."]]]
-,BulletList
- [[Plain [Str "The",Space,Str "list",Space,Str "can",Space,Str "be",Space,Str "indented",Space,Str "on",Space,Str "the",Space,Str "source",Space,Str "document."]]
- ,[Plain [Str "You",Space,Str "can",Space,Str "use",Space,Str "any",Space,Str "number",Space,Str "of",Space,Str "spaces."]]
- ,[Plain [Str "The",Space,Str "result",Space,Str "will",Space,Str "be",Space,Str "the",Space,Str "same."]]]
-,BulletList
- [[Para [Str "Let",Space,Str "one",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "the",Space,Str "list",Space,Str "items."]]
- ,[Para [Str "It",Space,Str "will",Space,Str "be",Space,Str "maintained",Space,Str "on",Space,Str "the",Space,Str "conversion."]]
- ,[Para [Str "Some",Space,Str "targets",Space,Str "don't",Space,Str "support",Space,Str "this",Space,Str "behavior."]]
- ,[Para [Str "This",Space,Str "one",Space,Str "was",Space,Str "separated",Space,Str "by",Space,Str "a",Space,Str "line",Space,Str "with",Space,Str "blanks.",SoftBreak,Str "You",Space,Str "can",Space,Str "also",Space,Str "put",Space,Str "a",Space,Str "blank",Space,Str "line",Space,Str "inside"]
- ,Para [Str "the",Space,Str "item",Space,Str "contents",Space,Str "and",Space,Str "it",Space,Str "will",Space,Str "be",Space,Str "preserved."]]]
-,Para [Str "-This",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "list",Space,Str "(no",Space,Str "space)"]
-,Para [Str "-",Space,Str "This",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "list",Space,Str "(more",Space,Str "than",Space,Str "one",Space,Str "space)"]
-,Para [Str "-",Space,Str "This",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "list",Space,Str "(a",Space,Str "TAB",Space,Str "instead",Space,Str "the",Space,Str "space)"]
-,BulletList
- [[BulletList
- [[Plain [Str "This",Space,Str "is",Space,Str "a",Space,Str "list"]]]]
- ,[OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "This",Space,Str "is",Space,Str "a",Space,Str "list"]]]]
- ,[DefinitionList
- [([Str "This",Space,Str "is",Space,Str "a",Space,Str "list"],
- [[]])]]]
-,BulletList
- [[Plain [Str "This",Space,Str "is",Space,Str "the",Space,Str "\"mother\"",Space,Str "list",Space,Str "first",Space,Str "item."]]
- ,[Plain [Str "Here",Space,Str "is",Space,Str "the",Space,Str "second,",Space,Str "but",Space,Str "inside",Space,Str "this",Space,Str "item,"]
- ,BulletList
- [[Plain [Str "there",Space,Str "is",Space,Str "a",Space,Str "sublist,",Space,Str "with",Space,Str "its",Space,Str "own",Space,Str "items."]]
- ,[Plain [Str "Note",Space,Str "that",Space,Str "the",Space,Str "items",Space,Str "of",Space,Str "the",Space,Str "same",Space,Str "sublist"]]
- ,[Plain [Str "must",Space,Str "have",Space,Str "the",Space,Str "same",Space,Str "indentation."]
- ,BulletList
- [[Plain [Str "And",Space,Str "this",Space,Str "can",Space,Str "go",Space,Str "on,",Space,Str "opening",Space,Str "sublists."]
- ,BulletList
- [[Plain [Str "Just",Space,Str "add",Space,Str "leading",Space,Str "spaces",Space,Str "before",Space,Str "the"]]
- ,[Plain [Str "hyphen",Space,Str "and",Space,Str "sublists",Space,Str "will",Space,Str "be",Space,Str "opened."]]
- ,[Plain [Str "The",Space,Str "two",Space,Str "blank",Space,Str "lines",Space,Str "closes",Space,Str "them",Space,Str "all."]]]]]]]]]
-,BulletList
- [[Plain [Str "When",Space,Str "nesting",Space,Str "lists,",Space,Str "the",Space,Str "additional",Space,Str "spaces",Space,Str "are",Space,Str "free."]]
- ,[Plain [Str "You",Space,Str "can",Space,Str "add",Space,Str "just",Space,Str "one,"]
- ,BulletList
- [[Plain [Str "or",Space,Str "many."]
- ,BulletList
- [[Plain [Str "What",Space,Str "matters",Space,Str "is",Space,Str "to",Space,Str "put",Space,Str "more",Space,Str "than",Space,Str "the",Space,Str "previous."]]
- ,[Plain [Str "But",Space,Str "remember",Space,Str "that",Space,Str "the",Space,Str "other",Space,Str "items",Space,Str "of",Space,Str "the",Space,Str "same",Space,Str "list"]]
- ,[Plain [Str "must",Space,Str "use",Space,Str "the",Space,Str "same",Space,Str "indentation."]]]]]]]
-,BulletList
- [[Plain [Str "There",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "depth",Space,Str "limit,"]
- ,BulletList
- [[Plain [Str "you",Space,Str "can",Space,Str "go",Space,Str "deeper",Space,Str "and",Space,Str "deeper."]
- ,BulletList
- [[Plain [Str "But",Space,Str "some",Space,Str "targets",Space,Str "may",Space,Str "have",Space,Str "restrictions."]
- ,BulletList
- [[Plain [Str "The",Space,Str "LaTeX",Space,Str "maximum",Space,Str "is",Space,Str "here,",Space,Str "4",Space,Str "levels."]]]]]]]]]
-,BulletList
- [[Plain [Str "Reverse",Space,Str "nesting",Space,Str "doesn't",Space,Str "work."]]
- ,[Plain [Str "Because",Space,Str "a",Space,Str "sublist",Space,Str "*must*",Space,Str "have",Space,Str "a",Space,Str "mother",Space,Str "list."]]
- ,[Plain [Str "It's",Space,Str "the",Space,Str "list",Space,Str "concept,",Space,Str "not",Space,Str "a",Space,Str "txt2tags",Space,Str "limitation."]]
- ,[Plain [Str "All",Space,Str "this",Space,Str "sublists",Space,Str "will",Space,Str "be",Space,Str "bumped",Space,Str "to",Space,Str "mother",Space,Str "lists."]]
- ,[Plain [Str "At",Space,Str "level",Space,Str "1,",Space,Str "like",Space,Str "this",Space,Str "one."]]]
-,BulletList
- [[Plain [Str "Level",Space,Str "1"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "2"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "3"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "4"]]]]
- ,[Plain [Str "Level",Space,Str "3",Space,Str "--",Space,Str "(closed",Space,Str "Level",Space,Str "4)"]]]]
- ,[Plain [Str "Level",Space,Str "2",Space,Str "--",Space,Str "(closed",Space,Str "Level",Space,Str "3)"]]]]
- ,[Plain [Str "Level",Space,Str "1",Space,Str "--",Space,Str "(closed",Space,Str "Level",Space,Str "2)"]]]
-,BulletList
- [[Plain [Str "Level",Space,Str "1"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "2"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "3"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "4"]]]]]]]]
- ,[Plain [Str "Level",Space,Str "1",Space,Str "--",Space,Str "(closed",Space,Str "Level",Space,Str "4,",Space,Str "Level",Space,Str "3",Space,Str "and",Space,Str "Level",Space,Str "2)"]]]
-,BulletList
- [[Para [Str "Level",Space,Str "1"]
- ,BulletList
- [[Para [Str "Level",Space,Str "2",Space,Str "--",Space,Str "blank",Space,Str "BEFORE",Space,Str "and",Space,Str "AFTER",Space,Str "(in)"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "3"]]]]]]]
-,BulletList
- [[Plain [Str "Level",Space,Str "4"]]]
-,BulletList
- [[Para [Str "Level",Space,Str "3"]]
- ,[Para [Str "Level",Space,Str "2",Space,Str "--",Space,Str "blank",Space,Str "BEFORE",Space,Str "and",Space,Str "AFTER",Space,Str "(out)"]]
- ,[Para [Str "Level",Space,Str "1"]
- ,BulletList
- [[Para [Str "Level",Space,Str "2",Space,Str "--",Space,Str "blank",Space,Str "BEFORE",Space,Str "(spaces)",Space,Str "and",Space,Str "AFTER",Space,Str "(TAB)"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "3"]]]]]]]
-,BulletList
- [[Plain [Str "Level",Space,Str "1"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "2"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "3"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "4"]]
- ,[Plain [Str "Level",Space,Str "3.5",Space,Str "???"]]]]
- ,[Plain [Str "Level",Space,Str "3"]]
- ,[Plain [Str "Level",Space,Str "2.5",Space,Str "???"]]]]
- ,[Plain [Str "Level",Space,Str "2"]]
- ,[Plain [Str "Level",Space,Str "1.5",Space,Str "???"]]]]
- ,[Plain [Str "Level",Space,Str "1"]]]
-,BulletList
- [[Plain [Str "This",Space,Str "list",Space,Str "is",Space,Str "closed",Space,Str "by",Space,Str "a",Space,Str "line",Space,Str "with",Space,Str "spaces",Space,Str "and",Space,Str "other",Space,Str "with",Space,Str "TABs"]]]
-,BulletList
- [[Plain [Str "This",Space,Str "list",Space,Str "is",Space,Str "NOT",Space,Str "closed",Space,Str "by",Space,Str "two",Space,Str "comment",Space,Str "lines"]]]
-,BulletList
- [[Plain [Str "This",Space,Str "list",Space,Str "is",Space,Str "closed",Space,Str "by",Space,Str "a",Space,Str "line",Space,Str "with",Space,Str "spaces",Space,Str "and",Space,Str "TAB,"]]
- ,[Plain [Str "then",Space,Str "a",Space,Str "comment",Space,Str "line,",Space,Str "then",Space,Str "an",Space,Str "empty",Space,Str "line."]]]
-,BulletList
- [[Plain [Str "Level",Space,Str "1"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "2"]
- ,BulletList
- [[Plain [Str "Level",Space,Str "3"]]]
- ,Plain [Str "-",SoftBreak,Str "Level",Space,Str "2"]]]
- ,Plain [Str "-",SoftBreak,Str "Level",Space,Str "1"]]]
-,Para [Str "-"]
-,BulletList
- [[Plain [Str "Empty",Space,Str "item",Space,Str "with",Space,Str "trailing",Space,Str "spaces."]]]
-,Para [Str "-"]
-,BulletList
- [[Plain [Str "Empty",Space,Str "item",Space,Str "with",Space,Str "trailing",Space,Str "TAB."]]]
-,Para [Str "-"]
-,BulletList
- [[Plain [Str "If",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "file",Space,Str "(EOF)",Space,Str "is",Space,Str "hit,"]
- ,BulletList
- [[Plain [Str "all",Space,Str "the",Space,Str "currently",Space,Str "opened",Space,Str "list",Space,Str "are",Space,Str "closed,"]
- ,BulletList
- [[Plain [Str "just",Space,Str "like",Space,Str "when",Space,Str "using",Space,Str "the",Space,Str "two",Space,Str "blank",Space,Str "lines."]]]]]]]
-,Header 1 ("table",[],[]) [Str "Table"]
-,Table [] [AlignRight] [0.0]
- []
- [[[Plain [Str "Cell",Space,Str "1"]]]]
-,Table [] [AlignCenter,AlignCenter,AlignRight] [0.0,0.0,0.0]
- []
- [[[Plain [Str "Cell",Space,Str "1"]]
- ,[Plain [Str "Cell",Space,Str "2"]]
- ,[Plain [Str "Cell",Space,Str "3"]]]]
-,Table [] [AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0]
- []
- [[[Plain [Str "Cell",Space,Str "1"]]
- ,[Plain [Str "Cell",Space,Str "2"]]
- ,[Plain [Str "Cell",Space,Str "3"]]]]
-,Para [Str "||",Space,Str "Cell",Space,Str "1",Space,Str "|",Space,Str "Cell",Space,Str "2",Space,Str "|",Space,Str "Cell",Space,Str "3",Space,Str "|"]
-,Table [] [AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0]
- []
- [[[Plain [Str "Cell",Space,Str "1"]]
- ,[Plain [Str "Cell",Space,Str "2"]]
- ,[Plain [Str "Cell",Space,Str "3"]]]]
-,Table [] [AlignDefault,AlignCenter,AlignDefault] [0.0,0.0,0.0]
- [[Plain [Str "Heading"]]
- ,[Plain [Str "Heading"]]
- ,[Plain [Str "Heading"]]]
- [[[Plain [Str "<-"]]
- ,[Plain [Str "--"]]
- ,[Plain [Str "->"]]]
- ,[[Plain [Str "--"]]
- ,[Plain [Str "--"]]
- ,[Plain [Str "--"]]]
- ,[[Plain [Str "->"]]
- ,[Plain [Str "--"]]
- ,[Plain [Str "<-"]]]]
-,Table [] [AlignDefault,AlignDefault,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0]
- [[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3+4"]]
- ,[]]
- [[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]
- ,[Plain [Str "4"]]]
- ,[[Plain [Str "1+2+3"]]
- ,[Plain [Str "4"]]
- ,[]
- ,[]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "2+3"]]
- ,[Plain [Str "4"]]
- ,[]]
- ,[[Plain [Str "1+2+3+4"]]
- ,[]
- ,[]
- ,[]]]
-,Table [] [AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0]
- []
- [[[Plain [Str "0"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[]]
- ,[[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[]
- ,[Plain [Str "7"]]]
- ,[[Plain [Str "8"]]
- ,[]
- ,[Plain [Str "A"]]
- ,[Plain [Str "B"]]]
- ,[[]
- ,[Plain [Str "D"]]
- ,[Plain [Str "E"]]
- ,[Plain [Str "F"]]]]
-,Table [] [AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0]
- []
- [[[Plain [Str "1"]]
- ,[]
- ,[]
- ,[]
- ,[]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[]
- ,[]
- ,[]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]
- ,[]
- ,[]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]
- ,[Plain [Str "4"]]
- ,[]]
- ,[[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]
- ,[Plain [Str "4"]]
- ,[Plain [Str "5"]]]]
-,Table [] [AlignDefault,AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0]
- []
- [[[Plain [Str "Jan"]]
- ,[]
- ,[]
- ,[]
- ,[]]
- ,[[Plain [Str "Fev"]]
- ,[]
- ,[]
- ,[]
- ,[]]
- ,[[Plain [Str "Mar"]]
- ,[]
- ,[]
- ,[]
- ,[]]
- ,[[Plain [Str "Apr"]]
- ,[]
- ,[]
- ,[]
- ,[]]
- ,[[Plain [Str "May"]]
- ,[]
- ,[]
- ,[]
- ,[]]
- ,[[Plain [Str "20%"]]
- ,[Plain [Str "40%"]]
- ,[Plain [Str "60%"]]
- ,[Plain [Str "80%"]]
- ,[Plain [Str "100%"]]]]
-,Table [] [AlignCenter,AlignDefault,AlignDefault,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0]
- []
- [[[]
- ,[]
- ,[Plain [Str "/"]]
- ,[]
- ,[]]
- ,[[]
- ,[Plain [Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/"]]
- ,[]
- ,[]
- ,[]]
- ,[[Plain [Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/",Space,Str "/"]]
- ,[]
- ,[]
- ,[]
- ,[]]
- ,[[]
- ,[Plain [Str "o"]]
- ,[]
- ,[Plain [Str "o"]]
- ,[]]
- ,[[]
- ,[]
- ,[Plain [Str "."]]
- ,[]
- ,[]]
- ,[[]
- ,[Plain [Str "=",Space,Str "=",Space,Str "=",Space,Str "="]]
- ,[]
- ,[]
- ,[]]]
-,Table [] [AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]
- []
- [[[Plain [Str "01"]]
- ,[Plain [Str "02"]]
- ,[]
- ,[]
- ,[Plain [Str "05"]]
- ,[]
- ,[Plain [Str "07"]]
- ,[]]
- ,[[]
- ,[]
- ,[Plain [Str "11"]]
- ,[]
- ,[Plain [Str "13"]]
- ,[]
- ,[]
- ,[Plain [Str "16"]]]
- ,[[Plain [Str "17"]]
- ,[]
- ,[Plain [Str "19"]]
- ,[Plain [Str "20"]]
- ,[]
- ,[]
- ,[Plain [Str "23"]]
- ,[]]
- ,[[Plain [Str "25"]]
- ,[Plain [Str "26"]]
- ,[]
- ,[]
- ,[Plain [Str "29"]]
- ,[Plain [Str "30"]]
- ,[]
- ,[Plain [Str "32"]]]
- ,[[]
- ,[]
- ,[Plain [Str "35"]]
- ,[]
- ,[Plain [Str "37"]]
- ,[]
- ,[Plain [Str "39"]]
- ,[Plain [Str "40"]]]]
-,Table [] [AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]
- []
- [[[Plain [Str "0"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]
- ,[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]
- ,[Plain [Str "7"]]
- ,[Plain [Str "8"]]
- ,[Plain [Str "9"]]
- ,[Plain [Str "A"]]
- ,[Plain [Str "B"]]
- ,[Plain [Str "C"]]
- ,[Plain [Str "D"]]
- ,[Plain [Str "E"]]
- ,[Plain [Str "F"]]
- ,[Plain [Str "0"]]
- ,[Plain [Str "1"]]
- ,[Plain [Str "2"]]
- ,[Plain [Str "3"]]
- ,[Plain [Str "4"]]
- ,[Plain [Str "5"]]
- ,[Plain [Str "6"]]
- ,[Plain [Str "7"]]
- ,[Plain [Str "8"]]
- ,[Plain [Str "9"]]
- ,[Plain [Str "A"]]
- ,[Plain [Str "B"]]
- ,[Plain [Str "C"]]
- ,[Plain [Str "D"]]
- ,[Plain [Str "E"]]
- ,[Plain [Str "F"]]]]
-,Table [] [AlignCenter] [0.0]
- []
- [[[]]
- ,[[]]
- ,[[]]]
-,Para [Str "|this|is|not|a|table|"]
-,Para [Str "|this|",Space,Str "is|",Space,Str "not|",Space,Str "a|",Space,Str "table|"]
-,Para [Str "|this",Space,Str "|is",Space,Str "|not",Space,Str "|a",Space,Str "|table",Space,Str "|"]
-,Para [Str "|",Space,Str "this\t|",Space,Str "is\t|",Space,Str "not\t|",Space,Str "a\t|",Space,Str "table\t|"]
-,HorizontalRule
-,Para [Str "The",Space,Str "End."]]
diff --git a/tests/writer.asciidoc b/tests/writer.asciidoc
deleted file mode 100644
index 2bf62e36f..000000000
--- a/tests/writer.asciidoc
+++ /dev/null
@@ -1,693 +0,0 @@
-Pandoc Test Suite
-=================
-John MacFarlane; Anonymous
-July 17, 2006
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
-markdown test suite.
-
-'''''
-
-[[headers]]
-Headers
--------
-
-[[level-2-with-an-embedded-link]]
-Level 2 with an link:/url[embedded link]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-[[level-3-with-emphasis]]
-Level 3 with _emphasis_
-^^^^^^^^^^^^^^^^^^^^^^^
-
-[[level-4]]
-Level 4
-+++++++
-
-[[level-5]]
-Level 5
-
-[[level-1]]
-Level 1
--------
-
-[[level-2-with-emphasis]]
-Level 2 with _emphasis_
-~~~~~~~~~~~~~~~~~~~~~~~
-
-[[level-3]]
-Level 3
-^^^^^^^
-
-with no blank line
-
-[[level-2]]
-Level 2
-~~~~~~~
-
-with no blank line
-
-'''''
-
-[[paragraphs]]
-Paragraphs
-----------
-
-Here’s a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here’s one with a bullet. * criminey.
-
-There should be a hard line break +
-here.
-
-'''''
-
-[[block-quotes]]
-Block Quotes
-------------
-
-E-mail style:
-
-__________________________________________
-This is a block quote. It is pretty short.
-__________________________________________
-
-______________________
---
-Code in a block quote:
-
-....
-sub status {
- print "working";
-}
-....
-
-A list:
-
-1. item one
-2. item two
-
-Nested block quotes:
-
-______
-nested
-______
-
-______
-nested
-______
-
---
-______________________
-
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
-'''''
-
-[[code-blocks]]
-Code Blocks
------------
-
-Code:
-
-....
----- (should be four hyphens)
-
-sub status {
- print "working";
-}
-
-this code block is indented by one tab
-....
-
-And:
-
-....
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \> \[ \{
-....
-
-'''''
-
-[[lists]]
-Lists
------
-
-[[unordered]]
-Unordered
-~~~~~~~~~
-
-Asterisks tight:
-
-* asterisk 1
-* asterisk 2
-* asterisk 3
-
-Asterisks loose:
-
-* asterisk 1
-* asterisk 2
-* asterisk 3
-
-Pluses tight:
-
-* Plus 1
-* Plus 2
-* Plus 3
-
-Pluses loose:
-
-* Plus 1
-* Plus 2
-* Plus 3
-
-Minuses tight:
-
-* Minus 1
-* Minus 2
-* Minus 3
-
-Minuses loose:
-
-* Minus 1
-* Minus 2
-* Minus 3
-
-[[ordered]]
-Ordered
-~~~~~~~
-
-Tight:
-
-1. First
-2. Second
-3. Third
-
-and:
-
-1. One
-2. Two
-3. Three
-
-Loose using tabs:
-
-1. First
-2. Second
-3. Third
-
-and using spaces:
-
-1. One
-2. Two
-3. Three
-
-Multiple paragraphs:
-
-1. Item 1, graf one.
-+
-Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
-2. Item 2.
-3. Item 3.
-
-[[nested]]
-Nested
-~~~~~~
-
-* Tab
-** Tab
-*** Tab
-
-Here’s another:
-
-1. First
-2. Second:
-* Fee
-* Fie
-* Foe
-3. Third
-
-Same thing but with paragraphs:
-
-1. First
-2. Second:
-* Fee
-* Fie
-* Foe
-3. Third
-
-[[tabs-and-spaces]]
-Tabs and spaces
-~~~~~~~~~~~~~~~
-
-* this is a list item indented with tabs
-* this is a list item indented with spaces
-** this is an example list item indented with tabs
-** this is an example list item indented with spaces
-
-[[fancy-list-markers]]
-Fancy list markers
-~~~~~~~~~~~~~~~~~~
-
-1. begins with 2
-2. and now 3
-+
-with a continuation
-a. sublist with roman numerals, starting with 4
-b. more items
-A. a subsublist
-B. a subsublist
-
-Nesting:
-
-A. Upper Alpha
-A. Upper Roman.
-1. Decimal start with 6
-a. Lower alpha with paren
-
-Autonumbering:
-
-1. Autonumber.
-2. More.
-1. Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-'''''
-
-[[definition-lists]]
-Definition Lists
-----------------
-
-Tight using spaces:
-
-apple::
- red fruit
-orange::
- orange fruit
-banana::
- yellow fruit
-
-Tight using tabs:
-
-apple::
- red fruit
-orange::
- orange fruit
-banana::
- yellow fruit
-
-Loose:
-
-apple::
- red fruit
-orange::
- orange fruit
-banana::
- yellow fruit
-
-Multiple blocks with italics:
-
-_apple_::
- red fruit
- +
- contains seeds, crisp, pleasant to taste
-_orange_::
- orange fruit
- +
-....
-{ orange code block }
-....
- +
- __________________
- orange block quote
- __________________
-
-Multiple definitions, tight:
-
-apple::
- red fruit
- +
- computer
-orange::
- orange fruit
- +
- bank
-
-Multiple definitions, loose:
-
-apple::
- red fruit
- +
- computer
-orange::
- orange fruit
- +
- bank
-
-Blank line after term, indented marker, alternate markers:
-
-apple::
- red fruit
- +
- computer
-orange::
- orange fruit
- +
- 1. sublist
- 2. sublist
-
-[[html-blocks]]
-HTML Blocks
------------
-
-Simple block on one line:
-
-foo
-
-And nested without indentation:
-
-foo
-
-bar
-
-Interpreted markdown in a table:
-
-This is _emphasized_
-
-And this is *strong*
-
-Here’s a simple block:
-
-foo
-
-This should be a code block, though:
-
-....
-<div>
- foo
-</div>
-....
-
-As should this:
-
-....
-<div>foo</div>
-....
-
-Now, nested:
-
-foo
-
-This should just be an HTML comment:
-
-Multiline:
-
-Code block:
-
-....
-<!-- Comment -->
-....
-
-Just plain comment, with trailing spaces on the line:
-
-Code:
-
-....
-<hr />
-....
-
-Hr’s:
-
-'''''
-
-[[inline-markup]]
-Inline Markup
--------------
-
-This is _emphasized_, and so _is this_.
-
-This is *strong*, and so *is this*.
-
-An _link:/url[emphasized link]_.
-
-*_This is strong and em._*
-
-So is *_this_* word.
-
-*_This is strong and em._*
-
-So is *_this_* word.
-
-This is code: `>`, `$`, `\`, `\$`, `<html>`.
-
-[line-through]*This is _strikeout_.*
-
-Superscripts: a^bc^d a^_hello_^ a^hello there^.
-
-Subscripts: H~2~O, H~23~O, H~many of them~O.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a^b c^d, a~b c~d.
-
-'''''
-
-[[smart-quotes-ellipses-dashes]]
-Smart quotes, ellipses, dashes
-------------------------------
-
-``Hello,'' said the spider. ```Shelob' is my name.''
-
-`A', `B', and `C' are letters.
-
-`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
-
-`He said, ``I want to go.''' Were you alive in the 70’s?
-
-Here is some quoted ``code`' and a ``http://example.com/?foo=1&bar=2[quoted
-link]''.
-
-Some dashes: one—two — three—four — five.
-
-Dashes between numbers: 5–7, 255–66, 1987–1999.
-
-Ellipses…and…and….
-
-'''''
-
-[[latex]]
-LaTeX
------
-
-*
-* latexmath:[$2+2=4$]
-* latexmath:[$x \in y$]
-* latexmath:[$\alpha \wedge \omega$]
-* latexmath:[$223$]
-* latexmath:[$p$]-Tree
-* Here’s some display math:
-latexmath:[\[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\]]
-* Here’s one that has a line break in it:
-latexmath:[$\alpha + \omega \times x^2$].
-
-These shouldn’t be math:
-
-* To get the famous equation, write `$e = mc^2$`.
-* $22,000 is a _lot_ of money. So is $34,000. (It worked if ``lot'' is
-emphasized.)
-* Shoes ($20) and socks ($5).
-* Escaped `$`: $73 _this should be emphasized_ 23$.
-
-Here’s a LaTeX table:
-
-'''''
-
-[[special-characters]]
-Special Characters
-------------------
-
-Here is some unicode:
-
-* I hat: Î
-* o umlaut: ö
-* section: §
-* set membership: ∈
-* copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: _
-
-Left brace: \{
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-'''''
-
-[[links]]
-Links
------
-
-[[explicit]]
-Explicit
-~~~~~~~~
-
-Just a link:/url/[URL].
-
-link:/url/[URL and title].
-
-link:/url/[URL and title].
-
-link:/url/[URL and title].
-
-link:/url/[URL and title]
-
-link:/url/[URL and title]
-
-link:/url/with_underscore[with_underscore]
-
-mailto:nobody@nowhere.net[Email link]
-
-link:[Empty].
-
-[[reference]]
-Reference
-~~~~~~~~~
-
-Foo link:/url/[bar].
-
-Foo link:/url/[bar].
-
-Foo link:/url/[bar].
-
-With link:/url/[embedded [brackets]].
-
-link:/url/[b] by itself should be a link.
-
-Indented link:/url[once].
-
-Indented link:/url[twice].
-
-Indented link:/url[thrice].
-
-This should [not][] be a link.
-
-....
-[not]: /url
-....
-
-Foo link:/url/[bar].
-
-Foo link:/url/[biz].
-
-[[with-ampersands]]
-With ampersands
-~~~~~~~~~~~~~~~
-
-Here’s a http://example.com/?foo=1&bar=2[link with an ampersand in the URL].
-
-Here’s a link with an amersand in the link text: http://att.com/[AT&T].
-
-Here’s an link:/script?foo=1&bar=2[inline link].
-
-Here’s an link:/script?foo=1&bar=2[inline link in pointy braces].
-
-[[autolinks]]
-Autolinks
-~~~~~~~~~
-
-With an ampersand: http://example.com/?foo=1&bar=2
-
-* In a list?
-* http://example.com/
-* It should.
-
-An e-mail address: nobody@nowhere.net
-
-________________________________
-Blockquoted: http://example.com/
-________________________________
-
-Auto-links should not occur here: `<http://example.com/>`
-
-....
-or here: <http://example.com/>
-....
-
-'''''
-
-[[images]]
-Images
-------
-
-From ``Voyage dans la Lune'' by Georges Melies (1902):
-
-image:lalune.jpg[lalune,title="Voyage dans la Lune"]
-
-Here is a movie image:movie.jpg[movie] icon.
-
-'''''
-
-[[footnotes]]
-Footnotes
----------
-
-Here is a footnote reference,footnote:[Here is the footnote. It can go
-anywhere after the footnote reference. It need not be placed at the end of the
-document.] and another.[multiblock footnote omitted] This should _not_ be a
-footnote reference, because it contains a space.[^my note] Here is an inline
-note.footnote:[This is _easier_ to type. Inline notes may contain
-http://google.com[links] and `]` verbatim characters, as well as [bracketed
-text].]
-
-___________________________________________
-Notes can go in quotes.footnote:[In quote.]
-___________________________________________
-
-1. And in list items.footnote:[In list.]
-
-This paragraph should not be part of the note, as it is not indented.
diff --git a/tests/writer.context b/tests/writer.context
deleted file mode 100644
index 04df66178..000000000
--- a/tests/writer.context
+++ /dev/null
@@ -1,888 +0,0 @@
-% Enable hyperlinks
-\setupinteraction
- [state=start,
- title={Pandoc Test Suite},
- author={John MacFarlane; Anonymous},
- style=,
- color=,
- contrastcolor=]
-% make chapter, section bookmarks visible when opening document
-\placebookmarks[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][chapter, section]
-\setupinteractionscreen[option=bookmark]
-\setuptagging[state=start]
-
-% use microtypography
-\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
-\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
-\setupalign[hz,hanging]
-\setupitaliccorrection[global, always]
-\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
-\usemodule[simplefonts]
-\setmainfontfallback[DejaVu Serif][range={greekandcoptic, greekextended}, force=yes, rscale=auto]
-\setupwhitespace[medium]
-
-\setuphead[chapter] [style=\tfd,header=empty]
-\setuphead[section] [style=\tfc]
-\setuphead[subsection] [style=\tfb]
-\setuphead[subsubsection] [style=\bf]
-\setuphead[subsubsubsection] [style=\sc]
-\setuphead[subsubsubsubsection][style=\it]
-
-\setuphead[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][number=no]
-
-\definedescription
- [description]
- [headstyle=bold, style=normal, location=hanging, width=broad, margin=1cm, alternative=hanging]
-
-\setupitemize[autointro] % prevent orphan list intro
-\setupitemize[indentnext=no]
-
-\setupfloat[figure][default={here,nonumber}]
-\setupfloat[table][default={here,nonumber}]
-
-\setupthinrules[width=15em] % width of horizontal rules
-
-
-\starttext
-\startalignment[middle]
- {\tfd Pandoc Test Suite}
- \smallskip
- {\tfa John MacFarlane\crlf Anonymous}
- \smallskip
- {\tfa July 17, 2006}
- \bigskip
-\stopalignment
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber's
-markdown test suite.
-
-\thinrule
-
-\section[headers]{Headers}
-
-\subsection[level-2-with-an-embedded-link]{Level 2 with an
-\useURL[url1][/url][][embedded link]\from[url1]}
-
-\subsubsection[level-3-with-emphasis]{Level 3 with {\em emphasis}}
-
-\subsubsubsection[level-4]{Level 4}
-
-\subsubsubsubsection[level-5]{Level 5}
-
-\section[level-1]{Level 1}
-
-\subsection[level-2-with-emphasis]{Level 2 with {\em emphasis}}
-
-\subsubsection[level-3]{Level 3}
-
-with no blank line
-
-\subsection[level-2]{Level 2}
-
-with no blank line
-
-\thinrule
-
-\section[paragraphs]{Paragraphs}
-
-Here's a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here's one with a bullet. * criminey.
-
-There should be a hard line break\crlf
-here.
-
-\thinrule
-
-\section[block-quotes]{Block Quotes}
-
-E-mail style:
-
-\startblockquote
-This is a block quote. It is pretty short.
-\stopblockquote
-
-\startblockquote
-Code in a block quote:
-
-\starttyping
-sub status {
- print "working";
-}
-\stoptyping
-
-A list:
-
-\startitemize[n,packed][stopper=.]
-\item
- item one
-\item
- item two
-\stopitemize
-
-Nested block quotes:
-
-\startblockquote
-nested
-\stopblockquote
-
-\startblockquote
-nested
-\stopblockquote
-\stopblockquote
-
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
-\thinrule
-
-\section[code-blocks]{Code Blocks}
-
-Code:
-
-\starttyping
----- (should be four hyphens)
-
-sub status {
- print "working";
-}
-
-this code block is indented by one tab
-\stoptyping
-
-And:
-
-\starttyping
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \> \[ \{
-\stoptyping
-
-\thinrule
-
-\section[lists]{Lists}
-
-\subsection[unordered]{Unordered}
-
-Asterisks tight:
-
-\startitemize[packed]
-\item
- asterisk 1
-\item
- asterisk 2
-\item
- asterisk 3
-\stopitemize
-
-Asterisks loose:
-
-\startitemize
-\item
- asterisk 1
-\item
- asterisk 2
-\item
- asterisk 3
-\stopitemize
-
-Pluses tight:
-
-\startitemize[packed]
-\item
- Plus 1
-\item
- Plus 2
-\item
- Plus 3
-\stopitemize
-
-Pluses loose:
-
-\startitemize
-\item
- Plus 1
-\item
- Plus 2
-\item
- Plus 3
-\stopitemize
-
-Minuses tight:
-
-\startitemize[packed]
-\item
- Minus 1
-\item
- Minus 2
-\item
- Minus 3
-\stopitemize
-
-Minuses loose:
-
-\startitemize
-\item
- Minus 1
-\item
- Minus 2
-\item
- Minus 3
-\stopitemize
-
-\subsection[ordered]{Ordered}
-
-Tight:
-
-\startitemize[n,packed][stopper=.]
-\item
- First
-\item
- Second
-\item
- Third
-\stopitemize
-
-and:
-
-\startitemize[n,packed][stopper=.]
-\item
- One
-\item
- Two
-\item
- Three
-\stopitemize
-
-Loose using tabs:
-
-\startitemize[n][stopper=.]
-\item
- First
-\item
- Second
-\item
- Third
-\stopitemize
-
-and using spaces:
-
-\startitemize[n][stopper=.]
-\item
- One
-\item
- Two
-\item
- Three
-\stopitemize
-
-Multiple paragraphs:
-
-\startitemize[n][stopper=.]
-\item
- Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
-\item
- Item 2.
-\item
- Item 3.
-\stopitemize
-
-\subsection[nested]{Nested}
-
-\startitemize[packed]
-\item
- Tab
- \startitemize[packed]
- \item
- Tab
- \startitemize[packed]
- \item
- Tab
- \stopitemize
- \stopitemize
-\stopitemize
-
-Here's another:
-
-\startitemize[n,packed][stopper=.]
-\item
- First
-\item
- Second:
- \startitemize[packed]
- \item
- Fee
- \item
- Fie
- \item
- Foe
- \stopitemize
-\item
- Third
-\stopitemize
-
-Same thing but with paragraphs:
-
-\startitemize[n][stopper=.]
-\item
- First
-\item
- Second:
-
- \startitemize[packed]
- \item
- Fee
- \item
- Fie
- \item
- Foe
- \stopitemize
-\item
- Third
-\stopitemize
-
-\subsection[tabs-and-spaces]{Tabs and spaces}
-
-\startitemize
-\item
- this is a list item indented with tabs
-\item
- this is a list item indented with spaces
-
- \startitemize
- \item
- this is an example list item indented with tabs
- \item
- this is an example list item indented with spaces
- \stopitemize
-\stopitemize
-
-\subsection[fancy-list-markers]{Fancy list markers}
-
-\startitemize[n][start=2,left=(,stopper=),width=2.0em]
-\item
- begins with 2
-\item
- and now 3
-
- with a continuation
-
- \startitemize[r,packed][start=4,stopper=.,width=2.0em]
- \item
- sublist with roman numerals, starting with 4
- \item
- more items
- \startitemize[A,packed][left=(,stopper=),width=2.0em]
- \item
- a subsublist
- \item
- a subsublist
- \stopitemize
- \stopitemize
-\stopitemize
-
-Nesting:
-
-\startitemize[A,packed][stopper=.]
-\item
- Upper Alpha
- \startitemize[R,packed][stopper=.]
- \item
- Upper Roman.
- \startitemize[n,packed][start=6,left=(,stopper=),width=2.0em]
- \item
- Decimal start with 6
- \startitemize[a,packed][start=3,stopper=)]
- \item
- Lower alpha with paren
- \stopitemize
- \stopitemize
- \stopitemize
-\stopitemize
-
-Autonumbering:
-
-\startitemize[n,packed]
-\item
- Autonumber.
-\item
- More.
- \startitemize[a,packed]
- \item
- Nested.
- \stopitemize
-\stopitemize
-
-Should not be a list item:
-
-M.A.~2007
-
-B. Williams
-
-\thinrule
-
-\section[definition-lists]{Definition Lists}
-
-Tight using spaces:
-
-\startdescription{apple}
- red fruit
-\stopdescription
-
-\startdescription{orange}
- orange fruit
-\stopdescription
-
-\startdescription{banana}
- yellow fruit
-\stopdescription
-
-Tight using tabs:
-
-\startdescription{apple}
- red fruit
-\stopdescription
-
-\startdescription{orange}
- orange fruit
-\stopdescription
-
-\startdescription{banana}
- yellow fruit
-\stopdescription
-
-Loose:
-
-\startdescription{apple}
- red fruit
-\stopdescription
-
-\startdescription{orange}
- orange fruit
-\stopdescription
-
-\startdescription{banana}
- yellow fruit
-\stopdescription
-
-Multiple blocks with italics:
-
-\startdescription{{\em apple}}
- red fruit
-
- contains seeds, crisp, pleasant to taste
-\stopdescription
-
-\startdescription{{\em orange}}
- orange fruit
-
-\starttyping
-{ orange code block }
-\stoptyping
-
- \startblockquote
- orange block quote
- \stopblockquote
-\stopdescription
-
-Multiple definitions, tight:
-
-\startdescription{apple}
- red fruit
-
- computer
-\stopdescription
-
-\startdescription{orange}
- orange fruit
-
- bank
-\stopdescription
-
-Multiple definitions, loose:
-
-\startdescription{apple}
- red fruit
-
- computer
-\stopdescription
-
-\startdescription{orange}
- orange fruit
-
- bank
-\stopdescription
-
-Blank line after term, indented marker, alternate markers:
-
-\startdescription{apple}
- red fruit
-
- computer
-\stopdescription
-
-\startdescription{orange}
- orange fruit
-
- \startitemize[n,packed][stopper=.]
- \item
- sublist
- \item
- sublist
- \stopitemize
-\stopdescription
-
-\section[html-blocks]{HTML Blocks}
-
-Simple block on one line:
-
-foo
-
-And nested without indentation:
-
-foo
-
-bar
-
-Interpreted markdown in a table:
-
-This is {\em emphasized}
-And this is {\bf strong}
-Here's a simple block:
-
-foo
-
-This should be a code block, though:
-
-\starttyping
-<div>
- foo
-</div>
-\stoptyping
-
-As should this:
-
-\starttyping
-<div>foo</div>
-\stoptyping
-
-Now, nested:
-
-foo
-
-This should just be an HTML comment:
-
-Multiline:
-
-Code block:
-
-\starttyping
-<!-- Comment -->
-\stoptyping
-
-Just plain comment, with trailing spaces on the line:
-
-Code:
-
-\starttyping
-<hr />
-\stoptyping
-
-Hr's:
-
-\thinrule
-
-\section[inline-markup]{Inline Markup}
-
-This is {\em emphasized}, and so {\em is this}.
-
-This is {\bf strong}, and so {\bf is this}.
-
-An {\em \useURL[url2][/url][][emphasized link]\from[url2]}.
-
-{\bf {\em This is strong and em.}}
-
-So is {\bf {\em this}} word.
-
-{\bf {\em This is strong and em.}}
-
-So is {\bf {\em this}} word.
-
-This is code: \type{>}, \type{$}, \type{\}, \type{\$}, \type{<html>}.
-
-\overstrikes{This is {\em strikeout}.}
-
-Superscripts: a\high{bc}d a\high{{\em hello}} a\high{hello~there}.
-
-Subscripts: H\low{2}O, H\low{23}O, H\low{many~of~them}O.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a^b c^d, a\lettertilde{}b c\lettertilde{}d.
-
-\thinrule
-
-\section[smart-quotes-ellipses-dashes]{Smart quotes, ellipses, dashes}
-
-\quotation{Hello,} said the spider. \quotation{\quote{Shelob} is my name.}
-
-\quote{A}, \quote{B}, and \quote{C} are letters.
-
-\quote{Oak,} \quote{elm,} and \quote{beech} are names of trees. So is
-\quote{pine.}
-
-\quote{He said, \quotation{I want to go.}} Were you alive in the 70's?
-
-Here is some quoted \quote{\type{code}} and a
-\quotation{\useURL[url3][http://example.com/?foo=1&bar=2][][quoted
-link]\from[url3]}.
-
-Some dashes: one---two --- three---four --- five.
-
-Dashes between numbers: 5--7, 255--66, 1987--1999.
-
-Ellipses\ldots{}and\ldots{}and\ldots{}.
-
-\thinrule
-
-\section[latex]{LaTeX}
-
-\startitemize[packed]
-\item
- \cite[22-23]{smith.1899}
-\item
- $2+2=4$
-\item
- $x \in y$
-\item
- $\alpha \wedge \omega$
-\item
- $223$
-\item
- $p$-Tree
-\item
- Here's some display math:
- \startformula \frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h} \stopformula
-\item
- Here's one that has a line break in it: $\alpha + \omega \times x^2$.
-\stopitemize
-
-These shouldn't be math:
-
-\startitemize[packed]
-\item
- To get the famous equation, write \type{$e = mc^2$}.
-\item
- \$22,000 is a {\em lot} of money. So is \$34,000. (It worked if
- \quotation{lot} is emphasized.)
-\item
- Shoes (\$20) and socks (\$5).
-\item
- Escaped \type{$}: \$73 {\em this should be emphasized} 23\$.
-\stopitemize
-
-Here's a LaTeX table:
-
-\thinrule
-
-\section[special-characters]{Special Characters}
-
-Here is some unicode:
-
-\startitemize[packed]
-\item
- I hat: Î
-\item
- o umlaut: ö
-\item
- section: §
-\item
- set membership: ∈
-\item
- copyright: ©
-\stopitemize
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \letterbackslash{}
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: _
-
-Left brace: \{
-
-Right brace: \}
-
-Left bracket: {[}
-
-Right bracket: {]}
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: \#
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-\thinrule
-
-\section[links]{Links}
-
-\subsection[explicit]{Explicit}
-
-Just a \useURL[url4][/url/][][URL]\from[url4].
-
-\useURL[url5][/url/][][URL and title]\from[url5].
-
-\useURL[url6][/url/][][URL and title]\from[url6].
-
-\useURL[url7][/url/][][URL and title]\from[url7].
-
-\useURL[url8][/url/][][URL and title]\from[url8]
-
-\useURL[url9][/url/][][URL and title]\from[url9]
-
-\useURL[url10][/url/with_underscore][][with_underscore]\from[url10]
-
-\useURL[url11][mailto:nobody@nowhere.net][][Email link]\from[url11]
-
-\useURL[url12][][][Empty]\from[url12].
-
-\subsection[reference]{Reference}
-
-Foo \useURL[url13][/url/][][bar]\from[url13].
-
-Foo \useURL[url14][/url/][][bar]\from[url14].
-
-Foo \useURL[url15][/url/][][bar]\from[url15].
-
-With \useURL[url16][/url/][][embedded {[}brackets{]}]\from[url16].
-
-\useURL[url17][/url/][][b]\from[url17] by itself should be a link.
-
-Indented \useURL[url18][/url][][once]\from[url18].
-
-Indented \useURL[url19][/url][][twice]\from[url19].
-
-Indented \useURL[url20][/url][][thrice]\from[url20].
-
-This should {[}not{]}{[}{]} be a link.
-
-\starttyping
-[not]: /url
-\stoptyping
-
-Foo \useURL[url21][/url/][][bar]\from[url21].
-
-Foo \useURL[url22][/url/][][biz]\from[url22].
-
-\subsection[with-ampersands]{With ampersands}
-
-Here's a \useURL[url23][http://example.com/?foo=1&bar=2][][link with an
-ampersand in the URL]\from[url23].
-
-Here's a link with an amersand in the link text:
-\useURL[url24][http://att.com/][][AT&T]\from[url24].
-
-Here's an \useURL[url25][/script?foo=1&bar=2][][inline link]\from[url25].
-
-Here's an \useURL[url26][/script?foo=1&bar=2][][inline link in pointy
-braces]\from[url26].
-
-\subsection[autolinks]{Autolinks}
-
-With an ampersand: \useURL[url27][http://example.com/?foo=1&bar=2]\from[url27]
-
-\startitemize[packed]
-\item
- In a list?
-\item
- \useURL[url28][http://example.com/]\from[url28]
-\item
- It should.
-\stopitemize
-
-An e-mail address:
-\useURL[url29][mailto:nobody@nowhere.net][][nobody@nowhere.net]\from[url29]
-
-\startblockquote
-Blockquoted: \useURL[url30][http://example.com/]\from[url30]
-\stopblockquote
-
-Auto-links should not occur here: \type{<http://example.com/>}
-
-\starttyping
-or here: <http://example.com/>
-\stoptyping
-
-\thinrule
-
-\section[images]{Images}
-
-From \quotation{Voyage dans la Lune} by Georges Melies (1902):
-
-\placefigure{lalune}{\externalfigure[lalune.jpg]}
-
-Here is a movie {\externalfigure[movie.jpg]} icon.
-
-\thinrule
-
-\section[footnotes]{Footnotes}
-
-Here is a footnote reference,\footnote{Here is the footnote. It can go
- anywhere after the footnote reference. It need not be placed at the end of
- the document.} and another.\startbuffer Here's the long note. This one
- contains multiple blocks.
-
- Subsequent blocks are indented to show that they belong to the footnote (as
- with list items).
-
-\starttyping
- { <code> }
-\stoptyping
-
- If you want, you can indent every line, but you can also be lazy and just
- indent the first line of each block.\stopbuffer\footnote{\getbuffer} This
-should {\em not} be a footnote reference, because it contains a space.{[}^my
-note{]} Here is an inline note.\footnote{This is {\em easier} to type. Inline
- notes may contain \useURL[url31][http://google.com][][links]\from[url31] and
- \type{]} verbatim characters, as well as {[}bracketed text{]}.}
-
-\startblockquote
-Notes can go in quotes.\footnote{In quote.}
-\stopblockquote
-
-\startitemize[n,packed][stopper=.]
-\item
- And in list items.\footnote{In list.}
-\stopitemize
-
-This paragraph should not be part of the note, as it is not indented.
-
-\stoptext
diff --git a/tests/writer.docbook b/tests/writer.docbook
deleted file mode 100644
index eee19cdd9..000000000
--- a/tests/writer.docbook
+++ /dev/null
@@ -1,1422 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<article>
- <articleinfo>
- <title>Pandoc Test Suite</title>
- <authorgroup>
- <author>
- <firstname>John</firstname>
- <surname>MacFarlane</surname>
- </author>
- <author>
- <firstname></firstname>
- <surname>Anonymous</surname>
- </author>
- </authorgroup>
- <date>July 17, 2006</date>
- </articleinfo>
-<para>
- This is a set of tests for pandoc. Most of them are adapted from John
- Gruber’s markdown test suite.
-</para>
-<sect1 id="headers">
- <title>Headers</title>
- <sect2 id="level-2-with-an-embedded-link">
- <title>Level 2 with an <ulink url="/url">embedded link</ulink></title>
- <sect3 id="level-3-with-emphasis">
- <title>Level 3 with <emphasis>emphasis</emphasis></title>
- <sect4 id="level-4">
- <title>Level 4</title>
- <sect5 id="level-5">
- <title>Level 5</title>
- <para>
- </para>
- </sect5>
- </sect4>
- </sect3>
- </sect2>
-</sect1>
-<sect1 id="level-1">
- <title>Level 1</title>
- <sect2 id="level-2-with-emphasis">
- <title>Level 2 with <emphasis>emphasis</emphasis></title>
- <sect3 id="level-3">
- <title>Level 3</title>
- <para>
- with no blank line
- </para>
- </sect3>
- </sect2>
- <sect2 id="level-2">
- <title>Level 2</title>
- <para>
- with no blank line
- </para>
- </sect2>
-</sect1>
-<sect1 id="paragraphs">
- <title>Paragraphs</title>
- <para>
- Here’s a regular paragraph.
- </para>
- <para>
- In Markdown 1.0.0 and earlier. Version 8. This line turns into a list
- item. Because a hard-wrapped line in the middle of a paragraph looked like
- a list item.
- </para>
- <para>
- Here’s one with a bullet. * criminey.
- </para>
-<literallayout>There should be a hard line break
-here.</literallayout>
-</sect1>
-<sect1 id="block-quotes">
- <title>Block Quotes</title>
- <para>
- E-mail style:
- </para>
- <blockquote>
- <para>
- This is a block quote. It is pretty short.
- </para>
- </blockquote>
- <blockquote>
- <para>
- Code in a block quote:
- </para>
- <programlisting>
-sub status {
- print &quot;working&quot;;
-}
-</programlisting>
- <para>
- A list:
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- item one
- </para>
- </listitem>
- <listitem>
- <para>
- item two
- </para>
- </listitem>
- </orderedlist>
- <para>
- Nested block quotes:
- </para>
- <blockquote>
- <para>
- nested
- </para>
- </blockquote>
- <blockquote>
- <para>
- nested
- </para>
- </blockquote>
- </blockquote>
- <para>
- This should not be a block quote: 2 &gt; 1.
- </para>
- <para>
- And a following paragraph.
- </para>
-</sect1>
-<sect1 id="code-blocks">
- <title>Code Blocks</title>
- <para>
- Code:
- </para>
- <programlisting>
----- (should be four hyphens)
-
-sub status {
- print &quot;working&quot;;
-}
-
-this code block is indented by one tab
-</programlisting>
- <para>
- And:
- </para>
- <programlisting>
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \&gt; \[ \{
-</programlisting>
-</sect1>
-<sect1 id="lists">
- <title>Lists</title>
- <sect2 id="unordered">
- <title>Unordered</title>
- <para>
- Asterisks tight:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- asterisk 1
- </para>
- </listitem>
- <listitem>
- <para>
- asterisk 2
- </para>
- </listitem>
- <listitem>
- <para>
- asterisk 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Asterisks loose:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- asterisk 1
- </para>
- </listitem>
- <listitem>
- <para>
- asterisk 2
- </para>
- </listitem>
- <listitem>
- <para>
- asterisk 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Pluses tight:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Plus 1
- </para>
- </listitem>
- <listitem>
- <para>
- Plus 2
- </para>
- </listitem>
- <listitem>
- <para>
- Plus 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Pluses loose:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Plus 1
- </para>
- </listitem>
- <listitem>
- <para>
- Plus 2
- </para>
- </listitem>
- <listitem>
- <para>
- Plus 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Minuses tight:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Minus 1
- </para>
- </listitem>
- <listitem>
- <para>
- Minus 2
- </para>
- </listitem>
- <listitem>
- <para>
- Minus 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Minuses loose:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Minus 1
- </para>
- </listitem>
- <listitem>
- <para>
- Minus 2
- </para>
- </listitem>
- <listitem>
- <para>
- Minus 3
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="ordered">
- <title>Ordered</title>
- <para>
- Tight:
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- First
- </para>
- </listitem>
- <listitem>
- <para>
- Second
- </para>
- </listitem>
- <listitem>
- <para>
- Third
- </para>
- </listitem>
- </orderedlist>
- <para>
- and:
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- One
- </para>
- </listitem>
- <listitem>
- <para>
- Two
- </para>
- </listitem>
- <listitem>
- <para>
- Three
- </para>
- </listitem>
- </orderedlist>
- <para>
- Loose using tabs:
- </para>
- <orderedlist numeration="arabic">
- <listitem>
- <para>
- First
- </para>
- </listitem>
- <listitem>
- <para>
- Second
- </para>
- </listitem>
- <listitem>
- <para>
- Third
- </para>
- </listitem>
- </orderedlist>
- <para>
- and using spaces:
- </para>
- <orderedlist numeration="arabic">
- <listitem>
- <para>
- One
- </para>
- </listitem>
- <listitem>
- <para>
- Two
- </para>
- </listitem>
- <listitem>
- <para>
- Three
- </para>
- </listitem>
- </orderedlist>
- <para>
- Multiple paragraphs:
- </para>
- <orderedlist numeration="arabic">
- <listitem>
- <para>
- Item 1, graf one.
- </para>
- <para>
- Item 1. graf two. The quick brown fox jumped over the lazy dog’s
- back.
- </para>
- </listitem>
- <listitem>
- <para>
- Item 2.
- </para>
- </listitem>
- <listitem>
- <para>
- Item 3.
- </para>
- </listitem>
- </orderedlist>
- </sect2>
- <sect2 id="nested">
- <title>Nested</title>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Tab
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Tab
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Tab
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- <para>
- Here’s another:
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- First
- </para>
- </listitem>
- <listitem>
- <para>
- Second:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Fee
- </para>
- </listitem>
- <listitem>
- <para>
- Fie
- </para>
- </listitem>
- <listitem>
- <para>
- Foe
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- Third
- </para>
- </listitem>
- </orderedlist>
- <para>
- Same thing but with paragraphs:
- </para>
- <orderedlist numeration="arabic">
- <listitem>
- <para>
- First
- </para>
- </listitem>
- <listitem>
- <para>
- Second:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Fee
- </para>
- </listitem>
- <listitem>
- <para>
- Fie
- </para>
- </listitem>
- <listitem>
- <para>
- Foe
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- Third
- </para>
- </listitem>
- </orderedlist>
- </sect2>
- <sect2 id="tabs-and-spaces">
- <title>Tabs and spaces</title>
- <itemizedlist>
- <listitem>
- <para>
- this is a list item indented with tabs
- </para>
- </listitem>
- <listitem>
- <para>
- this is a list item indented with spaces
- </para>
- <itemizedlist>
- <listitem>
- <para>
- this is an example list item indented with tabs
- </para>
- </listitem>
- <listitem>
- <para>
- this is an example list item indented with spaces
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="fancy-list-markers">
- <title>Fancy list markers</title>
- <orderedlist numeration="arabic">
- <listitem override="2">
- <para>
- begins with 2
- </para>
- </listitem>
- <listitem>
- <para>
- and now 3
- </para>
- <para>
- with a continuation
- </para>
- <orderedlist numeration="lowerroman" spacing="compact">
- <listitem override="4">
- <para>
- sublist with roman numerals, starting with 4
- </para>
- </listitem>
- <listitem>
- <para>
- more items
- </para>
- <orderedlist numeration="upperalpha" spacing="compact">
- <listitem>
- <para>
- a subsublist
- </para>
- </listitem>
- <listitem>
- <para>
- a subsublist
- </para>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- <para>
- Nesting:
- </para>
- <orderedlist numeration="upperalpha" spacing="compact">
- <listitem>
- <para>
- Upper Alpha
- </para>
- <orderedlist numeration="upperroman" spacing="compact">
- <listitem>
- <para>
- Upper Roman.
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem override="6">
- <para>
- Decimal start with 6
- </para>
- <orderedlist numeration="loweralpha" spacing="compact">
- <listitem override="3">
- <para>
- Lower alpha with paren
- </para>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- <para>
- Autonumbering:
- </para>
- <orderedlist spacing="compact">
- <listitem>
- <para>
- Autonumber.
- </para>
- </listitem>
- <listitem>
- <para>
- More.
- </para>
- <orderedlist spacing="compact">
- <listitem>
- <para>
- Nested.
- </para>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- <para>
- Should not be a list item:
- </para>
- <para>
- M.A. 2007
- </para>
- <para>
- B. Williams
- </para>
- </sect2>
-</sect1>
-<sect1 id="definition-lists">
- <title>Definition Lists</title>
- <para>
- Tight using spaces:
- </para>
- <variablelist spacing="compact">
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- banana
- </term>
- <listitem>
- <para>
- yellow fruit
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Tight using tabs:
- </para>
- <variablelist spacing="compact">
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- banana
- </term>
- <listitem>
- <para>
- yellow fruit
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Loose:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- banana
- </term>
- <listitem>
- <para>
- yellow fruit
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Multiple blocks with italics:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- <emphasis>apple</emphasis>
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- <para>
- contains seeds, crisp, pleasant to taste
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- <emphasis>orange</emphasis>
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- <programlisting>
-{ orange code block }
-</programlisting>
- <blockquote>
- <para>
- orange block quote
- </para>
- </blockquote>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Multiple definitions, tight:
- </para>
- <variablelist spacing="compact">
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- <para>
- computer
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- <para>
- bank
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Multiple definitions, loose:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- <para>
- computer
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- <para>
- bank
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Blank line after term, indented marker, alternate markers:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- <para>
- computer
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- sublist
- </para>
- </listitem>
- <listitem>
- <para>
- sublist
- </para>
- </listitem>
- </orderedlist>
- </listitem>
- </varlistentry>
- </variablelist>
-</sect1>
-<sect1 id="html-blocks">
- <title>HTML Blocks</title>
- <para>
- Simple block on one line:
- </para>
- <para>
- foo
- </para>
- <para>
- And nested without indentation:
- </para>
- <para>
- foo
- </para>
- <para>
- bar
- </para>
- <para>
- Interpreted markdown in a table:
- </para>
- <table>
- <tr>
- <td>
- This is <emphasis>emphasized</emphasis>
- </td>
- <td>
- And this is <emphasis role="strong">strong</emphasis>
- </td>
- </tr>
- </table>
- <script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
- <para>
- Here’s a simple block:
- </para>
- <para>
- foo
- </para>
- <para>
- This should be a code block, though:
- </para>
- <programlisting>
-&lt;div&gt;
- foo
-&lt;/div&gt;
-</programlisting>
- <para>
- As should this:
- </para>
- <programlisting>
-&lt;div&gt;foo&lt;/div&gt;
-</programlisting>
- <para>
- Now, nested:
- </para>
- <para>
- foo
- </para>
- <para>
- This should just be an HTML comment:
- </para>
- <!-- Comment -->
- <para>
- Multiline:
- </para>
- <!--
- Blah
- Blah
- -->
- <!--
- This is another comment.
- -->
- <para>
- Code block:
- </para>
- <programlisting>
-&lt;!-- Comment --&gt;
-</programlisting>
- <para>
- Just plain comment, with trailing spaces on the line:
- </para>
- <!-- foo -->
- <para>
- Code:
- </para>
- <programlisting>
-&lt;hr /&gt;
-</programlisting>
- <para>
- Hr’s:
- </para>
- <hr>
- <hr />
- <hr />
- <hr>
- <hr />
- <hr />
- <hr class="foo" id="bar" />
- <hr class="foo" id="bar" />
- <hr class="foo" id="bar">
-</sect1>
-<sect1 id="inline-markup">
- <title>Inline Markup</title>
- <para>
- This is <emphasis>emphasized</emphasis>, and so <emphasis>is
- this</emphasis>.
- </para>
- <para>
- This is <emphasis role="strong">strong</emphasis>, and so
- <emphasis role="strong">is this</emphasis>.
- </para>
- <para>
- An <emphasis><ulink url="/url">emphasized link</ulink></emphasis>.
- </para>
- <para>
- <emphasis role="strong"><emphasis>This is strong and
- em.</emphasis></emphasis>
- </para>
- <para>
- So is <emphasis role="strong"><emphasis>this</emphasis></emphasis> word.
- </para>
- <para>
- <emphasis role="strong"><emphasis>This is strong and
- em.</emphasis></emphasis>
- </para>
- <para>
- So is <emphasis role="strong"><emphasis>this</emphasis></emphasis> word.
- </para>
- <para>
- This is code: <literal>&gt;</literal>, <literal>$</literal>,
- <literal>\</literal>, <literal>\$</literal>,
- <literal>&lt;html&gt;</literal>.
- </para>
- <para>
- <emphasis role="strikethrough">This is
- <emphasis>strikeout</emphasis>.</emphasis>
- </para>
- <para>
- Superscripts: a<superscript>bc</superscript>d
- a<superscript><emphasis>hello</emphasis></superscript>
- a<superscript>hello there</superscript>.
- </para>
- <para>
- Subscripts: H<subscript>2</subscript>O, H<subscript>23</subscript>O,
- H<subscript>many of them</subscript>O.
- </para>
- <para>
- These should not be superscripts or subscripts, because of the unescaped
- spaces: a^b c^d, a~b c~d.
- </para>
-</sect1>
-<sect1 id="smart-quotes-ellipses-dashes">
- <title>Smart quotes, ellipses, dashes</title>
- <para>
- <quote>Hello,</quote> said the spider. <quote><quote>Shelob</quote> is my
- name.</quote>
- </para>
- <para>
- <quote>A</quote>, <quote>B</quote>, and <quote>C</quote> are letters.
- </para>
- <para>
- <quote>Oak,</quote> <quote>elm,</quote> and <quote>beech</quote> are names
- of trees. So is <quote>pine.</quote>
- </para>
- <para>
- <quote>He said, <quote>I want to go.</quote></quote> Were you alive in the
- 70’s?
- </para>
- <para>
- Here is some quoted <quote><literal>code</literal></quote> and a
- <quote><ulink url="http://example.com/?foo=1&amp;bar=2">quoted
- link</ulink></quote>.
- </para>
- <para>
- Some dashes: one—two — three—four — five.
- </para>
- <para>
- Dashes between numbers: 5–7, 255–66, 1987–1999.
- </para>
- <para>
- Ellipses…and…and….
- </para>
-</sect1>
-<sect1 id="latex">
- <title>LaTeX</title>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- </para>
- </listitem>
- <listitem>
- <para>
- 2 + 2 = 4
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>x</emphasis> ∈ <emphasis>y</emphasis>
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>α</emphasis> ∧ <emphasis>ω</emphasis>
- </para>
- </listitem>
- <listitem>
- <para>
- 223
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>p</emphasis>-Tree
- </para>
- </listitem>
- <listitem>
- <para>
- Here’s some display math:
- $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
- </para>
- </listitem>
- <listitem>
- <para>
- Here’s one that has a line break in it:
- <emphasis>α</emphasis> + <emphasis>ω</emphasis> × <emphasis>x</emphasis><superscript>2</superscript>.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- These shouldn’t be math:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- To get the famous equation, write <literal>$e = mc^2$</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It
- worked if <quote>lot</quote> is emphasized.)
- </para>
- </listitem>
- <listitem>
- <para>
- Shoes ($20) and socks ($5).
- </para>
- </listitem>
- <listitem>
- <para>
- Escaped <literal>$</literal>: $73 <emphasis>this should be
- emphasized</emphasis> 23$.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Here’s a LaTeX table:
- </para>
-</sect1>
-<sect1 id="special-characters">
- <title>Special Characters</title>
- <para>
- Here is some unicode:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- I hat: Î
- </para>
- </listitem>
- <listitem>
- <para>
- o umlaut: ö
- </para>
- </listitem>
- <listitem>
- <para>
- section: §
- </para>
- </listitem>
- <listitem>
- <para>
- set membership: ∈
- </para>
- </listitem>
- <listitem>
- <para>
- copyright: ©
- </para>
- </listitem>
- </itemizedlist>
- <para>
- AT&amp;T has an ampersand in their name.
- </para>
- <para>
- AT&amp;T is another way to write it.
- </para>
- <para>
- This &amp; that.
- </para>
- <para>
- 4 &lt; 5.
- </para>
- <para>
- 6 &gt; 5.
- </para>
- <para>
- Backslash: \
- </para>
- <para>
- Backtick: `
- </para>
- <para>
- Asterisk: *
- </para>
- <para>
- Underscore: _
- </para>
- <para>
- Left brace: {
- </para>
- <para>
- Right brace: }
- </para>
- <para>
- Left bracket: [
- </para>
- <para>
- Right bracket: ]
- </para>
- <para>
- Left paren: (
- </para>
- <para>
- Right paren: )
- </para>
- <para>
- Greater-than: &gt;
- </para>
- <para>
- Hash: #
- </para>
- <para>
- Period: .
- </para>
- <para>
- Bang: !
- </para>
- <para>
- Plus: +
- </para>
- <para>
- Minus: -
- </para>
-</sect1>
-<sect1 id="links">
- <title>Links</title>
- <sect2 id="explicit">
- <title>Explicit</title>
- <para>
- Just a <ulink url="/url/">URL</ulink>.
- </para>
- <para>
- <ulink url="/url/">URL and title</ulink>.
- </para>
- <para>
- <ulink url="/url/">URL and title</ulink>.
- </para>
- <para>
- <ulink url="/url/">URL and title</ulink>.
- </para>
- <para>
- <ulink url="/url/">URL and title</ulink>
- </para>
- <para>
- <ulink url="/url/">URL and title</ulink>
- </para>
- <para>
- <ulink url="/url/with_underscore">with_underscore</ulink>
- </para>
- <para>
- Email link (<email>nobody@nowhere.net</email>)
- </para>
- <para>
- <ulink url="">Empty</ulink>.
- </para>
- </sect2>
- <sect2 id="reference">
- <title>Reference</title>
- <para>
- Foo <ulink url="/url/">bar</ulink>.
- </para>
- <para>
- Foo <ulink url="/url/">bar</ulink>.
- </para>
- <para>
- Foo <ulink url="/url/">bar</ulink>.
- </para>
- <para>
- With <ulink url="/url/">embedded [brackets]</ulink>.
- </para>
- <para>
- <ulink url="/url/">b</ulink> by itself should be a link.
- </para>
- <para>
- Indented <ulink url="/url">once</ulink>.
- </para>
- <para>
- Indented <ulink url="/url">twice</ulink>.
- </para>
- <para>
- Indented <ulink url="/url">thrice</ulink>.
- </para>
- <para>
- This should [not][] be a link.
- </para>
- <programlisting>
-[not]: /url
-</programlisting>
- <para>
- Foo <ulink url="/url/">bar</ulink>.
- </para>
- <para>
- Foo <ulink url="/url/">biz</ulink>.
- </para>
- </sect2>
- <sect2 id="with-ampersands">
- <title>With ampersands</title>
- <para>
- Here’s a <ulink url="http://example.com/?foo=1&amp;bar=2">link with an
- ampersand in the URL</ulink>.
- </para>
- <para>
- Here’s a link with an amersand in the link text:
- <ulink url="http://att.com/">AT&amp;T</ulink>.
- </para>
- <para>
- Here’s an <ulink url="/script?foo=1&amp;bar=2">inline link</ulink>.
- </para>
- <para>
- Here’s an <ulink url="/script?foo=1&amp;bar=2">inline link in pointy
- braces</ulink>.
- </para>
- </sect2>
- <sect2 id="autolinks">
- <title>Autolinks</title>
- <para>
- With an ampersand:
- <ulink url="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</ulink>
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- In a list?
- </para>
- </listitem>
- <listitem>
- <para>
- <ulink url="http://example.com/">http://example.com/</ulink>
- </para>
- </listitem>
- <listitem>
- <para>
- It should.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- An e-mail address: <email>nobody@nowhere.net</email>
- </para>
- <blockquote>
- <para>
- Blockquoted:
- <ulink url="http://example.com/">http://example.com/</ulink>
- </para>
- </blockquote>
- <para>
- Auto-links should not occur here:
- <literal>&lt;http://example.com/&gt;</literal>
- </para>
- <programlisting>
-or here: &lt;http://example.com/&gt;
-</programlisting>
- </sect2>
-</sect1>
-<sect1 id="images">
- <title>Images</title>
- <para>
- From <quote>Voyage dans la Lune</quote> by Georges Melies (1902):
- </para>
- <figure>
- <title>lalune</title>
- <mediaobject>
- <imageobject>
- <imagedata fileref="lalune.jpg" />
- </imageobject>
- <textobject><phrase>lalune</phrase></textobject>
- </mediaobject>
- </figure>
- <para>
- Here is a movie <inlinemediaobject>
- <imageobject>
- <imagedata fileref="movie.jpg" />
- </imageobject>
- </inlinemediaobject> icon.
- </para>
-</sect1>
-<sect1 id="footnotes">
- <title>Footnotes</title>
- <para>
- Here is a footnote reference,<footnote>
- <para>
- Here is the footnote. It can go anywhere after the footnote reference.
- It need not be placed at the end of the document.
- </para>
- </footnote> and another.<footnote>
- <para>
- Here’s the long note. This one contains multiple blocks.
- </para>
- <para>
- Subsequent blocks are indented to show that they belong to the
- footnote (as with list items).
- </para>
- <programlisting>
- { &lt;code&gt; }
-</programlisting>
- <para>
- If you want, you can indent every line, but you can also be lazy and
- just indent the first line of each block.
- </para>
- </footnote> This should <emphasis>not</emphasis> be a footnote reference,
- because it contains a space.[^my note] Here is an inline note.<footnote>
- <para>
- This is <emphasis>easier</emphasis> to type. Inline notes may contain
- <ulink url="http://google.com">links</ulink> and <literal>]</literal>
- verbatim characters, as well as [bracketed text].
- </para>
- </footnote>
- </para>
- <blockquote>
- <para>
- Notes can go in quotes.<footnote>
- <para>
- In quote.
- </para>
- </footnote>
- </para>
- </blockquote>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- And in list items.<footnote>
- <para>
- In list.
- </para>
- </footnote>
- </para>
- </listitem>
- </orderedlist>
- <para>
- This paragraph should not be part of the note, as it is not indented.
- </para>
-</sect1>
-</article>
diff --git a/tests/writer.docbook5 b/tests/writer.docbook5
deleted file mode 100644
index 07ca0f827..000000000
--- a/tests/writer.docbook5
+++ /dev/null
@@ -1,1397 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE article>
-<article
- xmlns="http://docbook.org/ns/docbook" version="5.0"
- xmlns:xlink="http://www.w3.org/1999/xlink" >
- <info>
- <title>Pandoc Test Suite</title>
- <authorgroup>
- <author>
- <firstname>John</firstname>
- <surname>MacFarlane</surname>
- </author>
- <author>
- <firstname></firstname>
- <surname>Anonymous</surname>
- </author>
- </authorgroup>
- <date>July 17, 2006</date>
- </info>
-<para>
- This is a set of tests for pandoc. Most of them are adapted from John
- Gruber’s markdown test suite.
-</para>
-<section xml:id="headers">
- <title>Headers</title>
- <section xml:id="level-2-with-an-embedded-link">
- <title>Level 2 with an <link xlink:href="/url">embedded
- link</link></title>
- <section xml:id="level-3-with-emphasis">
- <title>Level 3 with <emphasis>emphasis</emphasis></title>
- <section xml:id="level-4">
- <title>Level 4</title>
- <section xml:id="level-5">
- <title>Level 5</title>
- <para>
- </para>
- </section>
- </section>
- </section>
- </section>
-</section>
-<section xml:id="level-1">
- <title>Level 1</title>
- <section xml:id="level-2-with-emphasis">
- <title>Level 2 with <emphasis>emphasis</emphasis></title>
- <section xml:id="level-3">
- <title>Level 3</title>
- <para>
- with no blank line
- </para>
- </section>
- </section>
- <section xml:id="level-2">
- <title>Level 2</title>
- <para>
- with no blank line
- </para>
- </section>
-</section>
-<section xml:id="paragraphs">
- <title>Paragraphs</title>
- <para>
- Here’s a regular paragraph.
- </para>
- <para>
- In Markdown 1.0.0 and earlier. Version 8. This line turns into a list
- item. Because a hard-wrapped line in the middle of a paragraph looked like
- a list item.
- </para>
- <para>
- Here’s one with a bullet. * criminey.
- </para>
-<literallayout>There should be a hard line break
-here.</literallayout>
-</section>
-<section xml:id="block-quotes">
- <title>Block Quotes</title>
- <para>
- E-mail style:
- </para>
- <blockquote>
- <para>
- This is a block quote. It is pretty short.
- </para>
- </blockquote>
- <blockquote>
- <para>
- Code in a block quote:
- </para>
- <programlisting>
-sub status {
- print &quot;working&quot;;
-}
-</programlisting>
- <para>
- A list:
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- item one
- </para>
- </listitem>
- <listitem>
- <para>
- item two
- </para>
- </listitem>
- </orderedlist>
- <para>
- Nested block quotes:
- </para>
- <blockquote>
- <para>
- nested
- </para>
- </blockquote>
- <blockquote>
- <para>
- nested
- </para>
- </blockquote>
- </blockquote>
- <para>
- This should not be a block quote: 2 &gt; 1.
- </para>
- <para>
- And a following paragraph.
- </para>
-</section>
-<section xml:id="code-blocks">
- <title>Code Blocks</title>
- <para>
- Code:
- </para>
- <programlisting>
----- (should be four hyphens)
-
-sub status {
- print &quot;working&quot;;
-}
-
-this code block is indented by one tab
-</programlisting>
- <para>
- And:
- </para>
- <programlisting>
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \&gt; \[ \{
-</programlisting>
-</section>
-<section xml:id="lists">
- <title>Lists</title>
- <section xml:id="unordered">
- <title>Unordered</title>
- <para>
- Asterisks tight:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- asterisk 1
- </para>
- </listitem>
- <listitem>
- <para>
- asterisk 2
- </para>
- </listitem>
- <listitem>
- <para>
- asterisk 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Asterisks loose:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- asterisk 1
- </para>
- </listitem>
- <listitem>
- <para>
- asterisk 2
- </para>
- </listitem>
- <listitem>
- <para>
- asterisk 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Pluses tight:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Plus 1
- </para>
- </listitem>
- <listitem>
- <para>
- Plus 2
- </para>
- </listitem>
- <listitem>
- <para>
- Plus 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Pluses loose:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Plus 1
- </para>
- </listitem>
- <listitem>
- <para>
- Plus 2
- </para>
- </listitem>
- <listitem>
- <para>
- Plus 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Minuses tight:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Minus 1
- </para>
- </listitem>
- <listitem>
- <para>
- Minus 2
- </para>
- </listitem>
- <listitem>
- <para>
- Minus 3
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Minuses loose:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Minus 1
- </para>
- </listitem>
- <listitem>
- <para>
- Minus 2
- </para>
- </listitem>
- <listitem>
- <para>
- Minus 3
- </para>
- </listitem>
- </itemizedlist>
- </section>
- <section xml:id="ordered">
- <title>Ordered</title>
- <para>
- Tight:
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- First
- </para>
- </listitem>
- <listitem>
- <para>
- Second
- </para>
- </listitem>
- <listitem>
- <para>
- Third
- </para>
- </listitem>
- </orderedlist>
- <para>
- and:
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- One
- </para>
- </listitem>
- <listitem>
- <para>
- Two
- </para>
- </listitem>
- <listitem>
- <para>
- Three
- </para>
- </listitem>
- </orderedlist>
- <para>
- Loose using tabs:
- </para>
- <orderedlist numeration="arabic">
- <listitem>
- <para>
- First
- </para>
- </listitem>
- <listitem>
- <para>
- Second
- </para>
- </listitem>
- <listitem>
- <para>
- Third
- </para>
- </listitem>
- </orderedlist>
- <para>
- and using spaces:
- </para>
- <orderedlist numeration="arabic">
- <listitem>
- <para>
- One
- </para>
- </listitem>
- <listitem>
- <para>
- Two
- </para>
- </listitem>
- <listitem>
- <para>
- Three
- </para>
- </listitem>
- </orderedlist>
- <para>
- Multiple paragraphs:
- </para>
- <orderedlist numeration="arabic">
- <listitem>
- <para>
- Item 1, graf one.
- </para>
- <para>
- Item 1. graf two. The quick brown fox jumped over the lazy dog’s
- back.
- </para>
- </listitem>
- <listitem>
- <para>
- Item 2.
- </para>
- </listitem>
- <listitem>
- <para>
- Item 3.
- </para>
- </listitem>
- </orderedlist>
- </section>
- <section xml:id="nested">
- <title>Nested</title>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Tab
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Tab
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Tab
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- <para>
- Here’s another:
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- First
- </para>
- </listitem>
- <listitem>
- <para>
- Second:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Fee
- </para>
- </listitem>
- <listitem>
- <para>
- Fie
- </para>
- </listitem>
- <listitem>
- <para>
- Foe
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- Third
- </para>
- </listitem>
- </orderedlist>
- <para>
- Same thing but with paragraphs:
- </para>
- <orderedlist numeration="arabic">
- <listitem>
- <para>
- First
- </para>
- </listitem>
- <listitem>
- <para>
- Second:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Fee
- </para>
- </listitem>
- <listitem>
- <para>
- Fie
- </para>
- </listitem>
- <listitem>
- <para>
- Foe
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- Third
- </para>
- </listitem>
- </orderedlist>
- </section>
- <section xml:id="tabs-and-spaces">
- <title>Tabs and spaces</title>
- <itemizedlist>
- <listitem>
- <para>
- this is a list item indented with tabs
- </para>
- </listitem>
- <listitem>
- <para>
- this is a list item indented with spaces
- </para>
- <itemizedlist>
- <listitem>
- <para>
- this is an example list item indented with tabs
- </para>
- </listitem>
- <listitem>
- <para>
- this is an example list item indented with spaces
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </section>
- <section xml:id="fancy-list-markers">
- <title>Fancy list markers</title>
- <orderedlist numeration="arabic">
- <listitem override="2">
- <para>
- begins with 2
- </para>
- </listitem>
- <listitem>
- <para>
- and now 3
- </para>
- <para>
- with a continuation
- </para>
- <orderedlist numeration="lowerroman" spacing="compact">
- <listitem override="4">
- <para>
- sublist with roman numerals, starting with 4
- </para>
- </listitem>
- <listitem>
- <para>
- more items
- </para>
- <orderedlist numeration="upperalpha" spacing="compact">
- <listitem>
- <para>
- a subsublist
- </para>
- </listitem>
- <listitem>
- <para>
- a subsublist
- </para>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- <para>
- Nesting:
- </para>
- <orderedlist numeration="upperalpha" spacing="compact">
- <listitem>
- <para>
- Upper Alpha
- </para>
- <orderedlist numeration="upperroman" spacing="compact">
- <listitem>
- <para>
- Upper Roman.
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem override="6">
- <para>
- Decimal start with 6
- </para>
- <orderedlist numeration="loweralpha" spacing="compact">
- <listitem override="3">
- <para>
- Lower alpha with paren
- </para>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- <para>
- Autonumbering:
- </para>
- <orderedlist spacing="compact">
- <listitem>
- <para>
- Autonumber.
- </para>
- </listitem>
- <listitem>
- <para>
- More.
- </para>
- <orderedlist spacing="compact">
- <listitem>
- <para>
- Nested.
- </para>
- </listitem>
- </orderedlist>
- </listitem>
- </orderedlist>
- <para>
- Should not be a list item:
- </para>
- <para>
- M.A. 2007
- </para>
- <para>
- B. Williams
- </para>
- </section>
-</section>
-<section xml:id="definition-lists">
- <title>Definition Lists</title>
- <para>
- Tight using spaces:
- </para>
- <variablelist spacing="compact">
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- banana
- </term>
- <listitem>
- <para>
- yellow fruit
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Tight using tabs:
- </para>
- <variablelist spacing="compact">
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- banana
- </term>
- <listitem>
- <para>
- yellow fruit
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Loose:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- banana
- </term>
- <listitem>
- <para>
- yellow fruit
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Multiple blocks with italics:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- <emphasis>apple</emphasis>
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- <para>
- contains seeds, crisp, pleasant to taste
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- <emphasis>orange</emphasis>
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- <programlisting>
-{ orange code block }
-</programlisting>
- <blockquote>
- <para>
- orange block quote
- </para>
- </blockquote>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Multiple definitions, tight:
- </para>
- <variablelist spacing="compact">
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- <para>
- computer
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- <para>
- bank
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Multiple definitions, loose:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- <para>
- computer
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- <para>
- bank
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Blank line after term, indented marker, alternate markers:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- apple
- </term>
- <listitem>
- <para>
- red fruit
- </para>
- <para>
- computer
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- orange
- </term>
- <listitem>
- <para>
- orange fruit
- </para>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- sublist
- </para>
- </listitem>
- <listitem>
- <para>
- sublist
- </para>
- </listitem>
- </orderedlist>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
-<section xml:id="html-blocks">
- <title>HTML Blocks</title>
- <para>
- Simple block on one line:
- </para>
- <para>
- foo
- </para>
- <para>
- And nested without indentation:
- </para>
- <para>
- foo
- </para>
- <para>
- bar
- </para>
- <para>
- Interpreted markdown in a table:
- </para>
- This is <emphasis>emphasized</emphasis>
- And this is <emphasis role="strong">strong</emphasis>
- <para>
- Here’s a simple block:
- </para>
- <para>
- foo
- </para>
- <para>
- This should be a code block, though:
- </para>
- <programlisting>
-&lt;div&gt;
- foo
-&lt;/div&gt;
-</programlisting>
- <para>
- As should this:
- </para>
- <programlisting>
-&lt;div&gt;foo&lt;/div&gt;
-</programlisting>
- <para>
- Now, nested:
- </para>
- <para>
- foo
- </para>
- <para>
- This should just be an HTML comment:
- </para>
- <para>
- Multiline:
- </para>
- <para>
- Code block:
- </para>
- <programlisting>
-&lt;!-- Comment --&gt;
-</programlisting>
- <para>
- Just plain comment, with trailing spaces on the line:
- </para>
- <para>
- Code:
- </para>
- <programlisting>
-&lt;hr /&gt;
-</programlisting>
- <para>
- Hr’s:
- </para>
-</section>
-<section xml:id="inline-markup">
- <title>Inline Markup</title>
- <para>
- This is <emphasis>emphasized</emphasis>, and so <emphasis>is
- this</emphasis>.
- </para>
- <para>
- This is <emphasis role="strong">strong</emphasis>, and so
- <emphasis role="strong">is this</emphasis>.
- </para>
- <para>
- An <emphasis><link xlink:href="/url">emphasized link</link></emphasis>.
- </para>
- <para>
- <emphasis role="strong"><emphasis>This is strong and
- em.</emphasis></emphasis>
- </para>
- <para>
- So is <emphasis role="strong"><emphasis>this</emphasis></emphasis> word.
- </para>
- <para>
- <emphasis role="strong"><emphasis>This is strong and
- em.</emphasis></emphasis>
- </para>
- <para>
- So is <emphasis role="strong"><emphasis>this</emphasis></emphasis> word.
- </para>
- <para>
- This is code: <literal>&gt;</literal>, <literal>$</literal>,
- <literal>\</literal>, <literal>\$</literal>,
- <literal>&lt;html&gt;</literal>.
- </para>
- <para>
- <emphasis role="strikethrough">This is
- <emphasis>strikeout</emphasis>.</emphasis>
- </para>
- <para>
- Superscripts: a<superscript>bc</superscript>d
- a<superscript><emphasis>hello</emphasis></superscript>
- a<superscript>hello there</superscript>.
- </para>
- <para>
- Subscripts: H<subscript>2</subscript>O, H<subscript>23</subscript>O,
- H<subscript>many of them</subscript>O.
- </para>
- <para>
- These should not be superscripts or subscripts, because of the unescaped
- spaces: a^b c^d, a~b c~d.
- </para>
-</section>
-<section xml:id="smart-quotes-ellipses-dashes">
- <title>Smart quotes, ellipses, dashes</title>
- <para>
- <quote>Hello,</quote> said the spider. <quote><quote>Shelob</quote> is my
- name.</quote>
- </para>
- <para>
- <quote>A</quote>, <quote>B</quote>, and <quote>C</quote> are letters.
- </para>
- <para>
- <quote>Oak,</quote> <quote>elm,</quote> and <quote>beech</quote> are names
- of trees. So is <quote>pine.</quote>
- </para>
- <para>
- <quote>He said, <quote>I want to go.</quote></quote> Were you alive in the
- 70’s?
- </para>
- <para>
- Here is some quoted <quote><literal>code</literal></quote> and a
- <quote><link xlink:href="http://example.com/?foo=1&amp;bar=2">quoted
- link</link></quote>.
- </para>
- <para>
- Some dashes: one—two — three—four — five.
- </para>
- <para>
- Dashes between numbers: 5–7, 255–66, 1987–1999.
- </para>
- <para>
- Ellipses…and…and….
- </para>
-</section>
-<section xml:id="latex">
- <title>LaTeX</title>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- </para>
- </listitem>
- <listitem>
- <para>
- 2 + 2 = 4
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>x</emphasis> ∈ <emphasis>y</emphasis>
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>α</emphasis> ∧ <emphasis>ω</emphasis>
- </para>
- </listitem>
- <listitem>
- <para>
- 223
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>p</emphasis>-Tree
- </para>
- </listitem>
- <listitem>
- <para>
- Here’s some display math:
- $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
- </para>
- </listitem>
- <listitem>
- <para>
- Here’s one that has a line break in it:
- <emphasis>α</emphasis> + <emphasis>ω</emphasis> × <emphasis>x</emphasis><superscript>2</superscript>.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- These shouldn’t be math:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- To get the famous equation, write <literal>$e = mc^2$</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It
- worked if <quote>lot</quote> is emphasized.)
- </para>
- </listitem>
- <listitem>
- <para>
- Shoes ($20) and socks ($5).
- </para>
- </listitem>
- <listitem>
- <para>
- Escaped <literal>$</literal>: $73 <emphasis>this should be
- emphasized</emphasis> 23$.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Here’s a LaTeX table:
- </para>
-</section>
-<section xml:id="special-characters">
- <title>Special Characters</title>
- <para>
- Here is some unicode:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- I hat: Î
- </para>
- </listitem>
- <listitem>
- <para>
- o umlaut: ö
- </para>
- </listitem>
- <listitem>
- <para>
- section: §
- </para>
- </listitem>
- <listitem>
- <para>
- set membership: ∈
- </para>
- </listitem>
- <listitem>
- <para>
- copyright: ©
- </para>
- </listitem>
- </itemizedlist>
- <para>
- AT&amp;T has an ampersand in their name.
- </para>
- <para>
- AT&amp;T is another way to write it.
- </para>
- <para>
- This &amp; that.
- </para>
- <para>
- 4 &lt; 5.
- </para>
- <para>
- 6 &gt; 5.
- </para>
- <para>
- Backslash: \
- </para>
- <para>
- Backtick: `
- </para>
- <para>
- Asterisk: *
- </para>
- <para>
- Underscore: _
- </para>
- <para>
- Left brace: {
- </para>
- <para>
- Right brace: }
- </para>
- <para>
- Left bracket: [
- </para>
- <para>
- Right bracket: ]
- </para>
- <para>
- Left paren: (
- </para>
- <para>
- Right paren: )
- </para>
- <para>
- Greater-than: &gt;
- </para>
- <para>
- Hash: #
- </para>
- <para>
- Period: .
- </para>
- <para>
- Bang: !
- </para>
- <para>
- Plus: +
- </para>
- <para>
- Minus: -
- </para>
-</section>
-<section xml:id="links">
- <title>Links</title>
- <section xml:id="explicit">
- <title>Explicit</title>
- <para>
- Just a <link xlink:href="/url/">URL</link>.
- </para>
- <para>
- <link xlink:href="/url/">URL and title</link>.
- </para>
- <para>
- <link xlink:href="/url/">URL and title</link>.
- </para>
- <para>
- <link xlink:href="/url/">URL and title</link>.
- </para>
- <para>
- <link xlink:href="/url/">URL and title</link>
- </para>
- <para>
- <link xlink:href="/url/">URL and title</link>
- </para>
- <para>
- <link xlink:href="/url/with_underscore">with_underscore</link>
- </para>
- <para>
- Email link (<email>nobody@nowhere.net</email>)
- </para>
- <para>
- <link xlink:href="">Empty</link>.
- </para>
- </section>
- <section xml:id="reference">
- <title>Reference</title>
- <para>
- Foo <link xlink:href="/url/">bar</link>.
- </para>
- <para>
- Foo <link xlink:href="/url/">bar</link>.
- </para>
- <para>
- Foo <link xlink:href="/url/">bar</link>.
- </para>
- <para>
- With <link xlink:href="/url/">embedded [brackets]</link>.
- </para>
- <para>
- <link xlink:href="/url/">b</link> by itself should be a link.
- </para>
- <para>
- Indented <link xlink:href="/url">once</link>.
- </para>
- <para>
- Indented <link xlink:href="/url">twice</link>.
- </para>
- <para>
- Indented <link xlink:href="/url">thrice</link>.
- </para>
- <para>
- This should [not][] be a link.
- </para>
- <programlisting>
-[not]: /url
-</programlisting>
- <para>
- Foo <link xlink:href="/url/">bar</link>.
- </para>
- <para>
- Foo <link xlink:href="/url/">biz</link>.
- </para>
- </section>
- <section xml:id="with-ampersands">
- <title>With ampersands</title>
- <para>
- Here’s a <link xlink:href="http://example.com/?foo=1&amp;bar=2">link
- with an ampersand in the URL</link>.
- </para>
- <para>
- Here’s a link with an amersand in the link text:
- <link xlink:href="http://att.com/">AT&amp;T</link>.
- </para>
- <para>
- Here’s an <link xlink:href="/script?foo=1&amp;bar=2">inline link</link>.
- </para>
- <para>
- Here’s an <link xlink:href="/script?foo=1&amp;bar=2">inline link in
- pointy braces</link>.
- </para>
- </section>
- <section xml:id="autolinks">
- <title>Autolinks</title>
- <para>
- With an ampersand:
- <link xlink:href="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</link>
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- In a list?
- </para>
- </listitem>
- <listitem>
- <para>
- <link xlink:href="http://example.com/">http://example.com/</link>
- </para>
- </listitem>
- <listitem>
- <para>
- It should.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- An e-mail address: <email>nobody@nowhere.net</email>
- </para>
- <blockquote>
- <para>
- Blockquoted:
- <link xlink:href="http://example.com/">http://example.com/</link>
- </para>
- </blockquote>
- <para>
- Auto-links should not occur here:
- <literal>&lt;http://example.com/&gt;</literal>
- </para>
- <programlisting>
-or here: &lt;http://example.com/&gt;
-</programlisting>
- </section>
-</section>
-<section xml:id="images">
- <title>Images</title>
- <para>
- From <quote>Voyage dans la Lune</quote> by Georges Melies (1902):
- </para>
- <figure>
- <title>lalune</title>
- <mediaobject>
- <imageobject>
- <imagedata fileref="lalune.jpg" />
- </imageobject>
- <textobject><phrase>lalune</phrase></textobject>
- </mediaobject>
- </figure>
- <para>
- Here is a movie <inlinemediaobject>
- <imageobject>
- <imagedata fileref="movie.jpg" />
- </imageobject>
- </inlinemediaobject> icon.
- </para>
-</section>
-<section xml:id="footnotes">
- <title>Footnotes</title>
- <para>
- Here is a footnote reference,<footnote>
- <para>
- Here is the footnote. It can go anywhere after the footnote reference.
- It need not be placed at the end of the document.
- </para>
- </footnote> and another.<footnote>
- <para>
- Here’s the long note. This one contains multiple blocks.
- </para>
- <para>
- Subsequent blocks are indented to show that they belong to the
- footnote (as with list items).
- </para>
- <programlisting>
- { &lt;code&gt; }
-</programlisting>
- <para>
- If you want, you can indent every line, but you can also be lazy and
- just indent the first line of each block.
- </para>
- </footnote> This should <emphasis>not</emphasis> be a footnote reference,
- because it contains a space.[^my note] Here is an inline note.<footnote>
- <para>
- This is <emphasis>easier</emphasis> to type. Inline notes may contain
- <link xlink:href="http://google.com">links</link> and
- <literal>]</literal> verbatim characters, as well as [bracketed text].
- </para>
- </footnote>
- </para>
- <blockquote>
- <para>
- Notes can go in quotes.<footnote>
- <para>
- In quote.
- </para>
- </footnote>
- </para>
- </blockquote>
- <orderedlist numeration="arabic" spacing="compact">
- <listitem>
- <para>
- And in list items.<footnote>
- <para>
- In list.
- </para>
- </footnote>
- </para>
- </listitem>
- </orderedlist>
- <para>
- This paragraph should not be part of the note, as it is not indented.
- </para>
-</section>
-</article>
diff --git a/tests/writer.dokuwiki b/tests/writer.dokuwiki
deleted file mode 100644
index 79fcdde8a..000000000
--- a/tests/writer.dokuwiki
+++ /dev/null
@@ -1,642 +0,0 @@
-This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.
-
-
-----
-
-====== Headers ======
-
-===== Level 2 with an embedded link =====
-
-==== Level 3 with emphasis ====
-
-=== Level 4 ===
-
-== Level 5 ==
-
-====== Level 1 ======
-
-===== Level 2 with emphasis =====
-
-==== Level 3 ====
-
-with no blank line
-
-===== Level 2 =====
-
-with no blank line
-
-
-----
-
-====== Paragraphs ======
-
-Here’s a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
-
-Here’s one with a bullet. * criminey.
-
-There should be a hard line break\\
-here.
-
-
-----
-
-====== Block Quotes ======
-
-E-mail style:
-
-> This is a block quote. It is pretty short.
-
-<HTML><blockquote>
-Code in a block quote:
-
-<code>
-sub status {
- print "working";
-}
-</code>
-A list:
-
- - item one
- - item two
-
-Nested block quotes:
-
-> nested
-
-> nested
-</blockquote></HTML>
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
-
-----
-
-====== Code Blocks ======
-
-Code:
-
-<code>
----- (should be four hyphens)
-
-sub status {
- print "working";
-}
-
-this code block is indented by one tab
-</code>
-And:
-
-<code>
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \> \[ \{
-</code>
-
-----
-
-====== Lists ======
-
-===== Unordered =====
-
-Asterisks tight:
-
- * asterisk 1
- * asterisk 2
- * asterisk 3
-
-Asterisks loose:
-
- * asterisk 1
- * asterisk 2
- * asterisk 3
-
-Pluses tight:
-
- * Plus 1
- * Plus 2
- * Plus 3
-
-Pluses loose:
-
- * Plus 1
- * Plus 2
- * Plus 3
-
-Minuses tight:
-
- * Minus 1
- * Minus 2
- * Minus 3
-
-Minuses loose:
-
- * Minus 1
- * Minus 2
- * Minus 3
-
-===== Ordered =====
-
-Tight:
-
- - First
- - Second
- - Third
-
-and:
-
- - One
- - Two
- - Three
-
-Loose using tabs:
-
- - First
- - Second
- - Third
-
-and using spaces:
-
- - One
- - Two
- - Three
-
-Multiple paragraphs:
-
-<HTML><ol style="list-style-type: decimal;"></HTML>
-<HTML><li></HTML><HTML><p></HTML>Item 1, graf one.<HTML></p></HTML>
-<HTML><p></HTML>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.<HTML></p></HTML><HTML></li></HTML>
-<HTML><li></HTML><HTML><p></HTML>Item 2.<HTML></p></HTML><HTML></li></HTML>
-<HTML><li></HTML><HTML><p></HTML>Item 3.<HTML></p></HTML><HTML></li></HTML><HTML></ol></HTML>
-
-===== Nested =====
-
- * Tab
- * Tab
- * Tab
-
-Here’s another:
-
- - First
- - Second:
- * Fee
- * Fie
- * Foe
- - Third
-
-Same thing but with paragraphs:
-
- - First
- - Second:
- * Fee
- * Fie
- * Foe
- - Third
-
-===== Tabs and spaces =====
-
- * this is a list item indented with tabs
- * this is a list item indented with spaces
- * this is an example list item indented with tabs
- * this is an example list item indented with spaces
-
-===== Fancy list markers =====
-
-<HTML><ol start="2" style="list-style-type: decimal;"></HTML>
-<HTML><li></HTML>begins with 2<HTML></li></HTML>
-<HTML><li></HTML><HTML><p></HTML>and now 3<HTML></p></HTML>
-<HTML><p></HTML>with a continuation<HTML></p></HTML>
-<HTML><ol start="4" style="list-style-type: lower-roman;"></HTML>
-<HTML><li></HTML>sublist with roman numerals, starting with 4<HTML></li></HTML>
-<HTML><li></HTML>more items
-<HTML><ol style="list-style-type: upper-alpha;"></HTML>
-<HTML><li></HTML>a subsublist<HTML></li></HTML>
-<HTML><li></HTML>a subsublist<HTML></li></HTML><HTML></ol></HTML>
-<HTML></li></HTML><HTML></ol></HTML>
-<HTML></li></HTML><HTML></ol></HTML>
-
-Nesting:
-
-<HTML><ol style="list-style-type: upper-alpha;"></HTML>
-<HTML><li></HTML>Upper Alpha
-<HTML><ol style="list-style-type: upper-roman;"></HTML>
-<HTML><li></HTML>Upper Roman.
-<HTML><ol start="6" style="list-style-type: decimal;"></HTML>
-<HTML><li></HTML>Decimal start with 6
-<HTML><ol start="3" style="list-style-type: lower-alpha;"></HTML>
-<HTML><li></HTML>Lower alpha with paren<HTML></li></HTML><HTML></ol></HTML>
-<HTML></li></HTML><HTML></ol></HTML>
-<HTML></li></HTML><HTML></ol></HTML>
-<HTML></li></HTML><HTML></ol></HTML>
-
-Autonumbering:
-
- - Autonumber.
- - More.
- - Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-
-----
-
-====== Definition Lists ======
-
-Tight using spaces:
-
- * **apple** red fruit
- * **orange** orange fruit
- * **banana** yellow fruit
-
-Tight using tabs:
-
- * **apple** red fruit
- * **orange** orange fruit
- * **banana** yellow fruit
-
-Loose:
-
- * **apple** red fruit
- * **orange** orange fruit
- * **banana** yellow fruit
-
-Multiple blocks with italics:
-
-<HTML><dl></HTML>
-<HTML><dt></HTML>//apple//<HTML></dt></HTML>
-<HTML><dd></HTML><HTML><p></HTML>red fruit<HTML></p></HTML>
-<HTML><p></HTML>contains seeds, crisp, pleasant to taste<HTML></p></HTML><HTML></dd></HTML>
-<HTML><dt></HTML>//orange//<HTML></dt></HTML>
-<HTML><dd></HTML><HTML><p></HTML>orange fruit<HTML></p></HTML>
-<code>
-{ orange code block }
-</code>
-> <HTML><p></HTML>orange block quote<HTML></p></HTML>
-<HTML></dd></HTML><HTML></dl></HTML>
-
-Multiple definitions, tight:
-
- * **apple** red fruitcomputer
- * **orange** orange fruitbank
-
-Multiple definitions, loose:
-
- * **apple** red fruitcomputer
- * **orange** orange fruitbank
-
-Blank line after term, indented marker, alternate markers:
-
- * **apple** red fruitcomputer
- * **orange** orange fruit
- - sublist
- - sublist
-
-====== HTML Blocks ======
-
-Simple block on one line:
-
-foo
-
-And nested without indentation:
-
-foo
-
-
-
-bar
-
-
-Interpreted markdown in a table:
-
-<HTML>
-<table>
-<tr>
-<td>
-</HTML>
-This is //emphasized//
-<HTML>
-</td>
-<td>
-</HTML>
-And this is **strong**
-<HTML>
-</td>
-</tr>
-</table>
-<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
-</HTML>
-Here’s a simple block:
-
-foo
-
-
-This should be a code block, though:
-
-<code>
-<div>
- foo
-</div>
-</code>
-As should this:
-
-<code>
-<div>foo</div>
-</code>
-Now, nested:
-
-foo
-
-
-
-This should just be an HTML comment:
-
-<HTML>
-<!-- Comment -->
-</HTML>
-Multiline:
-
-<HTML>
-<!--
-Blah
-Blah
--->
-<!--
- This is another comment.
--->
-</HTML>
-Code block:
-
-<code>
-<!-- Comment -->
-</code>
-Just plain comment, with trailing spaces on the line:
-
-<HTML>
-<!-- foo -->
-</HTML>
-Code:
-
-<code>
-<hr />
-</code>
-Hr’s:
-
-<HTML>
-<hr>
-<hr />
-<hr />
-<hr>
-<hr />
-<hr />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar">
-</HTML>
-
-----
-
-====== Inline Markup ======
-
-This is //emphasized//, and so //is this//.
-
-This is **strong**, and so **is this**.
-
-An //[[url|emphasized link]]//.
-
-**//This is strong and em.//**
-
-So is **//this//** word.
-
-**//This is strong and em.//**
-
-So is **//this//** word.
-
-This is code: ''%%>%%'', ''%%$%%'', ''%%\%%'', ''%%\$%%'', ''%%<html>%%''.
-
-<del>This is //strikeout//.</del>
-
-Superscripts: a<sup>bc</sup>d a<sup>//hello//</sup> a<sup>hello there</sup>.
-
-Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.
-
-These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
-
-
-----
-
-====== Smart quotes, ellipses, dashes ======
-
-“Hello,” said the spider. “‘Shelob’ is my name.”
-
-‘A’, ‘B’, and ‘C’ are letters.
-
-‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
-
-‘He said, “I want to go.”’ Were you alive in the 70’s?
-
-Here is some quoted ‘''%%code%%''’ and a “[[http://example.com/?foo=1&bar=2|quoted link]]”.
-
-Some dashes: one—two — three—four — five.
-
-Dashes between numbers: 5–7, 255–66, 1987–1999.
-
-Ellipses…and…and….
-
-
-----
-
-====== LaTeX ======
-
- *
- * $2+2=4$
- * $x \in y$
- * $\alpha \wedge \omega$
- * $223$
- * $p$-Tree
- * Here’s some display math: $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
- * Here’s one that has a line break in it: $\alpha + \omega \times x^2$.
-
-These shouldn’t be math:
-
- * To get the famous equation, write ''%%$e = mc^2$%%''.
- * $22,000 is a //lot// of money. So is $34,000. (It worked if “lot” is emphasized.)
- * Shoes ($20) and socks ($5).
- * Escaped ''%%$%%'': $73 //this should be emphasized// 23$.
-
-Here’s a LaTeX table:
-
-
-
-----
-
-====== Special Characters ======
-
-Here is some unicode:
-
- * I hat: Î
- * o umlaut: ö
- * section: §
- * set membership: ∈
- * copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: _
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-
-----
-
-====== Links ======
-
-===== Explicit =====
-
-Just a [[url/|URL]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]]
-
-[[url/|URL and title]]
-
-[[url/with_underscore|with_underscore]]
-
-[[mailto:nobody@nowhere.net|Email link]]
-
-[[|Empty]].
-
-===== Reference =====
-
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
-With [[url/|embedded [brackets]]].
-
-[[url/|b]] by itself should be a link.
-
-Indented [[url|once]].
-
-Indented [[url|twice]].
-
-Indented [[url|thrice]].
-
-This should [not][] be a link.
-
-<code>
-[not]: /url
-</code>
-Foo [[url/|bar]].
-
-Foo [[url/|biz]].
-
-===== With ampersands =====
-
-Here’s a [[http://example.com/?foo=1&bar=2|link with an ampersand in the URL]].
-
-Here’s a link with an amersand in the link text: [[http://att.com/|AT&T]].
-
-Here’s an [[script?foo=1&bar=2|inline link]].
-
-Here’s an [[script?foo=1&bar=2|inline link in pointy braces]].
-
-===== Autolinks =====
-
-With an ampersand: http://example.com/?foo=1&bar=2
-
- * In a list?
- * http://example.com/
- * It should.
-
-An e-mail address: <nobody@nowhere.net>
-
-> Blockquoted: http://example.com/
-
-Auto-links should not occur here: ''%%<http://example.com/>%%''
-
-<code>
-or here: <http://example.com/>
-</code>
-
-----
-
-====== Images ======
-
-From “Voyage dans la Lune” by Georges Melies (1902):
-
-{{:lalune.jpg|Voyage dans la Lune lalune}}
-
-Here is a movie {{:movie.jpg|movie}} icon.
-
-
-----
-
-====== Footnotes ======
-
-Here is a footnote reference,((Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
-)) and another.((Here’s the long note. This one contains multiple blocks.
-
-Subsequent blocks are indented to show that they belong to the footnote (as with list items).
-
-<code>
- { <code> }
-</code>
-If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
-)) This should //not// be a footnote reference, because it contains a space.[^my note] Here is an inline note.((This is //easier// to type. Inline notes may contain [[http://google.com|links]] and ''%%]%%'' verbatim characters, as well as [bracketed text].
-))
-
-> Notes can go in quotes.((In quote.
-> ))
-
- - And in list items.((In list.))
-
-This paragraph should not be part of the note, as it is not indented.
diff --git a/tests/writer.fb2 b/tests/writer.fb2
deleted file mode 100644
index 8cc271deb..000000000
--- a/tests/writer.fb2
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><book-title>Pandoc Test Suite</book-title><author><first-name>John</first-name><last-name>MacFarlane</last-name></author><author><nickname>Anonymous</nickname></author><date>July 17, 2006</date></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p>Pandoc Test Suite</p></title><annotation><p>John MacFarlane</p><p>Anonymous</p><p>July 17, 2006</p></annotation><section><p>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Headers</p></title><section><title><p>Level 2 with an embedded link &lt;/url&gt;</p></title><section><title><p>Level 3 with emphasis</p></title><section><title><p>Level 4</p></title><section><title><p>Level 5</p></title></section></section></section></section></section><section><title><p>Level 1</p></title><section><title><p>Level 2 with emphasis</p></title><section><title><p>Level 3</p></title><p>with no blank line</p></section></section><section><title><p>Level 2</p></title><p>with no blank line</p><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Paragraphs</p></title><p>Here’s a regular paragraph.</p><p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p><p>Here’s one with a bullet. * criminey.</p><p>There should be a hard line break<empty-line />here.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Block Quotes</p></title><p>E-mail style:</p><cite><p>This is a block quote. It is pretty short.</p></cite><cite><p>Code in a block quote:</p><empty-line /><p><code>sub status {</code></p><p><code> print &quot;working&quot;;</code></p><p><code>}</code></p><empty-line /><p>A list:</p><p> 1. item one</p><p> 2. item two</p><p>Nested block quotes:</p><cite><p>nested</p></cite><cite><p>nested</p></cite></cite><p>This should not be a block quote: 2 &gt; 1.</p><p>And a following paragraph.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Code Blocks</p></title><p>Code:</p><empty-line /><p><code>---- (should be four hyphens)</code></p><p><code></code></p><p><code>sub status {</code></p><p><code> print &quot;working&quot;;</code></p><p><code>}</code></p><p><code></code></p><p><code>this code block is indented by one tab</code></p><empty-line /><p>And:</p><empty-line /><p><code> this code block is indented by two tabs</code></p><p><code></code></p><p><code>These should not be escaped: \$ \\ \&gt; \[ \{</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Lists</p></title><section><title><p>Unordered</p></title><p>Asterisks tight:</p><p>• asterisk 1</p><p>• asterisk 2</p><p>• asterisk 3</p><p>Asterisks loose:</p><p>• asterisk 1<empty-line /></p><p>• asterisk 2<empty-line /></p><p>• asterisk 3<empty-line /></p><p>Pluses tight:</p><p>• Plus 1</p><p>• Plus 2</p><p>• Plus 3</p><p>Pluses loose:</p><p>• Plus 1<empty-line /></p><p>• Plus 2<empty-line /></p><p>• Plus 3<empty-line /></p><p>Minuses tight:</p><p>• Minus 1</p><p>• Minus 2</p><p>• Minus 3</p><p>Minuses loose:</p><p>• Minus 1<empty-line /></p><p>• Minus 2<empty-line /></p><p>• Minus 3<empty-line /></p></section><section><title><p>Ordered</p></title><p>Tight:</p><p> 1. First</p><p> 2. Second</p><p> 3. Third</p><p>and:</p><p> 1. One</p><p> 2. Two</p><p> 3. Three</p><p>Loose using tabs:</p><p> 1. First<empty-line /></p><p> 2. Second<empty-line /></p><p> 3. Third<empty-line /></p><p>and using spaces:</p><p> 1. One<empty-line /></p><p> 2. Two<empty-line /></p><p> 3. Three<empty-line /></p><p>Multiple paragraphs:</p><p> 1. Item 1, graf one.<empty-line />Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.<empty-line /></p><p> 2. Item 2.<empty-line /></p><p> 3. Item 3.<empty-line /></p></section><section><title><p>Nested</p></title><p>• Tab<p>◦ Tab<p>* Tab</p></p></p><p>Here’s another:</p><p> 1. First</p><p> 2. Second:<p>   • Fee</p><p>   • Fie</p><p>   • Foe</p></p><p> 3. Third</p><p>Same thing but with paragraphs:</p><p> 1. First<empty-line /></p><p> 2. Second:<empty-line /><p>   • Fee</p><p>   • Fie</p><p>   • Foe</p></p><p> 3. Third<empty-line /></p></section><section><title><p>Tabs and spaces</p></title><p>• this is a list item indented with tabs<empty-line /></p><p>• this is a list item indented with spaces<empty-line /><p>◦ this is an example list item indented with tabs<empty-line /></p><p>◦ this is an example list item indented with spaces<empty-line /></p></p></section><section><title><p>Fancy list markers</p></title><p> (2) begins with 2</p><p> (3) and now 3<empty-line />with a continuation<empty-line /><p> (3) iv. sublist with roman numerals, starting with 4</p><p> (3) v. more items<p> (3) v. (A) a subsublist</p><p> (3) v. (B) a subsublist</p></p></p><p>Nesting:</p><p> A. Upper Alpha<p> A. I. Upper Roman.<p> A. I. (6) Decimal start with 6<p> A. I. (6) c) Lower alpha with paren</p></p></p></p><p>Autonumbering:</p><p> 1. Autonumber.</p><p> 2. More.<p> 2. 1. Nested.</p></p><p>Should not be a list item:</p><p>M.A. 2007</p><p>B. Williams</p><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Definition Lists</p></title><p>Tight using spaces:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Tight using tabs:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Loose:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Multiple blocks with italics:</p><p><strong><emphasis>apple</emphasis></strong></p><p>    red fruit<empty-line />    contains seeds, crisp, pleasant to taste<empty-line /></p><p><strong><emphasis>orange</emphasis></strong></p><p>    orange fruit<empty-line /><empty-line /><p><code>    { orange code block }</code></p><empty-line /><cite><p>    orange block quote</p></cite></p><p>Multiple definitions, tight:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line />    bank<empty-line /></p><p>Multiple definitions, loose:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line />    bank<empty-line /></p><p>Blank line after term, indented marker, alternate markers:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /><p> 1. sublist</p><p> 2. sublist</p></p></section><section><title><p>HTML Blocks</p></title><p>Simple block on one line:</p>foo<p>And nested without indentation:</p><p>foo</p>bar<p>Interpreted markdown in a table:</p><empty-line /><p><code>&lt;table&gt;</code></p><empty-line /><empty-line /><p><code>&lt;tr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;td&gt;</code></p><empty-line />This is <emphasis>emphasized</emphasis><empty-line /><p><code>&lt;/td&gt;</code></p><empty-line /><empty-line /><p><code>&lt;td&gt;</code></p><empty-line />And this is <strong>strong</strong><empty-line /><p><code>&lt;/td&gt;</code></p><empty-line /><empty-line /><p><code>&lt;/tr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;/table&gt;</code></p><empty-line /><empty-line /><p><code>&lt;script type=&quot;text/javascript&quot;&gt;document.write(&#39;This *should not* be interpreted as markdown&#39;);&lt;/script&gt;</code></p><empty-line /><p>Here’s a simple block:</p><p>foo</p><p>This should be a code block, though:</p><empty-line /><p><code>&lt;div&gt;</code></p><p><code> foo</code></p><p><code>&lt;/div&gt;</code></p><empty-line /><p>As should this:</p><empty-line /><p><code>&lt;div&gt;foo&lt;/div&gt;</code></p><empty-line /><p>Now, nested:</p>foo<p>This should just be an HTML comment:</p><empty-line /><p><code>&lt;!-- Comment --&gt;</code></p><empty-line /><p>Multiline:</p><empty-line /><p><code>&lt;!--</code></p><p><code>Blah</code></p><p><code>Blah</code></p><p><code>--&gt;</code></p><empty-line /><empty-line /><p><code>&lt;!--</code></p><p><code> This is another comment.</code></p><p><code>--&gt;</code></p><empty-line /><p>Code block:</p><empty-line /><p><code>&lt;!-- Comment --&gt;</code></p><empty-line /><p>Just plain comment, with trailing spaces on the line:</p><empty-line /><p><code>&lt;!-- foo --&gt;</code></p><empty-line /><p>Code:</p><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><p>Hr’s:</p><empty-line /><p><code>&lt;hr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot;&gt;</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Inline Markup</p></title><p>This is <emphasis>emphasized</emphasis>, and so <emphasis>is this</emphasis>.</p><p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p><p>An <emphasis>emphasized link<a l:href="#l1" type="note"><sup>[1]</sup></a></emphasis>.</p><p><strong><emphasis>This is strong and em.</emphasis></strong></p><p>So is <strong><emphasis>this</emphasis></strong> word.</p><p><strong><emphasis>This is strong and em.</emphasis></strong></p><p>So is <strong><emphasis>this</emphasis></strong> word.</p><p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p><p><strikethrough>This is <emphasis>strikeout</emphasis>.</strikethrough></p><p>Superscripts: a<sup>bc</sup>d a<sup><emphasis>hello</emphasis></sup> a<sup>hello there</sup>.</p><p>Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.</p><p>These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Smart quotes, ellipses, dashes</p></title><p>“Hello,” said the spider. “‘Shelob’ is my name.”</p><p>‘A’, ‘B’, and ‘C’ are letters.</p><p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’</p><p>‘He said, “I want to go.”’ Were you alive in the 70’s?</p><p>Here is some quoted ‘<code>code</code>’ and a “quoted link<a l:href="#l2" type="note"><sup>[2]</sup></a>”.</p><p>Some dashes: one—two — three—four — five.</p><p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p><p>Ellipses…and…and….</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>LaTeX</p></title><p>• </p><p>• <code>2+2=4</code></p><p>• <code>x \in y</code></p><p>• <code>\alpha \wedge \omega</code></p><p>• <code>223</code></p><p>• <code>p</code>-Tree</p><p>• Here’s some display math: <code>\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</code></p><p>• Here’s one that has a line break in it: <code>\alpha + \omega \times x^2</code>.</p><p>These shouldn’t be math:</p><p>• To get the famous equation, write <code>$e = mc^2$</code>.</p><p>• $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It worked if “lot” is emphasized.)</p><p>• Shoes ($20) and socks ($5).</p><p>• Escaped <code>$</code>: $73 <emphasis>this should be emphasized</emphasis> 23$.</p><p>Here’s a LaTeX table:</p><empty-line /><p><code>\begin{tabular}{|l|l|}\hline</code></p><p><code>Animal &amp; Number \\ \hline</code></p><p><code>Dog &amp; 2 \\</code></p><p><code>Cat &amp; 1 \\ \hline</code></p><p><code>\end{tabular}</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Special Characters</p></title><p>Here is some unicode:</p><p>• I hat: Î</p><p>• o umlaut: ö</p><p>• section: §</p><p>• set membership: ∈</p><p>• copyright: ©</p><p>AT&amp;T has an ampersand in their name.</p><p>AT&amp;T is another way to write it.</p><p>This &amp; that.</p><p>4 &lt; 5.</p><p>6 &gt; 5.</p><p>Backslash: \</p><p>Backtick: `</p><p>Asterisk: *</p><p>Underscore: _</p><p>Left brace: {</p><p>Right brace: }</p><p>Left bracket: [</p><p>Right bracket: ]</p><p>Left paren: (</p><p>Right paren: )</p><p>Greater-than: &gt;</p><p>Hash: #</p><p>Period: .</p><p>Bang: !</p><p>Plus: +</p><p>Minus: -</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Links</p></title><section><title><p>Explicit</p></title><p>Just a URL<a l:href="#l3" type="note"><sup>[3]</sup></a>.</p><p>URL and title<a l:href="#l4" type="note"><sup>[4]</sup></a>.</p><p>URL and title<a l:href="#l5" type="note"><sup>[5]</sup></a>.</p><p>URL and title<a l:href="#l6" type="note"><sup>[6]</sup></a>.</p><p>URL and title<a l:href="#l7" type="note"><sup>[7]</sup></a></p><p>URL and title<a l:href="#l8" type="note"><sup>[8]</sup></a></p><p>with_underscore<a l:href="#l9" type="note"><sup>[9]</sup></a></p><p>Email link<a l:href="#l10" type="note"><sup>[10]</sup></a></p><p>Empty<a l:href="#l11" type="note"><sup>[11]</sup></a>.</p></section><section><title><p>Reference</p></title><p>Foo bar<a l:href="#l12" type="note"><sup>[12]</sup></a>.</p><p>Foo bar<a l:href="#l13" type="note"><sup>[13]</sup></a>.</p><p>Foo bar<a l:href="#l14" type="note"><sup>[14]</sup></a>.</p><p>With embedded [brackets]<a l:href="#l15" type="note"><sup>[15]</sup></a>.</p><p>b<a l:href="#l16" type="note"><sup>[16]</sup></a> by itself should be a link.</p><p>Indented once<a l:href="#l17" type="note"><sup>[17]</sup></a>.</p><p>Indented twice<a l:href="#l18" type="note"><sup>[18]</sup></a>.</p><p>Indented thrice<a l:href="#l19" type="note"><sup>[19]</sup></a>.</p><p>This should [not][] be a link.</p><empty-line /><p><code>[not]: /url</code></p><empty-line /><p>Foo bar<a l:href="#l20" type="note"><sup>[20]</sup></a>.</p><p>Foo biz<a l:href="#l21" type="note"><sup>[21]</sup></a>.</p></section><section><title><p>With ampersands</p></title><p>Here’s a link with an ampersand in the URL<a l:href="#l22" type="note"><sup>[22]</sup></a>.</p><p>Here’s a link with an amersand in the link text: AT&amp;T<a l:href="#l23" type="note"><sup>[23]</sup></a>.</p><p>Here’s an inline link<a l:href="#l24" type="note"><sup>[24]</sup></a>.</p><p>Here’s an inline link in pointy braces<a l:href="#l25" type="note"><sup>[25]</sup></a>.</p></section><section><title><p>Autolinks</p></title><p>With an ampersand: http://example.com/?foo=1&amp;bar=2<a l:href="#l26" type="note"><sup>[26]</sup></a></p><p>• In a list?</p><p>• http://example.com/<a l:href="#l27" type="note"><sup>[27]</sup></a></p><p>• It should.</p><p>An e-mail address: nobody@nowhere.net<a l:href="#l28" type="note"><sup>[28]</sup></a></p><cite><p>Blockquoted: http://example.com/<a l:href="#l29" type="note"><sup>[29]</sup></a></p></cite><p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p><empty-line /><p><code>or here: &lt;http://example.com/&gt;</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Images</p></title><p>From “Voyage dans la Lune” by Georges Melies (1902):</p><image l:href="#image1" l:type="imageType" alt="lalune" title="Voyage dans la Lune" /><p>Here is a movie <image l:href="#image2" l:type="inlineImageType" alt="movie" /> icon.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Footnotes</p></title><p>Here is a footnote reference,<a l:href="#n30" type="note"><sup>[30]</sup></a> and another.<a l:href="#n31" type="note"><sup>[31]</sup></a> This should <emphasis>not</emphasis> be a footnote reference, because it contains a space.[^my note] Here is an inline note.<a l:href="#n32" type="note"><sup>[32]</sup></a></p><cite><p>Notes can go in quotes.<a l:href="#n33" type="note"><sup>[33]</sup></a></p></cite><p> 1. And in list items.<a l:href="#n34" type="note"><sup>[34]</sup></a></p><p>This paragraph should not be part of the note, as it is not indented.</p></section></body><body name="notes"><section id="l1"><title><p>1</p></title><p><code>/url</code></p></section><section id="l2"><title><p>2</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l3"><title><p>3</p></title><p><code>/url/</code></p></section><section id="l4"><title><p>4</p></title><p>title: <code>/url/</code></p></section><section id="l5"><title><p>5</p></title><p>title preceded by two spaces: <code>/url/</code></p></section><section id="l6"><title><p>6</p></title><p>title preceded by a tab: <code>/url/</code></p></section><section id="l7"><title><p>7</p></title><p>title with &quot;quotes&quot; in it: <code>/url/</code></p></section><section id="l8"><title><p>8</p></title><p>title with single quotes: <code>/url/</code></p></section><section id="l9"><title><p>9</p></title><p><code>/url/with_underscore</code></p></section><section id="l10"><title><p>10</p></title><p><code>mailto:nobody@nowhere.net</code></p></section><section id="l11"><title><p>11</p></title><p><code></code></p></section><section id="l12"><title><p>12</p></title><p><code>/url/</code></p></section><section id="l13"><title><p>13</p></title><p><code>/url/</code></p></section><section id="l14"><title><p>14</p></title><p><code>/url/</code></p></section><section id="l15"><title><p>15</p></title><p><code>/url/</code></p></section><section id="l16"><title><p>16</p></title><p><code>/url/</code></p></section><section id="l17"><title><p>17</p></title><p><code>/url</code></p></section><section id="l18"><title><p>18</p></title><p><code>/url</code></p></section><section id="l19"><title><p>19</p></title><p><code>/url</code></p></section><section id="l20"><title><p>20</p></title><p>Title with &quot;quotes&quot; inside: <code>/url/</code></p></section><section id="l21"><title><p>21</p></title><p>Title with &quot;quote&quot; inside: <code>/url/</code></p></section><section id="l22"><title><p>22</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l23"><title><p>23</p></title><p>AT&amp;T: <code>http://att.com/</code></p></section><section id="l24"><title><p>24</p></title><p><code>/script?foo=1&amp;bar=2</code></p></section><section id="l25"><title><p>25</p></title><p><code>/script?foo=1&amp;bar=2</code></p></section><section id="l26"><title><p>26</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l27"><title><p>27</p></title><p><code>http://example.com/</code></p></section><section id="l28"><title><p>28</p></title><p><code>mailto:nobody@nowhere.net</code></p></section><section id="l29"><title><p>29</p></title><p><code>http://example.com/</code></p></section><section id="n30"><title><p>30</p></title><p>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</p></section><section id="n31"><title><p>31</p></title><p>Here’s the long note. This one contains multiple blocks.</p><p>Subsequent blocks are indented to show that they belong to the footnote (as with list items).</p><empty-line /><p><code> { &lt;code&gt; }</code></p><empty-line /><p>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</p></section><section id="n32"><title><p>32</p></title><p>This is <emphasis>easier</emphasis> to type. Inline notes may contain links<a l:href="#l32" type="note"><sup>[32]</sup></a> and <code>]</code> verbatim characters, as well as [bracketed text].</p></section><section id="n33"><title><p>33</p></title><p>In quote.</p></section><section id="n34"><title><p>34</p></title><p>In list.</p></section></body><binary id="image2" content-type="image/jpeg">/9j/4AAQSkZJRgABAQEASABIAAD//gBQVGhpcyBhcnQgaXMgaW4gdGhlIHB1YmxpYyBkb21haW4uIEtldmluIEh1Z2hlcywga2V2aW5oQGVpdC5jb20sIFNlcHRlbWJlciAxOTk1/9sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8AAEQgAFgAUAwEiAAIRAQMRAf/EABoAAQACAwEAAAAAAAAAAAAAAAAICQUGCgf/xAAjEAABBQEAAwABBQAAAAAAAAAGAwQFBwgCAAEJChEVOXa3/8QAFgEBAQEAAAAAAAAAAAAAAAAABggA/8QAJhEBAAECBQEJAAAAAAAAAAAAAQIAAwQFBhEhszE0NlFUcXR1tP/aAAwDAQACEQMRAD8AqQzziPNmpiqnIO1q4H+WkB84MdlzRSuM82/jVw/JCORtRmQz5d2VTy6WmS2eSYx3U/qkSRbgFsqRzH2Is4/mCluXc33vy8xTnJjTNqV/T8LKmkhr8Hq1da2aOvTfIh2CFeNt+GxFBP8AJFdFUbPWh+4FdXV7OtZOMR7mK9lBWNN+JBmMQ5cwmfH8DEFhTZUCRlE6CBq/ds/nBh9oYygeY1L9FnCUnBSN1t+w0l9bNomx1cllsOrL9OCTKtKOIqua6UVjP0dEvTyM7gp/3whbkAD0ScX3r6MLg+C2/XsMhCnJRn/5cVNHyJHiX6JKIFhhqnFeagm9BIgjfcJyNBTZiROBUk6Mp8CJRmT4NWU2MatV7n495DPk/wAbMJSRJOTBDItq0KR5s/nJN7LPW8AJWtYAoKQaDp+u4XShxgXhYcbHoxNTllCwETGQ8ag2jmDVsk8w/wCOp/C/hn+mWV/utpePH+D5wmF39NY6UakjUYR1Dn0YgRM5zQAAAMdfAA4AOAOArjkMNQ3vgm7UKtBR+m9QHFD5tpnDtpy+t2R20gK/OsmFtuDpaL5mVyiT5qdEVAvZci5ch5VoSGKbwlWTBr0RPoZT07av9lHfrXo6yLApWMugKpPM9SV1cDm65s/wkOHZBojoqiM+6GpMSj4FhtayNAUi5H3LfQBG2KWssFoSPuJdKyMLKtpuLi+e3jwFICUg7CSHsNVlYlKdizOTvKdq3KTsG8pQirsAG6vAB5FdhP490U4gfjxi+DedoqO4YftmKdKNulO26jiOv+2Ga/bftVNFXpHtVHrpLpRFJTpP3z77T469++fTx48e4LueE+NY6UKk7UniLP8A7rNf3X6//9k=</binary><binary id="image1" content-type="image/jpeg">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</binary></FictionBook>
diff --git a/tests/writer.haddock b/tests/writer.haddock
deleted file mode 100644
index 0772331e3..000000000
--- a/tests/writer.haddock
+++ /dev/null
@@ -1,660 +0,0 @@
-This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
-markdown test suite.
-
-______________________________________________________________________________
-
-= Headers
-#headers#
-
-== Level 2 with an </url embedded link>
-#level-2-with-an-embedded-link#
-
-=== Level 3 with /emphasis/
-#level-3-with-emphasis#
-
-==== Level 4
-#level-4#
-
-===== Level 5
-#level-5#
-
-= Level 1
-#level-1#
-
-== Level 2 with /emphasis/
-#level-2-with-emphasis#
-
-=== Level 3
-#level-3#
-
-with no blank line
-
-== Level 2
-#level-2#
-
-with no blank line
-
-______________________________________________________________________________
-
-= Paragraphs
-#paragraphs#
-
-Here’s a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here’s one with a bullet. * criminey.
-
-There should be a hard line break
-here.
-
-______________________________________________________________________________
-
-= Block Quotes
-#block-quotes#
-
-E-mail style:
-
-This is a block quote. It is pretty short.
-
-Code in a block quote:
-
-> sub status {
-> print "working";
-> }
-
-A list:
-
-1. item one
-2. item two
-
-Nested block quotes:
-
-nested
-
-nested
-
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
-______________________________________________________________________________
-
-= Code Blocks
-#code-blocks#
-
-Code:
-
-> ---- (should be four hyphens)
->
-> sub status {
-> print "working";
-> }
->
-> this code block is indented by one tab
-
-And:
-
-> this code block is indented by two tabs
->
-> These should not be escaped: \$ \\ \> \[ \{
-
-______________________________________________________________________________
-
-= Lists
-#lists#
-
-== Unordered
-#unordered#
-
-Asterisks tight:
-
-- asterisk 1
-- asterisk 2
-- asterisk 3
-
-Asterisks loose:
-
-- asterisk 1
-
-- asterisk 2
-
-- asterisk 3
-
-Pluses tight:
-
-- Plus 1
-- Plus 2
-- Plus 3
-
-Pluses loose:
-
-- Plus 1
-
-- Plus 2
-
-- Plus 3
-
-Minuses tight:
-
-- Minus 1
-- Minus 2
-- Minus 3
-
-Minuses loose:
-
-- Minus 1
-
-- Minus 2
-
-- Minus 3
-
-== Ordered
-#ordered#
-
-Tight:
-
-1. First
-2. Second
-3. Third
-
-and:
-
-1. One
-2. Two
-3. Three
-
-Loose using tabs:
-
-1. First
-
-2. Second
-
-3. Third
-
-and using spaces:
-
-1. One
-
-2. Two
-
-3. Three
-
-Multiple paragraphs:
-
-1. Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
-
-2. Item 2.
-
-3. Item 3.
-
-== Nested
-#nested#
-
-- Tab
- - Tab
- - Tab
-
-Here’s another:
-
-1. First
-2. Second:
- - Fee
- - Fie
- - Foe
-
-3. Third
-
-Same thing but with paragraphs:
-
-1. First
-
-2. Second:
-
- - Fee
- - Fie
- - Foe
-
-3. Third
-
-== Tabs and spaces
-#tabs-and-spaces#
-
-- this is a list item indented with tabs
-
-- this is a list item indented with spaces
-
- - this is an example list item indented with tabs
-
- - this is an example list item indented with spaces
-
-== Fancy list markers
-#fancy-list-markers#
-
-(2) begins with 2
-(3) and now 3
-
- with a continuation
-
- 4. sublist with roman numerals, starting with 4
- 5. more items
- (1) a subsublist
- (2) a subsublist
-
-Nesting:
-
-1. Upper Alpha
- 1. Upper Roman.
- (6) Decimal start with 6
- 3) Lower alpha with paren
-
-Autonumbering:
-
-1. Autonumber.
-2. More.
- 1. Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-______________________________________________________________________________
-
-= Definition Lists
-#definition-lists#
-
-Tight using spaces:
-
-[apple]
- red fruit
-[orange]
- orange fruit
-[banana]
- yellow fruit
-
-Tight using tabs:
-
-[apple]
- red fruit
-[orange]
- orange fruit
-[banana]
- yellow fruit
-
-Loose:
-
-[apple]
- red fruit
-
-[orange]
- orange fruit
-
-[banana]
- yellow fruit
-
-Multiple blocks with italics:
-
-[/apple/]
- red fruit
-
- contains seeds, crisp, pleasant to taste
-
-[/orange/]
- orange fruit
-
- > { orange code block }
-
- orange block quote
-
-Multiple definitions, tight:
-
-[apple]
- red fruit
- computer
-[orange]
- orange fruit
- bank
-
-Multiple definitions, loose:
-
-[apple]
- red fruit
-
- computer
-
-[orange]
- orange fruit
-
- bank
-
-Blank line after term, indented marker, alternate markers:
-
-[apple]
- red fruit
-
- computer
-
-[orange]
- orange fruit
-
- 1. sublist
- 2. sublist
-
-= HTML Blocks
-#html-blocks#
-
-Simple block on one line:
-
-foo
-
-And nested without indentation:
-
-foo
-
-bar
-
-Interpreted markdown in a table:
-
-This is /emphasized/
-And this is __strong__
-Here’s a simple block:
-
-foo
-
-This should be a code block, though:
-
-> <div>
-> foo
-> </div>
-
-As should this:
-
-> <div>foo</div>
-
-Now, nested:
-
-foo
-
-This should just be an HTML comment:
-
-Multiline:
-
-Code block:
-
-> <!-- Comment -->
-
-Just plain comment, with trailing spaces on the line:
-
-Code:
-
-> <hr />
-
-Hr’s:
-
-______________________________________________________________________________
-
-= Inline Markup
-#inline-markup#
-
-This is /emphasized/, and so /is this/.
-
-This is __strong__, and so __is this__.
-
-An /</url emphasized link>/.
-
-__/This is strong and em./__
-
-So is __/this/__ word.
-
-__/This is strong and em./__
-
-So is __/this/__ word.
-
-This is code: @>@, @$@, @\\@, @\\$@, @\<html>@.
-
-~~This is /strikeout/.~~
-
-Superscripts: abcd a/hello/ ahello there.
-
-Subscripts: H2O, H23O, Hmany of themO.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a^b c^d, a~b c~d.
-
-______________________________________________________________________________
-
-= Smart quotes, ellipses, dashes
-#smart-quotes-ellipses-dashes#
-
-“Hello,” said the spider. “‘Shelob’ is my name.”
-
-‘A’, ‘B’, and ‘C’ are letters.
-
-‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
-
-‘He said, “I want to go.”’ Were you alive in the 70’s?
-
-Here is some quoted ‘@code@’ and a
-“<http://example.com/?foo=1&bar=2 quoted link>”.
-
-Some dashes: one—two — three—four — five.
-
-Dashes between numbers: 5–7, 255–66, 1987–1999.
-
-Ellipses…and…and….
-
-______________________________________________________________________________
-
-= LaTeX
-#latex#
-
--
-- 2 + 2 = 4
-- /x/ ∈ /y/
-- /α/ ∧ /ω/
-- 223
-- /p/-Tree
-- Here’s some display math:
- $$\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}$$
-- Here’s one that has a line break in it: /α/ + /ω/ × /x/2.
-
-These shouldn’t be math:
-
-- To get the famous equation, write @$e = mc^2$@.
-- $22,000 is a /lot/ of money. So is $34,000. (It worked if “lot” is
- emphasized.)
-- Shoes ($20) and socks ($5).
-- Escaped @$@: $73 /this should be emphasized/ 23$.
-
-Here’s a LaTeX table:
-
-______________________________________________________________________________
-
-= Special Characters
-#special-characters#
-
-Here is some unicode:
-
-- I hat: Î
-- o umlaut: ö
-- section: §
-- set membership: ∈
-- copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 \< 5.
-
-6 > 5.
-
-Backslash: \\
-
-Backtick: \`
-
-Asterisk: *
-
-Underscore: _
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-______________________________________________________________________________
-
-= Links
-#links#
-
-== Explicit
-#explicit#
-
-Just a </url/ URL>.
-
-</url/ URL and title>.
-
-</url/ URL and title>.
-
-</url/ URL and title>.
-
-</url/ URL and title>
-
-</url/ URL and title>
-
-</url/with_underscore with_underscore>
-
-<mailto:nobody@nowhere.net Email link>
-
-< Empty>.
-
-== Reference
-#reference#
-
-Foo </url/ bar>.
-
-Foo </url/ bar>.
-
-Foo </url/ bar>.
-
-With </url/ embedded [brackets]>.
-
-</url/ b> by itself should be a link.
-
-Indented </url once>.
-
-Indented </url twice>.
-
-Indented </url thrice>.
-
-This should [not][] be a link.
-
-> [not]: /url
-
-Foo </url/ bar>.
-
-Foo </url/ biz>.
-
-== With ampersands
-#with-ampersands#
-
-Here’s a <http://example.com/?foo=1&bar=2 link with an ampersand in the URL>.
-
-Here’s a link with an amersand in the link text: <http://att.com/ AT&T>.
-
-Here’s an </script?foo=1&bar=2 inline link>.
-
-Here’s an </script?foo=1&bar=2 inline link in pointy braces>.
-
-== Autolinks
-#autolinks#
-
-With an ampersand: <http://example.com/?foo=1&bar=2>
-
-- In a list?
-- <http://example.com/>
-- It should.
-
-An e-mail address: <mailto:nobody@nowhere.net nobody\@nowhere.net>
-
-Blockquoted: <http://example.com/>
-
-Auto-links should not occur here: @\<http:\/\/example.com\/>@
-
-> or here: <http://example.com/>
-
-______________________________________________________________________________
-
-= Images
-#images#
-
-From “Voyage dans la Lune” by Georges Melies (1902):
-
-<<lalune.jpg lalune>>
-
-Here is a movie <<movie.jpg movie>> icon.
-
-______________________________________________________________________________
-
-= Footnotes
-#footnotes#
-
-Here is a footnote reference,<#notes [1]> and another.<#notes [2]> This should
-/not/ be a footnote reference, because it contains a space.[^my note] Here is
-an inline note.<#notes [3]>
-
-Notes can go in quotes.<#notes [4]>
-
-1. And in list items.<#notes [5]>
-
-This paragraph should not be part of the note, as it is not indented.
-
-#notes#
-
-1. Here is the footnote. It can go anywhere after the footnote reference. It
- need not be placed at the end of the document.
-
-2. Here’s the long note. This one contains multiple blocks.
-
- Subsequent blocks are indented to show that they belong to the footnote
- (as with list items).
-
- > { <code> }
-
- If you want, you can indent every line, but you can also be lazy and just
- indent the first line of each block.
-
-3. This is /easier/ to type. Inline notes may contain
- <http://google.com links> and @]@ verbatim characters, as well as
- [bracketed text].
-
-4. In quote.
-
-5. In list.
diff --git a/tests/writer.html b/tests/writer.html
deleted file mode 100644
index 3b63f4e16..000000000
--- a/tests/writer.html
+++ /dev/null
@@ -1,546 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="Content-Style-Type" content="text/css" />
- <meta name="generator" content="pandoc" />
- <meta name="author" content="John MacFarlane" />
- <meta name="author" content="Anonymous" />
- <meta name="date" content="2006-07-17" />
- <title>Pandoc Test Suite</title>
- <style type="text/css">code{white-space: pre;}</style>
-</head>
-<body>
-<div id="header">
-<h1 class="title">Pandoc Test Suite</h1>
-<h2 class="author">John MacFarlane</h2>
-<h2 class="author">Anonymous</h2>
-<h3 class="date">July 17, 2006</h3>
-</div>
-<p>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</p>
-<hr />
-<h1 id="headers">Headers</h1>
-<h2 id="level-2-with-an-embedded-link">Level 2 with an <a href="/url">embedded link</a></h2>
-<h3 id="level-3-with-emphasis">Level 3 with <em>emphasis</em></h3>
-<h4 id="level-4">Level 4</h4>
-<h5 id="level-5">Level 5</h5>
-<h1 id="level-1">Level 1</h1>
-<h2 id="level-2-with-emphasis">Level 2 with <em>emphasis</em></h2>
-<h3 id="level-3">Level 3</h3>
-<p>with no blank line</p>
-<h2 id="level-2">Level 2</h2>
-<p>with no blank line</p>
-<hr />
-<h1 id="paragraphs">Paragraphs</h1>
-<p>Here’s a regular paragraph.</p>
-<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</p>
-<p>Here’s one with a bullet. * criminey.</p>
-<p>There should be a hard line break<br />
-here.</p>
-<hr />
-<h1 id="block-quotes">Block Quotes</h1>
-<p>E-mail style:</p>
-<blockquote>
-<p>This is a block quote. It is pretty short.</p>
-</blockquote>
-<blockquote>
-<p>Code in a block quote:</p>
-<pre><code>sub status {
- print &quot;working&quot;;
-}</code></pre>
-<p>A list:</p>
-<ol style="list-style-type: decimal">
-<li>item one</li>
-<li>item two</li>
-</ol>
-<p>Nested block quotes:</p>
-<blockquote>
-<p>nested</p>
-</blockquote>
-<blockquote>
-<p>nested</p>
-</blockquote>
-</blockquote>
-<p>This should not be a block quote: 2 &gt; 1.</p>
-<p>And a following paragraph.</p>
-<hr />
-<h1 id="code-blocks">Code Blocks</h1>
-<p>Code:</p>
-<pre><code>---- (should be four hyphens)
-
-sub status {
- print &quot;working&quot;;
-}
-
-this code block is indented by one tab</code></pre>
-<p>And:</p>
-<pre><code> this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \&gt; \[ \{</code></pre>
-<hr />
-<h1 id="lists">Lists</h1>
-<h2 id="unordered">Unordered</h2>
-<p>Asterisks tight:</p>
-<ul>
-<li>asterisk 1</li>
-<li>asterisk 2</li>
-<li>asterisk 3</li>
-</ul>
-<p>Asterisks loose:</p>
-<ul>
-<li><p>asterisk 1</p></li>
-<li><p>asterisk 2</p></li>
-<li><p>asterisk 3</p></li>
-</ul>
-<p>Pluses tight:</p>
-<ul>
-<li>Plus 1</li>
-<li>Plus 2</li>
-<li>Plus 3</li>
-</ul>
-<p>Pluses loose:</p>
-<ul>
-<li><p>Plus 1</p></li>
-<li><p>Plus 2</p></li>
-<li><p>Plus 3</p></li>
-</ul>
-<p>Minuses tight:</p>
-<ul>
-<li>Minus 1</li>
-<li>Minus 2</li>
-<li>Minus 3</li>
-</ul>
-<p>Minuses loose:</p>
-<ul>
-<li><p>Minus 1</p></li>
-<li><p>Minus 2</p></li>
-<li><p>Minus 3</p></li>
-</ul>
-<h2 id="ordered">Ordered</h2>
-<p>Tight:</p>
-<ol style="list-style-type: decimal">
-<li>First</li>
-<li>Second</li>
-<li>Third</li>
-</ol>
-<p>and:</p>
-<ol style="list-style-type: decimal">
-<li>One</li>
-<li>Two</li>
-<li>Three</li>
-</ol>
-<p>Loose using tabs:</p>
-<ol style="list-style-type: decimal">
-<li><p>First</p></li>
-<li><p>Second</p></li>
-<li><p>Third</p></li>
-</ol>
-<p>and using spaces:</p>
-<ol style="list-style-type: decimal">
-<li><p>One</p></li>
-<li><p>Two</p></li>
-<li><p>Three</p></li>
-</ol>
-<p>Multiple paragraphs:</p>
-<ol style="list-style-type: decimal">
-<li><p>Item 1, graf one.</p>
-<p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.</p></li>
-<li><p>Item 2.</p></li>
-<li><p>Item 3.</p></li>
-</ol>
-<h2 id="nested">Nested</h2>
-<ul>
-<li>Tab
-<ul>
-<li>Tab
-<ul>
-<li>Tab</li>
-</ul></li>
-</ul></li>
-</ul>
-<p>Here’s another:</p>
-<ol style="list-style-type: decimal">
-<li>First</li>
-<li>Second:
-<ul>
-<li>Fee</li>
-<li>Fie</li>
-<li>Foe</li>
-</ul></li>
-<li>Third</li>
-</ol>
-<p>Same thing but with paragraphs:</p>
-<ol style="list-style-type: decimal">
-<li><p>First</p></li>
-<li><p>Second:</p>
-<ul>
-<li>Fee</li>
-<li>Fie</li>
-<li>Foe</li>
-</ul></li>
-<li><p>Third</p></li>
-</ol>
-<h2 id="tabs-and-spaces">Tabs and spaces</h2>
-<ul>
-<li><p>this is a list item indented with tabs</p></li>
-<li><p>this is a list item indented with spaces</p>
-<ul>
-<li><p>this is an example list item indented with tabs</p></li>
-<li><p>this is an example list item indented with spaces</p></li>
-</ul></li>
-</ul>
-<h2 id="fancy-list-markers">Fancy list markers</h2>
-<ol start="2" style="list-style-type: decimal">
-<li>begins with 2</li>
-<li><p>and now 3</p>
-<p>with a continuation</p>
-<ol start="4" style="list-style-type: lower-roman">
-<li>sublist with roman numerals, starting with 4</li>
-<li>more items
-<ol style="list-style-type: upper-alpha">
-<li>a subsublist</li>
-<li>a subsublist</li>
-</ol></li>
-</ol></li>
-</ol>
-<p>Nesting:</p>
-<ol style="list-style-type: upper-alpha">
-<li>Upper Alpha
-<ol style="list-style-type: upper-roman">
-<li>Upper Roman.
-<ol start="6" style="list-style-type: decimal">
-<li>Decimal start with 6
-<ol start="3" style="list-style-type: lower-alpha">
-<li>Lower alpha with paren</li>
-</ol></li>
-</ol></li>
-</ol></li>
-</ol>
-<p>Autonumbering:</p>
-<ol>
-<li>Autonumber.</li>
-<li>More.
-<ol>
-<li>Nested.</li>
-</ol></li>
-</ol>
-<p>Should not be a list item:</p>
-<p>M.A. 2007</p>
-<p>B. Williams</p>
-<hr />
-<h1 id="definition-lists">Definition Lists</h1>
-<p>Tight using spaces:</p>
-<dl>
-<dt>apple</dt>
-<dd>red fruit
-</dd>
-<dt>orange</dt>
-<dd>orange fruit
-</dd>
-<dt>banana</dt>
-<dd>yellow fruit
-</dd>
-</dl>
-<p>Tight using tabs:</p>
-<dl>
-<dt>apple</dt>
-<dd>red fruit
-</dd>
-<dt>orange</dt>
-<dd>orange fruit
-</dd>
-<dt>banana</dt>
-<dd>yellow fruit
-</dd>
-</dl>
-<p>Loose:</p>
-<dl>
-<dt>apple</dt>
-<dd><p>red fruit</p>
-</dd>
-<dt>orange</dt>
-<dd><p>orange fruit</p>
-</dd>
-<dt>banana</dt>
-<dd><p>yellow fruit</p>
-</dd>
-</dl>
-<p>Multiple blocks with italics:</p>
-<dl>
-<dt><em>apple</em></dt>
-<dd><p>red fruit</p>
-<p>contains seeds, crisp, pleasant to taste</p>
-</dd>
-<dt><em>orange</em></dt>
-<dd><p>orange fruit</p>
-<pre><code>{ orange code block }</code></pre>
-<blockquote>
-<p>orange block quote</p>
-</blockquote>
-</dd>
-</dl>
-<p>Multiple definitions, tight:</p>
-<dl>
-<dt>apple</dt>
-<dd>red fruit
-</dd>
-<dd>computer
-</dd>
-<dt>orange</dt>
-<dd>orange fruit
-</dd>
-<dd>bank
-</dd>
-</dl>
-<p>Multiple definitions, loose:</p>
-<dl>
-<dt>apple</dt>
-<dd><p>red fruit</p>
-</dd>
-<dd><p>computer</p>
-</dd>
-<dt>orange</dt>
-<dd><p>orange fruit</p>
-</dd>
-<dd><p>bank</p>
-</dd>
-</dl>
-<p>Blank line after term, indented marker, alternate markers:</p>
-<dl>
-<dt>apple</dt>
-<dd><p>red fruit</p>
-</dd>
-<dd><p>computer</p>
-</dd>
-<dt>orange</dt>
-<dd><p>orange fruit</p>
-<ol style="list-style-type: decimal">
-<li>sublist</li>
-<li>sublist</li>
-</ol>
-</dd>
-</dl>
-<h1 id="html-blocks">HTML Blocks</h1>
-<p>Simple block on one line:</p>
-<div>
-foo
-</div>
-<p>And nested without indentation:</p>
-<div>
-<div>
-<div>
-<p>foo</p>
-</div>
-</div>
-<div>
-bar
-</div>
-</div>
-<p>Interpreted markdown in a table:</p>
-<table>
-<tr>
-<td>
-This is <em>emphasized</em>
-</td>
-<td>
-And this is <strong>strong</strong>
-</td>
-</tr>
-</table>
-<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
-<p>Here’s a simple block:</p>
-<div>
-<p>foo</p>
-</div>
-<p>This should be a code block, though:</p>
-<pre><code>&lt;div&gt;
- foo
-&lt;/div&gt;</code></pre>
-<p>As should this:</p>
-<pre><code>&lt;div&gt;foo&lt;/div&gt;</code></pre>
-<p>Now, nested:</p>
-<div>
-<div>
-<div>
-foo
-</div>
-</div>
-</div>
-<p>This should just be an HTML comment:</p>
-<!-- Comment -->
-<p>Multiline:</p>
-<!--
-Blah
-Blah
--->
-<!--
- This is another comment.
--->
-<p>Code block:</p>
-<pre><code>&lt;!-- Comment --&gt;</code></pre>
-<p>Just plain comment, with trailing spaces on the line:</p>
-<!-- foo -->
-<p>Code:</p>
-<pre><code>&lt;hr /&gt;</code></pre>
-<p>Hr’s:</p>
-<hr>
-<hr />
-<hr />
-<hr>
-<hr />
-<hr />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar">
-<hr />
-<h1 id="inline-markup">Inline Markup</h1>
-<p>This is <em>emphasized</em>, and so <em>is this</em>.</p>
-<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
-<p>An <em><a href="/url">emphasized link</a></em>.</p>
-<p><strong><em>This is strong and em.</em></strong></p>
-<p>So is <strong><em>this</em></strong> word.</p>
-<p><strong><em>This is strong and em.</em></strong></p>
-<p>So is <strong><em>this</em></strong> word.</p>
-<p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p>
-<p><del>This is <em>strikeout</em>.</del></p>
-<p>Superscripts: a<sup>bc</sup>d a<sup><em>hello</em></sup> a<sup>hello there</sup>.</p>
-<p>Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.</p>
-<p>These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</p>
-<hr />
-<h1 id="smart-quotes-ellipses-dashes">Smart quotes, ellipses, dashes</h1>
-<p>“Hello,” said the spider. “‘Shelob’ is my name.”</p>
-<p>‘A’, ‘B’, and ‘C’ are letters.</p>
-<p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’</p>
-<p>‘He said, “I want to go.”’ Were you alive in the 70’s?</p>
-<p>Here is some quoted ‘<code>code</code>’ and a “<a href="http://example.com/?foo=1&amp;bar=2">quoted link</a>”.</p>
-<p>Some dashes: one—two — three—four — five.</p>
-<p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p>
-<p>Ellipses…and…and….</p>
-<hr />
-<h1 id="latex">LaTeX</h1>
-<ul>
-<li></li>
-<li><span class="math inline">2 + 2 = 4</span></li>
-<li><span class="math inline"><em>x</em> ∈ <em>y</em></span></li>
-<li><span class="math inline"><em>α</em> ∧ <em>ω</em></span></li>
-<li><span class="math inline">223</span></li>
-<li><span class="math inline"><em>p</em></span>-Tree</li>
-<li>Here’s some display math: <br /><span class="math display">$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</span><br /></li>
-<li>Here’s one that has a line break in it: <span class="math inline"><em>α</em> + <em>ω</em> × <em>x</em><sup>2</sup></span>.</li>
-</ul>
-<p>These shouldn’t be math:</p>
-<ul>
-<li>To get the famous equation, write <code>$e = mc^2$</code>.</li>
-<li>$22,000 is a <em>lot</em> of money. So is $34,000. (It worked if “lot” is emphasized.)</li>
-<li>Shoes ($20) and socks ($5).</li>
-<li>Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.</li>
-</ul>
-<p>Here’s a LaTeX table:</p>
-
-<hr />
-<h1 id="special-characters">Special Characters</h1>
-<p>Here is some unicode:</p>
-<ul>
-<li>I hat: Î</li>
-<li>o umlaut: ö</li>
-<li>section: §</li>
-<li>set membership: ∈</li>
-<li>copyright: ©</li>
-</ul>
-<p>AT&amp;T has an ampersand in their name.</p>
-<p>AT&amp;T is another way to write it.</p>
-<p>This &amp; that.</p>
-<p>4 &lt; 5.</p>
-<p>6 &gt; 5.</p>
-<p>Backslash: \</p>
-<p>Backtick: `</p>
-<p>Asterisk: *</p>
-<p>Underscore: _</p>
-<p>Left brace: {</p>
-<p>Right brace: }</p>
-<p>Left bracket: [</p>
-<p>Right bracket: ]</p>
-<p>Left paren: (</p>
-<p>Right paren: )</p>
-<p>Greater-than: &gt;</p>
-<p>Hash: #</p>
-<p>Period: .</p>
-<p>Bang: !</p>
-<p>Plus: +</p>
-<p>Minus: -</p>
-<hr />
-<h1 id="links">Links</h1>
-<h2 id="explicit">Explicit</h2>
-<p>Just a <a href="/url/">URL</a>.</p>
-<p><a href="/url/" title="title">URL and title</a>.</p>
-<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
-<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
-<p><a href="/url/" title="title with &quot;quotes&quot; in it">URL and title</a></p>
-<p><a href="/url/" title="title with single quotes">URL and title</a></p>
-<p><a href="/url/with_underscore">with_underscore</a></p>
-<p><a href="mailto:nobody@nowhere.net">Email link</a></p>
-<p><a href="">Empty</a>.</p>
-<h2 id="reference">Reference</h2>
-<p>Foo <a href="/url/">bar</a>.</p>
-<p>Foo <a href="/url/">bar</a>.</p>
-<p>Foo <a href="/url/">bar</a>.</p>
-<p>With <a href="/url/">embedded [brackets]</a>.</p>
-<p><a href="/url/">b</a> by itself should be a link.</p>
-<p>Indented <a href="/url">once</a>.</p>
-<p>Indented <a href="/url">twice</a>.</p>
-<p>Indented <a href="/url">thrice</a>.</p>
-<p>This should [not][] be a link.</p>
-<pre><code>[not]: /url</code></pre>
-<p>Foo <a href="/url/" title="Title with &quot;quotes&quot; inside">bar</a>.</p>
-<p>Foo <a href="/url/" title="Title with &quot;quote&quot; inside">biz</a>.</p>
-<h2 id="with-ampersands">With ampersands</h2>
-<p>Here’s a <a href="http://example.com/?foo=1&amp;bar=2">link with an ampersand in the URL</a>.</p>
-<p>Here’s a link with an amersand in the link text: <a href="http://att.com/" title="AT&amp;T">AT&amp;T</a>.</p>
-<p>Here’s an <a href="/script?foo=1&amp;bar=2">inline link</a>.</p>
-<p>Here’s an <a href="/script?foo=1&amp;bar=2">inline link in pointy braces</a>.</p>
-<h2 id="autolinks">Autolinks</h2>
-<p>With an ampersand: <a href="http://example.com/?foo=1&amp;bar=2" class="uri">http://example.com/?foo=1&amp;bar=2</a></p>
-<ul>
-<li>In a list?</li>
-<li><a href="http://example.com/" class="uri">http://example.com/</a></li>
-<li>It should.</li>
-</ul>
-<p>An e-mail address: <a href="mailto:nobody@nowhere.net">nobody@nowhere.net</a></p>
-<blockquote>
-<p>Blockquoted: <a href="http://example.com/" class="uri">http://example.com/</a></p>
-</blockquote>
-<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p>
-<pre><code>or here: &lt;http://example.com/&gt;</code></pre>
-<hr />
-<h1 id="images">Images</h1>
-<p>From “Voyage dans la Lune” by Georges Melies (1902):</p>
-<div class="figure">
-<img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune" />
-<p class="caption">lalune</p>
-</div>
-<p>Here is a movie <img src="movie.jpg" alt="movie" /> icon.</p>
-<hr />
-<h1 id="footnotes">Footnotes</h1>
-<p>Here is a footnote reference,<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a> and another.<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a> This should <em>not</em> be a footnote reference, because it contains a space.[^my note] Here is an inline note.<a href="#fn3" class="footnoteRef" id="fnref3"><sup>3</sup></a></p>
-<blockquote>
-<p>Notes can go in quotes.<a href="#fn4" class="footnoteRef" id="fnref4"><sup>4</sup></a></p>
-</blockquote>
-<ol style="list-style-type: decimal">
-<li>And in list items.<a href="#fn5" class="footnoteRef" id="fnref5"><sup>5</sup></a></li>
-</ol>
-<p>This paragraph should not be part of the note, as it is not indented.</p>
-<div class="footnotes">
-<hr />
-<ol>
-<li id="fn1"><p>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.<a href="#fnref1">↩</a></p></li>
-<li id="fn2"><p>Here’s the long note. This one contains multiple blocks.</p>
-<p>Subsequent blocks are indented to show that they belong to the footnote (as with list items).</p>
-<pre><code> { &lt;code&gt; }</code></pre>
-<p>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.<a href="#fnref2">↩</a></p></li>
-<li id="fn3"><p>This is <em>easier</em> to type. Inline notes may contain <a href="http://google.com">links</a> and <code>]</code> verbatim characters, as well as [bracketed text].<a href="#fnref3">↩</a></p></li>
-<li id="fn4"><p>In quote.<a href="#fnref4">↩</a></p></li>
-<li id="fn5"><p>In list.<a href="#fnref5">↩</a></p></li>
-</ol>
-</div>
-</body>
-</html>
diff --git a/tests/writer.icml b/tests/writer.icml
deleted file mode 100644
index b498f568b..000000000
--- a/tests/writer.icml
+++ /dev/null
@@ -1,3317 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<?aid style="50" type="snippet" readerVersion="6.0" featureSet="513" product="8.0(370)" ?>
-<?aid SnippetType="InCopyInterchange"?>
-<Document DOMVersion="8.0" Self="pandoc_doc">
- <RootCharacterStyleGroup Self="pandoc_character_styles">
- <CharacterStyle Self="$ID/NormalCharacterStyle" Name="Default" />
- <CharacterStyle Self="CharacterStyle/" Name="">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Bold" Name="Bold" FontStyle="Bold">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Bold Italic" Name="Bold Italic" FontStyle="Bold Italic">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Code" Name="Code">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- <AppliedFont type="string">Courier New</AppliedFont>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Italic" Name="Italic" FontStyle="Italic">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Italic Link" Name="Italic Link" FontStyle="Italic">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Italic Strikeout" Name="Italic Strikeout" FontStyle="Italic" StrikeThru="true">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Italic Superscript" Name="Italic Superscript" FontStyle="Italic" Position="Superscript">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Link" Name="Link">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Strikeout" Name="Strikeout" StrikeThru="true">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Subscript" Name="Subscript" Position="Subscript">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- <CharacterStyle Self="CharacterStyle/Superscript" Name="Superscript" Position="Superscript">
- <Properties>
- <BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
- </Properties>
- </CharacterStyle>
- </RootCharacterStyleGroup>
- <RootParagraphStyleGroup Self="pandoc_paragraph_styles">
- <ParagraphStyle Self="$ID/NormalParagraphStyle" Name="$ID/NormalParagraphStyle"
- SpaceBefore="6" SpaceAfter="6"> <!-- paragraph spacing -->
- <Properties>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string"></Leader>
- <Position type="unit">10</Position> <!-- first tab stop -->
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/" Name="" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; Blockquote &gt; Paragraph" Name="Blockquote &gt; Blockquote &gt; Paragraph" LeftIndent="30">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; CodeBlock" Name="Blockquote &gt; CodeBlock" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <AppliedFont type="string">Courier New</AppliedFont>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; NumList" Name="Blockquote &gt; NumList" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; NumList &gt; first" Name="Blockquote &gt; NumList &gt; first" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Blockquote &gt; Paragraph" Name="Blockquote &gt; Paragraph" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/BulList" Name="BulList" BulletsAndNumberingListType="BulletList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">10</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/BulList &gt; BulList &gt; BulList &gt; first" Name="BulList &gt; BulList &gt; BulList &gt; first" BulletsAndNumberingListType="BulletList" LeftIndent="20">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">30</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/BulList &gt; BulList &gt; Paragraph" Name="BulList &gt; BulList &gt; Paragraph" BulletsAndNumberingListType="BulletList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">20</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/BulList &gt; BulList &gt; first" Name="BulList &gt; BulList &gt; first" BulletsAndNumberingListType="BulletList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">20</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/BulList &gt; BulList &gt; first &gt; Paragraph" Name="BulList &gt; BulList &gt; first &gt; Paragraph" BulletsAndNumberingListType="BulletList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">20</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/BulList &gt; Paragraph" Name="BulList &gt; Paragraph" BulletsAndNumberingListType="BulletList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">10</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/BulList &gt; first" Name="BulList &gt; first" BulletsAndNumberingListType="BulletList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">10</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/BulList &gt; first &gt; Paragraph" Name="BulList &gt; first &gt; Paragraph" BulletsAndNumberingListType="BulletList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">10</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Caption" Name="Caption" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/CodeBlock" Name="CodeBlock" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <AppliedFont type="string">Courier New</AppliedFont>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/DefListDef" Name="DefListDef" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; Blockquote &gt; Paragraph" Name="DefListDef &gt; Blockquote &gt; Paragraph" LeftIndent="30">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; CodeBlock" Name="DefListDef &gt; CodeBlock" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <AppliedFont type="string">Courier New</AppliedFont>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; NumList" Name="DefListDef &gt; NumList" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; NumList &gt; first" Name="DefListDef &gt; NumList &gt; first" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/DefListDef &gt; Paragraph" Name="DefListDef &gt; Paragraph" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/DefListTerm" Name="DefListTerm" LeftIndent="0" BulletsAndNumberingListType="BulletList" FontStyle="Bold">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Figure" Name="Figure" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Footnote &gt; CodeBlock" Name="Footnote &gt; CodeBlock" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <AppliedFont type="string">Courier New</AppliedFont>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Footnote &gt; Paragraph" Name="Footnote &gt; Paragraph" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Header1" Name="Header1" LeftIndent="0" PointSize="36">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Header2" Name="Header2" LeftIndent="0" PointSize="30">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Header3" Name="Header3" LeftIndent="0" PointSize="24">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Header4" Name="Header4" LeftIndent="0" PointSize="18">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Header5" Name="Header5" LeftIndent="0" PointSize="14">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList" Name="NumList" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; BulList" Name="NumList &gt; BulList" BulletsAndNumberingListType="BulletList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">20</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; BulList &gt; first" Name="NumList &gt; BulList &gt; first" BulletsAndNumberingListType="BulletList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <TabList type="list">
- <ListItem type="record">
- <Alignment type="enumeration">LeftAlign</Alignment>
- <AlignmentCharacter type="string">.</AlignmentCharacter>
- <Leader type="string" />
- <Position type="unit">20</Position>
- </ListItem>
- </TabList>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-3 &gt; lowerAlpha" Name="NumList &gt; NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-3 &gt; lowerAlpha" NumberingExpression="^#.^t" NumberingLevel="4" BulletsAndNumberingListType="NumberedList" LeftIndent="30">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <NumberingFormat type="string">a, b, c, d...</NumberingFormat>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-6" Name="NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-6" NumberingExpression="^#.^t" NumberingLevel="3" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; first &gt; upperAlpha" Name="NumList &gt; NumList &gt; NumList &gt; first &gt; upperAlpha" NumberingExpression="^#.^t" NumberingLevel="3" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <NumberingFormat type="string">A, B, C, D...</NumberingFormat>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; upperAlpha" Name="NumList &gt; NumList &gt; NumList &gt; upperAlpha" NumberingExpression="^#.^t" NumberingLevel="3" BulletsAndNumberingListType="NumberedList" LeftIndent="20">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <NumberingFormat type="string">A, B, C, D...</NumberingFormat>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; beginsWith-4 &gt; lowerRoman" Name="NumList &gt; NumList &gt; beginsWith-4 &gt; lowerRoman" NumberingExpression="^#.^t" NumberingLevel="2" BulletsAndNumberingListType="NumberedList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <NumberingFormat type="string">i, ii, iii, iv...</NumberingFormat>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; first" Name="NumList &gt; NumList &gt; first" NumberingExpression="^#.^t" NumberingLevel="2" BulletsAndNumberingListType="NumberedList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; first &gt; beginsWith-4 &gt; lowerRoman" Name="NumList &gt; NumList &gt; first &gt; beginsWith-4 &gt; lowerRoman" NumberingExpression="^#.^t" NumberingLevel="2" BulletsAndNumberingListType="NumberedList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <NumberingFormat type="string">i, ii, iii, iv...</NumberingFormat>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; NumList &gt; first &gt; upperRoman" Name="NumList &gt; NumList &gt; first &gt; upperRoman" NumberingExpression="^#.^t" NumberingLevel="2" BulletsAndNumberingListType="NumberedList" LeftIndent="10">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <NumberingFormat type="string">I, II, III, IV...</NumberingFormat>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; Paragraph" Name="NumList &gt; Paragraph" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; beginsWith-2 &gt; Paragraph" Name="NumList &gt; beginsWith-2 &gt; Paragraph" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; first" Name="NumList &gt; first" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; first &gt; Paragraph" Name="NumList &gt; first &gt; Paragraph" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; first &gt; beginsWith-2" Name="NumList &gt; first &gt; beginsWith-2" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; first &gt; upperAlpha" Name="NumList &gt; first &gt; upperAlpha" NumberingExpression="^#.^t" NumberingLevel="1" BulletsAndNumberingListType="NumberedList" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- <NumberingFormat type="string">A, B, C, D...</NumberingFormat>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/NumList &gt; subParagraph &gt; Paragraph" Name="NumList &gt; subParagraph &gt; Paragraph" NumberingExpression="^#.^t" NumberingLevel="1" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Paragraph" Name="Paragraph" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
- </ParagraphStyle>
- </RootParagraphStyleGroup>
- <RootTableStyleGroup Self="pandoc_table_styles">
- <TableStyle Self="TableStyle/Table" Name="Table" />
- </RootTableStyleGroup>
- <RootCellStyleGroup Self="pandoc_cell_styles">
- <CellStyle Self="CellStyle/Cell" AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]" Name="Cell" />
- </RootCellStyleGroup>
- <Story Self="pandoc_story"
- TrackChanges="false"
- StoryTitle=""
- AppliedTOCStyle="n"
- AppliedNamedGrid="n" >
- <StoryPreference OpticalMarginAlignment="true" OpticalMarginSize="12" />
-
-<!-- body needs to be non-indented, otherwise code blocks are indented too far -->
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Headers</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Level 2 with an </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-1" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>embedded link</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header3">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Level 3 with </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>emphasis</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header4">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Level 4</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header5">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Level 5</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Level 1</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Level 2 with </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>emphasis</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header3">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Level 3</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>with no blank line</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Level 2</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>with no blank line</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Paragraphs</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s a regular paragraph.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s one with a bullet. * criminey.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>There should be a hard line break</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&#x2028;</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>here.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Block Quotes</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>E-mail style:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This is a block quote. It is pretty short.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Code in a block quote:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>sub status {
- print &quot;working&quot;;
-}</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>A list:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; NumList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>item one</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>item two</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Nested block quotes:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>nested</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>nested</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This should not be a block quote: 2 &gt; 1.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>And a following paragraph.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Code Blocks</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Code:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>---- (should be four hyphens)
-
-sub status {
- print &quot;working&quot;;
-}
-
-this code block is indented by one tab</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>And:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \&gt; \[ \{</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Lists</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Unordered</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Asterisks tight:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>asterisk 1</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>asterisk 2</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>asterisk 3</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Asterisks loose:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>asterisk 1</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>asterisk 2</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>asterisk 3</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Pluses tight:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Plus 1</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Plus 2</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Plus 3</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Pluses loose:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Plus 1</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Plus 2</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Plus 3</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minuses tight:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minus 1</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minus 2</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minus 3</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minuses loose:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minus 1</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minus 2</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minus 3</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Ordered</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Tight:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>First</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Second</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Third</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>and:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>One</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Two</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Three</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Loose using tabs:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>First</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Second</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Third</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>and using spaces:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>One</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Two</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Three</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Multiple paragraphs:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Item 1, graf one.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; subParagraph &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Item 2.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Item 3.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Nested</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Tab</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Tab</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; BulList &gt; BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Tab</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s another:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>First</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Second:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Fee</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Fie</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foe</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Third</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Same thing but with paragraphs:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>First</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Second:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Fee</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Fie</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foe</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Third</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Tabs and spaces</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>this is a list item indented with tabs</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>this is a list item indented with spaces</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; BulList &gt; first &gt; Paragraph" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>this is an example list item indented with tabs</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; BulList &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>this is an example list item indented with spaces</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Fancy list markers</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange NumberingStartAt="2" AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; beginsWith-2" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>begins with 2</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; beginsWith-2 &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>and now 3</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; subParagraph &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>with a continuation</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange NumberingStartAt="4" AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; first &gt; beginsWith-4 &gt; lowerRoman" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>sublist with roman numerals, starting with 4</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; beginsWith-4 &gt; lowerRoman">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>more items</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; first &gt; upperAlpha" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>a subsublist</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; upperAlpha">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>a subsublist</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Nesting:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first &gt; upperAlpha" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Upper Alpha</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; first &gt; upperRoman" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Upper Roman.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange NumberingStartAt="6" AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-6" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Decimal start with 6</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange NumberingStartAt="3" AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; NumList &gt; NumList &gt; first &gt; beginsWith-3 &gt; lowerAlpha" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Lower alpha with paren</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Autonumbering:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Autonumber.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>More.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; NumList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Nested.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Should not be a list item:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>M.A. 2007</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>B. Williams</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Definition Lists</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Tight using spaces:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>apple</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>red fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>banana</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>yellow fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Tight using tabs:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>apple</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>red fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>banana</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>yellow fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Loose:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>apple</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>red fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>banana</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>yellow fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Multiple blocks with italics:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>apple</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>red fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>contains seeds, crisp, pleasant to taste</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>orange</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>{ orange code block }</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange block quote</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Multiple definitions, tight:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>apple</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>red fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>computer</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>bank</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Multiple definitions, loose:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>apple</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>red fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>computer</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>bank</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Blank line after term, indented marker, alternate markers:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>apple</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>red fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>computer</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListTerm">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>orange fruit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; NumList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>sublist</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/DefListDef &gt; NumList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>sublist</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>HTML Blocks</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Simple block on one line:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>foo</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>And nested without indentation:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>foo</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>bar</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Interpreted markdown in a table:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>emphasized</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>And this is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold">
- <Content>strong</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s a simple block:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>foo</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This should be a code block, though:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;div&gt;
- foo
-&lt;/div&gt;</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>As should this:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;div&gt;foo&lt;/div&gt;</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Now, nested:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>foo</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This should just be an HTML comment:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Multiline:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Code block:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;!-- Comment --&gt;</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Just plain comment, with trailing spaces on the line:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Code:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr /&gt;</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Hr’s:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Inline Markup</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>emphasized</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>, and so </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>is this</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold">
- <Content>strong</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>, and so </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold">
- <Content>is this</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>An </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-2" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic Link">
- <Content>emphasized link</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold Italic">
- <Content>This is strong and em.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>So is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold Italic">
- <Content>this</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> word.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold Italic">
- <Content>This is strong and em.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>So is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Bold Italic">
- <Content>this</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> word.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This is code: </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>&gt;</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>, </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>$</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>, </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>\</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>, </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>\$</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>, </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>&lt;html&gt;</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Strikeout">
- <Content>This is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic Strikeout">
- <Content>strikeout</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Strikeout">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Superscripts: a</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Superscript">
- <Content>bc</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>d a</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic Superscript">
- <Content>hello</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> a</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Superscript">
- <Content>hello there</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Subscripts: H</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Subscript">
- <Content>2</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>O, H</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Subscript">
- <Content>23</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>O, H</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Subscript">
- <Content>many of them</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>O.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Smart quotes, ellipses, dashes</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>“</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Hello,</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>”</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> said the spider. </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>“</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Shelob</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> is my name.</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>”</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>A</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>, </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>B</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>, and </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>C</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> are letters.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Oak,</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>elm,</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> and </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>beech</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> are names of trees. So is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>pine.</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>He said, </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>“</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>I want to go.</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>”</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> Were you alive in the 70’s?</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here is some quoted </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>‘</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>code</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>’</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> and a </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>“</Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-3" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>quoted link</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>”</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Some dashes: one—two — three—four — five.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Dashes between numbers: 5–7, 255–66, 1987–1999.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Ellipses…and…and….</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>LaTeX</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>2</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>+</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>2</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>=</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>4</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>x</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>∈</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>y</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>α</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>∧</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>ω</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>223</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>p</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>-Tree</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s some display math: </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s one that has a line break in it: </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>α</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>+</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>ω</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>×</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>x</Content>
- </CharacterStyleRange><CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Superscript">
- <Content>2</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>These shouldn’t be math:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>To get the famous equation, write </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>$e = mc^2$</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>$22,000 is a </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>lot</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> of money. So is $34,000. (It worked if </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>“</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>lot</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>”</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> is emphasized.)</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Shoes ($20) and socks ($5).</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Escaped </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>$</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>: $73 </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>this should be emphasized</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> 23$.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s a LaTeX table:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Special Characters</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here is some unicode:</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>I hat: Î</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>o umlaut: ö</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>section: §</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>set membership: ∈</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>copyright: ©</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>AT&amp;T has an ampersand in their name.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>AT&amp;T is another way to write it.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This &amp; that.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>4 &lt; 5.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>6 &gt; 5.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Backslash: \</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Backtick: `</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Asterisk: *</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Underscore: _</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Left brace: {</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Right brace: }</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Left bracket: [</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Right bracket: ]</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Left paren: (</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Right paren: )</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Greater-than: &gt;</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Hash: #</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Period: .</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Bang: !</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Plus: +</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Minus: -</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Links</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Explicit</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Just a </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-4" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>URL</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-5" Name="title" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>URL and title</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-6" Name="title preceded by two spaces" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>URL and title</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-7" Name="title preceded by a tab" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>URL and title</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-8" Name="title with &quot;quotes&quot; in it" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>URL and title</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-9" Name="title with single quotes" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>URL and title</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-10" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>with_underscore</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-11" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>Email link</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-12" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>Empty</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Reference</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foo </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-13" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>bar</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foo </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-14" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>bar</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foo </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-15" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>bar</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>With </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-16" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>embedded [brackets]</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-17" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>b</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> by itself should be a link.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Indented </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-18" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>once</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Indented </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-19" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>twice</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Indented </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-20" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>thrice</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This should [not][] be a link.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>[not]: /url</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foo </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-21" Name="Title with &quot;quotes&quot; inside" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>bar</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foo </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-22" Name="Title with &quot;quote&quot; inside" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>biz</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>With ampersands</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s a </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-23" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>link with an ampersand in the URL</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s a link with an amersand in the link text: </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-24" Name="AT&amp;T" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>AT&amp;T</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s an </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-25" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>inline link</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s an </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-26" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>inline link in pointy braces</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header2">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Autolinks</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>With an ampersand: </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-27" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>http://example.com/?foo=1&amp;bar=2</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>In a list?</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <HyperlinkTextSource Self="htss-28" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>http://example.com/</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>It should.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>An e-mail address: </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-29" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>nobody@nowhere.net</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Blockquoted: </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-30" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>http://example.com/</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Auto-links should not occur here: </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>&lt;http://example.com/&gt;</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>or here: &lt;http://example.com/&gt;</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Images</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>From </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>“</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Voyage dans la Lune</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>”</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> by Georges Melies (1902):</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Figure">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1.00000 0 0 1.00000 75.00000 -75.00000">
- <Properties>
- <PathGeometry>
- <GeometryPathType PathOpen="false">
- <PathPointArray>
- <PathPointType Anchor="-75.00000 -75.00000" LeftDirection="-75.00000 -75.00000" RightDirection="-75.00000 -75.00000" />
- <PathPointType Anchor="-75.00000 75.00000" LeftDirection="-75.00000 75.00000" RightDirection="-75.00000 75.00000" />
- <PathPointType Anchor="75.00000 75.00000" LeftDirection="75.00000 75.00000" RightDirection="75.00000 75.00000" />
- <PathPointType Anchor="75.00000 -75.00000" LeftDirection="75.00000 -75.00000" RightDirection="75.00000 -75.00000" />
- </PathPointArray>
- </GeometryPathType>
- </PathGeometry>
- </Properties>
- <Image Self="ue6" ItemTransform="1.00000 0 0 1.00000 -75.00000 -75.00000">
- <Properties>
- <Profile type="string">
- $ID/Embedded
- </Profile>
- </Properties>
- <Link Self="ueb" LinkResourceURI="file:lalune.jpg" />
- </Image>
- </Rectangle>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Caption">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>lalune</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here is a movie </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1.00000 0 0 1.00000 10.00000 -11.00000">
- <Properties>
- <PathGeometry>
- <GeometryPathType PathOpen="false">
- <PathPointArray>
- <PathPointType Anchor="-10.00000 -11.00000" LeftDirection="-10.00000 -11.00000" RightDirection="-10.00000 -11.00000" />
- <PathPointType Anchor="-10.00000 11.00000" LeftDirection="-10.00000 11.00000" RightDirection="-10.00000 11.00000" />
- <PathPointType Anchor="10.00000 11.00000" LeftDirection="10.00000 11.00000" RightDirection="10.00000 11.00000" />
- <PathPointType Anchor="10.00000 -11.00000" LeftDirection="10.00000 -11.00000" RightDirection="10.00000 -11.00000" />
- </PathPointArray>
- </GeometryPathType>
- </PathGeometry>
- </Properties>
- <Image Self="ue6" ItemTransform="1.00000 0 0 1.00000 -10.00000 -11.00000">
- <Properties>
- <Profile type="string">
- $ID/Embedded
- </Profile>
- </Properties>
- <Link Self="ueb" LinkResourceURI="file:movie.jpg" />
- </Image>
- </Rectangle>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> icon.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Footnotes</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here is a footnote reference,</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
- <Footnote>
- <ParagraphStyleRange>
- <CharacterStyleRange>
- <Content><?ACE 4?></Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Footnote>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> and another.</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
- <Footnote>
- <ParagraphStyleRange>
- <CharacterStyleRange>
- <Content><?ACE 4?></Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Here’s the long note. This one contains multiple blocks.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- <Br />
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Subsequent blocks are indented to show that they belong to the footnote (as with list items).</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- <Br />
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; CodeBlock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> { &lt;code&gt; }</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- <Br />
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Footnote>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> This should </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>not</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> be a footnote reference, because it contains a space.[^my note] Here is an inline note.</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
- <Footnote>
- <ParagraphStyleRange>
- <CharacterStyleRange>
- <Content><?ACE 4?></Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This is </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Italic">
- <Content>easier</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> to type. Inline notes may contain </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-31" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>links</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> and </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Code">
- <Content>]</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> verbatim characters, as well as [bracketed text].</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Footnote>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Blockquote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Notes can go in quotes.</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
- <Footnote>
- <ParagraphStyleRange>
- <CharacterStyleRange>
- <Content><?ACE 4?></Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>In quote.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Footnote>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/NumList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>And in list items.</Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle" Position="Superscript">
- <Footnote>
- <ParagraphStyleRange>
- <CharacterStyleRange>
- <Content><?ACE 4?></Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Footnote &gt; Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content> </Content>
- </CharacterStyleRange>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>In list.</Content>
- </CharacterStyleRange>
- </ParagraphStyleRange>
- </Footnote>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>This paragraph should not be part of the note, as it is not indented.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-
- </Story>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//google.com" Name="link" DestinationURL="http://google.com" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-31" Name="http://google.com" Source="htss-31" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http%3a//google.com</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/" Name="link" DestinationURL="http://example.com/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-30" Name="http://example.com/" Source="htss-30" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http%3a//example.com/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/mailto%3anobody@nowhere.net" Name="link" DestinationURL="mailto:nobody@nowhere.net" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-29" Name="mailto:nobody@nowhere.net" Source="htss-29" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/mailto%3anobody@nowhere.net</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/" Name="link" DestinationURL="http://example.com/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-28" Name="http://example.com/" Source="htss-28" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http%3a//example.com/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-27" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-27" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//script?foo=1&amp;bar=2" Name="link" DestinationURL="/script?foo=1&amp;bar=2" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-26" Name="/script?foo=1&amp;bar=2" Source="htss-26" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//script?foo=1&amp;bar=2</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//script?foo=1&amp;bar=2" Name="link" DestinationURL="/script?foo=1&amp;bar=2" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-25" Name="/script?foo=1&amp;bar=2" Source="htss-25" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//script?foo=1&amp;bar=2</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//att.com/" Name="link" DestinationURL="http://att.com/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-24" Name="http://att.com/" Source="htss-24" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http%3a//att.com/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-23" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-23" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-22" Name="/url/" Source="htss-22" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-21" Name="/url/" Source="htss-21" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-20" Name="/url" Source="htss-20" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-19" Name="/url" Source="htss-19" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-18" Name="/url" Source="htss-18" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-17" Name="/url/" Source="htss-17" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-16" Name="/url/" Source="htss-16" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-15" Name="/url/" Source="htss-15" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-14" Name="/url/" Source="htss-14" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-13" Name="/url/" Source="htss-13" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/" Name="link" DestinationURL="" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-12" Name="" Source="htss-12" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/mailto%3anobody@nowhere.net" Name="link" DestinationURL="mailto:nobody@nowhere.net" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-11" Name="mailto:nobody@nowhere.net" Source="htss-11" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/mailto%3anobody@nowhere.net</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/with_underscore" Name="link" DestinationURL="/url/with_underscore" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-10" Name="/url/with_underscore" Source="htss-10" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/with_underscore</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-9" Name="/url/" Source="htss-9" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-8" Name="/url/" Source="htss-8" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-7" Name="/url/" Source="htss-7" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-6" Name="/url/" Source="htss-6" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-5" Name="/url/" Source="htss-5" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-4" Name="/url/" Source="htss-4" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-3" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-3" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-2" Name="/url" Source="htss-2" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-1" Name="/url" Source="htss-1" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url</Destination>
- </Properties>
- </Hyperlink>
-</Document>
diff --git a/tests/writer.latex b/tests/writer.latex
deleted file mode 100644
index 5cf39c9c3..000000000
--- a/tests/writer.latex
+++ /dev/null
@@ -1,971 +0,0 @@
-\documentclass[]{article}
-\usepackage{lmodern}
-\usepackage{amssymb,amsmath}
-\usepackage{ifxetex,ifluatex}
-\usepackage{fixltx2e} % provides \textsubscript
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[T1]{fontenc}
- \usepackage[utf8]{inputenc}
-\else % if luatex or xelatex
- \ifxetex
- \usepackage{mathspec}
- \else
- \usepackage{fontspec}
- \fi
- \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
-\fi
-% use upquote if available, for straight quotes in verbatim environments
-\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
-% use microtype if available
-\IfFileExists{microtype.sty}{%
-\usepackage[]{microtype}
-\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
-}{}
-\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
-\usepackage{fancyvrb}
-\usepackage[unicode=true]{hyperref}
-\hypersetup{
- pdftitle={Pandoc Test Suite},
- pdfauthor={John MacFarlane; Anonymous},
- pdfborder={0 0 0},
- breaklinks=true}
-\urlstyle{same} % don't use monospace font for urls
-\VerbatimFootnotes % allows verbatim text in footnotes
-\usepackage{graphicx,grffile}
-\makeatletter
-\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
-\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
-\makeatother
-% Scale images if necessary, so that they will not overflow the page
-% margins by default, and it is still possible to overwrite the defaults
-% using explicit options in \includegraphics[width, height, ...]{}
-\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
-\usepackage[normalem]{ulem}
-% avoid problems with \sout in headers with hyperref:
-\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
-\setlength{\emergencystretch}{3em} % prevent overfull lines
-\providecommand{\tightlist}{%
- \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-\setcounter{secnumdepth}{0}
-% Redefines (sub)paragraphs to behave more like sections
-\ifx\paragraph\undefined\else
-\let\oldparagraph\paragraph
-\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
-\fi
-\ifx\subparagraph\undefined\else
-\let\oldsubparagraph\subparagraph
-\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
-\fi
-
-% set default figure placement to htbp
-\makeatletter
-\def\fps@figure{htbp}
-\makeatother
-
-
-\title{Pandoc Test Suite}
-\author{John MacFarlane \and Anonymous}
-\date{July 17, 2006}
-
-\begin{document}
-\maketitle
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber's
-markdown test suite.
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Headers}\label{headers}
-
-\subsection{\texorpdfstring{Level 2 with an \href{/url}{embedded
-link}}{Level 2 with an embedded link}}\label{level-2-with-an-embedded-link}
-
-\subsubsection{\texorpdfstring{Level 3 with
-\emph{emphasis}}{Level 3 with emphasis}}\label{level-3-with-emphasis}
-
-\paragraph{Level 4}\label{level-4}
-
-\subparagraph{Level 5}\label{level-5}
-
-\section{Level 1}\label{level-1}
-
-\subsection{\texorpdfstring{Level 2 with
-\emph{emphasis}}{Level 2 with emphasis}}\label{level-2-with-emphasis}
-
-\subsubsection{Level 3}\label{level-3}
-
-with no blank line
-
-\subsection{Level 2}\label{level-2}
-
-with no blank line
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Paragraphs}\label{paragraphs}
-
-Here's a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here's one with a bullet. * criminey.
-
-There should be a hard line break\\
-here.
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Block Quotes}\label{block-quotes}
-
-E-mail style:
-
-\begin{quote}
-This is a block quote. It is pretty short.
-\end{quote}
-
-\begin{quote}
-Code in a block quote:
-
-\begin{verbatim}
-sub status {
- print "working";
-}
-\end{verbatim}
-
-A list:
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\tightlist
-\item
- item one
-\item
- item two
-\end{enumerate}
-
-Nested block quotes:
-
-\begin{quote}
-nested
-\end{quote}
-
-\begin{quote}
-nested
-\end{quote}
-\end{quote}
-
-This should not be a block quote: 2 \textgreater{} 1.
-
-And a following paragraph.
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Code Blocks}\label{code-blocks}
-
-Code:
-
-\begin{verbatim}
----- (should be four hyphens)
-
-sub status {
- print "working";
-}
-
-this code block is indented by one tab
-\end{verbatim}
-
-And:
-
-\begin{verbatim}
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \> \[ \{
-\end{verbatim}
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Lists}\label{lists}
-
-\subsection{Unordered}\label{unordered}
-
-Asterisks tight:
-
-\begin{itemize}
-\tightlist
-\item
- asterisk 1
-\item
- asterisk 2
-\item
- asterisk 3
-\end{itemize}
-
-Asterisks loose:
-
-\begin{itemize}
-\item
- asterisk 1
-\item
- asterisk 2
-\item
- asterisk 3
-\end{itemize}
-
-Pluses tight:
-
-\begin{itemize}
-\tightlist
-\item
- Plus 1
-\item
- Plus 2
-\item
- Plus 3
-\end{itemize}
-
-Pluses loose:
-
-\begin{itemize}
-\item
- Plus 1
-\item
- Plus 2
-\item
- Plus 3
-\end{itemize}
-
-Minuses tight:
-
-\begin{itemize}
-\tightlist
-\item
- Minus 1
-\item
- Minus 2
-\item
- Minus 3
-\end{itemize}
-
-Minuses loose:
-
-\begin{itemize}
-\item
- Minus 1
-\item
- Minus 2
-\item
- Minus 3
-\end{itemize}
-
-\subsection{Ordered}\label{ordered}
-
-Tight:
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\tightlist
-\item
- First
-\item
- Second
-\item
- Third
-\end{enumerate}
-
-and:
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\tightlist
-\item
- One
-\item
- Two
-\item
- Three
-\end{enumerate}
-
-Loose using tabs:
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\item
- First
-\item
- Second
-\item
- Third
-\end{enumerate}
-
-and using spaces:
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\item
- One
-\item
- Two
-\item
- Three
-\end{enumerate}
-
-Multiple paragraphs:
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\item
- Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
-\item
- Item 2.
-\item
- Item 3.
-\end{enumerate}
-
-\subsection{Nested}\label{nested}
-
-\begin{itemize}
-\tightlist
-\item
- Tab
-
- \begin{itemize}
- \tightlist
- \item
- Tab
-
- \begin{itemize}
- \tightlist
- \item
- Tab
- \end{itemize}
- \end{itemize}
-\end{itemize}
-
-Here's another:
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\tightlist
-\item
- First
-\item
- Second:
-
- \begin{itemize}
- \tightlist
- \item
- Fee
- \item
- Fie
- \item
- Foe
- \end{itemize}
-\item
- Third
-\end{enumerate}
-
-Same thing but with paragraphs:
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\item
- First
-\item
- Second:
-
- \begin{itemize}
- \tightlist
- \item
- Fee
- \item
- Fie
- \item
- Foe
- \end{itemize}
-\item
- Third
-\end{enumerate}
-
-\subsection{Tabs and spaces}\label{tabs-and-spaces}
-
-\begin{itemize}
-\item
- this is a list item indented with tabs
-\item
- this is a list item indented with spaces
-
- \begin{itemize}
- \item
- this is an example list item indented with tabs
- \item
- this is an example list item indented with spaces
- \end{itemize}
-\end{itemize}
-
-\subsection{Fancy list markers}\label{fancy-list-markers}
-
-\begin{enumerate}
-\def\labelenumi{(\arabic{enumi})}
-\setcounter{enumi}{1}
-\item
- begins with 2
-\item
- and now 3
-
- with a continuation
-
- \begin{enumerate}
- \def\labelenumii{\roman{enumii}.}
- \setcounter{enumii}{3}
- \tightlist
- \item
- sublist with roman numerals, starting with 4
- \item
- more items
-
- \begin{enumerate}
- \def\labelenumiii{(\Alph{enumiii})}
- \tightlist
- \item
- a subsublist
- \item
- a subsublist
- \end{enumerate}
- \end{enumerate}
-\end{enumerate}
-
-Nesting:
-
-\begin{enumerate}
-\def\labelenumi{\Alph{enumi}.}
-\tightlist
-\item
- Upper Alpha
-
- \begin{enumerate}
- \def\labelenumii{\Roman{enumii}.}
- \tightlist
- \item
- Upper Roman.
-
- \begin{enumerate}
- \def\labelenumiii{(\arabic{enumiii})}
- \setcounter{enumiii}{5}
- \tightlist
- \item
- Decimal start with 6
-
- \begin{enumerate}
- \def\labelenumiv{\alph{enumiv})}
- \setcounter{enumiv}{2}
- \tightlist
- \item
- Lower alpha with paren
- \end{enumerate}
- \end{enumerate}
- \end{enumerate}
-\end{enumerate}
-
-Autonumbering:
-
-\begin{enumerate}
-\tightlist
-\item
- Autonumber.
-\item
- More.
-
- \begin{enumerate}
- \tightlist
- \item
- Nested.
- \end{enumerate}
-\end{enumerate}
-
-Should not be a list item:
-
-M.A.~2007
-
-B. Williams
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Definition Lists}\label{definition-lists}
-
-Tight using spaces:
-
-\begin{description}
-\tightlist
-\item[apple]
-red fruit
-\item[orange]
-orange fruit
-\item[banana]
-yellow fruit
-\end{description}
-
-Tight using tabs:
-
-\begin{description}
-\tightlist
-\item[apple]
-red fruit
-\item[orange]
-orange fruit
-\item[banana]
-yellow fruit
-\end{description}
-
-Loose:
-
-\begin{description}
-\item[apple]
-red fruit
-\item[orange]
-orange fruit
-\item[banana]
-yellow fruit
-\end{description}
-
-Multiple blocks with italics:
-
-\begin{description}
-\item[\emph{apple}]
-red fruit
-
-contains seeds, crisp, pleasant to taste
-\item[\emph{orange}]
-orange fruit
-
-\begin{verbatim}
-{ orange code block }
-\end{verbatim}
-
-\begin{quote}
-orange block quote
-\end{quote}
-\end{description}
-
-Multiple definitions, tight:
-
-\begin{description}
-\tightlist
-\item[apple]
-red fruit
-
-computer
-\item[orange]
-orange fruit
-
-bank
-\end{description}
-
-Multiple definitions, loose:
-
-\begin{description}
-\item[apple]
-red fruit
-
-computer
-\item[orange]
-orange fruit
-
-bank
-\end{description}
-
-Blank line after term, indented marker, alternate markers:
-
-\begin{description}
-\item[apple]
-red fruit
-
-computer
-\item[orange]
-orange fruit
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\tightlist
-\item
- sublist
-\item
- sublist
-\end{enumerate}
-\end{description}
-
-\section{HTML Blocks}\label{html-blocks}
-
-Simple block on one line:
-
-foo
-
-And nested without indentation:
-
-foo
-
-bar
-
-Interpreted markdown in a table:
-
-This is \emph{emphasized}
-
-And this is \textbf{strong}
-
-Here's a simple block:
-
-foo
-
-This should be a code block, though:
-
-\begin{verbatim}
-<div>
- foo
-</div>
-\end{verbatim}
-
-As should this:
-
-\begin{verbatim}
-<div>foo</div>
-\end{verbatim}
-
-Now, nested:
-
-foo
-
-This should just be an HTML comment:
-
-Multiline:
-
-Code block:
-
-\begin{verbatim}
-<!-- Comment -->
-\end{verbatim}
-
-Just plain comment, with trailing spaces on the line:
-
-Code:
-
-\begin{verbatim}
-<hr />
-\end{verbatim}
-
-Hr's:
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Inline Markup}\label{inline-markup}
-
-This is \emph{emphasized}, and so \emph{is this}.
-
-This is \textbf{strong}, and so \textbf{is this}.
-
-An \emph{\href{/url}{emphasized link}}.
-
-\textbf{\emph{This is strong and em.}}
-
-So is \textbf{\emph{this}} word.
-
-\textbf{\emph{This is strong and em.}}
-
-So is \textbf{\emph{this}} word.
-
-This is code: \texttt{\textgreater{}}, \texttt{\$}, \texttt{\textbackslash{}},
-\texttt{\textbackslash{}\$}, \texttt{\textless{}html\textgreater{}}.
-
-\sout{This is \emph{strikeout}.}
-
-Superscripts: a\textsuperscript{bc}d a\textsuperscript{\emph{hello}}
-a\textsuperscript{hello~there}.
-
-Subscripts: H\textsubscript{2}O, H\textsubscript{23}O,
-H\textsubscript{many~of~them}O.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a\^{}b c\^{}d, a\textasciitilde{}b c\textasciitilde{}d.
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Smart quotes, ellipses, dashes}\label{smart-quotes-ellipses-dashes}
-
-``Hello,'' said the spider. ``\,`Shelob' is my name.''
-
-`A', `B', and `C' are letters.
-
-`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
-
-`He said, ``I want to go.''\,' Were you alive in the 70's?
-
-Here is some quoted `\texttt{code}' and a
-``\href{http://example.com/?foo=1\&bar=2}{quoted link}''.
-
-Some dashes: one---two --- three---four --- five.
-
-Dashes between numbers: 5--7, 255--66, 1987--1999.
-
-Ellipses\ldots{}and\ldots{}and\ldots{}.
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{LaTeX}\label{latex}
-
-\begin{itemize}
-\tightlist
-\item
- \cite[22-23]{smith.1899}
-\item
- \(2+2=4\)
-\item
- \(x \in y\)
-\item
- \(\alpha \wedge \omega\)
-\item
- \(223\)
-\item
- \(p\)-Tree
-\item
- Here's some display math:
- \[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\]
-\item
- Here's one that has a line break in it: \(\alpha + \omega \times x^2\).
-\end{itemize}
-
-These shouldn't be math:
-
-\begin{itemize}
-\tightlist
-\item
- To get the famous equation, write \texttt{\$e\ =\ mc\^{}2\$}.
-\item
- \$22,000 is a \emph{lot} of money. So is \$34,000. (It worked if ``lot'' is
- emphasized.)
-\item
- Shoes (\$20) and socks (\$5).
-\item
- Escaped \texttt{\$}: \$73 \emph{this should be emphasized} 23\$.
-\end{itemize}
-
-Here's a LaTeX table:
-
-\begin{tabular}{|l|l|}\hline
-Animal & Number \\ \hline
-Dog & 2 \\
-Cat & 1 \\ \hline
-\end{tabular}
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Special Characters}\label{special-characters}
-
-Here is some unicode:
-
-\begin{itemize}
-\tightlist
-\item
- I hat: Î
-\item
- o umlaut: ö
-\item
- section: §
-\item
- set membership: ∈
-\item
- copyright: ©
-\end{itemize}
-
-AT\&T has an ampersand in their name.
-
-AT\&T is another way to write it.
-
-This \& that.
-
-4 \textless{} 5.
-
-6 \textgreater{} 5.
-
-Backslash: \textbackslash{}
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: \_
-
-Left brace: \{
-
-Right brace: \}
-
-Left bracket: {[}
-
-Right bracket: {]}
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: \textgreater{}
-
-Hash: \#
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Links}\label{links}
-
-\subsection{Explicit}\label{explicit}
-
-Just a \href{/url/}{URL}.
-
-\href{/url/}{URL and title}.
-
-\href{/url/}{URL and title}.
-
-\href{/url/}{URL and title}.
-
-\href{/url/}{URL and title}
-
-\href{/url/}{URL and title}
-
-\href{/url/with_underscore}{with\_underscore}
-
-\href{mailto:nobody@nowhere.net}{Email link}
-
-\href{}{Empty}.
-
-\subsection{Reference}\label{reference}
-
-Foo \href{/url/}{bar}.
-
-Foo \href{/url/}{bar}.
-
-Foo \href{/url/}{bar}.
-
-With \href{/url/}{embedded {[}brackets{]}}.
-
-\href{/url/}{b} by itself should be a link.
-
-Indented \href{/url}{once}.
-
-Indented \href{/url}{twice}.
-
-Indented \href{/url}{thrice}.
-
-This should {[}not{]}{[}{]} be a link.
-
-\begin{verbatim}
-[not]: /url
-\end{verbatim}
-
-Foo \href{/url/}{bar}.
-
-Foo \href{/url/}{biz}.
-
-\subsection{With ampersands}\label{with-ampersands}
-
-Here's a \href{http://example.com/?foo=1\&bar=2}{link with an ampersand in the
-URL}.
-
-Here's a link with an amersand in the link text:
-\href{http://att.com/}{AT\&T}.
-
-Here's an \href{/script?foo=1\&bar=2}{inline link}.
-
-Here's an \href{/script?foo=1\&bar=2}{inline link in pointy braces}.
-
-\subsection{Autolinks}\label{autolinks}
-
-With an ampersand: \url{http://example.com/?foo=1\&bar=2}
-
-\begin{itemize}
-\tightlist
-\item
- In a list?
-\item
- \url{http://example.com/}
-\item
- It should.
-\end{itemize}
-
-An e-mail address:
-\href{mailto:nobody@nowhere.net}{\nolinkurl{nobody@nowhere.net}}
-
-\begin{quote}
-Blockquoted: \url{http://example.com/}
-\end{quote}
-
-Auto-links should not occur here:
-\texttt{\textless{}http://example.com/\textgreater{}}
-
-\begin{verbatim}
-or here: <http://example.com/>
-\end{verbatim}
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Images}\label{images}
-
-From ``Voyage dans la Lune'' by Georges Melies (1902):
-
-\begin{figure}
-\centering
-\includegraphics{lalune.jpg}
-\caption{lalune}
-\end{figure}
-
-Here is a movie \includegraphics{movie.jpg} icon.
-
-\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
-
-\section{Footnotes}\label{footnotes}
-
-Here is a footnote reference,\footnote{Here is the footnote. It can go
- anywhere after the footnote reference. It need not be placed at the end of
- the document.} and another.\footnote{Here's the long note. This one contains
- multiple blocks.
-
- Subsequent blocks are indented to show that they belong to the footnote (as
- with list items).
-
-\begin{Verbatim}
- { <code> }
-\end{Verbatim}
-
- If you want, you can indent every line, but you can also be lazy and just
- indent the first line of each block.} This should \emph{not} be a footnote
-reference, because it contains a space.{[}\^{}my note{]} Here is an inline
-note.\footnote{This is \emph{easier} to type. Inline notes may contain
- \href{http://google.com}{links} and \texttt{{]}} verbatim characters, as
- well as {[}bracketed text{]}.}
-
-\begin{quote}
-Notes can go in quotes.\footnote{In quote.}
-\end{quote}
-
-\begin{enumerate}
-\def\labelenumi{\arabic{enumi}.}
-\tightlist
-\item
- And in list items.\footnote{In list.}
-\end{enumerate}
-
-This paragraph should not be part of the note, as it is not indented.
-
-\end{document}
diff --git a/tests/writer.man b/tests/writer.man
deleted file mode 100644
index b0aece96b..000000000
--- a/tests/writer.man
+++ /dev/null
@@ -1,795 +0,0 @@
-.TH "Pandoc Test Suite" "" "July 17, 2006" "" ""
-.hy
-.PP
-This is a set of tests for pandoc.
-Most of them are adapted from John Gruber's markdown test suite.
-.PP
- * * * * *
-.SH Headers
-.SS Level 2 with an embedded link (/url)
-.SS Level 3 with \f[I]emphasis\f[]
-.SS Level 4
-.SS Level 5
-.SH Level 1
-.SS Level 2 with \f[I]emphasis\f[]
-.SS Level 3
-.PP
-with no blank line
-.SS Level 2
-.PP
-with no blank line
-.PP
- * * * * *
-.SH Paragraphs
-.PP
-Here's a regular paragraph.
-.PP
-In Markdown 1.0.0 and earlier.
-Version 8.
-This line turns into a list item.
-Because a hard\-wrapped line in the middle of a paragraph looked like a list
-item.
-.PP
-Here's one with a bullet.
-* criminey.
-.PP
-There should be a hard line break
-.PD 0
-.P
-.PD
-here.
-.PP
- * * * * *
-.SH Block Quotes
-.PP
-E\-mail style:
-.RS
-.PP
-This is a block quote.
-It is pretty short.
-.RE
-.RS
-.PP
-Code in a block quote:
-.IP
-.nf
-\f[C]
-sub\ status\ {
-\ \ \ \ print\ "working";
-}
-\f[]
-.fi
-.PP
-A list:
-.IP "1." 3
-item one
-.IP "2." 3
-item two
-.PP
-Nested block quotes:
-.RS
-.PP
-nested
-.RE
-.RS
-.PP
-nested
-.RE
-.RE
-.PP
-This should not be a block quote: 2 > 1.
-.PP
-And a following paragraph.
-.PP
- * * * * *
-.SH Code Blocks
-.PP
-Code:
-.IP
-.nf
-\f[C]
-\-\-\-\-\ (should\ be\ four\ hyphens)
-
-sub\ status\ {
-\ \ \ \ print\ "working";
-}
-
-this\ code\ block\ is\ indented\ by\ one\ tab
-\f[]
-.fi
-.PP
-And:
-.IP
-.nf
-\f[C]
-\ \ \ \ this\ code\ block\ is\ indented\ by\ two\ tabs
-
-These\ should\ not\ be\ escaped:\ \ \\$\ \\\\\ \\>\ \\[\ \\{
-\f[]
-.fi
-.PP
- * * * * *
-.SH Lists
-.SS Unordered
-.PP
-Asterisks tight:
-.IP \[bu] 2
-asterisk 1
-.IP \[bu] 2
-asterisk 2
-.IP \[bu] 2
-asterisk 3
-.PP
-Asterisks loose:
-.IP \[bu] 2
-asterisk 1
-.IP \[bu] 2
-asterisk 2
-.IP \[bu] 2
-asterisk 3
-.PP
-Pluses tight:
-.IP \[bu] 2
-Plus 1
-.IP \[bu] 2
-Plus 2
-.IP \[bu] 2
-Plus 3
-.PP
-Pluses loose:
-.IP \[bu] 2
-Plus 1
-.IP \[bu] 2
-Plus 2
-.IP \[bu] 2
-Plus 3
-.PP
-Minuses tight:
-.IP \[bu] 2
-Minus 1
-.IP \[bu] 2
-Minus 2
-.IP \[bu] 2
-Minus 3
-.PP
-Minuses loose:
-.IP \[bu] 2
-Minus 1
-.IP \[bu] 2
-Minus 2
-.IP \[bu] 2
-Minus 3
-.SS Ordered
-.PP
-Tight:
-.IP "1." 3
-First
-.IP "2." 3
-Second
-.IP "3." 3
-Third
-.PP
-and:
-.IP "1." 3
-One
-.IP "2." 3
-Two
-.IP "3." 3
-Three
-.PP
-Loose using tabs:
-.IP "1." 3
-First
-.IP "2." 3
-Second
-.IP "3." 3
-Third
-.PP
-and using spaces:
-.IP "1." 3
-One
-.IP "2." 3
-Two
-.IP "3." 3
-Three
-.PP
-Multiple paragraphs:
-.IP "1." 3
-Item 1, graf one.
-.RS 4
-.PP
-Item 1.
-graf two.
-The quick brown fox jumped over the lazy dog's back.
-.RE
-.IP "2." 3
-Item 2.
-.IP "3." 3
-Item 3.
-.SS Nested
-.IP \[bu] 2
-Tab
-.RS 2
-.IP \[bu] 2
-Tab
-.RS 2
-.IP \[bu] 2
-Tab
-.RE
-.RE
-.PP
-Here's another:
-.IP "1." 3
-First
-.IP "2." 3
-Second:
-.RS 4
-.IP \[bu] 2
-Fee
-.IP \[bu] 2
-Fie
-.IP \[bu] 2
-Foe
-.RE
-.IP "3." 3
-Third
-.PP
-Same thing but with paragraphs:
-.IP "1." 3
-First
-.IP "2." 3
-Second:
-.RS 4
-.IP \[bu] 2
-Fee
-.IP \[bu] 2
-Fie
-.IP \[bu] 2
-Foe
-.RE
-.IP "3." 3
-Third
-.SS Tabs and spaces
-.IP \[bu] 2
-this is a list item indented with tabs
-.IP \[bu] 2
-this is a list item indented with spaces
-.RS 2
-.IP \[bu] 2
-this is an example list item indented with tabs
-.IP \[bu] 2
-this is an example list item indented with spaces
-.RE
-.SS Fancy list markers
-.IP "(2)" 4
-begins with 2
-.IP "(3)" 4
-and now 3
-.RS 4
-.PP
-with a continuation
-.IP "iv." 4
-sublist with roman numerals, starting with 4
-.IP " v." 4
-more items
-.RS 4
-.IP "(A)" 4
-a subsublist
-.IP "(B)" 4
-a subsublist
-.RE
-.RE
-.PP
-Nesting:
-.IP "A." 3
-Upper Alpha
-.RS 4
-.IP "I." 3
-Upper Roman.
-.RS 4
-.IP "(6)" 4
-Decimal start with 6
-.RS 4
-.IP "c)" 3
-Lower alpha with paren
-.RE
-.RE
-.RE
-.PP
-Autonumbering:
-.IP "1." 3
-Autonumber.
-.IP "2." 3
-More.
-.RS 4
-.IP "1." 3
-Nested.
-.RE
-.PP
-Should not be a list item:
-.PP
-M.A.\ 2007
-.PP
-B.
-Williams
-.PP
- * * * * *
-.SH Definition Lists
-.PP
-Tight using spaces:
-.TP
-.B apple
-red fruit
-.RS
-.RE
-.TP
-.B orange
-orange fruit
-.RS
-.RE
-.TP
-.B banana
-yellow fruit
-.RS
-.RE
-.PP
-Tight using tabs:
-.TP
-.B apple
-red fruit
-.RS
-.RE
-.TP
-.B orange
-orange fruit
-.RS
-.RE
-.TP
-.B banana
-yellow fruit
-.RS
-.RE
-.PP
-Loose:
-.TP
-.B apple
-red fruit
-.RS
-.RE
-.TP
-.B orange
-orange fruit
-.RS
-.RE
-.TP
-.B banana
-yellow fruit
-.RS
-.RE
-.PP
-Multiple blocks with italics:
-.TP
-.B \f[I]apple\f[]
-red fruit
-.RS
-.PP
-contains seeds, crisp, pleasant to taste
-.RE
-.TP
-.B \f[I]orange\f[]
-orange fruit
-.RS
-.IP
-.nf
-\f[C]
-{\ orange\ code\ block\ }
-\f[]
-.fi
-.RS
-.PP
-orange block quote
-.RE
-.RE
-.PP
-Multiple definitions, tight:
-.TP
-.B apple
-red fruit
-.RS
-.RE
-computer
-.RS
-.RE
-.TP
-.B orange
-orange fruit
-.RS
-.RE
-bank
-.RS
-.RE
-.PP
-Multiple definitions, loose:
-.TP
-.B apple
-red fruit
-.RS
-.RE
-computer
-.RS
-.RE
-.TP
-.B orange
-orange fruit
-.RS
-.RE
-bank
-.RS
-.RE
-.PP
-Blank line after term, indented marker, alternate markers:
-.TP
-.B apple
-red fruit
-.RS
-.RE
-computer
-.RS
-.RE
-.TP
-.B orange
-orange fruit
-.RS
-.IP "1." 3
-sublist
-.IP "2." 3
-sublist
-.RE
-.SH HTML Blocks
-.PP
-Simple block on one line:
-foo
-.PP
-And nested without indentation:
-.PP
-foo
-bar
-.PP
-Interpreted markdown in a table:
-This is \f[I]emphasized\f[]
-And this is \f[B]strong\f[]
-.PP
-Here's a simple block:
-.PP
-foo
-.PP
-This should be a code block, though:
-.IP
-.nf
-\f[C]
-<div>
-\ \ \ \ foo
-</div>
-\f[]
-.fi
-.PP
-As should this:
-.IP
-.nf
-\f[C]
-<div>foo</div>
-\f[]
-.fi
-.PP
-Now, nested:
-foo
-.PP
-This should just be an HTML comment:
-.PP
-Multiline:
-.PP
-Code block:
-.IP
-.nf
-\f[C]
-<!\-\-\ Comment\ \-\->
-\f[]
-.fi
-.PP
-Just plain comment, with trailing spaces on the line:
-.PP
-Code:
-.IP
-.nf
-\f[C]
-<hr\ />
-\f[]
-.fi
-.PP
-Hr's:
-.PP
- * * * * *
-.SH Inline Markup
-.PP
-This is \f[I]emphasized\f[], and so \f[I]is this\f[].
-.PP
-This is \f[B]strong\f[], and so \f[B]is this\f[].
-.PP
-An \f[I]emphasized link (/url)\f[].
-.PP
-\f[B]\f[I]This is strong and em.\f[]\f[]
-.PP
-So is \f[B]\f[I]this\f[]\f[] word.
-.PP
-\f[B]\f[I]This is strong and em.\f[]\f[]
-.PP
-So is \f[B]\f[I]this\f[]\f[] word.
-.PP
-This is code: \f[C]>\f[], \f[C]$\f[], \f[C]\\\f[], \f[C]\\$\f[],
-\f[C]<html>\f[].
-.PP
-[STRIKEOUT:This is \f[I]strikeout\f[].]
-.PP
-Superscripts: a^bc^d a^\f[I]hello\f[]^ a^hello\ there^.
-.PP
-Subscripts: H~2~O, H~23~O, H~many\ of\ them~O.
-.PP
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a^b c^d, a~b c~d.
-.PP
- * * * * *
-.SH Smart quotes, ellipses, dashes
-.PP
-\[lq]Hello,\[rq] said the spider.
-\[lq]`Shelob' is my name.\[rq]
-.PP
-`A', `B', and `C' are letters.
-.PP
-`Oak,' `elm,' and `beech' are names of trees.
-So is `pine.'
-.PP
-`He said, \[lq]I want to go.\[rq]' Were you alive in the 70's?
-.PP
-Here is some quoted `\f[C]code\f[]' and a \[lq]quoted
-link (http://example.com/?foo=1&bar=2)\[rq].
-.PP
-Some dashes: one\[em]two \[em] three\[em]four \[em] five.
-.PP
-Dashes between numbers: 5\[en]7, 255\[en]66, 1987\[en]1999.
-.PP
-Ellipses\&...and\&...and\&....
-.PP
- * * * * *
-.SH LaTeX
-.IP \[bu] 2
-.IP \[bu] 2
-2 + 2 = 4
-.IP \[bu] 2
-\f[I]x\f[] ∈ \f[I]y\f[]
-.IP \[bu] 2
-\f[I]α\f[] ∧ \f[I]ω\f[]
-.IP \[bu] 2
-223
-.IP \[bu] 2
-\f[I]p\f[]\-Tree
-.IP \[bu] 2
-Here's some display math:
-.RS
-$$\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)\-f(x)}{h}$$
-.RE
-.IP \[bu] 2
-Here's one that has a line break in it:
-\f[I]α\f[] + \f[I]ω\f[] × \f[I]x\f[]^2^.
-.PP
-These shouldn't be math:
-.IP \[bu] 2
-To get the famous equation, write \f[C]$e\ =\ mc^2$\f[].
-.IP \[bu] 2
-$22,000 is a \f[I]lot\f[] of money.
-So is $34,000.
-(It worked if \[lq]lot\[rq] is emphasized.)
-.IP \[bu] 2
-Shoes ($20) and socks ($5).
-.IP \[bu] 2
-Escaped \f[C]$\f[]: $73 \f[I]this should be emphasized\f[] 23$.
-.PP
-Here's a LaTeX table:
-.PP
- * * * * *
-.SH Special Characters
-.PP
-Here is some unicode:
-.IP \[bu] 2
-I hat: Î
-.IP \[bu] 2
-o umlaut: ö
-.IP \[bu] 2
-section: §
-.IP \[bu] 2
-set membership: ∈
-.IP \[bu] 2
-copyright: ©
-.PP
-AT&T has an ampersand in their name.
-.PP
-AT&T is another way to write it.
-.PP
-This & that.
-.PP
-4 < 5.
-.PP
-6 > 5.
-.PP
-Backslash: \\
-.PP
-Backtick: `
-.PP
-Asterisk: *
-.PP
-Underscore: _
-.PP
-Left brace: {
-.PP
-Right brace: }
-.PP
-Left bracket: [
-.PP
-Right bracket: ]
-.PP
-Left paren: (
-.PP
-Right paren: )
-.PP
-Greater\-than: >
-.PP
-Hash: #
-.PP
-Period: .
-.PP
-Bang: !
-.PP
-Plus: +
-.PP
-Minus: \-
-.PP
- * * * * *
-.SH Links
-.SS Explicit
-.PP
-Just a URL (/url/).
-.PP
-URL and title (/url/).
-.PP
-URL and title (/url/).
-.PP
-URL and title (/url/).
-.PP
-URL and title (/url/)
-.PP
-URL and title (/url/)
-.PP
-with_underscore (/url/with_underscore)
-.PP
-Email link (mailto:nobody@nowhere.net)
-.PP
-Empty ().
-.SS Reference
-.PP
-Foo bar (/url/).
-.PP
-Foo bar (/url/).
-.PP
-Foo bar (/url/).
-.PP
-With embedded [brackets] (/url/).
-.PP
-b (/url/) by itself should be a link.
-.PP
-Indented once (/url).
-.PP
-Indented twice (/url).
-.PP
-Indented thrice (/url).
-.PP
-This should [not][] be a link.
-.IP
-.nf
-\f[C]
-[not]:\ /url
-\f[]
-.fi
-.PP
-Foo bar (/url/).
-.PP
-Foo biz (/url/).
-.SS With ampersands
-.PP
-Here's a link with an ampersand in the URL (http://example.com/?foo=1&bar=2).
-.PP
-Here's a link with an amersand in the link text: AT&T (http://att.com/).
-.PP
-Here's an inline link (/script?foo=1&bar=2).
-.PP
-Here's an inline link in pointy braces (/script?foo=1&bar=2).
-.SS Autolinks
-.PP
-With an ampersand: <http://example.com/?foo=1&bar=2>
-.IP \[bu] 2
-In a list?
-.IP \[bu] 2
-<http://example.com/>
-.IP \[bu] 2
-It should.
-.PP
-An e\-mail address: <nobody@nowhere.net>
-.RS
-.PP
-Blockquoted: <http://example.com/>
-.RE
-.PP
-Auto\-links should not occur here: \f[C]<http://example.com/>\f[]
-.IP
-.nf
-\f[C]
-or\ here:\ <http://example.com/>
-\f[]
-.fi
-.PP
- * * * * *
-.SH Images
-.PP
-From \[lq]Voyage dans la Lune\[rq] by Georges Melies (1902):
-.PP
-[IMAGE: lalune (lalune.jpg)]
-.PP
-Here is a movie [IMAGE: movie (movie.jpg)] icon.
-.PP
- * * * * *
-.SH Footnotes
-.PP
-Here is a footnote reference,[1] and another.[2] This should \f[I]not\f[] be a
-footnote reference, because it contains a space.[^my note] Here is an inline
-note.[3]
-.RS
-.PP
-Notes can go in quotes.[4]
-.RE
-.IP "1." 3
-And in list items.[5]
-.PP
-This paragraph should not be part of the note, as it is not indented.
-.SH NOTES
-.SS [1]
-.PP
-Here is the footnote.
-It can go anywhere after the footnote reference.
-It need not be placed at the end of the document.
-.SS [2]
-.PP
-Here's the long note.
-This one contains multiple blocks.
-.PP
-Subsequent blocks are indented to show that they belong to the footnote (as
-with list items).
-.IP
-.nf
-\f[C]
-\ \ {\ <code>\ }
-\f[]
-.fi
-.PP
-If you want, you can indent every line, but you can also be lazy and just
-indent the first line of each block.
-.SS [3]
-.PP
-This is \f[I]easier\f[] to type.
-Inline notes may contain links (http://google.com) and \f[C]]\f[] verbatim
-characters, as well as [bracketed text].
-.SS [4]
-.PP
-In quote.
-.SS [5]
-.PP
-In list.
-.SH AUTHORS
-John MacFarlane; Anonymous.
diff --git a/tests/writer.markdown b/tests/writer.markdown
deleted file mode 100644
index 4f91a803b..000000000
--- a/tests/writer.markdown
+++ /dev/null
@@ -1,746 +0,0 @@
----
-author:
-- John MacFarlane
-- Anonymous
-date: 'July 17, 2006'
-title: Pandoc Test Suite
----
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
-markdown test suite.
-
-------------------------------------------------------------------------------
-
-Headers
-=======
-
-Level 2 with an [embedded link](/url)
--------------------------------------
-
-### Level 3 with *emphasis*
-
-#### Level 4
-
-##### Level 5
-
-Level 1
-=======
-
-Level 2 with *emphasis*
------------------------
-
-### Level 3
-
-with no blank line
-
-Level 2
--------
-
-with no blank line
-
-------------------------------------------------------------------------------
-
-Paragraphs
-==========
-
-Here’s a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here’s one with a bullet. \* criminey.
-
-There should be a hard line break\
-here.
-
-------------------------------------------------------------------------------
-
-Block Quotes
-============
-
-E-mail style:
-
-> This is a block quote. It is pretty short.
-
-> Code in a block quote:
->
-> sub status {
-> print "working";
-> }
->
-> A list:
->
-> 1. item one
-> 2. item two
->
-> Nested block quotes:
->
-> > nested
->
-> > nested
-
-This should not be a block quote: 2 &gt; 1.
-
-And a following paragraph.
-
-------------------------------------------------------------------------------
-
-Code Blocks
-===========
-
-Code:
-
- ---- (should be four hyphens)
-
- sub status {
- print "working";
- }
-
- this code block is indented by one tab
-
-And:
-
- this code block is indented by two tabs
-
- These should not be escaped: \$ \\ \> \[ \{
-
-------------------------------------------------------------------------------
-
-Lists
-=====
-
-Unordered
----------
-
-Asterisks tight:
-
-- asterisk 1
-- asterisk 2
-- asterisk 3
-
-Asterisks loose:
-
-- asterisk 1
-
-- asterisk 2
-
-- asterisk 3
-
-Pluses tight:
-
-- Plus 1
-- Plus 2
-- Plus 3
-
-Pluses loose:
-
-- Plus 1
-
-- Plus 2
-
-- Plus 3
-
-Minuses tight:
-
-- Minus 1
-- Minus 2
-- Minus 3
-
-Minuses loose:
-
-- Minus 1
-
-- Minus 2
-
-- Minus 3
-
-Ordered
--------
-
-Tight:
-
-1. First
-2. Second
-3. Third
-
-and:
-
-1. One
-2. Two
-3. Three
-
-Loose using tabs:
-
-1. First
-
-2. Second
-
-3. Third
-
-and using spaces:
-
-1. One
-
-2. Two
-
-3. Three
-
-Multiple paragraphs:
-
-1. Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
-
-2. Item 2.
-
-3. Item 3.
-
-Nested
-------
-
-- Tab
- - Tab
- - Tab
-
-Here’s another:
-
-1. First
-2. Second:
- - Fee
- - Fie
- - Foe
-3. Third
-
-Same thing but with paragraphs:
-
-1. First
-
-2. Second:
-
- - Fee
- - Fie
- - Foe
-
-3. Third
-
-Tabs and spaces
----------------
-
-- this is a list item indented with tabs
-
-- this is a list item indented with spaces
-
- - this is an example list item indented with tabs
-
- - this is an example list item indented with spaces
-
-Fancy list markers
-------------------
-
-(2) begins with 2
-(3) and now 3
-
- with a continuation
-
- iv. sublist with roman numerals, starting with 4
- v. more items
- (A) a subsublist
- (B) a subsublist
-
-Nesting:
-
-A. Upper Alpha
- I. Upper Roman.
- (6) Decimal start with 6
- c) Lower alpha with paren
-
-Autonumbering:
-
-1. Autonumber.
-2. More.
- 1. Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-------------------------------------------------------------------------------
-
-Definition Lists
-================
-
-Tight using spaces:
-
-apple
-: red fruit
-
-orange
-: orange fruit
-
-banana
-: yellow fruit
-
-Tight using tabs:
-
-apple
-: red fruit
-
-orange
-: orange fruit
-
-banana
-: yellow fruit
-
-Loose:
-
-apple
-
-: red fruit
-
-orange
-
-: orange fruit
-
-banana
-
-: yellow fruit
-
-Multiple blocks with italics:
-
-*apple*
-
-: red fruit
-
- contains seeds, crisp, pleasant to taste
-
-*orange*
-
-: orange fruit
-
- { orange code block }
-
- > orange block quote
-
-Multiple definitions, tight:
-
-apple
-: red fruit
-: computer
-
-orange
-: orange fruit
-: bank
-
-Multiple definitions, loose:
-
-apple
-
-: red fruit
-
-: computer
-
-orange
-
-: orange fruit
-
-: bank
-
-Blank line after term, indented marker, alternate markers:
-
-apple
-
-: red fruit
-
-: computer
-
-orange
-
-: orange fruit
-
- 1. sublist
- 2. sublist
-
-HTML Blocks
-===========
-
-Simple block on one line:
-
-<div>
-
-foo
-
-</div>
-
-And nested without indentation:
-
-<div>
-
-<div>
-
-<div>
-
-foo
-
-</div>
-
-</div>
-
-<div>
-
-bar
-
-</div>
-
-</div>
-
-Interpreted markdown in a table:
-
-<table>
-<tr>
-<td>
-This is *emphasized*
-</td>
-<td>
-And this is **strong**
-</td>
-</tr>
-</table>
-<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
-Here’s a simple block:
-
-<div>
-
-foo
-
-</div>
-
-This should be a code block, though:
-
- <div>
- foo
- </div>
-
-As should this:
-
- <div>foo</div>
-
-Now, nested:
-
-<div>
-
-<div>
-
-<div>
-
-foo
-
-</div>
-
-</div>
-
-</div>
-
-This should just be an HTML comment:
-
-<!-- Comment -->
-Multiline:
-
-<!--
-Blah
-Blah
--->
-<!--
- This is another comment.
--->
-Code block:
-
- <!-- Comment -->
-
-Just plain comment, with trailing spaces on the line:
-
-<!-- foo -->
-Code:
-
- <hr />
-
-Hr’s:
-
-<hr>
-<hr />
-<hr />
-<hr>
-<hr />
-<hr />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar">
-
-------------------------------------------------------------------------------
-
-Inline Markup
-=============
-
-This is *emphasized*, and so *is this*.
-
-This is **strong**, and so **is this**.
-
-An *[emphasized link](/url)*.
-
-***This is strong and em.***
-
-So is ***this*** word.
-
-***This is strong and em.***
-
-So is ***this*** word.
-
-This is code: `>`, `$`, `\`, `\$`, `<html>`.
-
-~~This is *strikeout*.~~
-
-Superscripts: a^bc^d a^*hello*^ a^hello there^.
-
-Subscripts: H~2~O, H~23~O, H~many of them~O.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a\^b c\^d, a\~b c\~d.
-
-------------------------------------------------------------------------------
-
-Smart quotes, ellipses, dashes
-==============================
-
-“Hello,” said the spider. “‘Shelob’ is my name.”
-
-‘A’, ‘B’, and ‘C’ are letters.
-
-‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
-
-‘He said, “I want to go.”’ Were you alive in the 70’s?
-
-Here is some quoted ‘`code`’ and a “[quoted
-link](http://example.com/?foo=1&bar=2)”.
-
-Some dashes: one—two — three—four — five.
-
-Dashes between numbers: 5–7, 255–66, 1987–1999.
-
-Ellipses…and…and….
-
-------------------------------------------------------------------------------
-
-LaTeX
-=====
-
-- \cite[22-23]{smith.1899}
-- $2+2=4$
-- $x \in y$
-- $\alpha \wedge \omega$
-- $223$
-- $p$-Tree
-- Here’s some display math:
- $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
-- Here’s one that has a line break in it: $\alpha + \omega \times x^2$.
-
-These shouldn’t be math:
-
-- To get the famous equation, write `$e = mc^2$`.
-- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot” is
- emphasized.)
-- Shoes (\$20) and socks (\$5).
-- Escaped `$`: \$73 *this should be emphasized* 23\$.
-
-Here’s a LaTeX table:
-
-\begin{tabular}{|l|l|}\hline
-Animal & Number \\ \hline
-Dog & 2 \\
-Cat & 1 \\ \hline
-\end{tabular}
-
-------------------------------------------------------------------------------
-
-Special Characters
-==================
-
-Here is some unicode:
-
-- I hat: Î
-- o umlaut: ö
-- section: §
-- set membership: ∈
-- copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 &lt; 5.
-
-6 &gt; 5.
-
-Backslash: \\
-
-Backtick: \`
-
-Asterisk: \*
-
-Underscore: \_
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: \[
-
-Right bracket: \]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: &gt;
-
-Hash: \#
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-------------------------------------------------------------------------------
-
-Links
-=====
-
-Explicit
---------
-
-Just a [URL](/url/).
-
-[URL and title](/url/ "title").
-
-[URL and title](/url/ "title preceded by two spaces").
-
-[URL and title](/url/ "title preceded by a tab").
-
-[URL and title](/url/ "title with "quotes" in it")
-
-[URL and title](/url/ "title with single quotes")
-
-[with\_underscore](/url/with_underscore)
-
-[Email link](mailto:nobody@nowhere.net)
-
-[Empty]().
-
-Reference
----------
-
-Foo [bar](/url/).
-
-Foo [bar](/url/).
-
-Foo [bar](/url/).
-
-With [embedded \[brackets\]](/url/).
-
-[b](/url/) by itself should be a link.
-
-Indented [once](/url).
-
-Indented [twice](/url).
-
-Indented [thrice](/url).
-
-This should \[not\]\[\] be a link.
-
- [not]: /url
-
-Foo [bar](/url/ "Title with "quotes" inside").
-
-Foo [biz](/url/ "Title with "quote" inside").
-
-With ampersands
----------------
-
-Here’s a [link with an ampersand in the URL](http://example.com/?foo=1&bar=2).
-
-Here’s a link with an amersand in the link text:
-[AT&T](http://att.com/ "AT&T").
-
-Here’s an [inline link](/script?foo=1&bar=2).
-
-Here’s an [inline link in pointy braces](/script?foo=1&bar=2).
-
-Autolinks
----------
-
-With an ampersand: <http://example.com/?foo=1&bar=2>
-
-- In a list?
-- <http://example.com/>
-- It should.
-
-An e-mail address: <nobody@nowhere.net>
-
-> Blockquoted: <http://example.com/>
-
-Auto-links should not occur here: `<http://example.com/>`
-
- or here: <http://example.com/>
-
-------------------------------------------------------------------------------
-
-Images
-======
-
-From “Voyage dans la Lune” by Georges Melies (1902):
-
-![lalune](lalune.jpg "Voyage dans la Lune")
-
-Here is a movie ![movie](movie.jpg) icon.
-
-------------------------------------------------------------------------------
-
-Footnotes
-=========
-
-Here is a footnote reference,[^1] and another.[^2] This should *not* be a
-footnote reference, because it contains a space.\[\^my note\] Here is an
-inline note.[^3]
-
-> Notes can go in quotes.[^4]
-
-1. And in list items.[^5]
-
-This paragraph should not be part of the note, as it is not indented.
-
-[^1]: Here is the footnote. It can go anywhere after the footnote reference.
- It need not be placed at the end of the document.
-
-[^2]: Here’s the long note. This one contains multiple blocks.
-
- Subsequent blocks are indented to show that they belong to the footnote
- (as with list items).
-
- { <code> }
-
- If you want, you can indent every line, but you can also be lazy and just
- indent the first line of each block.
-
-[^3]: This is *easier* to type. Inline notes may contain
- [links](http://google.com) and `]` verbatim characters, as well as
- \[bracketed text\].
-
-[^4]: In quote.
-
-[^5]: In list.
diff --git a/tests/writer.mediawiki b/tests/writer.mediawiki
deleted file mode 100644
index 066606c00..000000000
--- a/tests/writer.mediawiki
+++ /dev/null
@@ -1,653 +0,0 @@
-This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.
-
-
------
-
-= Headers =
-
-== Level 2 with an [[url|embedded link]] ==
-
-=== Level 3 with ''emphasis'' ===
-
-==== Level 4 ====
-
-===== Level 5 =====
-
-= Level 1 =
-
-== Level 2 with ''emphasis'' ==
-
-=== Level 3 ===
-
-with no blank line
-
-== Level 2 ==
-
-with no blank line
-
-
------
-
-= Paragraphs =
-
-Here’s a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
-
-Here’s one with a bullet. * criminey.
-
-There should be a hard line break<br />
-here.
-
-
------
-
-= Block Quotes =
-
-E-mail style:
-
-<blockquote>This is a block quote. It is pretty short.
-</blockquote>
-<blockquote>Code in a block quote:
-
-<pre>sub status {
- print &quot;working&quot;;
-}</pre>
-A list:
-
-# item one
-# item two
-
-Nested block quotes:
-
-<blockquote>nested
-</blockquote>
-<blockquote>nested
-</blockquote></blockquote>
-This should not be a block quote: 2 &gt; 1.
-
-And a following paragraph.
-
-
------
-
-= Code Blocks =
-
-Code:
-
-<pre>---- (should be four hyphens)
-
-sub status {
- print &quot;working&quot;;
-}
-
-this code block is indented by one tab</pre>
-And:
-
-<pre> this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \&gt; \[ \{</pre>
-
------
-
-= Lists =
-
-== Unordered ==
-
-Asterisks tight:
-
-* asterisk 1
-* asterisk 2
-* asterisk 3
-
-Asterisks loose:
-
-* asterisk 1
-* asterisk 2
-* asterisk 3
-
-Pluses tight:
-
-* Plus 1
-* Plus 2
-* Plus 3
-
-Pluses loose:
-
-* Plus 1
-* Plus 2
-* Plus 3
-
-Minuses tight:
-
-* Minus 1
-* Minus 2
-* Minus 3
-
-Minuses loose:
-
-* Minus 1
-* Minus 2
-* Minus 3
-
-== Ordered ==
-
-Tight:
-
-# First
-# Second
-# Third
-
-and:
-
-# One
-# Two
-# Three
-
-Loose using tabs:
-
-# First
-# Second
-# Third
-
-and using spaces:
-
-# One
-# Two
-# Three
-
-Multiple paragraphs:
-
-<ol style="list-style-type: decimal;">
-<li><p>Item 1, graf one.</p>
-<p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.</p></li>
-<li><p>Item 2.</p></li>
-<li><p>Item 3.</p></li></ol>
-
-== Nested ==
-
-* Tab
-** Tab
-*** Tab
-
-Here’s another:
-
-# First
-# Second:
-#* Fee
-#* Fie
-#* Foe
-# Third
-
-Same thing but with paragraphs:
-
-# First
-# Second:
-#* Fee
-#* Fie
-#* Foe
-# Third
-
-== Tabs and spaces ==
-
-* this is a list item indented with tabs
-* this is a list item indented with spaces
-** this is an example list item indented with tabs
-** this is an example list item indented with spaces
-
-== Fancy list markers ==
-
-<ol start="2" style="list-style-type: decimal;">
-<li>begins with 2</li>
-<li><p>and now 3</p>
-<p>with a continuation</p>
-<ol start="4" style="list-style-type: lower-roman;">
-<li>sublist with roman numerals, starting with 4</li>
-<li>more items
-<ol style="list-style-type: upper-alpha;">
-<li>a subsublist</li>
-<li>a subsublist</li></ol>
-</li></ol>
-</li></ol>
-
-Nesting:
-
-<ol style="list-style-type: upper-alpha;">
-<li>Upper Alpha
-<ol style="list-style-type: upper-roman;">
-<li>Upper Roman.
-<ol start="6" style="list-style-type: decimal;">
-<li>Decimal start with 6
-<ol start="3" style="list-style-type: lower-alpha;">
-<li>Lower alpha with paren</li></ol>
-</li></ol>
-</li></ol>
-</li></ol>
-
-Autonumbering:
-
-# Autonumber.
-# More.
-## Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-
------
-
-= Definition Lists =
-
-Tight using spaces:
-
-; apple
-: red fruit
-; orange
-: orange fruit
-; banana
-: yellow fruit
-
-Tight using tabs:
-
-; apple
-: red fruit
-; orange
-: orange fruit
-; banana
-: yellow fruit
-
-Loose:
-
-; apple
-: red fruit
-; orange
-: orange fruit
-; banana
-: yellow fruit
-
-Multiple blocks with italics:
-
-<dl>
-<dt>''apple''</dt>
-<dd><p>red fruit</p>
-<p>contains seeds, crisp, pleasant to taste</p></dd>
-<dt>''orange''</dt>
-<dd><p>orange fruit</p>
-<pre>{ orange code block }</pre>
-<blockquote><p>orange block quote</p></blockquote></dd></dl>
-
-Multiple definitions, tight:
-
-; apple
-: red fruit
-: computer
-; orange
-: orange fruit
-: bank
-
-Multiple definitions, loose:
-
-; apple
-: red fruit
-: computer
-; orange
-: orange fruit
-: bank
-
-Blank line after term, indented marker, alternate markers:
-
-; apple
-: red fruit
-: computer
-; orange
-: orange fruit
-;# sublist
-;# sublist
-
-= HTML Blocks =
-
-Simple block on one line:
-
-<div>
-
-foo
-
-</div>
-And nested without indentation:
-
-<div>
-
-<div>
-
-<div>
-
-foo
-
-
-</div>
-
-</div>
-<div>
-
-bar
-
-</div>
-
-</div>
-Interpreted markdown in a table:
-
-<table>
-<tr>
-<td>
-This is ''emphasized''
-</td>
-<td>
-And this is '''strong'''
-</td>
-</tr>
-</table>
-<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
-Here’s a simple block:
-
-<div>
-
-foo
-
-
-</div>
-This should be a code block, though:
-
-<pre>&lt;div&gt;
- foo
-&lt;/div&gt;</pre>
-As should this:
-
-<pre>&lt;div&gt;foo&lt;/div&gt;</pre>
-Now, nested:
-
-<div>
-
-<div>
-
-<div>
-
-foo
-
-</div>
-
-</div>
-
-</div>
-This should just be an HTML comment:
-
-<!-- Comment -->
-Multiline:
-
-<!--
-Blah
-Blah
--->
-<!--
- This is another comment.
--->
-Code block:
-
-<pre>&lt;!-- Comment --&gt;</pre>
-Just plain comment, with trailing spaces on the line:
-
-<!-- foo -->
-Code:
-
-<pre>&lt;hr /&gt;</pre>
-Hr’s:
-
-<hr>
-<hr />
-<hr />
-<hr>
-<hr />
-<hr />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar">
-
------
-
-= Inline Markup =
-
-This is ''emphasized'', and so ''is this''.
-
-This is '''strong''', and so '''is this'''.
-
-An ''[[url|emphasized link]]''.
-
-'''''This is strong and em.'''''
-
-So is '''''this''''' word.
-
-'''''This is strong and em.'''''
-
-So is '''''this''''' word.
-
-This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.
-
-<s>This is ''strikeout''.</s>
-
-Superscripts: a<sup>bc</sup>d a<sup>''hello''</sup> a<sup>hello there</sup>.
-
-Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.
-
-These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
-
-
------
-
-= Smart quotes, ellipses, dashes =
-
-“Hello,” said the spider. “‘Shelob’ is my name.”
-
-‘A’, ‘B’, and ‘C’ are letters.
-
-‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
-
-‘He said, “I want to go.”’ Were you alive in the 70’s?
-
-Here is some quoted ‘<code>code</code>’ and a “[http://example.com/?foo=1&bar=2 quoted link]”.
-
-Some dashes: one—two — three—four — five.
-
-Dashes between numbers: 5–7, 255–66, 1987–1999.
-
-Ellipses…and…and….
-
-
------
-
-= LaTeX =
-
-*
-* <math>2+2=4</math>
-* <math>x \in y</math>
-* <math>\alpha \wedge \omega</math>
-* <math>223</math>
-* <math>p</math>-Tree
-* Here’s some display math: <math>\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</math>
-* Here’s one that has a line break in it: <math>\alpha + \omega \times x^2</math>.
-
-These shouldn’t be math:
-
-* To get the famous equation, write <code>$e = mc^2$</code>.
-* $22,000 is a ''lot'' of money. So is $34,000. (It worked if “lot” is emphasized.)
-* Shoes ($20) and socks ($5).
-* Escaped <code>$</code>: $73 ''this should be emphasized'' 23$.
-
-Here’s a LaTeX table:
-
-
-
------
-
-= Special Characters =
-
-Here is some unicode:
-
-* I hat: Î
-* o umlaut: ö
-* section: §
-* set membership: ∈
-* copyright: ©
-
-AT&amp;T has an ampersand in their name.
-
-AT&amp;T is another way to write it.
-
-This &amp; that.
-
-4 &lt; 5.
-
-6 &gt; 5.
-
-Backslash: \
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: _
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: &gt;
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-
------
-
-= Links =
-
-== Explicit ==
-
-Just a [[url/|URL]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]]
-
-[[url/|URL and title]]
-
-[[url/with_underscore|with_underscore]]
-
-[mailto:nobody@nowhere.net Email link]
-
-[[|Empty]].
-
-== Reference ==
-
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
-With [[url/|embedded [brackets]]].
-
-[[url/|b]] by itself should be a link.
-
-Indented [[url|once]].
-
-Indented [[url|twice]].
-
-Indented [[url|thrice]].
-
-This should [not][] be a link.
-
-<pre>[not]: /url</pre>
-Foo [[url/|bar]].
-
-Foo [[url/|biz]].
-
-== With ampersands ==
-
-Here’s a [http://example.com/?foo=1&bar=2 link with an ampersand in the URL].
-
-Here’s a link with an amersand in the link text: [http://att.com/ AT&amp;T].
-
-Here’s an [[script?foo=1&bar=2|inline link]].
-
-Here’s an [[script?foo=1&bar=2|inline link in pointy braces]].
-
-== Autolinks ==
-
-With an ampersand: http://example.com/?foo=1&bar=2
-
-* In a list?
-* http://example.com/
-* It should.
-
-An e-mail address: [mailto:nobody@nowhere.net nobody@nowhere.net]
-
-<blockquote>Blockquoted: http://example.com/
-</blockquote>
-Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code>
-
-<pre>or here: &lt;http://example.com/&gt;</pre>
-
------
-
-= Images =
-
-From “Voyage dans la Lune” by Georges Melies (1902):
-
-[[File:lalune.jpg|frame|none|alt=Voyage dans la Lune|caption lalune]]
-
-Here is a movie [[File:movie.jpg|movie]] icon.
-
-
------
-
-= Footnotes =
-
-Here is a footnote reference,<ref>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
-</ref> and another.<ref>Here’s the long note. This one contains multiple blocks.
-
-Subsequent blocks are indented to show that they belong to the footnote (as with list items).
-
-<pre> { &lt;code&gt; }</pre>
-If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
-</ref> This should ''not'' be a footnote reference, because it contains a space.[^my note] Here is an inline note.<ref>This is ''easier'' to type. Inline notes may contain [http://google.com links] and <code>]</code> verbatim characters, as well as [bracketed text].
-</ref>
-
-<blockquote>Notes can go in quotes.<ref>In quote.
-</ref>
-</blockquote>
-# And in list items.<ref>In list.</ref>
-
-This paragraph should not be part of the note, as it is not indented.
-
-<references />
diff --git a/tests/writer.native b/tests/writer.native
deleted file mode 100644
index fa234dfc2..000000000
--- a/tests/writer.native
+++ /dev/null
@@ -1,411 +0,0 @@
-Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
-[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",SoftBreak,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
-,HorizontalRule
-,Header 1 ("headers",[],[]) [Str "Headers"]
-,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
-,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
-,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
-,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
-,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
-,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
-,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,HorizontalRule
-,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
-,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",SoftBreak,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",SoftBreak,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",SoftBreak,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",SoftBreak,Str "list",Space,Str "item."]
-,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",SoftBreak,Str "*",Space,Str "criminey."]
-,Para [Str "There",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "hard",Space,Str "line",Space,Str "break",LineBreak,Str "here."]
-,HorizontalRule
-,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
-,Para [Str "E-mail",Space,Str "style:"]
-,BlockQuote
- [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",SoftBreak,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
-,BlockQuote
- [Para [Str "Code",Space,Str "in",Space,Str "a",Space,Str "block",Space,Str "quote:"]
- ,CodeBlock ("",[],[]) "sub status {\n print \"working\";\n}"
- ,Para [Str "A",Space,Str "list:"]
- ,OrderedList (1,Decimal,Period)
- [[Plain [Str "item",Space,Str "one"]]
- ,[Plain [Str "item",Space,Str "two"]]]
- ,Para [Str "Nested",Space,Str "block",Space,Str "quotes:"]
- ,BlockQuote
- [Para [Str "nested"]]
- ,BlockQuote
- [Para [Str "nested"]]]
-,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",SoftBreak,Str ">",Space,Str "1."]
-,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
-,HorizontalRule
-,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
-,Para [Str "And:"]
-,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
-,HorizontalRule
-,Header 1 ("lists",[],[]) [Str "Lists"]
-,Header 2 ("unordered",[],[]) [Str "Unordered"]
-,Para [Str "Asterisks",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "asterisk",Space,Str "1"]]
- ,[Plain [Str "asterisk",Space,Str "2"]]
- ,[Plain [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Asterisks",Space,Str "loose:"]
-,BulletList
- [[Para [Str "asterisk",Space,Str "1"]]
- ,[Para [Str "asterisk",Space,Str "2"]]
- ,[Para [Str "asterisk",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "Plus",Space,Str "1"]]
- ,[Plain [Str "Plus",Space,Str "2"]]
- ,[Plain [Str "Plus",Space,Str "3"]]]
-,Para [Str "Pluses",Space,Str "loose:"]
-,BulletList
- [[Para [Str "Plus",Space,Str "1"]]
- ,[Para [Str "Plus",Space,Str "2"]]
- ,[Para [Str "Plus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "tight:"]
-,BulletList
- [[Plain [Str "Minus",Space,Str "1"]]
- ,[Plain [Str "Minus",Space,Str "2"]]
- ,[Plain [Str "Minus",Space,Str "3"]]]
-,Para [Str "Minuses",Space,Str "loose:"]
-,BulletList
- [[Para [Str "Minus",Space,Str "1"]]
- ,[Para [Str "Minus",Space,Str "2"]]
- ,[Para [Str "Minus",Space,Str "3"]]]
-,Header 2 ("ordered",[],[]) [Str "Ordered"]
-,Para [Str "Tight:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second"]]
- ,[Plain [Str "Third"]]]
-,Para [Str "and:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "One"]]
- ,[Plain [Str "Two"]]
- ,[Plain [Str "Three"]]]
-,Para [Str "Loose",Space,Str "using",Space,Str "tabs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "First"]]
- ,[Para [Str "Second"]]
- ,[Para [Str "Third"]]]
-,Para [Str "and",Space,Str "using",Space,Str "spaces:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "One"]]
- ,[Para [Str "Two"]]
- ,[Para [Str "Three"]]]
-,Para [Str "Multiple",Space,Str "paragraphs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "Item",Space,Str "1,",Space,Str "graf",Space,Str "one."]
- ,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",SoftBreak,Str "back."]]
- ,[Para [Str "Item",Space,Str "2."]]
- ,[Para [Str "Item",Space,Str "3."]]]
-,Header 2 ("nested",[],[]) [Str "Nested"]
-,BulletList
- [[Plain [Str "Tab"]
- ,BulletList
- [[Plain [Str "Tab"]
- ,BulletList
- [[Plain [Str "Tab"]]]]]]]
-,Para [Str "Here\8217s",Space,Str "another:"]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "First"]]
- ,[Plain [Str "Second:"]
- ,BulletList
- [[Plain [Str "Fee"]]
- ,[Plain [Str "Fie"]]
- ,[Plain [Str "Foe"]]]]
- ,[Plain [Str "Third"]]]
-,Para [Str "Same",Space,Str "thing",Space,Str "but",Space,Str "with",Space,Str "paragraphs:"]
-,OrderedList (1,Decimal,Period)
- [[Para [Str "First"]]
- ,[Para [Str "Second:"]
- ,BulletList
- [[Plain [Str "Fee"]]
- ,[Plain [Str "Fie"]]
- ,[Plain [Str "Foe"]]]]
- ,[Para [Str "Third"]]]
-,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
-,BulletList
- [[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "tabs"]]
- ,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "spaces"]
- ,BulletList
- [[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "tabs"]]
- ,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",SoftBreak,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
-,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
-,OrderedList (2,Decimal,TwoParens)
- [[Plain [Str "begins",Space,Str "with",Space,Str "2"]]
- ,[Para [Str "and",Space,Str "now",Space,Str "3"]
- ,Para [Str "with",Space,Str "a",Space,Str "continuation"]
- ,OrderedList (4,LowerRoman,Period)
- [[Plain [Str "sublist",Space,Str "with",Space,Str "roman",Space,Str "numerals,",SoftBreak,Str "starting",Space,Str "with",Space,Str "4"]]
- ,[Plain [Str "more",Space,Str "items"]
- ,OrderedList (1,UpperAlpha,TwoParens)
- [[Plain [Str "a",Space,Str "subsublist"]]
- ,[Plain [Str "a",Space,Str "subsublist"]]]]]]]
-,Para [Str "Nesting:"]
-,OrderedList (1,UpperAlpha,Period)
- [[Plain [Str "Upper",Space,Str "Alpha"]
- ,OrderedList (1,UpperRoman,Period)
- [[Plain [Str "Upper",Space,Str "Roman."]
- ,OrderedList (6,Decimal,TwoParens)
- [[Plain [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
- ,OrderedList (3,LowerAlpha,OneParen)
- [[Plain [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
-,Para [Str "Autonumbering:"]
-,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "Autonumber."]]
- ,[Plain [Str "More."]
- ,OrderedList (1,DefaultStyle,DefaultDelim)
- [[Plain [Str "Nested."]]]]]
-,Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
-,Para [Str "M.A.\160\&2007"]
-,Para [Str "B.",Space,Str "Williams"]
-,HorizontalRule
-,Header 1 ("definition-lists",[],[]) [Str "Definition",Space,Str "Lists"]
-,Para [Str "Tight",Space,Str "using",Space,Str "spaces:"]
-,DefinitionList
- [([Str "apple"],
- [[Plain [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Plain [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Plain [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Tight",Space,Str "using",Space,Str "tabs:"]
-,DefinitionList
- [([Str "apple"],
- [[Plain [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Plain [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Plain [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Loose:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]]])
- ,([Str "banana"],
- [[Para [Str "yellow",Space,Str "fruit"]]])]
-,Para [Str "Multiple",Space,Str "blocks",Space,Str "with",Space,Str "italics:"]
-,DefinitionList
- [([Emph [Str "apple"]],
- [[Para [Str "red",Space,Str "fruit"]
- ,Para [Str "contains",Space,Str "seeds,",SoftBreak,Str "crisp,",Space,Str "pleasant",Space,Str "to",Space,Str "taste"]]])
- ,([Emph [Str "orange"]],
- [[Para [Str "orange",Space,Str "fruit"]
- ,CodeBlock ("",[],[]) "{ orange code block }"
- ,BlockQuote
- [Para [Str "orange",Space,Str "block",Space,Str "quote"]]]])]
-,Para [Str "Multiple",Space,Str "definitions,",Space,Str "tight:"]
-,DefinitionList
- [([Str "apple"],
- [[Plain [Str "red",Space,Str "fruit"]]
- ,[Plain [Str "computer"]]])
- ,([Str "orange"],
- [[Plain [Str "orange",Space,Str "fruit"]]
- ,[Plain [Str "bank"]]])]
-,Para [Str "Multiple",Space,Str "definitions,",Space,Str "loose:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]
- ,[Para [Str "computer"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]]
- ,[Para [Str "bank"]]])]
-,Para [Str "Blank",Space,Str "line",Space,Str "after",Space,Str "term,",Space,Str "indented",Space,Str "marker,",Space,Str "alternate",Space,Str "markers:"]
-,DefinitionList
- [([Str "apple"],
- [[Para [Str "red",Space,Str "fruit"]]
- ,[Para [Str "computer"]]])
- ,([Str "orange"],
- [[Para [Str "orange",Space,Str "fruit"]
- ,OrderedList (1,Decimal,Period)
- [[Plain [Str "sublist"]]
- ,[Plain [Str "sublist"]]]]])]
-,Header 1 ("html-blocks",[],[]) [Str "HTML",Space,Str "Blocks"]
-,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line:"]
-,Div ("",[],[])
- [Plain [Str "foo"]]
-,Para [Str "And",Space,Str "nested",Space,Str "without",Space,Str "indentation:"]
-,Div ("",[],[])
- [Div ("",[],[])
- [Div ("",[],[])
- [Para [Str "foo"]]]
- ,Div ("",[],[])
- [Plain [Str "bar"]]]
-,Para [Str "Interpreted",Space,Str "markdown",Space,Str "in",Space,Str "a",Space,Str "table:"]
-,RawBlock (Format "html") "<table>"
-,RawBlock (Format "html") "<tr>"
-,RawBlock (Format "html") "<td>"
-,Plain [Str "This",Space,Str "is",Space,Emph [Str "emphasized"]]
-,RawBlock (Format "html") "</td>"
-,RawBlock (Format "html") "<td>"
-,Plain [Str "And",Space,Str "this",Space,Str "is",Space,Strong [Str "strong"]]
-,RawBlock (Format "html") "</td>"
-,RawBlock (Format "html") "</tr>"
-,RawBlock (Format "html") "</table>"
-,RawBlock (Format "html") "<script type=\"text/javascript\">document.write('This *should not* be interpreted as markdown');</script>"
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "simple",Space,Str "block:"]
-,Div ("",[],[])
- [Para [Str "foo"]]
-,Para [Str "This",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "code",Space,Str "block,",Space,Str "though:"]
-,CodeBlock ("",[],[]) "<div>\n foo\n</div>"
-,Para [Str "As",Space,Str "should",Space,Str "this:"]
-,CodeBlock ("",[],[]) "<div>foo</div>"
-,Para [Str "Now,",Space,Str "nested:"]
-,Div ("",[],[])
- [Div ("",[],[])
- [Div ("",[],[])
- [Plain [Str "foo"]]]]
-,Para [Str "This",Space,Str "should",Space,Str "just",Space,Str "be",Space,Str "an",Space,Str "HTML",Space,Str "comment:"]
-,RawBlock (Format "html") "<!-- Comment -->"
-,Para [Str "Multiline:"]
-,RawBlock (Format "html") "<!--\nBlah\nBlah\n-->"
-,RawBlock (Format "html") "<!--\n This is another comment.\n-->"
-,Para [Str "Code",Space,Str "block:"]
-,CodeBlock ("",[],[]) "<!-- Comment -->"
-,Para [Str "Just",Space,Str "plain",Space,Str "comment,",Space,Str "with",Space,Str "trailing",Space,Str "spaces",Space,Str "on",Space,Str "the",Space,Str "line:"]
-,RawBlock (Format "html") "<!-- foo -->"
-,Para [Str "Code:"]
-,CodeBlock ("",[],[]) "<hr />"
-,Para [Str "Hr\8217s:"]
-,RawBlock (Format "html") "<hr>"
-,RawBlock (Format "html") "<hr />"
-,RawBlock (Format "html") "<hr />"
-,RawBlock (Format "html") "<hr>"
-,RawBlock (Format "html") "<hr />"
-,RawBlock (Format "html") "<hr />"
-,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\" />"
-,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\" />"
-,RawBlock (Format "html") "<hr class=\"foo\" id=\"bar\">"
-,HorizontalRule
-,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
-,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
-,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
-,Para [Str "An",Space,Emph [Link ("",[],[]) [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
-,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
-,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
-,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
-,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
-,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
-,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
-,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello\160there"],Str "."]
-,Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",Space,Str "H",Subscript [Str "many\160of\160them"],Str "O."]
-,Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",SoftBreak,Str "because",Space,Str "of",Space,Str "the",Space,Str "unescaped",Space,Str "spaces:",Space,Str "a^b",Space,Str "c^d,",Space,Str "a~b",Space,Str "c~d."]
-,HorizontalRule
-,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
-,Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
-,Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
-,Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",SoftBreak,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine."]]
-,Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",SoftBreak,Str "70\8217s?"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code ("",[],[]) "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
-,Para [Str "Some",Space,Str "dashes:",Space,Str "one\8212two",Space,Str "\8212",Space,Str "three\8212four",Space,Str "\8212",Space,Str "five."]
-,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5\8211\&7,",Space,Str "255\8211\&66,",Space,Str "1987\8211\&1999."]
-,Para [Str "Ellipses\8230and\8230and\8230."]
-,HorizontalRule
-,Header 1 ("latex",[],[]) [Str "LaTeX"]
-,BulletList
- [[Plain [RawInline (Format "tex") "\\cite[22-23]{smith.1899}"]]
- ,[Plain [Math InlineMath "2+2=4"]]
- ,[Plain [Math InlineMath "x \\in y"]]
- ,[Plain [Math InlineMath "\\alpha \\wedge \\omega"]]
- ,[Plain [Math InlineMath "223"]]
- ,[Plain [Math InlineMath "p",Str "-Tree"]]
- ,[Plain [Str "Here\8217s",Space,Str "some",Space,Str "display",Space,Str "math:",SoftBreak,Math DisplayMath "\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}"]]
- ,[Plain [Str "Here\8217s",Space,Str "one",Space,Str "that",Space,Str "has",Space,Str "a",Space,Str "line",Space,Str "break",Space,Str "in",Space,Str "it:",Space,Math InlineMath "\\alpha + \\omega \\times x^2",Str "."]]]
-,Para [Str "These",Space,Str "shouldn\8217t",Space,Str "be",Space,Str "math:"]
-,BulletList
- [[Plain [Str "To",Space,Str "get",Space,Str "the",Space,Str "famous",Space,Str "equation,",Space,Str "write",Space,Code ("",[],[]) "$e = mc^2$",Str "."]]
- ,[Plain [Str "$22,000",Space,Str "is",Space,Str "a",Space,Emph [Str "lot"],Space,Str "of",Space,Str "money.",Space,Str "So",Space,Str "is",Space,Str "$34,000.",SoftBreak,Str "(It",Space,Str "worked",Space,Str "if",Space,Quoted DoubleQuote [Str "lot"],Space,Str "is",Space,Str "emphasized.)"]]
- ,[Plain [Str "Shoes",Space,Str "($20)",Space,Str "and",Space,Str "socks",Space,Str "($5)."]]
- ,[Plain [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"]
-,RawBlock (Format "latex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}"
-,HorizontalRule
-,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
-,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
-,BulletList
- [[Plain [Str "I",Space,Str "hat:",Space,Str "\206"]]
- ,[Plain [Str "o",Space,Str "umlaut:",Space,Str "\246"]]
- ,[Plain [Str "section:",Space,Str "\167"]]
- ,[Plain [Str "set",Space,Str "membership:",Space,Str "\8712"]]
- ,[Plain [Str "copyright:",Space,Str "\169"]]]
-,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
-,Para [Str "AT&T",Space,Str "is",Space,Str "another",Space,Str "way",Space,Str "to",Space,Str "write",Space,Str "it."]
-,Para [Str "This",Space,Str "&",Space,Str "that."]
-,Para [Str "4",Space,Str "<",Space,Str "5."]
-,Para [Str "6",Space,Str ">",Space,Str "5."]
-,Para [Str "Backslash:",Space,Str "\\"]
-,Para [Str "Backtick:",Space,Str "`"]
-,Para [Str "Asterisk:",Space,Str "*"]
-,Para [Str "Underscore:",Space,Str "_"]
-,Para [Str "Left",Space,Str "brace:",Space,Str "{"]
-,Para [Str "Right",Space,Str "brace:",Space,Str "}"]
-,Para [Str "Left",Space,Str "bracket:",Space,Str "["]
-,Para [Str "Right",Space,Str "bracket:",Space,Str "]"]
-,Para [Str "Left",Space,Str "paren:",Space,Str "("]
-,Para [Str "Right",Space,Str "paren:",Space,Str ")"]
-,Para [Str "Greater-than:",Space,Str ">"]
-,Para [Str "Hash:",Space,Str "#"]
-,Para [Str "Period:",Space,Str "."]
-,Para [Str "Bang:",Space,Str "!"]
-,Para [Str "Plus:",Space,Str "+"]
-,Para [Str "Minus:",Space,Str "-"]
-,HorizontalRule
-,Header 1 ("links",[],[]) [Str "Links"]
-,Header 2 ("explicit",[],[]) [Str "Explicit"]
-,Para [Str "Just",Space,Str "a",Space,Link ("",[],[]) [Str "URL"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
-,Para [Link ("",[],[]) [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
-,Para [Link ("",[],[]) [Str "with_underscore"] ("/url/with_underscore","")]
-,Para [Link ("",[],[]) [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
-,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
-,Header 2 ("reference",[],[]) [Str "Reference"]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."]
-,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
-,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "twice"] ("/url",""),Str "."]
-,Para [Str "Indented",Space,Link ("",[],[]) [Str "thrice"] ("/url",""),Str "."]
-,Para [Str "This",Space,Str "should",Space,Str "[not][]",Space,Str "be",Space,Str "a",Space,Str "link."]
-,CodeBlock ("",[],[]) "[not]: /url"
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
-,Para [Str "Foo",Space,Link ("",[],[]) [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
-,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
-,Para [Str "Here\8217s",Space,Str "a",Space,Link ("",[],[]) [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link ("",[],[]) [Str "AT&T"] ("http://att.com/","AT&T"),Str "."]
-,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
-,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
-,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
-,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
-,BulletList
- [[Plain [Str "In",Space,Str "a",Space,Str "list?"]]
- ,[Plain [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
- ,[Plain [Str "It",Space,Str "should."]]]
-,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
-,BlockQuote
- [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]]
-,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
-,CodeBlock ("",[],[]) "or here: <http://example.com/>"
-,HorizontalRule
-,Header 1 ("images",[],[]) [Str "Images"]
-,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
-,Para [Image ("",[],[]) [Str "lalune"] ("lalune.jpg","fig:Voyage dans la Lune")]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image ("",[],[]) [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
-,HorizontalRule
-,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",SoftBreak,Str "reference.",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document."]],Space,Str "and",Space,Str "another.",Note [Para [Str "Here\8217s",Space,Str "the",Space,Str "long",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",SoftBreak,Str "blocks."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",SoftBreak,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",SoftBreak,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block."]],SoftBreak,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",SoftBreak,Str "contains",Space,Str "a",Space,Str "space.[^my",Space,Str "note]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note.",Note [Para [Str "This",SoftBreak,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type.",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",SoftBreak,Link ("",[],[]) [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code ("",[],[]) "]",Space,Str "verbatim",Space,Str "characters,",SoftBreak,Str "as",Space,Str "well",Space,Str "as",Space,Str "[bracketed",Space,Str "text]."]]]
-,BlockQuote
- [Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes.",Note [Para [Str "In",Space,Str "quote."]]]]
-,OrderedList (1,Decimal,Period)
- [[Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]]]]
-,Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented."]]
diff --git a/tests/writer.opendocument b/tests/writer.opendocument
deleted file mode 100644
index d613ab5b8..000000000
--- a/tests/writer.opendocument
+++ /dev/null
@@ -1,1539 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.2">
- <office:font-face-decls>
- <style:font-face style:name="Courier New" style:font-family-generic="modern" style:font-pitch="fixed" svg:font-family="'Courier New'" />
- </office:font-face-decls>
- <office:automatic-styles>
- <text:list-style style:name="L1">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L2">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L3">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L4">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L5">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L6">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L7">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L8">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L9">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L10">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L11">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L12">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L13">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L14">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L15">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L16">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L17">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L18">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L19">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L20">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L21">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L22">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="2" style:num-prefix="(" style:num-suffix=")">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="i" text:start-value="4" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- <text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-format="A" text:start-value="1" style:num-prefix="(" style:num-suffix=")">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L23">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="A" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="I" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- <text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="6" style:num-prefix="(" style:num-suffix=")">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- <text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-format="a" text:start-value="3" style:num-suffix=")">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L24">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L25">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <text:list-style style:name="L26">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L27">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L28">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L29">
- <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="0.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="0.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="1.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="1.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="1.75in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="‣">
- <style:list-level-properties text:space-before="2.0in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="⁃">
- <style:list-level-properties text:space-before="2.25in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•">
- <style:list-level-properties text:space-before="2.5in" text:min-label-width="0.25in" />
- </text:list-level-style-bullet>
- </text:list-style>
- <text:list-style style:name="L30">
- <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-format="1" text:start-value="1" style:num-suffix=".">
- <style:list-level-properties text:space-before="0.25in" text:min-label-width="0.25in" />
- </text:list-level-style-number>
- </text:list-style>
- <style:style style:name="T1" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" /></style:style>
- <style:style style:name="T2" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
- <style:style style:name="T3" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>
- <style:style style:name="T4" style:family="text"><style:text-properties style:text-line-through-style="solid" /></style:style>
- <style:style style:name="T5" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" style:text-line-through-style="solid" /></style:style>
- <style:style style:name="T6" style:family="text"><style:text-properties style:text-position="super 58%" /></style:style>
- <style:style style:name="T7" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic" style:text-position="super 58%" /></style:style>
- <style:style style:name="T8" style:family="text"><style:text-properties style:text-position="sub 58%" /></style:style>
- <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Quotations">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Quotations">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L1">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Quotations">
- <style:paragraph-properties fo:margin-left="1.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Quotations">
- <style:paragraph-properties fo:margin-left="1.0in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P10" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P11" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P12" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P13" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P14" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P15" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P16" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P17" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P18" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P19" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L2">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P20" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L3">
- </style:style>
- <style:style style:name="P21" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L4">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P22" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L5">
- </style:style>
- <style:style style:name="P23" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L6">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P24" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L7">
- </style:style>
- <style:style style:name="P25" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L8">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P26" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L9">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P27" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L10">
- </style:style>
- <style:style style:name="P28" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L11">
- </style:style>
- <style:style style:name="P29" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L12">
- </style:style>
- <style:style style:name="P30" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L13">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P31" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L14">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P32" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L15">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P33" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L16">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P34" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L17">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P35" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L18">
- </style:style>
- <style:style style:name="P36" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L19">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P37" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L20">
- </style:style>
- <style:style style:name="P38" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L21">
- </style:style>
- <style:style style:name="P39" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L22">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P40" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L23">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P41" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L24">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P42" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P43" style:family="paragraph" style:parent-style-name="Quotations">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P44" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L25">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P45" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P46" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P47" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P48" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P49" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P50" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P51" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L26">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P52" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L27">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P53" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L28">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P54" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P55" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L29">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- <style:style style:name="P56" style:family="paragraph" style:parent-style-name="Quotations">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P57" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P58" style:family="paragraph" style:parent-style-name="Preformatted_20_Text">
- </style:style>
- <style:style style:name="P59" style:family="paragraph" style:parent-style-name="Quotations">
- <style:paragraph-properties fo:margin-left="0.5in" fo:margin-right="0in" fo:text-indent="0in" style:auto-text-indent="false" />
- </style:style>
- <style:style style:name="P60" style:family="paragraph" style:parent-style-name="Text_20_body" style:list-style-name="L30">
- <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" />
- </style:style>
- </office:automatic-styles>
-<office:body>
-<office:text>
-<text:p text:style-name="Title">Pandoc Test Suite</text:p>
-<text:p text:style-name="Author">John MacFarlane</text:p>
-<text:p text:style-name="Author">Anonymous</text:p>
-<text:p text:style-name="Date">July 17, 2006</text:p>
-<text:p text:style-name="Text_20_body">This is a set of tests for pandoc. Most
-of them are adapted from John Gruber’s markdown test suite.</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Headers</text:h>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Level 2 with an
-<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">embedded
-link</text:span></text:a></text:h>
-<text:h text:style-name="Heading_20_3" text:outline-level="3">Level 3 with
-<text:span text:style-name="T1">emphasis</text:span></text:h>
-<text:h text:style-name="Heading_20_4" text:outline-level="4">Level 4</text:h>
-<text:h text:style-name="Heading_20_5" text:outline-level="5">Level 5</text:h>
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Level 1</text:h>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Level 2 with
-<text:span text:style-name="T1">emphasis</text:span></text:h>
-<text:h text:style-name="Heading_20_3" text:outline-level="3">Level 3</text:h>
-<text:p text:style-name="First_20_paragraph">with no blank line</text:p>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Level 2</text:h>
-<text:p text:style-name="First_20_paragraph">with no blank line</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Paragraphs</text:h>
-<text:p text:style-name="First_20_paragraph">Here’s a regular
-paragraph.</text:p>
-<text:p text:style-name="Text_20_body">In Markdown 1.0.0 and earlier. Version
-8. This line turns into a list item. Because a hard-wrapped line in the middle
-of a paragraph looked like a list item.</text:p>
-<text:p text:style-name="Text_20_body">Here’s one with a bullet. *
-criminey.</text:p>
-<text:p text:style-name="Text_20_body">There should be a hard line
-break<text:line-break />here.</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Block
-Quotes</text:h>
-<text:p text:style-name="First_20_paragraph">E-mail style:</text:p>
-<text:p text:style-name="P1">This is a block quote. It is pretty
-short.</text:p>
-<text:p text:style-name="P2">Code in a block quote:</text:p>
-<text:p text:style-name="P3">sub status {</text:p>
-<text:p text:style-name="P4"><text:s text:c="4" />print &quot;working&quot;;</text:p>
-<text:p text:style-name="P5">}</text:p>
-<text:p text:style-name="P2">A list:</text:p>
-<text:list text:style-name="L1">
- <text:list-item>
- <text:p text:style-name="P6">item one</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P6">item two</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="P2">Nested block quotes:</text:p>
-<text:p text:style-name="P7">nested</text:p>
-<text:p text:style-name="P8">nested</text:p>
-<text:p text:style-name="First_20_paragraph">This should not be a block quote:
-2 &gt; 1.</text:p>
-<text:p text:style-name="Text_20_body">And a following paragraph.</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Code
-Blocks</text:h>
-<text:p text:style-name="First_20_paragraph">Code:</text:p>
-<text:p text:style-name="P9">---- (should be four hyphens)</text:p>
-<text:p text:style-name="P10"></text:p>
-<text:p text:style-name="P11">sub status {</text:p>
-<text:p text:style-name="P12"><text:s text:c="4" />print &quot;working&quot;;</text:p>
-<text:p text:style-name="P13">}</text:p>
-<text:p text:style-name="P14"></text:p>
-<text:p text:style-name="P15">this code block is indented by one tab</text:p>
-<text:p text:style-name="First_20_paragraph">And:</text:p>
-<text:p text:style-name="P16"><text:s text:c="4" />this code block is indented by two tabs</text:p>
-<text:p text:style-name="P17"></text:p>
-<text:p text:style-name="P18">These should not be escaped: <text:s text:c="1" />\$ \\ \&gt; \[ \{</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Lists</text:h>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Unordered</text:h>
-<text:p text:style-name="First_20_paragraph">Asterisks tight:</text:p>
-<text:list text:style-name="L2">
- <text:list-item>
- <text:p text:style-name="P19">asterisk 1</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P19">asterisk 2</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P19">asterisk 3</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Asterisks loose:</text:p>
-<text:list text:style-name="L3">
- <text:list-item>
- <text:p text:style-name="P20">asterisk 1</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P20">asterisk 2</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P20">asterisk 3</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Pluses tight:</text:p>
-<text:list text:style-name="L4">
- <text:list-item>
- <text:p text:style-name="P21">Plus 1</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P21">Plus 2</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P21">Plus 3</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Pluses loose:</text:p>
-<text:list text:style-name="L5">
- <text:list-item>
- <text:p text:style-name="P22">Plus 1</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P22">Plus 2</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P22">Plus 3</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Minuses tight:</text:p>
-<text:list text:style-name="L6">
- <text:list-item>
- <text:p text:style-name="P23">Minus 1</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P23">Minus 2</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P23">Minus 3</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Minuses loose:</text:p>
-<text:list text:style-name="L7">
- <text:list-item>
- <text:p text:style-name="P24">Minus 1</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P24">Minus 2</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P24">Minus 3</text:p>
- </text:list-item>
-</text:list>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Ordered</text:h>
-<text:p text:style-name="First_20_paragraph">Tight:</text:p>
-<text:list text:style-name="L8">
- <text:list-item>
- <text:p text:style-name="P25">First</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P25">Second</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P25">Third</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">and:</text:p>
-<text:list text:style-name="L9">
- <text:list-item>
- <text:p text:style-name="P26">One</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P26">Two</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P26">Three</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Loose using tabs:</text:p>
-<text:list text:style-name="L10">
- <text:list-item>
- <text:p text:style-name="P27">First</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P27">Second</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P27">Third</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">and using spaces:</text:p>
-<text:list text:style-name="L11">
- <text:list-item>
- <text:p text:style-name="P28">One</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P28">Two</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P28">Three</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Multiple paragraphs:</text:p>
-<text:list text:style-name="L12">
- <text:list-item>
- <text:p text:style-name="P29">Item 1, graf one.</text:p>
- <text:p text:style-name="P29">Item 1. graf two. The quick brown fox jumped
- over the lazy dog’s back.</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P29">Item 2.</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P29">Item 3.</text:p>
- </text:list-item>
-</text:list>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Nested</text:h>
-<text:list text:style-name="L13">
- <text:list-item>
- <text:p text:style-name="P30">Tab</text:p><text:list text:style-name="L14">
- <text:list-item>
- <text:p text:style-name="P31">Tab</text:p><text:list text:style-name="L15">
- <text:list-item>
- <text:p text:style-name="P32">Tab</text:p>
- </text:list-item>
- </text:list>
- </text:list-item>
- </text:list>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Here’s another:</text:p>
-<text:list text:style-name="L16">
- <text:list-item>
- <text:p text:style-name="P33">First</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P33">Second:</text:p>
- <text:list text:style-name="L17">
- <text:list-item>
- <text:p text:style-name="P34">Fee</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P34">Fie</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P34">Foe</text:p>
- </text:list-item>
- </text:list>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P33">Third</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Same thing but with
-paragraphs:</text:p>
-<text:list text:style-name="L18">
- <text:list-item>
- <text:p text:style-name="P35">First</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P35">Second:</text:p>
- <text:list text:style-name="L19">
- <text:list-item>
- <text:p text:style-name="P36">Fee</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P36">Fie</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P36">Foe</text:p>
- </text:list-item>
- </text:list>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P35">Third</text:p>
- </text:list-item>
-</text:list>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Tabs and
-spaces</text:h>
-<text:list text:style-name="L20">
- <text:list-item>
- <text:p text:style-name="P37">this is a list item indented with
- tabs</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P37">this is a list item indented with
- spaces</text:p><text:list text:style-name="L21">
- <text:list-item>
- <text:p text:style-name="P38">this is an example list item indented
- with tabs</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P38">this is an example list item indented
- with spaces</text:p>
- </text:list-item>
- </text:list>
- </text:list-item>
-</text:list>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Fancy list
-markers</text:h>
-<text:list text:style-name="L22">
- <text:list-item>
- <text:p text:style-name="P39">begins with 2</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P39">and now 3</text:p>
- <text:p text:style-name="P39">with a continuation</text:p>
- <text:list>
- <text:list-item>
- <text:p text:style-name="P39">sublist with roman numerals, starting
- with 4</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P39">more items</text:p>
- <text:list>
- <text:list-item>
- <text:p text:style-name="P39">a subsublist</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P39">a subsublist</text:p>
- </text:list-item>
- </text:list>
- </text:list-item>
- </text:list>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Nesting:</text:p>
-<text:list text:style-name="L23">
- <text:list-item>
- <text:p text:style-name="P40">Upper Alpha</text:p>
- <text:list>
- <text:list-item>
- <text:p text:style-name="P40">Upper Roman.</text:p>
- <text:list>
- <text:list-item>
- <text:p text:style-name="P40">Decimal start with 6</text:p>
- <text:list>
- <text:list-item>
- <text:p text:style-name="P40">Lower alpha with paren</text:p>
- </text:list-item>
- </text:list>
- </text:list-item>
- </text:list>
- </text:list-item>
- </text:list>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Autonumbering:</text:p>
-<text:list text:style-name="L24">
- <text:list-item>
- <text:p text:style-name="P41">Autonumber.</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P41">More.</text:p>
- <text:list>
- <text:list-item>
- <text:p text:style-name="P41">Nested.</text:p>
- </text:list-item>
- </text:list>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Should not be a list
-item:</text:p>
-<text:p text:style-name="Text_20_body">M.A. 2007</text:p>
-<text:p text:style-name="Text_20_body">B. Williams</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Definition
-Lists</text:h>
-<text:p text:style-name="First_20_paragraph">Tight using spaces:</text:p>
-<text:p text:style-name="Definition_20_Term_20_Tight">apple</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">red fruit</text:p>
-<text:p text:style-name="Definition_20_Term_20_Tight">orange</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">orange
-fruit</text:p>
-<text:p text:style-name="Definition_20_Term_20_Tight">banana</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">yellow
-fruit</text:p>
-<text:p text:style-name="First_20_paragraph">Tight using tabs:</text:p>
-<text:p text:style-name="Definition_20_Term_20_Tight">apple</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">red fruit</text:p>
-<text:p text:style-name="Definition_20_Term_20_Tight">orange</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">orange
-fruit</text:p>
-<text:p text:style-name="Definition_20_Term_20_Tight">banana</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">yellow
-fruit</text:p>
-<text:p text:style-name="First_20_paragraph">Loose:</text:p>
-<text:p text:style-name="Definition_20_Term">apple</text:p>
-<text:p text:style-name="Definition_20_Definition">red fruit</text:p>
-<text:p text:style-name="Definition_20_Term">orange</text:p>
-<text:p text:style-name="Definition_20_Definition">orange fruit</text:p>
-<text:p text:style-name="Definition_20_Term">banana</text:p>
-<text:p text:style-name="Definition_20_Definition">yellow fruit</text:p>
-<text:p text:style-name="First_20_paragraph">Multiple blocks with
-italics:</text:p>
-<text:p text:style-name="Definition_20_Term"><text:span text:style-name="T1">apple</text:span></text:p>
-<text:p text:style-name="Definition_20_Definition">red
-fruit</text:p><text:p text:style-name="Definition_20_Definition">contains
-seeds, crisp, pleasant to taste</text:p>
-<text:p text:style-name="Definition_20_Term"><text:span text:style-name="T1">orange</text:span></text:p>
-<text:p text:style-name="Definition_20_Definition">orange fruit</text:p><text:p text:style-name="P42">{ orange code block }</text:p><text:p text:style-name="P43">orange
-block quote</text:p>
-<text:p text:style-name="First_20_paragraph">Multiple definitions,
-tight:</text:p>
-<text:p text:style-name="Definition_20_Term_20_Tight">apple</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">red fruit</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">computer</text:p>
-<text:p text:style-name="Definition_20_Term_20_Tight">orange</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">orange
-fruit</text:p>
-<text:p text:style-name="Definition_20_Definition_20_Tight">bank</text:p>
-<text:p text:style-name="First_20_paragraph">Multiple definitions,
-loose:</text:p>
-<text:p text:style-name="Definition_20_Term">apple</text:p>
-<text:p text:style-name="Definition_20_Definition">red fruit</text:p>
-<text:p text:style-name="Definition_20_Definition">computer</text:p>
-<text:p text:style-name="Definition_20_Term">orange</text:p>
-<text:p text:style-name="Definition_20_Definition">orange fruit</text:p>
-<text:p text:style-name="Definition_20_Definition">bank</text:p>
-<text:p text:style-name="First_20_paragraph">Blank line after term, indented
-marker, alternate markers:</text:p>
-<text:p text:style-name="Definition_20_Term">apple</text:p>
-<text:p text:style-name="Definition_20_Definition">red fruit</text:p>
-<text:p text:style-name="Definition_20_Definition">computer</text:p>
-<text:p text:style-name="Definition_20_Term">orange</text:p>
-<text:p text:style-name="Definition_20_Definition">orange
-fruit</text:p><text:list text:style-name="L25">
- <text:list-item>
- <text:p text:style-name="P44">sublist</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P44">sublist</text:p>
- </text:list-item>
-</text:list>
-<text:h text:style-name="Heading_20_1" text:outline-level="1">HTML
-Blocks</text:h>
-<text:p text:style-name="First_20_paragraph">Simple block on one
-line:</text:p>
-<text:p text:style-name="Text_20_body">foo</text:p>
-<text:p text:style-name="Text_20_body">And nested without
-indentation:</text:p>
-<text:p text:style-name="Text_20_body">foo</text:p>
-<text:p text:style-name="Text_20_body">bar</text:p>
-<text:p text:style-name="Text_20_body">Interpreted markdown in a
-table:</text:p>
-<text:p text:style-name="Text_20_body">This is
-<text:span text:style-name="T1">emphasized</text:span></text:p>
-<text:p text:style-name="Text_20_body">And this is
-<text:span text:style-name="T2">strong</text:span></text:p>
-<text:p text:style-name="Text_20_body">Here’s a simple block:</text:p>
-<text:p text:style-name="Text_20_body">foo</text:p>
-<text:p text:style-name="Text_20_body">This should be a code block,
-though:</text:p>
-<text:p text:style-name="P45">&lt;div&gt;</text:p>
-<text:p text:style-name="P46"><text:s text:c="4" />foo</text:p>
-<text:p text:style-name="P47">&lt;/div&gt;</text:p>
-<text:p text:style-name="First_20_paragraph">As should this:</text:p>
-<text:p text:style-name="P48">&lt;div&gt;foo&lt;/div&gt;</text:p>
-<text:p text:style-name="First_20_paragraph">Now, nested:</text:p>
-<text:p text:style-name="Text_20_body">foo</text:p>
-<text:p text:style-name="Text_20_body">This should just be an HTML
-comment:</text:p>
-<text:p text:style-name="Text_20_body">Multiline:</text:p>
-<text:p text:style-name="Text_20_body">Code block:</text:p>
-<text:p text:style-name="P49">&lt;!-- Comment --&gt;</text:p>
-<text:p text:style-name="First_20_paragraph">Just plain comment, with trailing
-spaces on the line:</text:p>
-<text:p text:style-name="Text_20_body">Code:</text:p>
-<text:p text:style-name="P50">&lt;hr /&gt;</text:p>
-<text:p text:style-name="First_20_paragraph">Hr’s:</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Inline
-Markup</text:h>
-<text:p text:style-name="First_20_paragraph">This is
-<text:span text:style-name="T1">emphasized</text:span>, and so
-<text:span text:style-name="T1">is this</text:span>.</text:p>
-<text:p text:style-name="Text_20_body">This is
-<text:span text:style-name="T2">strong</text:span>, and so
-<text:span text:style-name="T2">is this</text:span>.</text:p>
-<text:p text:style-name="Text_20_body">An
-<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition"><text:span text:style-name="T1">emphasized
-link</text:span></text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body"><text:span text:style-name="T3">This is
-strong and em.</text:span></text:p>
-<text:p text:style-name="Text_20_body">So is
-<text:span text:style-name="T3">this</text:span> word.</text:p>
-<text:p text:style-name="Text_20_body"><text:span text:style-name="T3">This is
-strong and em.</text:span></text:p>
-<text:p text:style-name="Text_20_body">So is
-<text:span text:style-name="T3">this</text:span> word.</text:p>
-<text:p text:style-name="Text_20_body">This is code:
-<text:span text:style-name="Source_Text">&gt;</text:span>,
-<text:span text:style-name="Source_Text">$</text:span>,
-<text:span text:style-name="Source_Text">\</text:span>,
-<text:span text:style-name="Source_Text">\$</text:span>,
-<text:span text:style-name="Source_Text">&lt;html&gt;</text:span>.</text:p>
-<text:p text:style-name="Text_20_body"><text:span text:style-name="T4">This is
-</text:span><text:span text:style-name="T5">strikeout</text:span><text:span text:style-name="T4">.</text:span></text:p>
-<text:p text:style-name="Text_20_body">Superscripts:
-a<text:span text:style-name="T6">bc</text:span>d
-a<text:span text:style-name="T7">hello</text:span>
-a<text:span text:style-name="T6">hello there</text:span>.</text:p>
-<text:p text:style-name="Text_20_body">Subscripts:
-H<text:span text:style-name="T8">2</text:span>O,
-H<text:span text:style-name="T8">23</text:span>O,
-H<text:span text:style-name="T8">many of them</text:span>O.</text:p>
-<text:p text:style-name="Text_20_body">These should not be superscripts or
-subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Smart quotes,
-ellipses, dashes</text:h>
-<text:p text:style-name="First_20_paragraph">“Hello,” said the spider.
-“‘Shelob’ is my name.”</text:p>
-<text:p text:style-name="Text_20_body">‘A’, ‘B’, and ‘C’ are letters.</text:p>
-<text:p text:style-name="Text_20_body">‘Oak,’ ‘elm,’ and ‘beech’ are names of
-trees. So is ‘pine.’</text:p>
-<text:p text:style-name="Text_20_body">‘He said, “I want to go.”’ Were you
-alive in the 70’s?</text:p>
-<text:p text:style-name="Text_20_body">Here is some quoted
-‘<text:span text:style-name="Source_Text">code</text:span>’ and a
-“<text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">quoted
-link</text:span></text:a>”.</text:p>
-<text:p text:style-name="Text_20_body">Some dashes: one—two — three—four —
-five.</text:p>
-<text:p text:style-name="Text_20_body">Dashes between numbers: 5–7, 255–66,
-1987–1999.</text:p>
-<text:p text:style-name="Text_20_body">Ellipses…and…and….</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">LaTeX</text:h>
-<text:list text:style-name="L26">
- <text:list-item>
- <text:p text:style-name="P51"></text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P51">2 + 2 = 4</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P51"><text:span text:style-name="T1">x</text:span> ∈ <text:span text:style-name="T1">y</text:span></text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P51"><text:span text:style-name="T1">α</text:span> ∧ <text:span text:style-name="T1">ω</text:span></text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P51">223</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P51"><text:span text:style-name="T1">p</text:span>-Tree</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P51">Here’s some display math:
- $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P51">Here’s one that has a line break in it:
- <text:span text:style-name="T1">α</text:span> + <text:span text:style-name="T1">ω</text:span> × <text:span text:style-name="T1">x</text:span><text:span text:style-name="T6">2</text:span>.</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">These shouldn’t be math:</text:p>
-<text:list text:style-name="L27">
- <text:list-item>
- <text:p text:style-name="P52">To get the famous equation, write
- <text:span text:style-name="Source_Text">$e = mc^2$</text:span>.</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P52">$22,000 is a
- <text:span text:style-name="T1">lot</text:span> of money. So is $34,000.
- (It worked if “lot” is emphasized.)</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P52">Shoes ($20) and socks ($5).</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P52">Escaped
- <text:span text:style-name="Source_Text">$</text:span>: $73
- <text:span text:style-name="T1">this should be emphasized</text:span>
- 23$.</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">Here’s a LaTeX table:</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Special
-Characters</text:h>
-<text:p text:style-name="First_20_paragraph">Here is some unicode:</text:p>
-<text:list text:style-name="L28">
- <text:list-item>
- <text:p text:style-name="P53">I hat: Î</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P53">o umlaut: ö</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P53">section: §</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P53">set membership: ∈</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P53">copyright: ©</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">AT&amp;T has an ampersand in
-their name.</text:p>
-<text:p text:style-name="Text_20_body">AT&amp;T is another way to write
-it.</text:p>
-<text:p text:style-name="Text_20_body">This &amp; that.</text:p>
-<text:p text:style-name="Text_20_body">4 &lt; 5.</text:p>
-<text:p text:style-name="Text_20_body">6 &gt; 5.</text:p>
-<text:p text:style-name="Text_20_body">Backslash: \</text:p>
-<text:p text:style-name="Text_20_body">Backtick: `</text:p>
-<text:p text:style-name="Text_20_body">Asterisk: *</text:p>
-<text:p text:style-name="Text_20_body">Underscore: _</text:p>
-<text:p text:style-name="Text_20_body">Left brace: {</text:p>
-<text:p text:style-name="Text_20_body">Right brace: }</text:p>
-<text:p text:style-name="Text_20_body">Left bracket: [</text:p>
-<text:p text:style-name="Text_20_body">Right bracket: ]</text:p>
-<text:p text:style-name="Text_20_body">Left paren: (</text:p>
-<text:p text:style-name="Text_20_body">Right paren: )</text:p>
-<text:p text:style-name="Text_20_body">Greater-than: &gt;</text:p>
-<text:p text:style-name="Text_20_body">Hash: #</text:p>
-<text:p text:style-name="Text_20_body">Period: .</text:p>
-<text:p text:style-name="Text_20_body">Bang: !</text:p>
-<text:p text:style-name="Text_20_body">Plus: +</text:p>
-<text:p text:style-name="Text_20_body">Minus: -</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Links</text:h>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Explicit</text:h>
-<text:p text:style-name="First_20_paragraph">Just a
-<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">URL</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title"><text:span text:style-name="Definition">URL
-and title</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title preceded by two spaces"><text:span text:style-name="Definition">URL
-and title</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title preceded by a tab"><text:span text:style-name="Definition">URL
-and title</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title with &quot;quotes&quot; in it"><text:span text:style-name="Definition">URL
-and title</text:span></text:a></text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name="title with single quotes"><text:span text:style-name="Definition">URL
-and title</text:span></text:a></text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/with_underscore" office:name=""><text:span text:style-name="Definition">with_underscore</text:span></text:a></text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="mailto:nobody@nowhere.net" office:name=""><text:span text:style-name="Definition">Email
-link</text:span></text:a></text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="" office:name=""><text:span text:style-name="Definition">Empty</text:span></text:a>.</text:p>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Reference</text:h>
-<text:p text:style-name="First_20_paragraph">Foo
-<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Foo
-<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Foo
-<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">With
-<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">embedded
-[brackets]</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body"><text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">b</text:span></text:a>
-by itself should be a link.</text:p>
-<text:p text:style-name="Text_20_body">Indented
-<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">once</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Indented
-<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">twice</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Indented
-<text:a xlink:type="simple" xlink:href="/url" office:name=""><text:span text:style-name="Definition">thrice</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">This should [not][] be a link.</text:p>
-<text:p text:style-name="P54">[not]: /url</text:p>
-<text:p text:style-name="First_20_paragraph">Foo
-<text:a xlink:type="simple" xlink:href="/url/" office:name="Title with &quot;quotes&quot; inside"><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Foo
-<text:a xlink:type="simple" xlink:href="/url/" office:name="Title with &quot;quote&quot; inside"><text:span text:style-name="Definition">biz</text:span></text:a>.</text:p>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">With
-ampersands</text:h>
-<text:p text:style-name="First_20_paragraph">Here’s a
-<text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">link
-with an ampersand in the URL</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Here’s a link with an amersand in the
-link text:
-<text:a xlink:type="simple" xlink:href="http://att.com/" office:name="AT&amp;T"><text:span text:style-name="Definition">AT&amp;T</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Here’s an
-<text:a xlink:type="simple" xlink:href="/script?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">inline
-link</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Here’s an
-<text:a xlink:type="simple" xlink:href="/script?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">inline
-link in pointy braces</text:span></text:a>.</text:p>
-<text:h text:style-name="Heading_20_2" text:outline-level="2">Autolinks</text:h>
-<text:p text:style-name="First_20_paragraph">With an ampersand:
-<text:a xlink:type="simple" xlink:href="http://example.com/?foo=1&amp;bar=2" office:name=""><text:span text:style-name="Definition">http://example.com/?foo=1&amp;bar=2</text:span></text:a></text:p>
-<text:list text:style-name="L29">
- <text:list-item>
- <text:p text:style-name="P55">In a list?</text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P55"><text:a xlink:type="simple" xlink:href="http://example.com/" office:name=""><text:span text:style-name="Definition">http://example.com/</text:span></text:a></text:p>
- </text:list-item>
- <text:list-item>
- <text:p text:style-name="P55">It should.</text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">An e-mail address:
-<text:a xlink:type="simple" xlink:href="mailto:nobody@nowhere.net" office:name=""><text:span text:style-name="Definition">nobody@nowhere.net</text:span></text:a></text:p>
-<text:p text:style-name="P56">Blockquoted:
-<text:a xlink:type="simple" xlink:href="http://example.com/" office:name=""><text:span text:style-name="Definition">http://example.com/</text:span></text:a></text:p>
-<text:p text:style-name="First_20_paragraph">Auto-links should not occur here:
-<text:span text:style-name="Source_Text">&lt;http://example.com/&gt;</text:span></text:p>
-<text:p text:style-name="P57">or here: &lt;http://example.com/&gt;</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Images</text:h>
-<text:p text:style-name="First_20_paragraph">From “Voyage dans la Lune” by
-Georges Melies (1902):</text:p>
-<text:p text:style-name="FigureWithCaption"><draw:frame draw:name="img1"><draw:image xlink:href="lalune.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame></text:p>
-<text:p text:style-name="FigureCaption">lalune</text:p>
-<text:p text:style-name="Text_20_body">Here is a movie
-<draw:frame draw:name="img2"><draw:image xlink:href="movie.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame>
-icon.</text:p>
-<text:p text:style-name="Horizontal_20_Line" />
-<text:h text:style-name="Heading_20_1" text:outline-level="1">Footnotes</text:h>
-<text:p text:style-name="First_20_paragraph">Here is a footnote
-reference,<text:note text:id="ftn0" text:note-class="footnote"><text:note-citation>1</text:note-citation><text:note-body><text:p text:style-name="Footnote">Here
-is the footnote. It can go anywhere after the footnote reference. It need not
-be placed at the end of the document.</text:p></text:note-body></text:note>
-and
-another.<text:note text:id="ftn1" text:note-class="footnote"><text:note-citation>2</text:note-citation><text:note-body><text:p text:style-name="Footnote">Here’s
-the long note. This one contains multiple
-blocks.</text:p><text:p text:style-name="Footnote">Subsequent blocks are
-indented to show that they belong to the footnote (as with list
-items).</text:p><text:p text:style-name="P58"><text:s text:c="2" />{ &lt;code&gt; }</text:p><text:p text:style-name="Footnote">If
-you want, you can indent every line, but you can also be lazy and just indent
-the first line of each block.</text:p></text:note-body></text:note> This
-should <text:span text:style-name="T1">not</text:span> be a footnote
-reference, because it contains a space.[^my note] Here is an inline
-note.<text:note text:id="ftn2" text:note-class="footnote"><text:note-citation>3</text:note-citation><text:note-body><text:p text:style-name="Footnote">This
-is <text:span text:style-name="T1">easier</text:span> to type. Inline notes
-may contain
-<text:a xlink:type="simple" xlink:href="http://google.com" office:name=""><text:span text:style-name="Definition">links</text:span></text:a>
-and <text:span text:style-name="Source_Text">]</text:span> verbatim
-characters, as well as [bracketed
-text].</text:p></text:note-body></text:note></text:p>
-<text:p text:style-name="P59">Notes can go in
-quotes.<text:note text:id="ftn3" text:note-class="footnote"><text:note-citation>4</text:note-citation><text:note-body><text:p text:style-name="Footnote">In
-quote.</text:p></text:note-body></text:note></text:p>
-<text:list text:style-name="L30">
- <text:list-item>
- <text:p text:style-name="P60">And in list
- items.<text:note text:id="ftn4" text:note-class="footnote"><text:note-citation>5</text:note-citation><text:note-body><text:p text:style-name="Footnote">In
- list.</text:p></text:note-body></text:note></text:p>
- </text:list-item>
-</text:list>
-<text:p text:style-name="First_20_paragraph">This paragraph should not be part
-of the note, as it is not indented.</text:p>
-</office:text>
-</office:body>
-</office:document-content>
diff --git a/tests/writer.opml b/tests/writer.opml
deleted file mode 100644
index c94a88f77..000000000
--- a/tests/writer.opml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<opml version="2.0">
- <head>
- <title>Pandoc Test Suite</title>
- <dateModified>Mon, 17 Jul 2006 00:00:00 UTC</dateModified>
- <ownerName>John MacFarlane; Anonymous</ownerName>
- </head>
- <body>
-<outline text="Headers">
- <outline text="Level 2 with an &lt;a href=&quot;/url&quot;&gt;embedded link&lt;/a&gt;">
- <outline text="Level 3 with &lt;em&gt;emphasis&lt;/em&gt;">
- <outline text="Level 4">
- <outline text="Level 5">
- </outline>
- </outline>
- </outline>
- </outline>
-</outline>
-<outline text="Level 1">
- <outline text="Level 2 with &lt;em&gt;emphasis&lt;/em&gt;">
- <outline text="Level 3" _note="with no blank line">
- </outline>
- </outline>
- <outline text="Level 2" _note="with no blank line&#10;&#10;------------------------------------------------------------------------">
- </outline>
-</outline>
-<outline text="Paragraphs" _note="Here’s a regular paragraph.&#10;&#10;In Markdown 1.0.0 and earlier. Version 8. This line turns into a list&#10;item. Because a hard-wrapped line in the middle of a paragraph looked&#10;like a list item.&#10;&#10;Here’s one with a bullet. \* criminey.&#10;&#10;There should be a hard line break\&#10;here.&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="Block Quotes" _note="E-mail style:&#10;&#10;&gt; This is a block quote. It is pretty short.&#10;&#10;&gt; Code in a block quote:&#10;&gt;&#10;&gt; sub status {&#10;&gt; print &quot;working&quot;;&#10;&gt; }&#10;&gt;&#10;&gt; A list:&#10;&gt;&#10;&gt; 1. item one&#10;&gt; 2. item two&#10;&gt;&#10;&gt; Nested block quotes:&#10;&gt;&#10;&gt; &gt; nested&#10;&gt;&#10;&gt; &gt; nested&#10;&#10;This should not be a block quote: 2 &amp;gt; 1.&#10;&#10;And a following paragraph.&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="Code Blocks" _note="Code:&#10;&#10; ---- (should be four hyphens)&#10;&#10; sub status {&#10; print &quot;working&quot;;&#10; }&#10;&#10; this code block is indented by one tab&#10;&#10;And:&#10;&#10; this code block is indented by two tabs&#10;&#10; These should not be escaped: \$ \\ \&gt; \[ \{&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="Lists">
- <outline text="Unordered" _note="Asterisks tight:&#10;&#10;- asterisk 1&#10;- asterisk 2&#10;- asterisk 3&#10;&#10;Asterisks loose:&#10;&#10;- asterisk 1&#10;&#10;- asterisk 2&#10;&#10;- asterisk 3&#10;&#10;Pluses tight:&#10;&#10;- Plus 1&#10;- Plus 2&#10;- Plus 3&#10;&#10;Pluses loose:&#10;&#10;- Plus 1&#10;&#10;- Plus 2&#10;&#10;- Plus 3&#10;&#10;Minuses tight:&#10;&#10;- Minus 1&#10;- Minus 2&#10;- Minus 3&#10;&#10;Minuses loose:&#10;&#10;- Minus 1&#10;&#10;- Minus 2&#10;&#10;- Minus 3&#10;&#10;">
- </outline>
- <outline text="Ordered" _note="Tight:&#10;&#10;1. First&#10;2. Second&#10;3. Third&#10;&#10;and:&#10;&#10;1. One&#10;2. Two&#10;3. Three&#10;&#10;Loose using tabs:&#10;&#10;1. First&#10;&#10;2. Second&#10;&#10;3. Third&#10;&#10;and using spaces:&#10;&#10;1. One&#10;&#10;2. Two&#10;&#10;3. Three&#10;&#10;Multiple paragraphs:&#10;&#10;1. Item 1, graf one.&#10;&#10; Item 1. graf two. The quick brown fox jumped over the lazy dog’s&#10; back.&#10;&#10;2. Item 2.&#10;&#10;3. Item 3.&#10;&#10;">
- </outline>
- <outline text="Nested" _note="- Tab&#10; - Tab&#10; - Tab&#10;&#10;Here’s another:&#10;&#10;1. First&#10;2. Second:&#10; - Fee&#10; - Fie&#10; - Foe&#10;3. Third&#10;&#10;Same thing but with paragraphs:&#10;&#10;1. First&#10;&#10;2. Second:&#10;&#10; - Fee&#10; - Fie&#10; - Foe&#10;&#10;3. Third&#10;&#10;">
- </outline>
- <outline text="Tabs and spaces" _note="- this is a list item indented with tabs&#10;&#10;- this is a list item indented with spaces&#10;&#10; - this is an example list item indented with tabs&#10;&#10; - this is an example list item indented with spaces&#10;&#10;">
- </outline>
- <outline text="Fancy list markers" _note="(2) begins with 2&#10;(3) and now 3&#10;&#10; with a continuation&#10;&#10; iv. sublist with roman numerals, starting with 4&#10; v. more items&#10; (A) a subsublist&#10; (B) a subsublist&#10;&#10;Nesting:&#10;&#10;A. Upper Alpha&#10; I. Upper Roman.&#10; (6) Decimal start with 6&#10; c) Lower alpha with paren&#10;&#10;Autonumbering:&#10;&#10;1. Autonumber.&#10;2. More.&#10; 1. Nested.&#10;&#10;Should not be a list item:&#10;&#10;M.A. 2007&#10;&#10;B. Williams&#10;&#10;------------------------------------------------------------------------">
- </outline>
-</outline>
-<outline text="Definition Lists" _note="Tight using spaces:&#10;&#10;apple&#10;: red fruit&#10;&#10;orange&#10;: orange fruit&#10;&#10;banana&#10;: yellow fruit&#10;&#10;Tight using tabs:&#10;&#10;apple&#10;: red fruit&#10;&#10;orange&#10;: orange fruit&#10;&#10;banana&#10;: yellow fruit&#10;&#10;Loose:&#10;&#10;apple&#10;&#10;: red fruit&#10;&#10;orange&#10;&#10;: orange fruit&#10;&#10;banana&#10;&#10;: yellow fruit&#10;&#10;Multiple blocks with italics:&#10;&#10;*apple*&#10;&#10;: red fruit&#10;&#10; contains seeds, crisp, pleasant to taste&#10;&#10;*orange*&#10;&#10;: orange fruit&#10;&#10; { orange code block }&#10;&#10; &gt; orange block quote&#10;&#10;Multiple definitions, tight:&#10;&#10;apple&#10;: red fruit&#10;: computer&#10;&#10;orange&#10;: orange fruit&#10;: bank&#10;&#10;Multiple definitions, loose:&#10;&#10;apple&#10;&#10;: red fruit&#10;&#10;: computer&#10;&#10;orange&#10;&#10;: orange fruit&#10;&#10;: bank&#10;&#10;Blank line after term, indented marker, alternate markers:&#10;&#10;apple&#10;&#10;: red fruit&#10;&#10;: computer&#10;&#10;orange&#10;&#10;: orange fruit&#10;&#10; 1. sublist&#10; 2. sublist&#10;&#10;">
-</outline>
-<outline text="HTML Blocks" _note="Simple block on one line:&#10;&#10;&lt;div&gt;&#10;&#10;foo&#10;&#10;&lt;/div&gt;&#10;&#10;And nested without indentation:&#10;&#10;&lt;div&gt;&#10;&#10;&lt;div&gt;&#10;&#10;&lt;div&gt;&#10;&#10;foo&#10;&#10;&lt;/div&gt;&#10;&#10;&lt;/div&gt;&#10;&#10;&lt;div&gt;&#10;&#10;bar&#10;&#10;&lt;/div&gt;&#10;&#10;&lt;/div&gt;&#10;&#10;Interpreted markdown in a table:&#10;&#10;&lt;table&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&#10;This is *emphasized*&#10;&lt;/td&gt;&#10;&lt;td&gt;&#10;And this is **strong**&#10;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/table&gt;&#10;&lt;script type=&quot;text/javascript&quot;&gt;document.write('This *should not* be interpreted as markdown');&lt;/script&gt;&#10;Here’s a simple block:&#10;&#10;&lt;div&gt;&#10;&#10;foo&#10;&#10;&lt;/div&gt;&#10;&#10;This should be a code block, though:&#10;&#10; &lt;div&gt;&#10; foo&#10; &lt;/div&gt;&#10;&#10;As should this:&#10;&#10; &lt;div&gt;foo&lt;/div&gt;&#10;&#10;Now, nested:&#10;&#10;&lt;div&gt;&#10;&#10;&lt;div&gt;&#10;&#10;&lt;div&gt;&#10;&#10;foo&#10;&#10;&lt;/div&gt;&#10;&#10;&lt;/div&gt;&#10;&#10;&lt;/div&gt;&#10;&#10;This should just be an HTML comment:&#10;&#10;&lt;!-- Comment --&gt;&#10;Multiline:&#10;&#10;&lt;!--&#10;Blah&#10;Blah&#10;--&gt;&#10;&lt;!--&#10; This is another comment.&#10;--&gt;&#10;Code block:&#10;&#10; &lt;!-- Comment --&gt;&#10;&#10;Just plain comment, with trailing spaces on the line:&#10;&#10;&lt;!-- foo --&gt;&#10;Code:&#10;&#10; &lt;hr /&gt;&#10;&#10;Hr’s:&#10;&#10;&lt;hr&gt;&#10;&lt;hr /&gt;&#10;&lt;hr /&gt;&#10;&lt;hr&gt;&#10;&lt;hr /&gt;&#10;&lt;hr /&gt;&#10;&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;&#10;&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;&#10;&lt;hr class=&quot;foo&quot; id=&quot;bar&quot;&gt;&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="Inline Markup" _note="This is *emphasized*, and so *is this*.&#10;&#10;This is **strong**, and so **is this**.&#10;&#10;An *[emphasized link](/url)*.&#10;&#10;***This is strong and em.***&#10;&#10;So is ***this*** word.&#10;&#10;***This is strong and em.***&#10;&#10;So is ***this*** word.&#10;&#10;This is code: `&gt;`, `$`, `\`, `\$`, `&lt;html&gt;`.&#10;&#10;~~This is *strikeout*.~~&#10;&#10;Superscripts: a^bc^d a^*hello*^ a^hello there^.&#10;&#10;Subscripts: H~2~O, H~23~O, H~many of them~O.&#10;&#10;These should not be superscripts or subscripts, because of the unescaped&#10;spaces: a\^b c\^d, a\~b c\~d.&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="Smart quotes, ellipses, dashes" _note="“Hello,” said the spider. “‘Shelob’ is my name.”&#10;&#10;‘A’, ‘B’, and ‘C’ are letters.&#10;&#10;‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’&#10;&#10;‘He said, “I want to go.”’ Were you alive in the 70’s?&#10;&#10;Here is some quoted ‘`code`’ and a “[quoted&#10;link](http://example.com/?foo=1&amp;bar=2)”.&#10;&#10;Some dashes: one—two — three—four — five.&#10;&#10;Dashes between numbers: 5–7, 255–66, 1987–1999.&#10;&#10;Ellipses…and…and….&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="LaTeX" _note="- \cite[22-23]{smith.1899}&#10;- $2+2=4$&#10;- $x \in y$&#10;- $\alpha \wedge \omega$&#10;- $223$&#10;- $p$-Tree&#10;- Here’s some display math:&#10; $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$&#10;- Here’s one that has a line break in it:&#10; $\alpha + \omega \times x^2$.&#10;&#10;These shouldn’t be math:&#10;&#10;- To get the famous equation, write `$e = mc^2$`.&#10;- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot” is&#10; emphasized.)&#10;- Shoes (\$20) and socks (\$5).&#10;- Escaped `$`: \$73 *this should be emphasized* 23\$.&#10;&#10;Here’s a LaTeX table:&#10;&#10;\begin{tabular}{|l|l|}\hline&#10;Animal &amp; Number \\ \hline&#10;Dog &amp; 2 \\&#10;Cat &amp; 1 \\ \hline&#10;\end{tabular}&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="Special Characters" _note="Here is some unicode:&#10;&#10;- I hat: Î&#10;- o umlaut: ö&#10;- section: §&#10;- set membership: ∈&#10;- copyright: ©&#10;&#10;AT&amp;T has an ampersand in their name.&#10;&#10;AT&amp;T is another way to write it.&#10;&#10;This &amp; that.&#10;&#10;4 &amp;lt; 5.&#10;&#10;6 &amp;gt; 5.&#10;&#10;Backslash: \\&#10;&#10;Backtick: \`&#10;&#10;Asterisk: \*&#10;&#10;Underscore: \_&#10;&#10;Left brace: {&#10;&#10;Right brace: }&#10;&#10;Left bracket: \[&#10;&#10;Right bracket: \]&#10;&#10;Left paren: (&#10;&#10;Right paren: )&#10;&#10;Greater-than: &amp;gt;&#10;&#10;Hash: \#&#10;&#10;Period: .&#10;&#10;Bang: !&#10;&#10;Plus: +&#10;&#10;Minus: -&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="Links">
- <outline text="Explicit" _note="Just a [URL](/url/).&#10;&#10;[URL and title](/url/ &quot;title&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by two spaces&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by a tab&quot;).&#10;&#10;[URL and title](/url/ &quot;title with &quot;quotes&quot; in it&quot;)&#10;&#10;[URL and title](/url/ &quot;title with single quotes&quot;)&#10;&#10;[with\_underscore](/url/with_underscore)&#10;&#10;[Email link](mailto:nobody@nowhere.net)&#10;&#10;[Empty]().">
- </outline>
- <outline text="Reference" _note="Foo [bar](/url/).&#10;&#10;Foo [bar](/url/).&#10;&#10;Foo [bar](/url/).&#10;&#10;With [embedded \[brackets\]](/url/).&#10;&#10;[b](/url/) by itself should be a link.&#10;&#10;Indented [once](/url).&#10;&#10;Indented [twice](/url).&#10;&#10;Indented [thrice](/url).&#10;&#10;This should \[not\]\[\] be a link.&#10;&#10; [not]: /url&#10;&#10;Foo [bar](/url/ &quot;Title with &quot;quotes&quot; inside&quot;).&#10;&#10;Foo [biz](/url/ &quot;Title with &quot;quote&quot; inside&quot;).">
- </outline>
- <outline text="With ampersands" _note="Here’s a [link with an ampersand in the&#10;URL](http://example.com/?foo=1&amp;bar=2).&#10;&#10;Here’s a link with an amersand in the link text:&#10;[AT&amp;T](http://att.com/ &quot;AT&amp;T&quot;).&#10;&#10;Here’s an [inline link](/script?foo=1&amp;bar=2).&#10;&#10;Here’s an [inline link in pointy braces](/script?foo=1&amp;bar=2).">
- </outline>
- <outline text="Autolinks" _note="With an ampersand: &lt;http://example.com/?foo=1&amp;bar=2&gt;&#10;&#10;- In a list?&#10;- &lt;http://example.com/&gt;&#10;- It should.&#10;&#10;An e-mail address: &lt;nobody@nowhere.net&gt;&#10;&#10;&gt; Blockquoted: &lt;http://example.com/&gt;&#10;&#10;Auto-links should not occur here: `&lt;http://example.com/&gt;`&#10;&#10; or here: &lt;http://example.com/&gt;&#10;&#10;------------------------------------------------------------------------">
- </outline>
-</outline>
-<outline text="Images" _note="From “Voyage dans la Lune” by Georges Melies (1902):&#10;&#10;![lalune](lalune.jpg &quot;Voyage dans la Lune&quot;)&#10;&#10;Here is a movie ![movie](movie.jpg) icon.&#10;&#10;------------------------------------------------------------------------">
-</outline>
-<outline text="Footnotes" _note="Here is a footnote reference,[^1] and another.[^2] This should *not* be&#10;a footnote reference, because it contains a space.\[\^my note\] Here is&#10;an inline note.[^3]&#10;&#10;&gt; Notes can go in quotes.[^4]&#10;&#10;1. And in list items.[^5]&#10;&#10;This paragraph should not be part of the note, as it is not indented.&#10;&#10;[^1]: Here is the footnote. It can go anywhere after the footnote&#10; reference. It need not be placed at the end of the document.&#10;&#10;[^2]: Here’s the long note. This one contains multiple blocks.&#10;&#10; Subsequent blocks are indented to show that they belong to the&#10; footnote (as with list items).&#10;&#10; { &lt;code&gt; }&#10;&#10; If you want, you can indent every line, but you can also be lazy and&#10; just indent the first line of each block.&#10;&#10;[^3]: This is *easier* to type. Inline notes may contain&#10; [links](http://google.com) and `]` verbatim characters, as well as&#10; \[bracketed text\].&#10;&#10;[^4]: In quote.&#10;&#10;[^5]: In list.">
-</outline>
- </body>
-</opml>
diff --git a/tests/writer.org b/tests/writer.org
deleted file mode 100644
index 92f130054..000000000
--- a/tests/writer.org
+++ /dev/null
@@ -1,855 +0,0 @@
-#+TITLE: Pandoc Test Suite
-
-#+AUTHOR: John MacFarlane; Anonymous
-#+DATE: July 17, 2006
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber's
-markdown test suite.
-
---------------
-
-* Headers
- :PROPERTIES:
- :CUSTOM_ID: headers
- :END:
-
-** Level 2 with an [[/url][embedded link]]
- :PROPERTIES:
- :CUSTOM_ID: level-2-with-an-embedded-link
- :END:
-
-*** Level 3 with /emphasis/
- :PROPERTIES:
- :CUSTOM_ID: level-3-with-emphasis
- :END:
-
-**** Level 4
- :PROPERTIES:
- :CUSTOM_ID: level-4
- :END:
-
-***** Level 5
- :PROPERTIES:
- :CUSTOM_ID: level-5
- :END:
-
-* Level 1
- :PROPERTIES:
- :CUSTOM_ID: level-1
- :END:
-
-** Level 2 with /emphasis/
- :PROPERTIES:
- :CUSTOM_ID: level-2-with-emphasis
- :END:
-
-*** Level 3
- :PROPERTIES:
- :CUSTOM_ID: level-3
- :END:
-
-with no blank line
-
-** Level 2
- :PROPERTIES:
- :CUSTOM_ID: level-2
- :END:
-
-with no blank line
-
---------------
-
-* Paragraphs
- :PROPERTIES:
- :CUSTOM_ID: paragraphs
- :END:
-
-Here's a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here's one with a bullet. * criminey.
-
-There should be a hard line break\\
-here.
-
---------------
-
-* Block Quotes
- :PROPERTIES:
- :CUSTOM_ID: block-quotes
- :END:
-
-E-mail style:
-
-#+BEGIN_QUOTE
- This is a block quote. It is pretty short.
-#+END_QUOTE
-
-#+BEGIN_QUOTE
- Code in a block quote:
-
- #+BEGIN_EXAMPLE
- sub status {
- print "working";
- }
- #+END_EXAMPLE
-
- A list:
-
- 1. item one
- 2. item two
-
- Nested block quotes:
-
- #+BEGIN_QUOTE
- nested
- #+END_QUOTE
-
- #+BEGIN_QUOTE
- nested
- #+END_QUOTE
-#+END_QUOTE
-
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
---------------
-
-* Code Blocks
- :PROPERTIES:
- :CUSTOM_ID: code-blocks
- :END:
-
-Code:
-
-#+BEGIN_EXAMPLE
- ---- (should be four hyphens)
-
- sub status {
- print "working";
- }
-
- this code block is indented by one tab
-#+END_EXAMPLE
-
-And:
-
-#+BEGIN_EXAMPLE
- this code block is indented by two tabs
-
- These should not be escaped: \$ \\ \> \[ \{
-#+END_EXAMPLE
-
---------------
-
-* Lists
- :PROPERTIES:
- :CUSTOM_ID: lists
- :END:
-
-** Unordered
- :PROPERTIES:
- :CUSTOM_ID: unordered
- :END:
-
-Asterisks tight:
-
-- asterisk 1
-- asterisk 2
-- asterisk 3
-
-Asterisks loose:
-
-- asterisk 1
-
-- asterisk 2
-
-- asterisk 3
-
-Pluses tight:
-
-- Plus 1
-- Plus 2
-- Plus 3
-
-Pluses loose:
-
-- Plus 1
-
-- Plus 2
-
-- Plus 3
-
-Minuses tight:
-
-- Minus 1
-- Minus 2
-- Minus 3
-
-Minuses loose:
-
-- Minus 1
-
-- Minus 2
-
-- Minus 3
-
-** Ordered
- :PROPERTIES:
- :CUSTOM_ID: ordered
- :END:
-
-Tight:
-
-1. First
-2. Second
-3. Third
-
-and:
-
-1. One
-2. Two
-3. Three
-
-Loose using tabs:
-
-1. First
-
-2. Second
-
-3. Third
-
-and using spaces:
-
-1. One
-
-2. Two
-
-3. Three
-
-Multiple paragraphs:
-
-1. Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
-
-2. Item 2.
-
-3. Item 3.
-
-** Nested
- :PROPERTIES:
- :CUSTOM_ID: nested
- :END:
-
-- Tab
-
- - Tab
-
- - Tab
-
-Here's another:
-
-1. First
-2. Second:
-
- - Fee
- - Fie
- - Foe
-
-3. Third
-
-Same thing but with paragraphs:
-
-1. First
-
-2. Second:
-
- - Fee
- - Fie
- - Foe
-
-3. Third
-
-** Tabs and spaces
- :PROPERTIES:
- :CUSTOM_ID: tabs-and-spaces
- :END:
-
-- this is a list item indented with tabs
-
-- this is a list item indented with spaces
-
- - this is an example list item indented with tabs
-
- - this is an example list item indented with spaces
-
-** Fancy list markers
- :PROPERTIES:
- :CUSTOM_ID: fancy-list-markers
- :END:
-
-2) begins with 2
-3) and now 3
-
- with a continuation
-
- 4. sublist with roman numerals, starting with 4
- 5. more items
-
- 1) a subsublist
- 2) a subsublist
-
-Nesting:
-
-1. Upper Alpha
-
- 1. Upper Roman.
-
- 6) Decimal start with 6
-
- 3) Lower alpha with paren
-
-Autonumbering:
-
-1. Autonumber.
-2. More.
-
- 1. Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
---------------
-
-* Definition Lists
- :PROPERTIES:
- :CUSTOM_ID: definition-lists
- :END:
-
-Tight using spaces:
-
-- apple :: red fruit
-- orange :: orange fruit
-- banana :: yellow fruit
-
-Tight using tabs:
-
-- apple :: red fruit
-- orange :: orange fruit
-- banana :: yellow fruit
-
-Loose:
-
-- apple :: red fruit
-
-- orange :: orange fruit
-
-- banana :: yellow fruit
-
-Multiple blocks with italics:
-
-- /apple/ :: red fruit
-
- contains seeds, crisp, pleasant to taste
-
-- /orange/ :: orange fruit
-
- #+BEGIN_EXAMPLE
- { orange code block }
- #+END_EXAMPLE
-
- #+BEGIN_QUOTE
- orange block quote
- #+END_QUOTE
-
-Multiple definitions, tight:
-
-- apple :: red fruit
- computer
-- orange :: orange fruit
- bank
-
-Multiple definitions, loose:
-
-- apple :: red fruit
-
- computer
-
-- orange :: orange fruit
-
- bank
-
-Blank line after term, indented marker, alternate markers:
-
-- apple :: red fruit
-
- computer
-
-- orange :: orange fruit
-
- 1. sublist
- 2. sublist
-
-* HTML Blocks
- :PROPERTIES:
- :CUSTOM_ID: html-blocks
- :END:
-
-Simple block on one line:
-
-foo
-
-And nested without indentation:
-
-foo
-
-bar
-
-Interpreted markdown in a table:
-
-#+BEGIN_HTML
- <table>
-#+END_HTML
-
-#+BEGIN_HTML
- <tr>
-#+END_HTML
-
-#+BEGIN_HTML
- <td>
-#+END_HTML
-
-This is /emphasized/
-
-#+BEGIN_HTML
- </td>
-#+END_HTML
-
-#+BEGIN_HTML
- <td>
-#+END_HTML
-
-And this is *strong*
-
-#+BEGIN_HTML
- </td>
-#+END_HTML
-
-#+BEGIN_HTML
- </tr>
-#+END_HTML
-
-#+BEGIN_HTML
- </table>
-#+END_HTML
-
-#+BEGIN_HTML
- <script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
-#+END_HTML
-
-Here's a simple block:
-
-foo
-
-This should be a code block, though:
-
-#+BEGIN_EXAMPLE
- <div>
- foo
- </div>
-#+END_EXAMPLE
-
-As should this:
-
-#+BEGIN_EXAMPLE
- <div>foo</div>
-#+END_EXAMPLE
-
-Now, nested:
-
-foo
-
-This should just be an HTML comment:
-
-#+BEGIN_HTML
- <!-- Comment -->
-#+END_HTML
-
-Multiline:
-
-#+BEGIN_HTML
- <!--
- Blah
- Blah
- -->
-#+END_HTML
-
-#+BEGIN_HTML
- <!--
- This is another comment.
- -->
-#+END_HTML
-
-Code block:
-
-#+BEGIN_EXAMPLE
- <!-- Comment -->
-#+END_EXAMPLE
-
-Just plain comment, with trailing spaces on the line:
-
-#+BEGIN_HTML
- <!-- foo -->
-#+END_HTML
-
-Code:
-
-#+BEGIN_EXAMPLE
- <hr />
-#+END_EXAMPLE
-
-Hr's:
-
-#+BEGIN_HTML
- <hr>
-#+END_HTML
-
-#+BEGIN_HTML
- <hr />
-#+END_HTML
-
-#+BEGIN_HTML
- <hr />
-#+END_HTML
-
-#+BEGIN_HTML
- <hr>
-#+END_HTML
-
-#+BEGIN_HTML
- <hr />
-#+END_HTML
-
-#+BEGIN_HTML
- <hr />
-#+END_HTML
-
-#+BEGIN_HTML
- <hr class="foo" id="bar" />
-#+END_HTML
-
-#+BEGIN_HTML
- <hr class="foo" id="bar" />
-#+END_HTML
-
-#+BEGIN_HTML
- <hr class="foo" id="bar">
-#+END_HTML
-
---------------
-
-* Inline Markup
- :PROPERTIES:
- :CUSTOM_ID: inline-markup
- :END:
-
-This is /emphasized/, and so /is this/.
-
-This is *strong*, and so *is this*.
-
-An /[[/url][emphasized link]]/.
-
-*/This is strong and em./*
-
-So is */this/* word.
-
-*/This is strong and em./*
-
-So is */this/* word.
-
-This is code: =>=, =$=, =\=, =\$=, =<html>=.
-
-+This is /strikeout/.+
-
-Superscripts: a^{bc}d a^{/hello/} a^{hello there}.
-
-Subscripts: H_{2}O, H_{23}O, H_{many of them}O.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a\^b c\^d, a~b c~d.
-
---------------
-
-* Smart quotes, ellipses, dashes
- :PROPERTIES:
- :CUSTOM_ID: smart-quotes-ellipses-dashes
- :END:
-
-"Hello," said the spider. "'Shelob' is my name."
-
-'A', 'B', and 'C' are letters.
-
-'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
-
-'He said, "I want to go."' Were you alive in the 70's?
-
-Here is some quoted '=code=' and a "[[http://example.com/?foo=1&bar=2][quoted
-link]]".
-
-Some dashes: one---two --- three---four --- five.
-
-Dashes between numbers: 5--7, 255--66, 1987--1999.
-
-Ellipses...and...and....
-
---------------
-
-* LaTeX
- :PROPERTIES:
- :CUSTOM_ID: latex
- :END:
-
-- \cite[22-23]{smith.1899}
-- $2+2=4$
-- $x \in y$
-- $\alpha \wedge \omega$
-- $223$
-- $p$-Tree
-- Here's some display math:
- $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
-- Here's one that has a line break in it: $\alpha + \omega \times x^2$.
-
-These shouldn't be math:
-
-- To get the famous equation, write =$e = mc^2$=.
-- $22,000 is a /lot/ of money. So is $34,000. (It worked if "lot" is
- emphasized.)
-- Shoes ($20) and socks ($5).
-- Escaped =$=: $73 /this should be emphasized/ 23$.
-
-Here's a LaTeX table:
-
-\begin{tabular}{|l|l|}\hline
-Animal & Number \\ \hline
-Dog & 2 \\
-Cat & 1 \\ \hline
-\end{tabular}
-
---------------
-
-* Special Characters
- :PROPERTIES:
- :CUSTOM_ID: special-characters
- :END:
-
-Here is some unicode:
-
-- I hat: Î
-- o umlaut: ö
-- section: §
-- set membership: ∈
-- copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: \_
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
---------------
-
-* Links
- :PROPERTIES:
- :CUSTOM_ID: links
- :END:
-
-** Explicit
- :PROPERTIES:
- :CUSTOM_ID: explicit
- :END:
-
-Just a [[/url/][URL]].
-
-[[/url/][URL and title]].
-
-[[/url/][URL and title]].
-
-[[/url/][URL and title]].
-
-[[/url/][URL and title]]
-
-[[/url/][URL and title]]
-
-[[/url/with_underscore][with\_underscore]]
-
-[[mailto:nobody@nowhere.net][Email link]]
-
-[[][Empty]].
-
-** Reference
- :PROPERTIES:
- :CUSTOM_ID: reference
- :END:
-
-Foo [[/url/][bar]].
-
-Foo [[/url/][bar]].
-
-Foo [[/url/][bar]].
-
-With [[/url/][embedded [brackets]]].
-
-[[/url/][b]] by itself should be a link.
-
-Indented [[/url][once]].
-
-Indented [[/url][twice]].
-
-Indented [[/url][thrice]].
-
-This should [not][] be a link.
-
-#+BEGIN_EXAMPLE
- [not]: /url
-#+END_EXAMPLE
-
-Foo [[/url/][bar]].
-
-Foo [[/url/][biz]].
-
-** With ampersands
- :PROPERTIES:
- :CUSTOM_ID: with-ampersands
- :END:
-
-Here's a [[http://example.com/?foo=1&bar=2][link with an ampersand in the
-URL]].
-
-Here's a link with an amersand in the link text: [[http://att.com/][AT&T]].
-
-Here's an [[/script?foo=1&bar=2][inline link]].
-
-Here's an [[/script?foo=1&bar=2][inline link in pointy braces]].
-
-** Autolinks
- :PROPERTIES:
- :CUSTOM_ID: autolinks
- :END:
-
-With an ampersand: [[http://example.com/?foo=1&bar=2]]
-
-- In a list?
-- [[http://example.com/]]
-- It should.
-
-An e-mail address: [[mailto:nobody@nowhere.net][nobody@nowhere.net]]
-
-#+BEGIN_QUOTE
- Blockquoted: [[http://example.com/]]
-#+END_QUOTE
-
-Auto-links should not occur here: =<http://example.com/>=
-
-#+BEGIN_EXAMPLE
- or here: <http://example.com/>
-#+END_EXAMPLE
-
---------------
-
-* Images
- :PROPERTIES:
- :CUSTOM_ID: images
- :END:
-
-From "Voyage dans la Lune" by Georges Melies (1902):
-
-#+CAPTION: lalune
-[[file:lalune.jpg]]
-
-Here is a movie [[file:movie.jpg]] icon.
-
---------------
-
-* Footnotes
- :PROPERTIES:
- :CUSTOM_ID: footnotes
- :END:
-
-Here is a footnote reference,[fn:1] and another.[fn:2] This should /not/ be a
-footnote reference, because it contains a space.[\^my note] Here is an inline
-note.[fn:3]
-
-#+BEGIN_QUOTE
- Notes can go in quotes.[fn:4]
-#+END_QUOTE
-
-1. And in list items.[fn:5]
-
-This paragraph should not be part of the note, as it is not indented.
-
-[fn:1] Here is the footnote. It can go anywhere after the footnote reference.
- It need not be placed at the end of the document.
-
-[fn:2] Here's the long note. This one contains multiple blocks.
-
- Subsequent blocks are indented to show that they belong to the footnote
- (as with list items).
-
- #+BEGIN_EXAMPLE
- { <code> }
- #+END_EXAMPLE
-
- If you want, you can indent every line, but you can also be lazy and
- just indent the first line of each block.
-
-[fn:3] This is /easier/ to type. Inline notes may contain
- [[http://google.com][links]] and =]= verbatim characters, as well as
- [bracketed text].
-
-[fn:4] In quote.
-
-[fn:5] In list.
diff --git a/tests/writer.plain b/tests/writer.plain
deleted file mode 100644
index f34af9100..000000000
--- a/tests/writer.plain
+++ /dev/null
@@ -1,695 +0,0 @@
-Pandoc Test Suite
-John MacFarlane; Anonymous
-July 17, 2006
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
-markdown test suite.
-
-------------------------------------------------------------------------------
-
-
-
-HEADERS
-
-
-Level 2 with an embedded link
-
-Level 3 with _emphasis_
-
-Level 4
-
-Level 5
-
-
-
-LEVEL 1
-
-
-Level 2 with _emphasis_
-
-Level 3
-
-with no blank line
-
-
-Level 2
-
-with no blank line
-
-------------------------------------------------------------------------------
-
-
-
-PARAGRAPHS
-
-
-Here’s a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here’s one with a bullet. * criminey.
-
-There should be a hard line break
-here.
-
-------------------------------------------------------------------------------
-
-
-
-BLOCK QUOTES
-
-
-E-mail style:
-
- This is a block quote. It is pretty short.
-
- Code in a block quote:
-
- sub status {
- print "working";
- }
-
- A list:
-
- 1. item one
- 2. item two
-
- Nested block quotes:
-
- nested
-
- nested
-
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
-------------------------------------------------------------------------------
-
-
-
-CODE BLOCKS
-
-
-Code:
-
- ---- (should be four hyphens)
-
- sub status {
- print "working";
- }
-
- this code block is indented by one tab
-
-And:
-
- this code block is indented by two tabs
-
- These should not be escaped: \$ \\ \> \[ \{
-
-------------------------------------------------------------------------------
-
-
-
-LISTS
-
-
-Unordered
-
-Asterisks tight:
-
-- asterisk 1
-- asterisk 2
-- asterisk 3
-
-Asterisks loose:
-
-- asterisk 1
-
-- asterisk 2
-
-- asterisk 3
-
-Pluses tight:
-
-- Plus 1
-- Plus 2
-- Plus 3
-
-Pluses loose:
-
-- Plus 1
-
-- Plus 2
-
-- Plus 3
-
-Minuses tight:
-
-- Minus 1
-- Minus 2
-- Minus 3
-
-Minuses loose:
-
-- Minus 1
-
-- Minus 2
-
-- Minus 3
-
-
-Ordered
-
-Tight:
-
-1. First
-2. Second
-3. Third
-
-and:
-
-1. One
-2. Two
-3. Three
-
-Loose using tabs:
-
-1. First
-
-2. Second
-
-3. Third
-
-and using spaces:
-
-1. One
-
-2. Two
-
-3. Three
-
-Multiple paragraphs:
-
-1. Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
-
-2. Item 2.
-
-3. Item 3.
-
-
-Nested
-
-- Tab
- - Tab
- - Tab
-
-Here’s another:
-
-1. First
-2. Second:
- - Fee
- - Fie
- - Foe
-3. Third
-
-Same thing but with paragraphs:
-
-1. First
-
-2. Second:
-
- - Fee
- - Fie
- - Foe
-
-3. Third
-
-
-Tabs and spaces
-
-- this is a list item indented with tabs
-
-- this is a list item indented with spaces
-
- - this is an example list item indented with tabs
-
- - this is an example list item indented with spaces
-
-
-Fancy list markers
-
-(2) begins with 2
-(3) and now 3
-
- with a continuation
-
- iv. sublist with roman numerals, starting with 4
- v. more items
- (A) a subsublist
- (B) a subsublist
-
-Nesting:
-
-A. Upper Alpha
- I. Upper Roman.
- (6) Decimal start with 6
- c) Lower alpha with paren
-
-Autonumbering:
-
-1. Autonumber.
-2. More.
- 1. Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-------------------------------------------------------------------------------
-
-
-
-DEFINITION LISTS
-
-
-Tight using spaces:
-
-apple
- red fruit
-
-orange
- orange fruit
-
-banana
- yellow fruit
-
-Tight using tabs:
-
-apple
- red fruit
-
-orange
- orange fruit
-
-banana
- yellow fruit
-
-Loose:
-
-apple
-
- red fruit
-
-orange
-
- orange fruit
-
-banana
-
- yellow fruit
-
-Multiple blocks with italics:
-
-_apple_
-
- red fruit
-
- contains seeds, crisp, pleasant to taste
-
-_orange_
-
- orange fruit
-
- { orange code block }
-
- orange block quote
-
-Multiple definitions, tight:
-
-apple
- red fruit
- computer
-
-orange
- orange fruit
- bank
-
-Multiple definitions, loose:
-
-apple
-
- red fruit
-
- computer
-
-orange
-
- orange fruit
-
- bank
-
-Blank line after term, indented marker, alternate markers:
-
-apple
-
- red fruit
-
- computer
-
-orange
-
- orange fruit
-
- 1. sublist
- 2. sublist
-
-
-
-HTML BLOCKS
-
-
-Simple block on one line:
-
-foo
-
-And nested without indentation:
-
-foo
-
-bar
-
-Interpreted markdown in a table:
-
-This is _emphasized_
-And this is STRONG
-Here’s a simple block:
-
-foo
-
-This should be a code block, though:
-
- <div>
- foo
- </div>
-
-As should this:
-
- <div>foo</div>
-
-Now, nested:
-
-foo
-
-This should just be an HTML comment:
-
-Multiline:
-
-Code block:
-
- <!-- Comment -->
-
-Just plain comment, with trailing spaces on the line:
-
-Code:
-
- <hr />
-
-Hr’s:
-
-------------------------------------------------------------------------------
-
-
-
-INLINE MARKUP
-
-
-This is _emphasized_, and so _is this_.
-
-This is STRONG, and so IS THIS.
-
-An _emphasized link_.
-
-_THIS IS STRONG AND EM._
-
-So is _THIS_ word.
-
-_THIS IS STRONG AND EM._
-
-So is _THIS_ word.
-
-This is code: >, $, \, \$, <html>.
-
-~~This is _strikeout_.~~
-
-Superscripts: abcd a_hello_ ahello there.
-
-Subscripts: H₂O, H₂₃O, Hmany of themO.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a^b c^d, a~b c~d.
-
-------------------------------------------------------------------------------
-
-
-
-SMART QUOTES, ELLIPSES, DASHES
-
-
-“Hello,” said the spider. “‘Shelob’ is my name.”
-
-‘A’, ‘B’, and ‘C’ are letters.
-
-‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
-
-‘He said, “I want to go.”’ Were you alive in the 70’s?
-
-Here is some quoted ‘code’ and a “quoted link”.
-
-Some dashes: one—two — three—four — five.
-
-Dashes between numbers: 5–7, 255–66, 1987–1999.
-
-Ellipses…and…and….
-
-------------------------------------------------------------------------------
-
-
-
-LATEX
-
-
--
-- 2 + 2 = 4
-- x ∈ y
-- α ∧ ω
-- 223
-- p-Tree
-- Here’s some display math:
- $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
-- Here’s one that has a line break in it: α + ω × x².
-
-These shouldn’t be math:
-
-- To get the famous equation, write $e = mc^2$.
-- $22,000 is a _lot_ of money. So is $34,000. (It worked if “lot” is
- emphasized.)
-- Shoes ($20) and socks ($5).
-- Escaped $: $73 _this should be emphasized_ 23$.
-
-Here’s a LaTeX table:
-
-------------------------------------------------------------------------------
-
-
-
-SPECIAL CHARACTERS
-
-
-Here is some unicode:
-
-- I hat: Î
-- o umlaut: ö
-- section: §
-- set membership: ∈
-- copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: _
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-------------------------------------------------------------------------------
-
-
-
-LINKS
-
-
-Explicit
-
-Just a URL.
-
-URL and title.
-
-URL and title.
-
-URL and title.
-
-URL and title
-
-URL and title
-
-with_underscore
-
-Email link
-
-Empty.
-
-
-Reference
-
-Foo bar.
-
-Foo bar.
-
-Foo bar.
-
-With embedded [brackets].
-
-b by itself should be a link.
-
-Indented once.
-
-Indented twice.
-
-Indented thrice.
-
-This should [not][] be a link.
-
- [not]: /url
-
-Foo bar.
-
-Foo biz.
-
-
-With ampersands
-
-Here’s a link with an ampersand in the URL.
-
-Here’s a link with an amersand in the link text: AT&T.
-
-Here’s an inline link.
-
-Here’s an inline link in pointy braces.
-
-
-Autolinks
-
-With an ampersand: http://example.com/?foo=1&bar=2
-
-- In a list?
-- http://example.com/
-- It should.
-
-An e-mail address: nobody@nowhere.net
-
- Blockquoted: http://example.com/
-
-Auto-links should not occur here: <http://example.com/>
-
- or here: <http://example.com/>
-
-------------------------------------------------------------------------------
-
-
-
-IMAGES
-
-
-From “Voyage dans la Lune” by Georges Melies (1902):
-
-[lalune]
-
-Here is a movie [movie] icon.
-
-------------------------------------------------------------------------------
-
-
-
-FOOTNOTES
-
-
-Here is a footnote reference,[1] and another.[2] This should _not_ be a
-footnote reference, because it contains a space.[^my note] Here is an inline
-note.[3]
-
- Notes can go in quotes.[4]
-
-1. And in list items.[5]
-
-This paragraph should not be part of the note, as it is not indented.
-
-[1] Here is the footnote. It can go anywhere after the footnote reference. It
-need not be placed at the end of the document.
-
-[2] Here’s the long note. This one contains multiple blocks.
-
-Subsequent blocks are indented to show that they belong to the footnote (as
-with list items).
-
- { <code> }
-
-If you want, you can indent every line, but you can also be lazy and just
-indent the first line of each block.
-
-[3] This is _easier_ to type. Inline notes may contain links and ] verbatim
-characters, as well as [bracketed text].
-
-[4] In quote.
-
-[5] In list.
diff --git a/tests/writer.rst b/tests/writer.rst
deleted file mode 100644
index 1aeeacacb..000000000
--- a/tests/writer.rst
+++ /dev/null
@@ -1,892 +0,0 @@
-=================
-Pandoc Test Suite
-=================
-
-:Author: John MacFarlane
-:Author: Anonymous
-:Date: July 17, 2006
-
-.. role:: math(raw)
- :format: html latex
-..
-
-.. role:: raw-latex(raw)
- :format: latex
-..
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
-markdown test suite.
-
---------------
-
-Headers
-=======
-
-Level 2 with an `embedded link </url>`__
-----------------------------------------
-
-Level 3 with *emphasis*
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Level 4
-^^^^^^^
-
-Level 5
-'''''''
-
-Level 1
-=======
-
-Level 2 with *emphasis*
------------------------
-
-Level 3
-~~~~~~~
-
-with no blank line
-
-Level 2
--------
-
-with no blank line
-
---------------
-
-Paragraphs
-==========
-
-Here’s a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here’s one with a bullet. \* criminey.
-
-| There should be a hard line break
-| here.
-
---------------
-
-Block Quotes
-============
-
-E-mail style:
-
- This is a block quote. It is pretty short.
-
- Code in a block quote:
-
- ::
-
- sub status {
- print "working";
- }
-
- A list:
-
- 1. item one
- 2. item two
-
- Nested block quotes:
-
- nested
-
- nested
-
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
---------------
-
-Code Blocks
-===========
-
-Code:
-
-::
-
- ---- (should be four hyphens)
-
- sub status {
- print "working";
- }
-
- this code block is indented by one tab
-
-And:
-
-::
-
- this code block is indented by two tabs
-
- These should not be escaped: \$ \\ \> \[ \{
-
---------------
-
-Lists
-=====
-
-Unordered
----------
-
-Asterisks tight:
-
-- asterisk 1
-- asterisk 2
-- asterisk 3
-
-Asterisks loose:
-
-- asterisk 1
-
-- asterisk 2
-
-- asterisk 3
-
-Pluses tight:
-
-- Plus 1
-- Plus 2
-- Plus 3
-
-Pluses loose:
-
-- Plus 1
-
-- Plus 2
-
-- Plus 3
-
-Minuses tight:
-
-- Minus 1
-- Minus 2
-- Minus 3
-
-Minuses loose:
-
-- Minus 1
-
-- Minus 2
-
-- Minus 3
-
-Ordered
--------
-
-Tight:
-
-1. First
-2. Second
-3. Third
-
-and:
-
-1. One
-2. Two
-3. Three
-
-Loose using tabs:
-
-1. First
-
-2. Second
-
-3. Third
-
-and using spaces:
-
-1. One
-
-2. Two
-
-3. Three
-
-Multiple paragraphs:
-
-1. Item 1, graf one.
-
- Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
-
-2. Item 2.
-
-3. Item 3.
-
-Nested
-------
-
-- Tab
-
- - Tab
-
- - Tab
-
-Here’s another:
-
-1. First
-2. Second:
-
- - Fee
- - Fie
- - Foe
-
-3. Third
-
-Same thing but with paragraphs:
-
-1. First
-
-2. Second:
-
- - Fee
- - Fie
- - Foe
-
-3. Third
-
-Tabs and spaces
----------------
-
-- this is a list item indented with tabs
-
-- this is a list item indented with spaces
-
- - this is an example list item indented with tabs
-
- - this is an example list item indented with spaces
-
-Fancy list markers
-------------------
-
-(2) begins with 2
-(3) and now 3
-
- with a continuation
-
- iv. sublist with roman numerals, starting with 4
- v. more items
-
- (A) a subsublist
- (B) a subsublist
-
-Nesting:
-
-A. Upper Alpha
-
- I. Upper Roman.
-
- (6) Decimal start with 6
-
- c) Lower alpha with paren
-
-Autonumbering:
-
-#. Autonumber.
-#. More.
-
- #. Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
---------------
-
-Definition Lists
-================
-
-Tight using spaces:
-
-apple
- red fruit
-orange
- orange fruit
-banana
- yellow fruit
-
-Tight using tabs:
-
-apple
- red fruit
-orange
- orange fruit
-banana
- yellow fruit
-
-Loose:
-
-apple
- red fruit
-
-orange
- orange fruit
-
-banana
- yellow fruit
-
-Multiple blocks with italics:
-
-*apple*
- red fruit
-
- contains seeds, crisp, pleasant to taste
-
-*orange*
- orange fruit
-
- ::
-
- { orange code block }
-
- orange block quote
-
-Multiple definitions, tight:
-
-apple
- red fruit
- computer
-orange
- orange fruit
- bank
-
-Multiple definitions, loose:
-
-apple
- red fruit
-
- computer
-
-orange
- orange fruit
-
- bank
-
-Blank line after term, indented marker, alternate markers:
-
-apple
- red fruit
-
- computer
-
-orange
- orange fruit
-
- 1. sublist
- 2. sublist
-
-HTML Blocks
-===========
-
-Simple block on one line:
-
-.. raw:: html
-
- <div>
-
-foo
-
-.. raw:: html
-
- </div>
-
-And nested without indentation:
-
-.. raw:: html
-
- <div>
-
-.. raw:: html
-
- <div>
-
-.. raw:: html
-
- <div>
-
-foo
-
-.. raw:: html
-
- </div>
-
-.. raw:: html
-
- </div>
-
-.. raw:: html
-
- <div>
-
-bar
-
-.. raw:: html
-
- </div>
-
-.. raw:: html
-
- </div>
-
-Interpreted markdown in a table:
-
-.. raw:: html
-
- <table>
-
-.. raw:: html
-
- <tr>
-
-.. raw:: html
-
- <td>
-
-This is *emphasized*
-
-.. raw:: html
-
- </td>
-
-.. raw:: html
-
- <td>
-
-And this is **strong**
-
-.. raw:: html
-
- </td>
-
-.. raw:: html
-
- </tr>
-
-.. raw:: html
-
- </table>
-
-.. raw:: html
-
- <script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
-
-Here’s a simple block:
-
-.. raw:: html
-
- <div>
-
-foo
-
-.. raw:: html
-
- </div>
-
-This should be a code block, though:
-
-::
-
- <div>
- foo
- </div>
-
-As should this:
-
-::
-
- <div>foo</div>
-
-Now, nested:
-
-.. raw:: html
-
- <div>
-
-.. raw:: html
-
- <div>
-
-.. raw:: html
-
- <div>
-
-foo
-
-.. raw:: html
-
- </div>
-
-.. raw:: html
-
- </div>
-
-.. raw:: html
-
- </div>
-
-This should just be an HTML comment:
-
-.. raw:: html
-
- <!-- Comment -->
-
-Multiline:
-
-.. raw:: html
-
- <!--
- Blah
- Blah
- -->
-
-.. raw:: html
-
- <!--
- This is another comment.
- -->
-
-Code block:
-
-::
-
- <!-- Comment -->
-
-Just plain comment, with trailing spaces on the line:
-
-.. raw:: html
-
- <!-- foo -->
-
-Code:
-
-::
-
- <hr />
-
-Hr’s:
-
-.. raw:: html
-
- <hr>
-
-.. raw:: html
-
- <hr />
-
-.. raw:: html
-
- <hr />
-
-.. raw:: html
-
- <hr>
-
-.. raw:: html
-
- <hr />
-
-.. raw:: html
-
- <hr />
-
-.. raw:: html
-
- <hr class="foo" id="bar" />
-
-.. raw:: html
-
- <hr class="foo" id="bar" />
-
-.. raw:: html
-
- <hr class="foo" id="bar">
-
---------------
-
-Inline Markup
-=============
-
-This is *emphasized*, and so *is this*.
-
-This is **strong**, and so **is this**.
-
-An *`emphasized link </url>`__*.
-
-***This is strong and em.***
-
-So is ***this*** word.
-
-***This is strong and em.***
-
-So is ***this*** word.
-
-This is code: ``>``, ``$``, ``\``, ``\$``, ``<html>``.
-
-[STRIKEOUT:This is *strikeout*.]
-
-Superscripts: a\ :sup:`bc`\ d a\ :sup:`*hello*` a\ :sup:`hello there`.
-
-Subscripts: H\ :sub:`2`\ O, H\ :sub:`23`\ O, H\ :sub:`many of them`\ O.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a^b c^d, a~b c~d.
-
---------------
-
-Smart quotes, ellipses, dashes
-==============================
-
-“Hello,” said the spider. “‘Shelob’ is my name.”
-
-‘A’, ‘B’, and ‘C’ are letters.
-
-‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
-
-‘He said, “I want to go.”’ Were you alive in the 70’s?
-
-Here is some quoted ‘``code``’ and a “`quoted
-link <http://example.com/?foo=1&bar=2>`__”.
-
-Some dashes: one—two — three—four — five.
-
-Dashes between numbers: 5–7, 255–66, 1987–1999.
-
-Ellipses…and…and….
-
---------------
-
-LaTeX
-=====
-
-- :raw-latex:`\cite[22-23]{smith.1899}`
-- :math:`2+2=4`
-- :math:`x \in y`
-- :math:`\alpha \wedge \omega`
-- :math:`223`
-- :math:`p`-Tree
-- Here’s some display math:
-
- .. math:: \frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}
-
-- Here’s one that has a line break in it: :math:`\alpha + \omega \times x^2`.
-
-These shouldn’t be math:
-
-- To get the famous equation, write ``$e = mc^2$``.
-- $22,000 is a *lot* of money. So is $34,000. (It worked if “lot” is
- emphasized.)
-- Shoes ($20) and socks ($5).
-- Escaped ``$``: $73 *this should be emphasized* 23$.
-
-Here’s a LaTeX table:
-
-.. raw:: latex
-
- \begin{tabular}{|l|l|}\hline
- Animal & Number \\ \hline
- Dog & 2 \\
- Cat & 1 \\ \hline
- \end{tabular}
-
---------------
-
-Special Characters
-==================
-
-Here is some unicode:
-
-- I hat: Î
-- o umlaut: ö
-- section: §
-- set membership: ∈
-- copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \\
-
-Backtick: \`
-
-Asterisk: \*
-
-Underscore: \_
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
---------------
-
-Links
-=====
-
-Explicit
---------
-
-Just a `URL </url/>`__.
-
-`URL and title </url/>`__.
-
-`URL and title </url/>`__.
-
-`URL and title </url/>`__.
-
-`URL and title </url/>`__
-
-`URL and title </url/>`__
-
-`with\_underscore </url/with_underscore>`__
-
-`Email link <mailto:nobody@nowhere.net>`__
-
-`Empty <>`__.
-
-Reference
----------
-
-Foo `bar </url/>`__.
-
-Foo `bar </url/>`__.
-
-Foo `bar </url/>`__.
-
-With `embedded [brackets] </url/>`__.
-
-`b </url/>`__ by itself should be a link.
-
-Indented `once </url>`__.
-
-Indented `twice </url>`__.
-
-Indented `thrice </url>`__.
-
-This should [not][] be a link.
-
-::
-
- [not]: /url
-
-Foo `bar </url/>`__.
-
-Foo `biz </url/>`__.
-
-With ampersands
----------------
-
-Here’s a `link with an ampersand in the
-URL <http://example.com/?foo=1&bar=2>`__.
-
-Here’s a link with an amersand in the link text: `AT&T <http://att.com/>`__.
-
-Here’s an `inline link </script?foo=1&bar=2>`__.
-
-Here’s an `inline link in pointy braces </script?foo=1&bar=2>`__.
-
-Autolinks
----------
-
-With an ampersand: http://example.com/?foo=1&bar=2
-
-- In a list?
-- http://example.com/
-- It should.
-
-An e-mail address: nobody@nowhere.net
-
- Blockquoted: http://example.com/
-
-Auto-links should not occur here: ``<http://example.com/>``
-
-::
-
- or here: <http://example.com/>
-
---------------
-
-Images
-======
-
-From “Voyage dans la Lune” by Georges Melies (1902):
-
-.. figure:: lalune.jpg
- :alt: Voyage dans la Lune
-
- lalune
-
-Here is a movie |movie| icon.
-
---------------
-
-Footnotes
-=========
-
-Here is a footnote reference, [1]_ and another. [2]_ This should *not* be a
-footnote reference, because it contains a space.[^my note] Here is an inline
-note. [3]_
-
- Notes can go in quotes. [4]_
-
-1. And in list items. [5]_
-
-This paragraph should not be part of the note, as it is not indented.
-
-.. [1]
- Here is the footnote. It can go anywhere after the footnote reference. It
- need not be placed at the end of the document.
-
-.. [2]
- Here’s the long note. This one contains multiple blocks.
-
- Subsequent blocks are indented to show that they belong to the footnote (as
- with list items).
-
- ::
-
- { <code> }
-
- If you want, you can indent every line, but you can also be lazy and just
- indent the first line of each block.
-
-.. [3]
- This is *easier* to type. Inline notes may contain
- `links <http://google.com>`__ and ``]`` verbatim characters, as well as
- [bracketed text].
-
-.. [4]
- In quote.
-
-.. [5]
- In list.
-
-.. |movie| image:: movie.jpg
diff --git a/tests/writer.rtf b/tests/writer.rtf
deleted file mode 100644
index a79ae6fb5..000000000
--- a/tests/writer.rtf
+++ /dev/null
@@ -1,451 +0,0 @@
-{\rtf1\ansi\deff0{\fonttbl{\f0 \fswiss Helvetica;}{\f1 Courier;}}
-{\colortbl;\red255\green0\blue0;\red0\green0\blue255;}
-\widowctrl\hyphauto
-
-{\pard \qc \f0 \sa180 \li0 \fi0 \b \fs36 Pandoc Test Suite\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 John MacFarlane\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 Anonymous\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 July 17, 2006\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This is a set of tests for pandoc. Most of them are adapted from John Gruber\u8217's markdown test suite.\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Headers\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2 with an {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
-embedded link
-}}}
-\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Level 3 with {\i emphasis}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Level 4\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs20 Level 5\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Level 1\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2 with {\i emphasis}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Level 3\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 with no blank line\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Level 2\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 with no blank line\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Paragraphs\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a regular paragraph.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's one with a bullet. * criminey.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 There should be a hard line break\line here.\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Block Quotes\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 E-mail style:\par}
-{\pard \ql \f0 \sa180 \li720 \fi0 This is a block quote. It is pretty short.\par}
-{\pard \ql \f0 \sa180 \li720 \fi0 Code in a block quote:\par}
-{\pard \ql \f0 \sa180 \li720 \fi0 \f1 sub status \{\line
- print "working";\line
-\}\par}
-{\pard \ql \f0 \sa180 \li720 \fi0 A list:\par}
-{\pard \ql \f0 \sa0 \li1080 \fi-360 1.\tx360\tab item one\par}
-{\pard \ql \f0 \sa0 \li1080 \fi-360 2.\tx360\tab item two\sa180\par}
-{\pard \ql \f0 \sa180 \li720 \fi0 Nested block quotes:\par}
-{\pard \ql \f0 \sa180 \li1440 \fi0 nested\par}
-{\pard \ql \f0 \sa180 \li1440 \fi0 nested\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This should not be a block quote: 2 > 1.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 And a following paragraph.\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Code Blocks\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Code:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 ---- (should be four hyphens)\line
-\line
-sub status \{\line
- print "working";\line
-\}\line
-\line
-this code block is indented by one tab\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 And:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 this code block is indented by two tabs\line
-\line
-These should not be escaped: \\$ \\\\ \\> \\[ \\\{\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Lists\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Unordered\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Asterisks tight:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 1\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 2\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab asterisk 3\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Asterisks loose:\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 1\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 2\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab asterisk 3\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Pluses tight:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 1\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 2\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Plus 3\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Pluses loose:\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 1\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 2\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Plus 3\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Minuses tight:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 1\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 2\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Minus 3\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Minuses loose:\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 1\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 2\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Minus 3\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Ordered\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Tight:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab First\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Second\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 and:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab One\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Two\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Three\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Loose using tabs:\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab First\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Second\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 and using spaces:\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab One\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Two\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Three\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Multiple paragraphs:\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab Item 1, graf one.\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 Item 1. graf two. The quick brown fox jumped over the lazy dog\u8217's back.\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Item 2.\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Item 3.\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Nested\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Tab\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Tab\par}
-{\pard \ql \f0 \sa0 \li1080 \fi-360 \bullet \tx360\tab Tab\sa180\sa180\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's another:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab First\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Second:\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fee\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fie\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Foe\sa180\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Same thing but with paragraphs:\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 1.\tx360\tab First\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 2.\tx360\tab Second:\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fee\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Fie\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 \endash \tx360\tab Foe\sa180\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 3.\tx360\tab Third\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Tabs and spaces\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab this is a list item indented with tabs\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab this is a list item indented with spaces\par}
-{\pard \ql \f0 \sa180 \li720 \fi-360 \endash \tx360\tab this is an example list item indented with tabs\par}
-{\pard \ql \f0 \sa180 \li720 \fi-360 \endash \tx360\tab this is an example list item indented with spaces\sa180\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Fancy list markers\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 (2)\tx360\tab begins with 2\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 (3)\tx360\tab and now 3\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 with a continuation\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 iv.\tx360\tab sublist with roman numerals, starting with 4\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 v.\tx360\tab more items\par}
-{\pard \ql \f0 \sa0 \li1080 \fi-360 (A)\tx360\tab a subsublist\par}
-{\pard \ql \f0 \sa0 \li1080 \fi-360 (B)\tx360\tab a subsublist\sa180\sa180\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Nesting:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 A.\tx360\tab Upper Alpha\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 I.\tx360\tab Upper Roman.\par}
-{\pard \ql \f0 \sa0 \li1080 \fi-360 (6)\tx360\tab Decimal start with 6\par}
-{\pard \ql \f0 \sa0 \li1440 \fi-360 c)\tx360\tab Lower alpha with paren\sa180\sa180\sa180\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Autonumbering:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab Autonumber.\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab More.\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 a.\tx360\tab Nested.\sa180\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Should not be a list item:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 M.A.\u160?2007\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 B. Williams\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Definition Lists\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Tight using spaces:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 red fruit\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 orange fruit\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 yellow fruit\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Tight using tabs:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 red fruit\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 orange fruit\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 yellow fruit\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Loose:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 banana\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 yellow fruit\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Multiple blocks with italics:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 {\i apple}\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 contains seeds, crisp, pleasant to taste\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 {\i orange}\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 \f1 \{ orange code block \}\par}
-{\pard \ql \f0 \sa180 \li1080 \fi0 orange block quote\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Multiple definitions, tight:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 red fruit\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 computer\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 orange fruit\par}
-{\pard \ql \f0 \sa0 \li360 \fi0 bank\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Multiple definitions, loose:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 computer\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 bank\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Blank line after term, indented marker, alternate markers:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 apple\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 red fruit\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 computer\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 orange\par}
-{\pard \ql \f0 \sa180 \li360 \fi0 orange fruit\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 1.\tx360\tab sublist\par}
-{\pard \ql \f0 \sa0 \li720 \fi-360 2.\tx360\tab sublist\sa180\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 HTML Blocks\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Simple block on one line:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 foo\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 And nested without indentation:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 foo\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 bar\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Interpreted markdown in a table:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 This is {\i emphasized}\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 And this is {\b strong}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a simple block:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 foo\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This should be a code block, though:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <div>\line
- foo\line
-</div>\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 As should this:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <div>foo</div>\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Now, nested:\par}
-{\pard \ql \f0 \sa0 \li0 \fi0 foo\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This should just be an HTML comment:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Multiline:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Code block:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <!-- Comment -->\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Just plain comment, with trailing spaces on the line:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Code:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 <hr />\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Hr\u8217's:\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Inline Markup\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This is {\i emphasized}, and so {\i is this}.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This is {\b strong}, and so {\b is this}.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 An {\i {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
-emphasized link
-}}}
-}.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\b {\i This is strong and em.}}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 So is {\b {\i this}} word.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\b {\i This is strong and em.}}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 So is {\b {\i this}} word.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This is code: {\f1 >}, {\f1 $}, {\f1 \\}, {\f1 \\$}, {\f1 <html>}.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\strike This is {\i strikeout}.}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Superscripts: a{\super bc}d a{\super {\i hello}} a{\super hello\u160?there}.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Subscripts: H{\sub 2}O, H{\sub 23}O, H{\sub many\u160?of\u160?them}O.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Smart quotes, ellipses, dashes\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \u8220"Hello,\u8221" said the spider. \u8220"\u8216'Shelob\u8217' is my name.\u8221"\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'A\u8217', \u8216'B\u8217', and \u8216'C\u8217' are letters.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'Oak,\u8217' \u8216'elm,\u8217' and \u8216'beech\u8217' are names of trees. So is \u8216'pine.\u8217'\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \u8216'He said, \u8220"I want to go.\u8221"\u8217' Were you alive in the 70\u8217's?\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here is some quoted \u8216'{\f1 code}\u8217' and a \u8220"{\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
-quoted link
-}}}
-\u8221".\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Some dashes: one\u8212-two \u8212- three\u8212-four \u8212- five.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Dashes between numbers: 5\u8211-7, 255\u8211-66, 1987\u8211-1999.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Ellipses\u8230?and\u8230?and\u8230?.\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 LaTeX\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab \par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab 2\u8197?+\u8197?2\u8196?=\u8196?4\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\i x}\u8196?\u8712?\u8196?{\i y}\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\i \u945?}\u8197?\u8743?\u8197?{\i \u969?}\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab 223\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\i p}-Tree\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Here\u8217's some display math: $$\\frac\{d\}\{dx\}f(x)=\\lim_\{h\\to 0\}\\frac\{f(x+h)-f(x)\}\{h\}$$\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Here\u8217's one that has a line break in it: {\i \u945?}\u8197?+\u8197?{\i \u969?}\u8197?\u215?\u8197?{\i x}{\super 2}.\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 These shouldn\u8217't be math:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab To get the famous equation, write {\f1 $e = mc^2$}.\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab $22,000 is a {\i lot} of money. So is $34,000. (It worked if \u8220"lot\u8221" is emphasized.)\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Shoes ($20) and socks ($5).\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Escaped {\f1 $}: $73 {\i this should be emphasized} 23$.\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a LaTeX table:\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Special Characters\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here is some unicode:\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab I hat: \u206?\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab o umlaut: \u246?\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab section: \u167?\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab set membership: \u8712?\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab copyright: \u169?\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 AT&T has an ampersand in their name.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 AT&T is another way to write it.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This & that.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 4 < 5.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 6 > 5.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Backslash: \\\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Backtick: `\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Asterisk: *\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Underscore: _\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Left brace: \{\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Right brace: \}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Left bracket: [\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Right bracket: ]\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Left paren: (\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Right paren: )\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Greater-than: >\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Hash: #\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Period: .\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Bang: !\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Plus: +\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Minus: -\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Links\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Explicit\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Just a {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-URL
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-URL and title
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-URL and title
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-URL and title
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-URL and title
-}}}
-\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-URL and title
-}}}
-\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/with_underscore"}}{\fldrslt{\ul
-with_underscore
-}}}
-\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "mailto:nobody@nowhere.net"}}{\fldrslt{\ul
-Email link
-}}}
-\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK ""}}{\fldrslt{\ul
-Empty
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Reference\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-bar
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-bar
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-bar
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 With {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-embedded [brackets]
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-b
-}}}
- by itself should be a link.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
-once
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
-twice
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Indented {\field{\*\fldinst{HYPERLINK "/url"}}{\fldrslt{\ul
-thrice
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This should [not][] be a link.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 [not]: /url\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-bar
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-biz
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 With ampersands\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a {\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
-link with an ampersand in the URL
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's a link with an amersand in the link text: {\field{\*\fldinst{HYPERLINK "http://att.com/"}}{\fldrslt{\ul
-AT&T
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's an {\field{\*\fldinst{HYPERLINK "/script?foo=1&bar=2"}}{\fldrslt{\ul
-inline link
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's an {\field{\*\fldinst{HYPERLINK "/script?foo=1&bar=2"}}{\fldrslt{\ul
-inline link in pointy braces
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Autolinks\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 With an ampersand: {\field{\*\fldinst{HYPERLINK "http://example.com/?foo=1&bar=2"}}{\fldrslt{\ul
-http://example.com/?foo=1&bar=2
-}}}
-\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab In a list?\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\field{\*\fldinst{HYPERLINK "http://example.com/"}}{\fldrslt{\ul
-http://example.com/
-}}}
-\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab It should.\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 An e-mail address: {\field{\*\fldinst{HYPERLINK "mailto:nobody@nowhere.net"}}{\fldrslt{\ul
-nobody@nowhere.net
-}}}
-\par}
-{\pard \ql \f0 \sa180 \li720 \fi0 Blockquoted: {\field{\*\fldinst{HYPERLINK "http://example.com/"}}{\fldrslt{\ul
-http://example.com/
-}}}
-\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Auto-links should not occur here: {\f1 <http://example.com/>}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 or here: <http://example.com/>\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Images\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 From \u8220"Voyage dans la Lune\u8221" by Georges Melies (1902):\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\pict\jpegblip\picw250\pich250\picwgoal3000\pichgoal3000\bin ffd8ffe000104a46494600010101007800780000ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a2828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828ffc000110800fa00fa03011100021101031101ffc4001c0000000701010000000000000000000000010203040506070008ffc4003e100002010303020404040502050500030001020300041105122106311322415107617181143291a1234252b1c115f016336272d1082443e1f1265382ffc40017010101010100000000000000000000000000010204ffc4001b11010101010003010000000000000000000001110212213141ffda000c03010002110311003f00dadd18a10a704f6a95ccc57e37750782b0d8d9ea0cd32e7c5446e07e9f4ad723119a7b89e61e348f260719278aad613cbb640002938c76a182b264fc87bd13009c0c019c76e3d68a072e1cf6f4cd502d330c28269a61bb39c923923d4fad44c08dccb95cfd28b8280769ee08a263891e1808739e4f1d8d149392172cc714050dbb9fde8960ed8c60b79b1ed44103b05c331dbdb1dc5026ac1946d20ff8140aa631c773ec738a0346a003bf93e9cf02801895e7b9a01886796c923bd0090a06393c76a0142003ce3d86680d8dd9392303f5341ccc1b3cf7a2c812c37e4923d381429757013209fa511c18146c9247a0f6a007900c0c671c6280854e086c673eb45c27c038fd68aedff2fda836ef881f136f25d5e6b7d1262964aa02b03f98fbf153131935edcc97576f35c33349212cc4f39f7ab26186dfce5b200f73451f7600dcb8cf27e7400c0b291914046c9e0718fde81371b8e7273f4ef4007691919240e714097f31f376e7b5008caee27807b0f5a02c8e1b3c6d27d33cd0201d839523144d1a149ae084b78da47638211771fd050d582c3a0faab5119b6d12f8ab1c06788a0fd4e2ac356fd1fe08754ddccaba849696309e598c9e2103fed1dcfdeadc44fea5ff00a7f956366d375e492403ca935bedcf1eea4ff6ac68a55efc1beb3b552574f8e7009ff933a927ec715bc82b3a8f4d6bba5ca1352d22fe061cf9a0383f71dea5119cc6c0baed3eaac0f1fad40897dcc3d81f7a052366c1007df3400f21edefc5008c28f30c9c5170ee4fc37830086395250a7c66770c18e78da31c0c63de8609b41f7c515c5172a30c3b76344a3e377cb2339cf7a242aea89808cce368272b8c1a2e107c672a49f5c1a181c9c7ae7da8a2119e7b1f5068099ffa68258a132062d8f9e0f34059502b61bf2824e681bb297ced2a71efda80f19c47b9c77fdbe74057c13e539cf3c1a0eeeb9c73f33405ddb4f18249c1e28062b79ae242902024465b9214614649e7bd0362a7249eddc513456e5720f38f5a1a98e96e95d6baa6ebc2d1ad1e65521649bb469f563534d6d7d31f04347d2a2fc5f535db6a0e83718906c887cbbe5a9a8bef44dce9f731ca9a2e89169d6d6f2184b1455dc07b11dcfeb4d16f119c649a681285b03d3e5500f87820ff006a0e098191de80ac9b8904647b55d11da9681a56a31f87a869f6970b8ffe4883629a289aefc16e92d441682da5b098f21ed9f033f353914d19b751fc08d66cc16d12fe2bf45ec92ff0df1fdbfb559ec667aff4eeb1a04db359d3ae6d40eccebe53f46ec7f5ab82263da7dcf3eb5174e5181076918c7de869503232491ee4515c1803824f03b51287f30e0e7d803449494832c157278a2e8c71fcb9f9d144639236824d01e142efb1768cfb9c7ef40512a818de78ff00a682518e7cc30ab9e00a02cce9953247bd41e467191ed9a04205ee99da4e4e3d283a524b0427b5026c18a8e082067db8341ce0e39ed409b6502907391edda80f2dfdc496f0c124ac6184b144cf0a4e338fd2894f7a7342d4ba9b568f4fd261f12571966270a8bfd47d8511bae85f02b47b7fc34bac5d5c5dc88a0c90ab6c8d9bedce3ef4d1ad691a6dae976a96d616d15b409f9638d70054a1dbc68ea51d4329f4619a8022b78e04548515117b05000a035c5c4702a995c26e3819f534047bcb68a458cce866719540724d02e41c0f7a012a40f6141cbc8e7bd01719e38e6838af1c0a04ca8206d3cd037bdb082fad9e0bd8a39e0718649141047d0d5d18f759fc0cd3af164b8e9999acae4e4f81236e898f7c0f55fed574615aee83a96817ef67abda3db4ebdb7f66f983d88a061bb8db9e3d45165076db83c1f950a53780d8247c80a2398f182724f1c7ad080c608cfa7a51a0062adc7afbd0130173bb9c5070f071cb37e82826106e8f615e01c9e680d6b35bc534be3c1e3831b2aa962bb188f2b71df1de819ae4b1048c7f57bd01a58268e332642ae0704f7cf6207af6a01b99e17b7b6416e227407c494139909ed9f4c0a04a4e501e0f1eb40d263e53dce7fa682c9d0bd13abf58dd6db18bc2b157c4975270ab8ef8f563f21447a73a03a1f4de8eb031582b497328066b97fcd21ff038edfde88b7e32703bd64188e7e6283864b73400cd804b67ca3268317eacea6d56ff005233592f8b6303f953fa4af7c2fa93417fe98b763e0ea171297bab98558068f695ce0e08fdbd281e5c6a57ba5e9d14d716ef7774f2ec112601da4f27ec2827ada74bab559a20e148fcae36b0f91140283729c77a0e0a7777a01dac68395719e39a029607cb901b19c501480ab9279f4a086ea8d0b48d76c0586b7143224a76c61ce1831fe93e86b43cd1f12fe19ea7d2533dcdbeebcd20b612651e68f9ece3fcf6fa5067cbcf20ff009a051724905411e94032799060723da8406d6c67e7ea68d0e1770fe5cfb5026c37039ef9a02eca098c91e6e01e71c500b1d8a49c12786cf6a06a4e256008e3d050119958007920e2801154e32fb4120927b014017eb1c523ac5209a356215c291b87be28957ef853f0d66eaa99352d515e1d190f947669ce7b0ffa7e74a8f4be996569a5d9c56b6704705b46bb5238d42851f2ac875712bc70b3c30f892019540704d01ad2669a0491936330c95ce7140b2e4939a03638c7e8680ae485e33bbe540d60d3ada162c90a02c7270a39340a4f28b68da4645007a8f6a069a746f73235ddcefc391e12b2e1916824948742c99382473c73404791c617695279dc0640f9502c578c9efeb4095cb4cb0830ba21cf999c6401f4f5a05061d430c8079a02e03b3004311c7d281b5e3cd676c65489ee594e4aafe6c7ae07a9a0a075bbea3a8ea96f047d3935ebc404f04ad29411e08e011d98fed416fd212ee5b05b4d5ad6300c615807f1171eaa49eff5ad418c7c55f8466dd66d57a521f20cbcd66a7247a9283dbe5418a63862479877cf1f6c5008e400bdf1ce684016fe53dfbd1a73794600e08ce3d6800377c8c7d6800a9cf75fd4503d91492460f7ee3d28247a7b459f5fd592d22711c206f9e563858a31f99cfd050583518ba75247b1d134f9aed21396d4669769931dc01c003f7a329c4d17458ac5b55d36c12e040a3f1da75c1cb04ede2447f7f6a94567ad7a66db4fbbb29ba7d65b8b4bd8ccd09c8231eaa07b8ab04a7c2cf87b3f53ea8d77abc72c1a5dabe2452bb5a561fc83e5ee7e541e988218ed2dd22b7855228d76a46a00000ec00a510bd4dd511f4fe84da95cc31f880022da4902b1e7d3e99ac86fd03d631f565b4ee6d4dbbc649009cab2e48c83f514165b8b94b6895c44f279c280839e78ce28178ae6de46748a789e453865570483ec6812d42e85a421fc37918b00a883924d024c6e99b7a2a966c0009e17dc9f9fed40f81c77e28139218e4ff9815b9cf23340a01c907b9140201038ed402fcafd28386464e4fd33c50272bc60032609cf00fbd024f722dc66f24822ddf972f8feff00e280f69b24844919cac9ce7de83a447f30ded823007b50459d6ecacb528349b979127651b1dc795f1f3f7a0990148054823dc5015d491c0a0c3be337c2ff00c489b5ee9c87172016b9b541c49ff5a8f7f71eb560c1fc43e0a47e1aa94277310431f91fa551c1727f29ed409b641c86e31839a3454805739c1f6a026f1fd740f64665fc8c31cfde82db79bb40e9e8f49b62eb7d7e8b717ec832c91ff247fa1dc7df2281bcc9369d671493c422b7911654c1215f92bb8827bf068624ba635392df5eb4b9924558ee5bc19b71cee43c6dc7cf34c657be8db0b0b9d0f51d2afe668934dbf9628ddb8c2b8c0073f3a80da37546a7d25174fd95dc125c69f7313ee5655dfc313bd483cf07b1f6a68d5b48d5ec758b612e9d7293211c8fe653f35ee2a084eb9e8bb1eafb3582fe496278f3e1c919fcb9f97ad03ee8dd017a6741b6d3229dae161057c5750a48249ec3eb4139238568f6a9e7b103b5037934cb3793c610a2cd9277a8da73f5140ee38f6280c4b11c65b934023006d50050030e4647de80c846de3b500fcf9fbd0197273ed4007b91400e580c8e45074a82400e72682b36fd2162b7f25ddc09af2766ceeb872db79cf00f6a0b3229550140e07007a50092db860673de818df473c862686dad6470d9cce3b7b63e740fa1de6252ebb5bd81cd00bee2d800d003a6464004763ce683ce9f1cbe1f1d3a67ea1d1a30b68edffba814708c7f9c63d0fafceaca31e6dc71e1f07daa82608c83819f7a1a11ce149238fd68d0a579ec682cfd27a7c3a86bd10bc38b3b756b8b93c1fe1a8c91f7381f7a034f752ea5aa5c5eb292f732128037619c018f6ec282e5a2cb047abda74d5ce9b6da80f136de4a496219b3e48c92000323ea73467519d3da5bb757dbda410ac90c77c23058f99007ee7ec31416882ee47d23acb5185caf8bab4691b1efe57fff0038a9457ee75a82f6e7429350466b482f2742c0f74241c80c38c64541a9cfa1e89ac0177d33ab3d8de28f2b5bca429f91140e2c7a9b5ae9fb85b6ea9b46b9b3c796fe040768f76ec0fafb1f9505df4ebdb3d4edd6e74db98ee216fe68ce47d280648f75e2485a44da385ddc13f4a025ddbdbea16a633286566ce55f9c8f6c502ad750db2c514f30dec428247e6340bbf04100b73402afb943ed2b9e30683836defe9403bc1e06734020e06280cafe8683a375941d841c77c1a0151b467b50159f00e4127e5402872371040c5046eb5aadbe9b1c02e2f6dad25b89047099c677b7b0140fe3f1010afc803f3018e68160c3041ee2823f5dba92d34db89a1d9e2843b03b6d05bd013560c1748d57aa2797c6b35bab78e6959dc47231580ff336dcfb03c1a58364b5bbb7d7fa7b7427f1f673830c8664285bd1815238fad20f2c7c41e979ba43aa2e2c1cb1b663bede438f3a13c7dc76fb5515e9065b851f7a02950002a09c51a1b83cf14176e90d3645e9ad7752752aac23b3439c066665c827e944d29a6410aea725c4567135bd840d3c88a723728c29c9efe6c50d3ee9545b0bf8ef2e6e3c2fc2c6f72f2920e5f19039ee4938a9a875d03278377acf52ddf867f036ef71923932bfe51fbd3475cdc369df0db4fb389d4ea37970fa9cc0b00511795ce7d4f181eb4cd2451755fc45ac16d637381b14ca36b641dfce723e4053170d6cb52bbb362f6d3cb19241f2b9029862f09f143549ba7e7d2eef6caf2797c66ee17fdfd69862d1a069da7dfdac579d17adcda5ea9e1a992376c4723e39e3b024fd7e94c458ac3e25dee8d31d3bae74e7b79002bf8b8549471db38f5f4ed4c165e943a06a328d4ba605b4b22a1523c420c64fbaf38a82d36f0ce7cf7463790729b53017e940e0b0ceceed8ce0500e1b70daa08f5c9ed41d271cd0132476e7d7ff00aa069797d2411168ed9a41fcc858211f73c5075acb25ca6fb82aa31e58a36c81f561dcd033d42169e158ac64b98151b3981c2966cf639f4a064c7a8ac55e4865b7d493701e1c8e52403ea3cbfda827e390ca3f2c914aa81991bd281cdacc2747215c60e0ee5c67e940cb51b0b2bcbd824bfb08ee1a252d1caea1821cfa67b1fa504982b2283ce08f518a08abb82f6dd0369a5662081e14ce40c7ae1b04fda82275cb0bfd4f4536f7114589a5412461f3e4ce4e0e060f63f6ab2893d3b4b5b5b78e22ed22aae3cc3cc7e64fad3449a22a461500007602a0cd7e3b74c26b5d2ad79147baf34eccca40e4a7f30ff3f6aba3cd0543267eb5427b86f1f4c76ef45d0eca1ad5ef224d13e1cf4fd9b22192fa67bc955f8c8c617fba9fb510d7a6ed3fd43a735e5b54964be658c048fb6cdd9e7eb8a186bac97d174e6d22e23437b7ac26b95e77c68bf950fa7279e2b22dba45b59e97a669fa4ea36aeff89cea9a90451fc355ff0096ad9f4ce3f41570675d4fa8c77da8de5cde5be26bc653171ca47dc1f6c9fed5562b97f70276808da7c24f0c1c63804e33fa8a2928c0e0383c8f7ed41d92a41393f4a2548595c2c37493db4cd04e8a08f139566edfef3445b6e7aeaf65d2df48ea2b11776ae02a93e564c772adef409f4ee8ba9a21d73a36fa579ad9f325afe599171ed9c30a960d5ba0fe2843abb47a6f510fc26a4c36890f9558fcc6783506a1147b510024e30339ce680d2c6ae9861eb9a009178a0205443b989e39cd01d8075e3047ce80563057ca381ed4011c4531e503d85013c91b804a21279c903341131cda8c3abdc8650f6d20c4321232adec3dc504bab2c113c9293bb1963df3408dd4b75e1efb2856463dbc43b4631fad047e9177ad4fe32ea16b1db4b8fe1aa92571f5f5a0916bc8e0895af5c46c17cd8c9ff7da80f6d736f7f6915c59cab35bc837238ed8a072a31c1ef4062870718a06f7702dc5b3c522ee4752ae0fa8230683c75d6ba3b74ef535fe984929149e4278ca9e47edfdab42058003763ed409f88ffd6dfad06b1f12ae612fa0c76e0b471e9916d23f973eb4158d3efeff004a984da5debc1295d8e4018dbf3145d583a2ad96f356bbd7f5d90dc59587f1e79a6392f28fcaa3ee47159444ea3aa5ddfc7acf50dcdc344d7a4dbc317f52641200f6000fdeb41b5ef51d8eab672ffa9e971c97c11638268e431a46000012a3b9a351567db823b11f3ef40948e428048207a8340ab48ae83cb83ee0f3428a982719edf3e68c9cc97d3fe15ad8c9be138f2bf38e7b8f6ef40f7a5f55bdd3f56b46d3649127f1405f08e7249c76f5fa50689d48ba5f545cdcbdb462cba9206411b2b055bb07d4fb1c73528d4fa8f52d62cf47b6b8d2e65fc458c49f8a818795c151939f977a823ba0fe253750eb7fe937b04293f9f6c90be41dbdc7ff006283473c1efc1a06f69776d73bbf0f2aca32572bc80470450284a46dfca19f819f5a04e799614def26c0bdce09cfd85045dc75769d12dc3c3e2491db0dd3c85195235f7c91cfd066ae0cdba9be31f4ec61a386c1ef9d4ee473e45cfb1cf34c101d3ff1ac9d481d46c628ed24751881880833f988e7b0fa5328dfed2f2def2ce2b9b79925b791772ca87208f7a60182ee2b95cc0c48f53823fbd40ac658b30f4f4a086d4ee1d75bb6b78f4e965596366fc5211b23238008fde81f43692da5bc30d97831a0397dc09e3d714087506bf61a2c4cd77324726d2caaec141f9fd2ae0c435bf8c57173ad7876f7a2daca10489121244cdf319ce3dbf5a834fe81f881a6f57bcb6ba7c53c72c11873e28cee1db391dbef4199ff00ea4348116a5a66a8a8a04aad04847a90723f6ad7d18c312ddc02a3815423ba0f63fa541687bd9efe1b533b3c9e0a78473e899e318a09bd0ba6eef543e3b2bd8e9b10064bd9e4da001dc81401aeeb29a984d0ba7d5e1d06d4e6594f06523bc8e7f5c0ac8af752dfc17d7090d9218ec6d9447129ee71fcc4fb9cd6842ab10dc0014f3e5a2c1704b671dfdc734525226dc939e283a362c7f940344a380393df144733e2276e38f5efcd01b4bbbfc3dda4a9298a44395902e4a9c70682660d4265d62de40b1bdc1545054f95c8fe627df141af7c3af8808f3dd68dd5d2a45765884b8908d8c3b6c27b7a77a945d7a5fa474bd2ba8e4d5748b28624955d5d8b13b79ee9e983d8d40a753758c7a46b96f6114725dc92279a2810b3a64f94900763cfafa503fd3b59b79ed84da34713c0cd890f0a158fa1f981de826e1b548959fc4dc5cee24b6467e59ed4101ff19e9f676baa5d6a72c50adb4ad1ac790ccc076200f7ad41e7df881d79a87576a5f87b0f161d381db1c2a36e7e6d8ff3416bf87ff082c6f208ef7a82f22b9761bd6d619785f6dc477fa53705ab57f83bd297ceb1e9caf67708db9c4526723e849e3e94f212dd25d117fd29a8c09a76b534fa39cf8b6b71ced38e36fb73417f52e64548e34007e673e9f21ef590a1c918c90718dc281a69b68f67118d9da5058b798f6fa7fe280daadd1b2d36eae70710c4d263df0a4d583cc7a668fd4bf11b5837d7c93dcd9a3146959822a0e781f4cfa55161e9dd7fa67a4f55b9e9aea3e9f81fc09ca0ba118998fcdb2338c7b528d39f4cd2ba76e2d357d292df4eb391809963420ce1b1b576fa1e7359119f1eb4e17dd033ca172d6b2a4df303383fdeb5c8f2eef3bce4e0e335684cb0c9f354160d36f64b0baf16072b91b5f03391f43c51aab23a5debe91c4fad4d73689e6fc3a290573ff4f03e59f4a3280d67581ce916567f84b58ce0a1fccec3d58fa9a084de08c90464e4d1a8e419059b201f4a05630a176918efc50176293872c17bf14042aa0125b03db14046c60b60123fde6827fa0c68edd5365ff11346ba6292ee64194240c807e59a32b7fc51bfe8bd5ed5db424860beb62b89218422ce09c11c01dbbd0660ae110bf1bf2154838dbebfefeb41a8f4cdac7f117458f4d9ecd2df53b4cf81a822808c47255c0f7c8e7fb54a2ec2cfabba3b4b4b8d3af12eedad40926b0f070a13f9b633649f7a82eba6ea4357d321d4ecad512daf20df26e016507fa4fbfaf3e98f9d067dd2bd2faac9aa4d72d72d1e9510ca46a7631c7a320e18f1dfd7bd059afb7da816d23de4ba5de211346a1e4785f190548e4648c63b64e6b43ce9d5baafe3b539c5b452dbda46c638a167cb281c73ee4ff9340e3a3fa5f5aea4ba58f4bb57dbfcf2b02a8bf7f7a0de3a5fa0b50d2a2d92eb3e048c0a97c867dbedcf6a944e5cf4f6b76d1b3d8ea42795066266c87c81c65b9cfaf15048e83af3cd64abac08edaf01546c38dae4e0657ee6826e5b892de3702292e2545ddb55700fd0fbfca81c4b3bc718716eef9eeaa402280d14ab3c0b2c65c06fe571823ed40df56b217fa6dd5ab9216689a33f2c8c558307e83b8d77a37aaa7d22f2512c28768800c9954671b3d33ebef568d0ef7a7749eb0b5bbbb162d657b32b46d2e1564c8ed9c5644d1b0b9bbd261d2a440af6cb0e2e5b1e7dbc1238e0f7a0375b696daa7496a3a4dac8a92cf078685b271db04d391e40d5ec4586a1716de2a49e0c8c85d3b120f715ba1899173ff305413070abd89cfe9f5a2d3ee9c8639fa874eb6b804c52dc46b20c9f302c3bd11e84d47e1af4d5dc6521d3e3b662c19a58721ff5a9a321f89bd27a374b456d158dccd34d333332c9b4b2afbe47a7cb1f7aa33d2bc0d8c0f1c8f6a2c14b6d501b39cf63450897380c319e3de8065031c038f7ed40d8faf1ce41e4d004876a8dc3cc7e743025c956c818028c904579e7f0e15695c9c0541924f6c00283d0bf07f42d6b48820b8d62d20b2b58d656404959e52f83c8ff00fcfafbd4a35bb06f12391a48dd55cee2b2f3818ed8f6a8158a159890f02242079147623e631c502b0db436d1ecb7458d4738038fb0a087d6eeb508f48bb7d32d95750752b6c26c905b3ddb6f61eb574794f5cb6b9d0fa9678b512b25d24bbe52b8c1638278fbd582c57ff12afaed45b5bc0d0d8a8c08a2731ee3eec5793f40450466a1d59af446293c186cd53ca0c36eab93dc649e49fbd048e89f1675ed35e301e293919dcbf9867b37cbe94a35fe94ea4d33aba6824306dc48015750d86c6e247b0cf63591a40b8dc23fc30f14138dcac3000f9d03687547f12e8dd5af816b13148dddbcd29039c0f6f6f7a0eb5d62caf5636825db70c9bc4328f0dc0271c8a090627d3073ce681acf6505ccf14d35bc2f2c2731bb28254fb8a075144a83ca806792400334049ee6281e2496408656d880ff0031f61fa50446bd76058ea1b9e21025a3bb48afe71df9c7b71de9c8f196a0de23ca7b827d4f7add117e0cbfd4b5059392369663ff004e71c51aa97e8f555eadd258f2bf8a889cff00dc28cbd0bf123a926e96d163bdb74490bca2321c678209ff001591e71eafd7a7d7ef45cde2c20aae144638033fb9ad2e1b5e69d058da431ccf21d4a5c3b4631b62523807feaf5c7a50222f2d648c25f5aeec8c2cd19dae3d3e87e944d3eb7e90d425b49ef2292de38224f1505c3f8724a9eeaa7bd0d57a60406059436306868a7803839c7ad1a158039c13f4a33a716767f8cb9b6b55e1ae2458813e9938cd07a9f42d0b4de99b4b7d1f41b58ff19b03c93ba06607fa8b1f5f619a5b8266d74a65d42da6ba90cce996dcdc8c9fff006a5a2c2635083b05ef83eb5028076341db4b1ed9f7a04651fc41db18ed419d75b744dbea335fcb0db0335f2057901c05da73c8f9d5d18a75174a3f4c47335e35da4ce418a489374254f707d463d33565d1529b569a489a17944b06ec8057d71dcd037b4b6b8bfba31584124b27e62a8a4f1ea68357f83da7ea5a76bfe0912453ccabb49194653cb60f6ce3dfda983d196cd108c2401711f9768e306b2297d73fc6d02773a8b591922693c5004bb9d72542fa2f6efde8314ff867aeeec27500b77bb5670e36ca19b1dff2e7f2fd2837ce8bd5dd348b78b552219022870d9c46e792a4f6c608a0b846c8e03232b29ec41cd0199f1410fd4b24b1e8f712c0a5e4452d851e6c639dbf3238a0afa42ba77475e4ba8470896681da45180b18da76af3c9029c8f26dc1df2b9c606e273e86b743331924f27f4a82c12280e59b008e79f6a2d4d74188ff00e30d203a82ad7519c1ff00b860d11ba7c5e86c9fa3afae6f4091e043e021270b21e01c7dcd6479ab4dd3aeb56be4b7b184cf2b301b57d07bfd2b4bad0fe25e9f6960ba7c7a55ac50cd750335ccaade7723b83b8f6e38a2207a5ba4e7ea3d93780cb616ca53781f99fbff009a0b675a5be9765d43a75a6ad3b25adb4185429b831c70303dfdfd2831eb8954ca48f3827819c71ed406b2b1b9bf9a5fc1c4ce2253238047957dc9345d122b792eee522811a495ce1157b93ed444ff0049f476b1aaf51c761345269d25be269259570c833c6077249e062a68f53e8ef0da69509d4ae225b92a04af232ab16f98cf1f4a5a266d4dbca8af13a329ecca723f51502d14f0cb9f05d1c8ee01c91f6a0393b4edfe63c8a031608859b38f97340d84d04e5846eae50f9829ce3eb400fb24466041f5e3d2823f56d22db57b192d6e61468a41c823ff0035651916bbf04ada7badda5cad6d1b72c09dc33f2a6875d25f0865d06fe2bc6d4c4d3282026cca8cfafcfd29a34cd234a10c768f711a78f1bb392a3001208e3ec69a26a58d640c832091c90706a084ea1d3eeafdadf4f86da3166c0b4b397c18f046140f5ce4d04f4702436e91c28a9122e028ed8a0a9f5a5b6a09a1bc5a135bc72cce048b3c5bc15c638f9d59043fc2db997481aa69dae49e1cb6bb643239211939e467818f97bd305965ebce9a10bc8da9dbaa2679dd9ce3d8530572cfac87566ab05ae9f1490692b9696e1f833738555f96793504df5f25945d2576b7ec16dc46792381c7b7ad5e60f234980e42f6c9c56a82ec3eff00bd4124e49700f1c646e3cd169ce9575f83d52cee324347323f6e3861ff008a23d47d4ba6a75074fdcd8ef317e2e2ff0098bdd4706a60c3f4ae8cd5f44eb8fc3e97248a638cbc73bf90483d463b373e9574685abf42a6b5649fea72bbdeac4a8d3b018cfae31f7a6895b6b29b41d30d8e9f6bbed9213e1b7a994e724fcbb5064bd7835a9752d3af75d8116354778f660788cbd9483dbb0a0cd20b2b8d43528ad2088bdcccf854039cff00e2827a0d34e9da1de896f2182492efc0976f998aa827d3d334113a74aa9a9298628e74570478bc0c7cf1da83724bb8246d3e6416b0384da61b5501c9f5c3704f152c037561a95f5fce61d3ad6db4ab950f34b331dd9f4191db8fdcd406d67a675ab4b6d325d1af248272a43430315ddec7038f6ad4b3f448bf47eb71cb69abddebf21d5e26896203846c30c8603b9c6452d9835901405660376319ac84bf13180779d8bb82827d4fb0a06f777367a75acd7170f1430a9f331200cfceae061a0cf6dac692d7365266191db0578f5edf3a6075a6c9278b3433188a467860d96fbd40fe540471409aa0c1140750001ed8ed4058e15133c983960077edf6a06faade5c5b7822d2d926766cb967da2341dd8f0727d85033d27597d62e2ee3163756915bbf8799d71e2f19dcbf2a092b88dd9a311950a0e5b70ce47fe6ac18af53f5b69da9752dd69da9ca906876e24465d9e69881c6ff005c679c0aa2bfd267a347512c93dbb5d42d90d3c800b68c9ce0ec3cfa528db74ad034db5905ee8be1ac728dc153984f3f980f4fb56453be2de8f647a6aff53796596f0aed46798ec033ce149c0fb0ad71479c9bb9dc3bf3c55a0b95f65a825150b481a407b93c0fda8a29c06671dc93803bd131eafd0af6dffe18d2ee25982a4b04603b7a9c631fad03bbe586381bc5945b96385718c827db3eb5288eb8ba934eb15fc3c535f05427796dcccdec7150637d5bd55d5362b7975aa4d0d919018adec8637807bb60723000e4f7cd58203538aefa8aeb478a7b9beba924547b8774cf8608036a80704639cf1f9855d1a7f4c68b67a03de5e5d59dad8d988c62e1c0f107a1e7fdf7a082ea6d07a6e3e99375a7cb6b3db093c727701e2360f7f53dfb50653d4130d42ee18f48b3f0232a15218936963ebf5fbd06dbf0cfa74855b9d46e04b730c6144691e12307d33ea7de8348ba6b5478a279a004f98c479247b81f5a9438805ac0be2e02e73c9ef8fbd40c2346d43578eefc40da7da1dc8b8eefea4fcb9fef419beabf12a4bcebcb2d2fa7ee0dc58492084b30236bb6467dce383f6a0b87556a67a7f4d95a0bbb5468816f0a69c78b2e072572719ce78357079dfab3af2e7a92c963b88d94abbbf91cedc93edf418aa2c5f0dbe2a6a9a0c90d8de34773a6a8da1186d6403fa48fec682d9adeb7a9b4c9d572dacc9a6c9700456e5ca910e000ecbd8e580352fb1ae7476bd6dd49a325e5a9f3025245fe961dea097523cc0919a032af039a006936c81423104649c703ef40dcce64bc3035a87b6f0c378f9fe7cf2b8fdf340a4b6e25962915d94a67807839f7a043586922b5636ec44c061063f31f6ab079d7fe19b7eb2d4efeef55d5d74f992e9a0fc3a441dcb13927b838c9aa2d4bf042c618e178efee6e18104870172318edf5c1e6945bbe1a748ea7d2315edbea3a99bcb190030c401010e4e783ee0fa56455be3d6b90c1a6268d69e17f1486900ee98ec29ccc183119419e7e55ba11f089f523ef5058363a8059fb8e31e9421b491056c01819e28d3d0ff07eea3d53a1e3b6b8db235aca63c139c0eea68ca47a9fa6ef757b83ff00bf68ad428c2f248c7a8f9fcea518df516adac74e7544f63a2ea172f1800291e6cee19ec78cd5826344e85b6bad25ba8fade5b99dae0ee11efc71e858f7e7d054a2d7d39a75ae8f7b6b00b8917f1516624b78429da327cec493db1db1d8540cf4aea28f58d6aeae2f6dd64b498082d880488d149fcea7d4939ab04175e6850a8d32de3b78e380c8de32c4db4e18e430fef543cf86fd0d691b4fabdf6648b3b2db69ce7dd87be68342d2f4fb9b5b891af1a28a2dc05bc5036d001e0eef7352884b961a2ea9aa7555c885e08d45b5bc52b61b686c120fb939fb541276bd4b61d53624d942e2f6200bc32290633e99f4233416dd3ad3f0d611c0c77b632e71dc9ef41156dd27a45addcb3dbd9c513b1dd941821bdc7b558333b9f873757fd69a85e3f813e9c7723b5d93265d872473c11544a68ff08fa75e290b42ec4e4124e70738fa5048e89f0f745d2aeadd2decedda6525c975121183c77f7a945c754d0e0d563682ed43425369403bff00bcd58308ba7d5fe13f5a05889974a9d8b46aede4914f707d88ff001528ddf4fd7edb54d1a1d56c312dab2e64dbc9418e78f5c541296d70b716d1cd6f8789977230ecc280cb7519b816f212b205de4e0843ce300f6cfcb39a0545c42cee88e0b458ddec33ee680eac92266360debc7b5056fad2d354b9b189745744be121daf27e550548ce3d4d58324d07a725e98ea2b7ff5381f5169a7579d021fe13904ee43ddfbe49038ab46e76cf05cc714f6d309232a4a98ce54fd6b2196bb7f2e9b631b2c427b891b6851db3eff002007341e5bf887aa2ea3d4f77378be381e42fdb711ed5a1554395caf1cd07617dcd04fc85402101da791421b49920331381c60d1a69bf02f56f03a925b12c162b98c955f775e47df19a32d99b518268e4491668704a79d4aeec7b7bd4a30feb7e9144d76e265697c3e2693631674273803e556087d76f35fd49859e9925ccf611141106f2e182e3241f727f5a94681a268f79ad1b1b8b9dd66b1c2b1ce9bb06361c1e7bf3fe6a096b0d3ba57488e485b52b40909c386901607d47bf7a0ae758eb69ac4d15be81a748f0a9c35cc90b2eff4c03c1c638a0b77405c5d5d45f87be5fe359a88b81b401dc1c7d38fb50586fed18ea3015790091591e447c1518c8c7a0a0a5754d8c9d49a8d9f4ee9dba0b3b5224b9692327728f627e7c6682f9a7e996b6b3a8b6b748a348820c7720761412c064e3041ce282b5d4bd73d3bd3f33daea97ac2e540dd0a292dc8cd043c1f15ba2a7923b65bb910371b9a12141f9d02edf13ba2ade56857551e5e77244c54fd0e280746ebfe99bbbd655d56dcdc9ce08465565f4ee3bfca82d53eb3a6dac3e25c5f5ba646402e33fa77a0aff5b74ad8757e9ca972844aa37c520fcca7d3f5ab067bd369a8f467544d626c98e9f7118f0200e4465c903049c8c9e6ad1b24334b6fa6249716cab20037c309dd83db03b5640dddac3764a4f02cb1103863919fa7a1a06d6f600c37162911b7b252b87dc773f1927393f4a079f868edae1ae6328a8b1ed38e30050226e85d5dc1f879011b3c47c2f604719f9d01eff4f4b83e3c6b18bb452b1cac9b8a83de80b16e8208a3b7b58e1407cc061427cc0ff1560ce7a8f592d69a97504cad2dac01a2b53900c3e9e51ea58f727d0551e73bfb86b99a49a46dcf21c96340dc13804f20f6f9501c0e3b8a0963316fcc4607007f57bd084d64dec01200ce483468ff0040d525d1755b4d4206ff0095207c11dc67ff0019a18f56584f6daad9dade4211e39104a8ded9152b235cd8c530613229c8c1c8ef50472e81690ee00322b0c100f0debdbb7ca8111ace856371358cba85aa5cc407891ccf83f2ef4048b4ad2e59bf116769672c72f99dd1437239078e2824a4d3e1b94559234110e781839fa0a0561b38ad532a12319c86c6307e740a9732a3a00cac870cd8e0faf0681be8b6db965bb909df3c85806eeabced5a09523647e6e0fef419a6adf116daf7ac34be9dd1da686e7f1ca2e243b76320ce57df9ff1560cc3e3f470ff00c78255b842b35bc6c4af9b6e323d3e95467b6365f8dbcf062beb68c119595d8aaff6e282422e9899b4f6bb5d46cda2562a76316c1078f4a0859e1b9b762c0bf94f0e84feb4125a57505c58ea70dd5d0174a986d92b1c13f6f5a0de7a5be366877260b5d42dee2d2423124a487507ebdf15289dd3fac7a7bab6feded74d61733473acdb5a162142ff00313d81ed505fa58fc6d809380c1b9f5c502e0e05040ea367a85dea454de2ff00a610375b04c16c7a16ef8340b5f6930dce9375636acf6a278f04c5dd4f1dbf4a084e91d06f3a52dee62bbd4a2b882494ced3c8a448063b63b638fde803ab7ae749b2b3096d792c93c8c109b55dcd18ce3710473ffdd043dc758dc5869044565aa5dda4c3c2b7bc78c1f14e3963db03e7c0ab066bf1327d41ba76ca6bc48ecad24c456f6b0c87cf8e4bbfa138c0fa9aa3297c83dd4e28395811cf2680a5b93c7ed413cd1ff0f3c797b8031406645236b0508406f30e68ba49c051b97d0e0e7d28ad57e19f575c5be8f269515dac772877c11bc464dea7ba8c739ce78f9d3193bb8ebfea2bcbd6b5b6b8b58bb7f13c2f0ce31cf0deb4c0f2dbad6d743d2ee99efae752d6c02a86e0054524f6383c7ff94c0b6af274c75149a46a5a82c46f1e1479fc3190bd8156fbe7f4a960bf74e9d253f1167a3ac09e0856610e3041ec7f6c540f67b892cee7f8d18368232ef2af2508c7047cf340ead5bf130accc9b1186541e723d09ffc5033bbb1b82d74d6b37f1244daa1b38073df3f4a08eeb1d3b50d4fa6a5b4d32f12cef1902ee73e523d476fde8306eb0d3fabfa4ba92c278af67bb7281606472f90bdd58558253a6afb40ea1d62283a8b461a66a6f931cf6a7c2466f7cfb939e7b5515fbed3747b5eb8f06eb78d35080a2ec9719c76f98049a0b4ebdd37d1bad869acbf0b03c5c16b29444adf50ded41995f68564a263a66b31cd02be152505493f51c1a088bab69ad1bc179e320f07c37c8a0692b46c4995f0381db39a0b2fc34e971d57d4705bc8db6c50ef9dd97b81fcbf7381528f5ae97a1d8e996d1db69b0c7648855b10a81b80f43c739c54134147b9a036063279fb5046e957726a0f2cfe04915b06db1788305ffeac7a0a00d72f8d9c491c06337533050ac7185cf2df6a06da2da4293488f34973328c34aea428c9ec3eded40ee7d2ad249448f6b133820ee2833df3fde819ea96897461b05b87815f2ee919e5d47704fa039ab079b3e326b70eafd4ef6d6650d8e9ebf868b69c8247723efebf2aa280eb9193ebedc5002a124e015340018fb8fde82cf32b1603d0678cd02406dce3008e47ce81b499c331383c9c9f5a2e9c69377369f7d6f796a4acf148acb83fb511e91b3b3d0bab745b7d45acedd8e3732b71b1fd73f7a5a19eafd09a56a0a96b1c705b49c48510761ce4fcfbd4d0d752826b2b583476fc3daacb295b79d768de8a32b1e71f989e49f6a7d14dd1af5ba275a45b8b093c054492ea769092373765c1da4679fbd306e36ba9595fe9f0dcdbcc92c33e1579cf27d0d409ea178f68521b6b76926ee8a7853f7ff140bc768d78f6f73748d1cd103b543f0091cf6efc502f7319dac194371d8b6326829f0c501d7ae6fa568d5d4942c806d4db81839f53c8cd59456fae6e628749b5bab8b1865b08e4726588ec11e7f2e49071c93da9a31dd4341d675e9a5bad374f9858162d0b4ac70e18f0573df35a0c759f87bd53a404f174f965dfff00f479b1ef570576e34bd4b4cc0bdb3b9b7258a00e846e3f2a94376475cee4914af7ca9150685f09ba61efb52fc7dd69bf8eb7c158d1d0b47bb38f37efde968d6eeb4eb5e91d6ad25b660aee59974db6881690918e31ce39279e062a5a34bb57b88adedd1e379679065d80036679e6a07e8391bce7e940c659ef5afe1286de3b16f2b8903094b7b2fa7ce81eb380c4260ed193f2a0cd6fa5d4a4ea0fc7bdadcce923158a3039db83c038e3ef41a0e96b2ad8a35e009291b8a939d9f227e43bd590436bbd6fa269202c974b7123602c76e779624e00e29833bf897d493e896525dbcb2a6b5a9c3e1456b91b6d60cf989c7f31f7a60c02490961ebcf3eb541308e39e067b507007b96007a67fb50178f97eb4165ce18165c2927b773fad023202d9c8dbb7818ff003408300b87f2f1c107d0d0c15a4f2e339c90467f6a18bdfc2cea8ff4bd561b4b9ba686d6e64552c4f954e7d7e46a60f4688d240af1b2bc6cbf5047ca960617ba658de1b792f2d94a5ab33461b18524633fa1a81b5c8b5168967369d23c0e0a24622dc981d81c76aba29df0bb48d660d52fceb88d069f04aeb69130037127f37b9c0ed9a8350781240bbc06da72323b1f7a0eb8816e633192ebc8c9472a78fa50349b4c83c068e24f0ddbcc1c13b837be4d055b57e98b996d4db5b4a893dc1e6620b6ccf2c467efc504ce97a38d3f4d874bf09af6d46e2f25cb82724e791db15650a43f878b51fc34f3da8f132b6d6a98c80a39ff007e99aba249631b58b9047239ec3e55368aeeb7d2da6f52c0eb7f16e87f2c6e836ba90724ab7a67b55d115ac7c3e8aed2182def4c56a14096368959a423d77e3229a27b41e9d8343b01069c8a8dc9660aa3713df3c64d4a1c695d3d6b67a8cba94b9b8d4e61869e4e4a8c636a7f4afcaa09a485519caae19b966f7a0435196582c656b74df3e308beec7b50629375775b691ac5bdb6b16d6378779f019b00a31cf391c9c2f1daae0b35ef52f5374de88d77aa45a6cd25ddc0108694ee2188c28007603d6a0d16c92430a4b2ed3230dc401855cfa0a0a07c45d7b5db9d462e9ee960b14b2ee134ef8c850012147ec78ab0670b643a2efae753d72686e6e2da211db42176079c8e768f65e39f7aa332d6f58bbd635096f6fe6692695b24f603d801e82823cb900ee00e68006460051dfd680ed9f0c905b713d8d006d5f5419fa505a18f94e40501b1b81a04186d62402c87be3d6810b81290aea8467201231cd1749dbc437f9f1e201db3de8ba07dc0175c027f28a335b17c26f888d6b6d0e8fabf892a29c453b1e547f49f7a946d6424f08236491c833ee0835073294888894120700f0280813c40a6711bc8843e00fca7d3ef40e41dc081f9a811681c6f7565329185623b7e9de812b3bcf11ff0b74563bd50494cf120071b97e5fda80d7577046c9019d5669dbc340324eec67fb734103d5da96bf67a7cf0e916f6e2765f25ddc4c11107ab1c8c647cce2816d3ec7f0f6564cae6e67da375e6d52cc4af2e4fb13ed4145f899d47b3499f4bb6d46cda49b69b92921565c3648e3dd40c81cd5c0ae89f13ec246d3e379ed2d6da180b5d34849da1780b128e49271c9f4a60ba685d5fa36bc42d95c324ec7090cc9b1d87b81ed50588958977cacaaa3b9341c655f12348d1dcb8dc1946540f99a019e2134454eeda7bed3839cd052fe2136b536b5d3563a1ca53c49da4b9507198940ce7e5c9fbe281c6b7a974cf4ee4ea7242d76dc784a3c595b3e9b464e3f6ad0ac745ccbd4fadcbabea42da56959a382ce7460d6b1a93c01f97272093ebf6a82f1ad6af0e9da5cb3cecf6902216919f82aa3818c7a9f4c530649a9f5269ba7429d472239bc991a1b0d3c3152880f0f23039e7bf3de90635ab6a377aa5ebdcdecef2c9239e59f3827e5ed54302195fcc38cd01245395c1f5f4a05b606538e483c501b6939e3b5077860f3914165754c33e549000dbe87de813b820c27fa7baafb8a04a69c98e281e42618c795338033df1f3a06c03e4e029247007ad010093c35674da71f977640340081a190658e41c820f141b0fc33f8926c218b4ed609366a02249bb2d19ce3ea4528dbece68eead926b7916689c643a9e0d643387521fea2f693c2d6efc786ee46d9bfed3eff2a04669edf5295ff057a60bd865309246d3bbbedc1efef41d63a8dec9ab4fa7dd4510fc3c69234ca186e2d9c003b7a67bd034bad0a5bb96e25d575267889cc1b54446d9bd0a37bfbfbd02925945a72cba8dddc48b3f87b1e58f23c623f292bdb7fa7cf38a0a5750f54ebba56a9a67fc516b6d6fd3970ea9234677c8dc7f38f6e4640ce282d1ac4b16bfa72c1d2bad430cd1ba822061865f5007d3daac19cf547c189357d561bbd3eee683c62cd786e9b73337b8c7bd512bd39f06adedec2de0d5ae639da372e6485363107f97767b505cee755d03a5e58ac228659af123184b7b733322e38c91dbf5a943ab3d52e64b49ee755d2e64950e238e35f10c884e17cbe87dc540e6d7509a4f110e9f7566a471712850abf6ce463e6280bacea36fd33a4497f773cf32c698dcc4beee33938edc7ad05534aea683ae61d64c4d2a69b6b88d16d5ca5c303f3e386cf61db140e27b5e99e96b64bdd562b6b30aa36c6c37cac7dc9eec6b42c1a66a962fa70beb6b516d0cbe76322f86c78f6c66831bf8b5d5d2dfa35a5dce60b1933b6ce3c788769f2b331ec1b8fd2831b79649984b239773c1dc68129725c1c640e73400ec781d8fb1a03c4a85d0c8582640257bd01e51fc42236263c9c67be280429c6037eb405dbf5fd682c2a0bb976cf07d3fc5009279ef8ec4e68193a9902b28e7dc71fb501d95b098e0f6dd9e0d0049131019b047b8390281bb292484e47c8500c4f242c3076bf704704739a0be7c3febfbae9a5daf23cd017c7e19fb107bb67d0f6fd6837cd2757d1fab34f4f05e37dde630b1c3a91edf4f7159103d6eb7da65fdbdf59dadb5e2460ac876ed9e1c8c060f9efe9c8a0a75cfc42d5742d2ee5a7e9dbb494b6d6b9bc930cce4f940e3cd81ed4160e98f88315e689fff0022b57664199cc5196f0c7a164ef8f98cd0589baffa68590985eb15c0db1985839f6c2919340b69d03f5285bdd6f4bf021424db4329cb153fccc3d09c76a090d3340d2f479a7bab3b38e2924e5e451cfd280d7dafe936f6c5e4bd89813b02a36589ce318a0358dc35cc4e17f9bf234cdbb78fa0c607a7340e6cec20b1596610c6934b8323226379edda81da8dcb9ec40a042f50b5bb21645473b58b11dbd7bfca8304f8add5d67a9ea8ba5d8ea72c1a4d8a952f10f2c920e368cf71e99fad5833dd0754d6ed66bdb2e9a91a5babb2a310465a57c1ddc1038e7bd5171d3748b8d46ee1ff005298dc6a764c27d4eeaee7fe1c01795881c9e7804fe940dbe287c4b6d75a1b1d1c986d62277c91bf131f4c0f6fad0663737135d3b497124924871f98e7803007d2811dc5b83903dc0a0333f03be7de8122df2c9a05a11e5f51f7a05ce7071804fca8033e5da0734020b0183bb23e5416269577ed0e5323078ceeefdff6a03dbcd62914c2f629a47c622689800879e4fbd046f9d8a2a03e31385c0e73da8b83ca590947dcaead8208e73da8849b3e19ce704f7c5015586d006431f5cf61f3a04ee586ff002481c8fe6191408f0011eb8e30682774dea9bbb5784492ca6385832e1ca95e3d2834be9df8c312e2db5eb4375080337000f1303d18763591a469baef4d755989ec6f6dae5a23e20b599406dd8e080ddbed41272f4dd8caf1c86d163910f9595882a3d718a035edd695d3b6a926b57d0ac65b10b4e06eedd863bf141077fd7af2782bd3fa26a1a8891d57c630948c0279393dcd04cf5875258f4de9f0cb7b7b6d66d2b81ba752d85f5214724fed41036bd79d2fe319d7a8f4b9c81e58de2f04827b9ce09a07a3acecf54b790685ace8697606009e52c377b7f2e682b097d7d36acf0f55df5edbdc0977412468cb6ce3be10af3c63b9c8a0b0751f505be9690dd5d752436f62a3fe4c6448f3b7b0c64e38f615734651f107e3045ac42b67a7693018633b965bc1bc838ee173807bf7cd33065baaeb1a95f2c11dfcd2bc51fe48880aa3e8a062a8b059f595df4ae9a74de9e9ec499d43c97b1427c6e47e525bb63e4282ad3ea3712893c599dbc4259c1627713c927de81043950df97db1406da8411c92063be280230839627078e79a0390a71b5bb5003a8c1232338e4507025573e9fbd02a0e41dc0e680c3691cf714053bb34160895dc16f291d98d02322aa39f3e14707ffaa06f202a5bb0c7201f4a343aca51090497efdfbfce89840c8db8e46573923ff14410b00490d9f5c1a0425dd8ce4673e873cd0265e4dbe7041ed814009b8cbb8e5863bd07163b7716e0607b6698060b96b7b9478dc8643918247ee39a60b7e97f133a8b4e0c63d4ee597380923970a3ef4c0e13e25dfcfab457ba95bdbddb212016501867b9cfbfda982f907c74b282da34874a9048aa479c83838edc62982b7ac7c42d235cd67f15ac5b40c366418a2cb0c1c81e6f5e31db14c160d035de8cd4a3f18ea96562cc37359dfe9cac887fef039fd6b39446f56ea5d13a9dca4579a922496b1975b8d22dfc3566cf9557230703be715ac1431d4d2275325d7fae6b4f6f182a93ef1e32a9f41938f6a60afeb1a95c5fea53dccf772cf2c8c489240031f627e7565c0d67bbf160487c1801073bc0c31f91f953420f2bc8c7c52cc540032738a809905c0f4fa501940208e73df34028e703938a0577ae013f4a001300db4f03b71407461ce0502dca8c9c7dcf6a003fafcbdcd0070bc1e0fd734070db467b8a04cb9c9e68274b93bcb1daa40200ed4099765249ec476cf340849b8b264823bf34689ee009cb671df1409bc8e8b8e770e3ec68984d9c953cf97be2860b248caaebc107dc67f7a184c31232db88fd451031ce50e76039f5c8045026efb8f93279e0fd680b239504f0483d88ef409ee25bb90c79c0e050151c6e21b39ce783eb40adbcc2cefa17bdb61322387781c950e3dbdf9c8a066f28790b22e013db3dbef54726081e63c6460d34191b1bb0720f634060e7600412c781502409c8e3d7b500ed71dbef8ed40243f181c0a02e5d4e0fad006f644e4819e3b501f7e3049e7b501bc43b4e391da80558003392d40a23305e320d02e64cf998e1bf5a032b0c927b8e68049c8c8e71c6280377043118f4e680bbff00de0504ddbb3128371c1c64668024e59f3cd02521254e4fad1a2107e48fe6a6809ddb9e78a029e1463d05027ffc744a6c3857c7b1a205ff00e637fbf4a02b12b1794e39f4a02024e7249ed409924720906800005173fd7404989698ee39e4f7a04cf723d07a501fff0097ed406ffe36a018ff00281e99a037f4d0731f3bfd28007e53400ff99a810248c0cf140bc60123233cff008a0557f9beb4056eff007a07109243e79a03778b27bfbd02b128c27039a054001b818a06609de793da815006070283ffd9}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here is a movie {\pict\jpegblip\picw20\pich22\picwgoal400\pichgoal440\bin ffd8ffe000104a46494600010101004800480000fffe0050546869732061727420697320696e20746865207075626c696320646f6d61696e2e204b6576696e204875676865732c206b6576696e68406569742e636f6d2c2053657074656d6265722031393935ffdb00430001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101ffdb00430101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101ffc00011080016001403012200021101031101ffc4001a000100020301000000000000000000000000080905060a07ffc400231000010501000300010500000000000000060304050708020001090a11153976b7ffc400160101010100000000000000000000000000060800ffc400261101000102050109000000000000000000010200030405061121b33134365154717475b4ffda000c03010002110311003f00a90cf388f366a62aa720ed6ae07f96901f3831d973452b8cf36fe3570fc908e46d466433e5dd954f2e96992d9e498c7753faa44916e016ca91cc7d88b38fe60a5b97737defcbcc539c98d336a57f4fc2ca9a486bf07ab575ad9a3af4df221d8215e36df86c4504ff0024574551b3d687ee0575757b3ad64e311ee62bd94158d37e24198c43973099f1fc0c41614d950246513a081abf76cfe7061f6863281e6352fd1670949c148dd6dfb0d25f5b3689b1d5c965b0eacbf4e0932ad28e22ab9ae945633f4744bd3c8cee0a7fdf085b9000f449c5f7afa30b83e0b6fd7b0c8429c9467ff9715347c891e25fa24a205861aa715e6a09bd0488237dc2723414d9891381524e8ca7c0894664f835653631ab55ee7e3de433e4ff001b30949124e4c10c8b6ad0a479b3f9c937b2cf5bc0095ad600a0a41a0e9faee174a1c605e161c6c7a313539650b0113190f1a8368e60d5b24f30ff008ea7f0bf867fa6595feeb6978f1fe0f9c26177f4d63a51a9235184750e7d18811339cd000000c75f000e00380380ae390c350def826ed42ad051fa6f501c50f9b699c3b69cbeb76476d202bf3ac985b6e0e968be66572893e6a744540bd9722e5c87956848629bc2559306bd113e8653d3b6aff651dfad7a3ac8b02958cba02a93ccf525757039bae6cff090e1d90688e8aa233ee86a4c4a3e0586d6b2340522e47dcb7d0046d8a5acb05a123ee25d2b230b2ada6e2e2f9ede3c05202520ec2487b0d56562529d8b3393bca76adca4ec1bca508abb001babc007915d84fe3dd14e207e3c62f8379da2a3b861fb6629d28dba53b6ea388ebfed866bf6dfb553455e91ed547ae92e9445253a4fdf3efb4f8ebdfbe7d3c78f1ee0bb9e13e358e942a4ed49e22cff00eeb35fdd7ebfffd9} icon.\par}
-{\pard \qc \f0 \sa180 \li0 \fi0 \emdash\emdash\emdash\emdash\emdash\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Footnotes\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Here is a footnote reference,{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.\par}
-} and another.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 Here\u8217's the long note. This one contains multiple blocks.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Subsequent blocks are indented to show that they belong to the footnote (as with list items).\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 \f1 \{ <code> \}\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.\par}
-} This should {\i not} be a footnote reference, because it contains a space.[^my note] Here is an inline note.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 This is {\i easier} to type. Inline notes may contain {\field{\*\fldinst{HYPERLINK "http://google.com"}}{\fldrslt{\ul
-links
-}}}
- and {\f1 ]} verbatim characters, as well as [bracketed text].\par}
-}\par}
-{\pard \ql \f0 \sa180 \li720 \fi0 Notes can go in quotes.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 In quote.\par}
-}\par}
-{\pard \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab And in list items.{\super\chftn}{\*\footnote\chftn\~\plain\pard {\pard \ql \f0 \sa180 \li0 \fi0 In list.\par}
-}\sa180\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 This paragraph should not be part of the note, as it is not indented.\par}
-}
diff --git a/tests/writer.tei b/tests/writer.tei
deleted file mode 100644
index 41f258775..000000000
--- a/tests/writer.tei
+++ /dev/null
@@ -1,861 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<TEI xmlns="http://www.tei-c.org/ns/1.0">
-<teiHeader>
- <fileDesc>
- <titleStmt>
- <title>Pandoc Test Suite</title>
- <author>John MacFarlane</author>
- <author>Anonymous</author>
- </titleStmt>
- <publicationStmt>
- <p></p>
- </publicationStmt>
- <sourceDesc>
- <p>Produced by pandoc.</p>
- </sourceDesc>
- </fileDesc>
-</teiHeader>
-<text>
-<body>
-<p>This is a set of tests for pandoc. Most of them are adapted from John
-Gruber’s markdown test suite.</p>
-<milestone unit="undefined" type="separator" rendition="line" />
-<div type="level1">
- <head>Headers</head>
- <div type="level2">
- <head>Level 2 with an <ref target="/url">embedded link</ref></head>
- <div type="level3">
- <head>Level 3 with <hi rendition="simple:italic">emphasis</hi></head>
- <div type="level4">
- <head>Level 4</head>
- <div type="level5">
- <head>Level 5</head>
- <p></p>
- </div>
- </div>
- </div>
- </div>
-</div>
-<div type="level1">
- <head>Level 1</head>
- <div type="level2">
- <head>Level 2 with <hi rendition="simple:italic">emphasis</hi></head>
- <div type="level3">
- <head>Level 3</head>
- <p>with no blank line</p>
- </div>
- </div>
- <div type="level2">
- <head>Level 2</head>
- <p>with no blank line</p>
- <milestone unit="undefined" type="separator" rendition="line" />
- </div>
-</div>
-<div type="level1">
- <head>Paragraphs</head>
- <p>Here’s a regular paragraph.</p>
- <p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a list
- item. Because a hard-wrapped line in the middle of a paragraph looked like a
- list item.</p>
- <p>Here’s one with a bullet. * criminey.</p>
- <p>There should be a hard line break<lb />here.</p>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>Block Quotes</head>
- <p>E-mail style:</p>
- <quote>
- <p>This is a block quote. It is pretty short.</p>
- </quote>
- <quote>
- <p>Code in a block quote:</p>
- <ab type='codeblock '>
-sub status {
- print &quot;working&quot;;
-}
-</ab>
- <p>A list:</p>
- <list type="ordered:arabic">
- <item>
- <p>item one</p>
- </item>
- <item>
- <p>item two</p>
- </item>
- </list>
- <p>Nested block quotes:</p>
- <quote>
- <p>nested</p>
- </quote>
- <quote>
- <p>nested</p>
- </quote>
- </quote>
- <p>This should not be a block quote: 2 &gt; 1.</p>
- <p>And a following paragraph.</p>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>Code Blocks</head>
- <p>Code:</p>
- <ab type='codeblock '>
----- (should be four hyphens)
-
-sub status {
- print &quot;working&quot;;
-}
-
-this code block is indented by one tab
-</ab>
- <p>And:</p>
- <ab type='codeblock '>
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \&gt; \[ \{
-</ab>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>Lists</head>
- <div type="level2">
- <head>Unordered</head>
- <p>Asterisks tight:</p>
- <list type="unordered">
- <item>
- <p>asterisk 1</p>
- </item>
- <item>
- <p>asterisk 2</p>
- </item>
- <item>
- <p>asterisk 3</p>
- </item>
- </list>
- <p>Asterisks loose:</p>
- <list type="unordered">
- <item>
- <p>asterisk 1</p>
- </item>
- <item>
- <p>asterisk 2</p>
- </item>
- <item>
- <p>asterisk 3</p>
- </item>
- </list>
- <p>Pluses tight:</p>
- <list type="unordered">
- <item>
- <p>Plus 1</p>
- </item>
- <item>
- <p>Plus 2</p>
- </item>
- <item>
- <p>Plus 3</p>
- </item>
- </list>
- <p>Pluses loose:</p>
- <list type="unordered">
- <item>
- <p>Plus 1</p>
- </item>
- <item>
- <p>Plus 2</p>
- </item>
- <item>
- <p>Plus 3</p>
- </item>
- </list>
- <p>Minuses tight:</p>
- <list type="unordered">
- <item>
- <p>Minus 1</p>
- </item>
- <item>
- <p>Minus 2</p>
- </item>
- <item>
- <p>Minus 3</p>
- </item>
- </list>
- <p>Minuses loose:</p>
- <list type="unordered">
- <item>
- <p>Minus 1</p>
- </item>
- <item>
- <p>Minus 2</p>
- </item>
- <item>
- <p>Minus 3</p>
- </item>
- </list>
- </div>
- <div type="level2">
- <head>Ordered</head>
- <p>Tight:</p>
- <list type="ordered:arabic">
- <item>
- <p>First</p>
- </item>
- <item>
- <p>Second</p>
- </item>
- <item>
- <p>Third</p>
- </item>
- </list>
- <p>and:</p>
- <list type="ordered:arabic">
- <item>
- <p>One</p>
- </item>
- <item>
- <p>Two</p>
- </item>
- <item>
- <p>Three</p>
- </item>
- </list>
- <p>Loose using tabs:</p>
- <list type="ordered:arabic">
- <item>
- <p>First</p>
- </item>
- <item>
- <p>Second</p>
- </item>
- <item>
- <p>Third</p>
- </item>
- </list>
- <p>and using spaces:</p>
- <list type="ordered:arabic">
- <item>
- <p>One</p>
- </item>
- <item>
- <p>Two</p>
- </item>
- <item>
- <p>Three</p>
- </item>
- </list>
- <p>Multiple paragraphs:</p>
- <list type="ordered:arabic">
- <item>
- <p>Item 1, graf one.</p>
- <p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s
- back.</p>
- </item>
- <item>
- <p>Item 2.</p>
- </item>
- <item>
- <p>Item 3.</p>
- </item>
- </list>
- </div>
- <div type="level2">
- <head>Nested</head>
- <list type="unordered">
- <item>
- <p>Tab</p>
- <list type="unordered">
- <item>
- <p>Tab</p>
- <list type="unordered">
- <item>
- <p>Tab</p>
- </item>
- </list>
- </item>
- </list>
- </item>
- </list>
- <p>Here’s another:</p>
- <list type="ordered:arabic">
- <item>
- <p>First</p>
- </item>
- <item>
- <p>Second:</p>
- <list type="unordered">
- <item>
- <p>Fee</p>
- </item>
- <item>
- <p>Fie</p>
- </item>
- <item>
- <p>Foe</p>
- </item>
- </list>
- </item>
- <item>
- <p>Third</p>
- </item>
- </list>
- <p>Same thing but with paragraphs:</p>
- <list type="ordered:arabic">
- <item>
- <p>First</p>
- </item>
- <item>
- <p>Second:</p>
- <list type="unordered">
- <item>
- <p>Fee</p>
- </item>
- <item>
- <p>Fie</p>
- </item>
- <item>
- <p>Foe</p>
- </item>
- </list>
- </item>
- <item>
- <p>Third</p>
- </item>
- </list>
- </div>
- <div type="level2">
- <head>Tabs and spaces</head>
- <list type="unordered">
- <item>
- <p>this is a list item indented with tabs</p>
- </item>
- <item>
- <p>this is a list item indented with spaces</p>
- <list type="unordered">
- <item>
- <p>this is an example list item indented with tabs</p>
- </item>
- <item>
- <p>this is an example list item indented with spaces</p>
- </item>
- </list>
- </item>
- </list>
- </div>
- <div type="level2">
- <head>Fancy list markers</head>
- <list type="ordered:arabic">
- <item n="2">
- <p>begins with 2</p>
- </item>
- <item>
- <p>and now 3</p>
- <p>with a continuation</p>
- <list type="ordered:lowerroman">
- <item n="4">
- <p>sublist with roman numerals, starting with 4</p>
- </item>
- <item>
- <p>more items</p>
- <list type="ordered:upperalpha">
- <item>
- <p>a subsublist</p>
- </item>
- <item>
- <p>a subsublist</p>
- </item>
- </list>
- </item>
- </list>
- </item>
- </list>
- <p>Nesting:</p>
- <list type="ordered:upperalpha">
- <item>
- <p>Upper Alpha</p>
- <list type="ordered:upperroman">
- <item>
- <p>Upper Roman.</p>
- <list type="ordered:arabic">
- <item n="6">
- <p>Decimal start with 6</p>
- <list type="ordered:loweralpha">
- <item n="3">
- <p>Lower alpha with paren</p>
- </item>
- </list>
- </item>
- </list>
- </item>
- </list>
- </item>
- </list>
- <p>Autonumbering:</p>
- <list>
- <item>
- <p>Autonumber.</p>
- </item>
- <item>
- <p>More.</p>
- <list>
- <item>
- <p>Nested.</p>
- </item>
- </list>
- </item>
- </list>
- <p>Should not be a list item:</p>
- <p>M.A. 2007</p>
- <p>B. Williams</p>
- <milestone unit="undefined" type="separator" rendition="line" />
- </div>
-</div>
-<div type="level1">
- <head>Definition Lists</head>
- <p>Tight using spaces:</p>
- <list type="definition">
- <label>
- apple
- </label>
- <item>
- <p>red fruit</p>
- </item>
- <label>
- orange
- </label>
- <item>
- <p>orange fruit</p>
- </item>
- <label>
- banana
- </label>
- <item>
- <p>yellow fruit</p>
- </item>
- </list>
- <p>Tight using tabs:</p>
- <list type="definition">
- <label>
- apple
- </label>
- <item>
- <p>red fruit</p>
- </item>
- <label>
- orange
- </label>
- <item>
- <p>orange fruit</p>
- </item>
- <label>
- banana
- </label>
- <item>
- <p>yellow fruit</p>
- </item>
- </list>
- <p>Loose:</p>
- <list type="definition">
- <label>
- apple
- </label>
- <item>
- <p>red fruit</p>
- </item>
- <label>
- orange
- </label>
- <item>
- <p>orange fruit</p>
- </item>
- <label>
- banana
- </label>
- <item>
- <p>yellow fruit</p>
- </item>
- </list>
- <p>Multiple blocks with italics:</p>
- <list type="definition">
- <label>
- <hi rendition="simple:italic">apple</hi>
- </label>
- <item>
- <p>red fruit</p>
- <p>contains seeds, crisp, pleasant to taste</p>
- </item>
- <label>
- <hi rendition="simple:italic">orange</hi>
- </label>
- <item>
- <p>orange fruit</p>
- <ab type='codeblock '>
-{ orange code block }
-</ab>
- <quote>
- <p>orange block quote</p>
- </quote>
- </item>
- </list>
- <p>Multiple definitions, tight:</p>
- <list type="definition">
- <label>
- apple
- </label>
- <item>
- <p>red fruit</p>
- <p>computer</p>
- </item>
- <label>
- orange
- </label>
- <item>
- <p>orange fruit</p>
- <p>bank</p>
- </item>
- </list>
- <p>Multiple definitions, loose:</p>
- <list type="definition">
- <label>
- apple
- </label>
- <item>
- <p>red fruit</p>
- <p>computer</p>
- </item>
- <label>
- orange
- </label>
- <item>
- <p>orange fruit</p>
- <p>bank</p>
- </item>
- </list>
- <p>Blank line after term, indented marker, alternate markers:</p>
- <list type="definition">
- <label>
- apple
- </label>
- <item>
- <p>red fruit</p>
- <p>computer</p>
- </item>
- <label>
- orange
- </label>
- <item>
- <p>orange fruit</p>
- <list type="ordered:arabic">
- <item>
- <p>sublist</p>
- </item>
- <item>
- <p>sublist</p>
- </item>
- </list>
- </item>
- </list>
-</div>
-<div type="level1">
- <head>HTML Blocks</head>
- <p>Simple block on one line:</p>
- <p>foo</p>
- <p>And nested without indentation:</p>
- <p>foo</p>
- <p>bar</p>
- <p>Interpreted markdown in a table:</p>
- <p>This is <hi rendition="simple:italic">emphasized</hi></p>
- <p>And this is <hi rendition="simple:bold">strong</hi></p>
- <p>Here’s a simple block:</p>
- <p>foo</p>
- <p>This should be a code block, though:</p>
- <ab type='codeblock '>
-&lt;div&gt;
- foo
-&lt;/div&gt;
-</ab>
- <p>As should this:</p>
- <ab type='codeblock '>
-&lt;div&gt;foo&lt;/div&gt;
-</ab>
- <p>Now, nested:</p>
- <p>foo</p>
- <p>This should just be an HTML comment:</p>
- <p>Multiline:</p>
- <p>Code block:</p>
- <ab type='codeblock '>
-&lt;!-- Comment --&gt;
-</ab>
- <p>Just plain comment, with trailing spaces on the line:</p>
- <p>Code:</p>
- <ab type='codeblock '>
-&lt;hr /&gt;
-</ab>
- <p>Hr’s:</p>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>Inline Markup</head>
- <p>This is <hi rendition="simple:italic">emphasized</hi>, and so
- <hi rendition="simple:italic">is this</hi>.</p>
- <p>This is <hi rendition="simple:bold">strong</hi>, and so
- <hi rendition="simple:bold">is this</hi>.</p>
- <p>An <hi rendition="simple:italic"><ref target="/url">emphasized
- link</ref></hi>.</p>
- <p><hi rendition="simple:bold"><hi rendition="simple:italic">This is strong
- and em.</hi></hi></p>
- <p>So is
- <hi rendition="simple:bold"><hi rendition="simple:italic">this</hi></hi>
- word.</p>
- <p><hi rendition="simple:bold"><hi rendition="simple:italic">This is strong
- and em.</hi></hi></p>
- <p>So is
- <hi rendition="simple:bold"><hi rendition="simple:italic">this</hi></hi>
- word.</p>
- <p>This is code: <seg type="code">&gt;</seg>, <seg type="code">$</seg>,
- <seg type="code">\</seg>, <seg type="code">\$</seg>,
- <seg type="code">&lt;html&gt;</seg>.</p>
- <p><hi rendition="simple:strikethrough">This is
- <hi rendition="simple:italic">strikeout</hi>.</hi></p>
- <p>Superscripts: a<hi rendition="simple:superscript">bc</hi>d
- a<hi rendition="simple:superscript"><hi rendition="simple:italic">hello</hi></hi>
- a<hi rendition="simple:superscript">hello there</hi>.</p>
- <p>Subscripts: H<hi rendition="simple:subscript">2</hi>O,
- H<hi rendition="simple:subscript">23</hi>O,
- H<hi rendition="simple:subscript">many of them</hi>O.</p>
- <p>These should not be superscripts or subscripts, because of the unescaped
- spaces: a^b c^d, a~b c~d.</p>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>Smart quotes, ellipses, dashes</head>
- <p><quote>Hello,</quote> said the spider. <quote><quote>Shelob</quote> is my
- name.</quote></p>
- <p><quote>A</quote>, <quote>B</quote>, and <quote>C</quote> are letters.</p>
- <p><quote>Oak,</quote> <quote>elm,</quote> and <quote>beech</quote> are
- names of trees. So is <quote>pine.</quote></p>
- <p><quote>He said, <quote>I want to go.</quote></quote> Were you alive in
- the 70’s?</p>
- <p>Here is some quoted <quote><seg type="code">code</seg></quote> and a
- <quote><ref target="http://example.com/?foo=1&amp;bar=2">quoted
- link</ref></quote>.</p>
- <p>Some dashes: one—two — three—four — five.</p>
- <p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p>
- <p>Ellipses…and…and….</p>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>LaTeX</head>
- <list type="unordered">
- <item>
- <p></p>
- </item>
- <item>
- <p><formula notation="TeX">2+2=4</formula></p>
- </item>
- <item>
- <p><formula notation="TeX">x \in y</formula></p>
- </item>
- <item>
- <p><formula notation="TeX">\alpha \wedge \omega</formula></p>
- </item>
- <item>
- <p><formula notation="TeX">223</formula></p>
- </item>
- <item>
- <p><formula notation="TeX">p</formula>-Tree</p>
- </item>
- <item>
- <p>Here’s some display math: <figure type="math">
- <formula notation="TeX">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</formula>
- </figure></p>
- </item>
- <item>
- <p>Here’s one that has a line break in it:
- <formula notation="TeX">\alpha + \omega \times x^2</formula>.</p>
- </item>
- </list>
- <p>These shouldn’t be math:</p>
- <list type="unordered">
- <item>
- <p>To get the famous equation, write
- <seg type="code">$e = mc^2$</seg>.</p>
- </item>
- <item>
- <p>$22,000 is a <hi rendition="simple:italic">lot</hi> of money. So is
- $34,000. (It worked if <quote>lot</quote> is emphasized.)</p>
- </item>
- <item>
- <p>Shoes ($20) and socks ($5).</p>
- </item>
- <item>
- <p>Escaped <seg type="code">$</seg>: $73
- <hi rendition="simple:italic">this should be emphasized</hi> 23$.</p>
- </item>
- </list>
- <p>Here’s a LaTeX table:</p>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>Special Characters</head>
- <p>Here is some unicode:</p>
- <list type="unordered">
- <item>
- <p>I hat: Î</p>
- </item>
- <item>
- <p>o umlaut: ö</p>
- </item>
- <item>
- <p>section: §</p>
- </item>
- <item>
- <p>set membership: ∈</p>
- </item>
- <item>
- <p>copyright: ©</p>
- </item>
- </list>
- <p>AT&amp;T has an ampersand in their name.</p>
- <p>AT&amp;T is another way to write it.</p>
- <p>This &amp; that.</p>
- <p>4 &lt; 5.</p>
- <p>6 &gt; 5.</p>
- <p>Backslash: \</p>
- <p>Backtick: `</p>
- <p>Asterisk: *</p>
- <p>Underscore: _</p>
- <p>Left brace: {</p>
- <p>Right brace: }</p>
- <p>Left bracket: [</p>
- <p>Right bracket: ]</p>
- <p>Left paren: (</p>
- <p>Right paren: )</p>
- <p>Greater-than: &gt;</p>
- <p>Hash: #</p>
- <p>Period: .</p>
- <p>Bang: !</p>
- <p>Plus: +</p>
- <p>Minus: -</p>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>Links</head>
- <div type="level2">
- <head>Explicit</head>
- <p>Just a <ref target="/url/">URL</ref>.</p>
- <p><ref target="/url/">URL and title</ref>.</p>
- <p><ref target="/url/">URL and title</ref>.</p>
- <p><ref target="/url/">URL and title</ref>.</p>
- <p><ref target="/url/">URL and title</ref></p>
- <p><ref target="/url/">URL and title</ref></p>
- <p><ref target="/url/with_underscore">with_underscore</ref></p>
- <p>Email link (nobody@nowhere.net)</p>
- <p><ref target="">Empty</ref>.</p>
- </div>
- <div type="level2">
- <head>Reference</head>
- <p>Foo <ref target="/url/">bar</ref>.</p>
- <p>Foo <ref target="/url/">bar</ref>.</p>
- <p>Foo <ref target="/url/">bar</ref>.</p>
- <p>With <ref target="/url/">embedded [brackets]</ref>.</p>
- <p><ref target="/url/">b</ref> by itself should be a link.</p>
- <p>Indented <ref target="/url">once</ref>.</p>
- <p>Indented <ref target="/url">twice</ref>.</p>
- <p>Indented <ref target="/url">thrice</ref>.</p>
- <p>This should [not][] be a link.</p>
- <ab type='codeblock '>
-[not]: /url
-</ab>
- <p>Foo <ref target="/url/">bar</ref>.</p>
- <p>Foo <ref target="/url/">biz</ref>.</p>
- </div>
- <div type="level2">
- <head>With ampersands</head>
- <p>Here’s a <ref target="http://example.com/?foo=1&amp;bar=2">link with an
- ampersand in the URL</ref>.</p>
- <p>Here’s a link with an amersand in the link text:
- <ref target="http://att.com/">AT&amp;T</ref>.</p>
- <p>Here’s an <ref target="/script?foo=1&amp;bar=2">inline link</ref>.</p>
- <p>Here’s an <ref target="/script?foo=1&amp;bar=2">inline link in pointy
- braces</ref>.</p>
- </div>
- <div type="level2">
- <head>Autolinks</head>
- <p>With an ampersand:
- <ref target="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</ref></p>
- <list type="unordered">
- <item>
- <p>In a list?</p>
- </item>
- <item>
- <p><ref target="http://example.com/">http://example.com/</ref></p>
- </item>
- <item>
- <p>It should.</p>
- </item>
- </list>
- <p>An e-mail address: nobody@nowhere.net</p>
- <quote>
- <p>Blockquoted:
- <ref target="http://example.com/">http://example.com/</ref></p>
- </quote>
- <p>Auto-links should not occur here:
- <seg type="code">&lt;http://example.com/&gt;</seg></p>
- <ab type='codeblock '>
-or here: &lt;http://example.com/&gt;
-</ab>
- <milestone unit="undefined" type="separator" rendition="line" />
- </div>
-</div>
-<div type="level1">
- <head>Images</head>
- <p>From <quote>Voyage dans la Lune</quote> by Georges Melies (1902):</p>
- <p><figure>
- <head>lalune</head>
- <graphic url="lalune.jpg" />
- <figDesc>fig:Voyage dans la Lune</figDesc>
- </figure></p>
- <p>Here is a movie <figure>
- <head>movie</head>
- <graphic url="movie.jpg" />
- </figure> icon.</p>
- <milestone unit="undefined" type="separator" rendition="line" />
-</div>
-<div type="level1">
- <head>Footnotes</head>
- <p>Here is a footnote reference,<note>
- <p>Here is the footnote. It can go anywhere after the footnote reference.
- It need not be placed at the end of the document.</p>
- </note> and another.<note>
- <p>Here’s the long note. This one contains multiple blocks.</p>
- <p>Subsequent blocks are indented to show that they belong to the footnote
- (as with list items).</p>
- <ab type='codeblock '>
- { &lt;code&gt; }
-</ab>
- <p>If you want, you can indent every line, but you can also be lazy and
- just indent the first line of each block.</p>
- </note> This should <hi rendition="simple:italic">not</hi> be a footnote
- reference, because it contains a space.[^my note] Here is an inline
- note.<note>
- <p>This is <hi rendition="simple:italic">easier</hi> to type. Inline notes
- may contain <ref target="http://google.com">links</ref> and
- <seg type="code">]</seg> verbatim characters, as well as [bracketed
- text].</p>
- </note></p>
- <quote>
- <p>Notes can go in quotes.<note>
- <p>In quote.</p>
- </note></p>
- </quote>
- <list type="ordered:arabic">
- <item>
- <p>And in list items.<note>
- <p>In list.</p>
- </note></p>
- </item>
- </list>
- <p>This paragraph should not be part of the note, as it is not indented.</p>
-</div>
-</body>
-</text>
-</TEI>
diff --git a/tests/writer.texinfo b/tests/writer.texinfo
deleted file mode 100644
index ca87da1a9..000000000
--- a/tests/writer.texinfo
+++ /dev/null
@@ -1,1061 +0,0 @@
-\input texinfo
-@documentencoding UTF-8
-
-@macro textstrikeout{text}
-~~\text\~~
-@end macro
-
-@macro textsubscript{text}
-@iftex
-@textsubscript{\text\}
-@end iftex
-@ifnottex
-_@{\text\@}
-@end ifnottex
-@end macro
-
-@macro textsuperscript{text}
-@iftex
-@textsuperscript{\text\}
-@end iftex
-@ifnottex
-^@{\text\@}
-@end ifnottex
-@end macro
-
-@ifnottex
-@paragraphindent 0
-@end ifnottex
-@titlepage
-@title Pandoc Test Suite
-@author John MacFarlane
-@author Anonymous
-July 17, 2006
-@end titlepage
-
-@node Top
-@top Pandoc Test Suite
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber's
-markdown test suite.
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-@menu
-* Headers::
-* Level 1::
-* Paragraphs::
-* Block Quotes::
-* Code Blocks::
-* Lists::
-* Definition Lists::
-* HTML Blocks::
-* Inline Markup::
-* Smart quotes ellipses dashes::
-* LaTeX::
-* Special Characters::
-* Links::
-* Images::
-* Footnotes::
-@end menu
-
-@node Headers
-@chapter Headers
-@anchor{#headers}
-@menu
-* Level 2 with an embedded link::
-@end menu
-
-@node Level 2 with an embedded link
-@section Level 2 with an @uref{/url,embedded link}
-@anchor{#level-2-with-an-embedded-link}
-@menu
-* Level 3 with emphasis::
-@end menu
-
-@node Level 3 with emphasis
-@subsection Level 3 with @emph{emphasis}
-@anchor{#level-3-with-emphasis}
-@menu
-* Level 4::
-@end menu
-
-@node Level 4
-@subsubsection Level 4
-@anchor{#level-4}
-Level 5
-
-@node Level 1
-@chapter Level 1
-@anchor{#level-1}
-@menu
-* Level 2 with emphasis::
-* Level 2::
-@end menu
-
-@node Level 2 with emphasis
-@section Level 2 with @emph{emphasis}
-@anchor{#level-2-with-emphasis}
-@menu
-* Level 3::
-@end menu
-
-@node Level 3
-@subsection Level 3
-@anchor{#level-3}
-with no blank line
-
-@node Level 2
-@section Level 2
-@anchor{#level-2}
-with no blank line
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Paragraphs
-@chapter Paragraphs
-@anchor{#paragraphs}
-Here's a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
-Because a hard-wrapped line in the middle of a paragraph looked like a list
-item.
-
-Here's one with a bullet. * criminey.
-
-There should be a hard line break@*
-here.
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Block Quotes
-@chapter Block Quotes
-@anchor{#block-quotes}
-E-mail style:
-
-@quotation
-This is a block quote. It is pretty short.
-@end quotation
-@quotation
-Code in a block quote:
-
-@verbatim
-sub status {
- print "working";
-}
-@end verbatim
-
-A list:
-
-@enumerate
-@item
-item one
-@item
-item two
-@end enumerate
-
-Nested block quotes:
-
-@quotation
-nested
-@end quotation
-@quotation
-nested
-@end quotation
-@end quotation
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Code Blocks
-@chapter Code Blocks
-@anchor{#code-blocks}
-Code:
-
-@verbatim
----- (should be four hyphens)
-
-sub status {
- print "working";
-}
-
-this code block is indented by one tab
-@end verbatim
-
-And:
-
-@verbatim
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \> \[ \{
-@end verbatim
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Lists
-@chapter Lists
-@anchor{#lists}
-@menu
-* Unordered::
-* Ordered::
-* Nested::
-* Tabs and spaces::
-* Fancy list markers::
-@end menu
-
-@node Unordered
-@section Unordered
-@anchor{#unordered}
-Asterisks tight:
-
-@itemize
-@item
-asterisk 1
-@item
-asterisk 2
-@item
-asterisk 3
-@end itemize
-
-Asterisks loose:
-
-@itemize
-@item
-asterisk 1
-
-@item
-asterisk 2
-
-@item
-asterisk 3
-
-@end itemize
-
-Pluses tight:
-
-@itemize
-@item
-Plus 1
-@item
-Plus 2
-@item
-Plus 3
-@end itemize
-
-Pluses loose:
-
-@itemize
-@item
-Plus 1
-
-@item
-Plus 2
-
-@item
-Plus 3
-
-@end itemize
-
-Minuses tight:
-
-@itemize
-@item
-Minus 1
-@item
-Minus 2
-@item
-Minus 3
-@end itemize
-
-Minuses loose:
-
-@itemize
-@item
-Minus 1
-
-@item
-Minus 2
-
-@item
-Minus 3
-
-@end itemize
-
-@node Ordered
-@section Ordered
-@anchor{#ordered}
-Tight:
-
-@enumerate
-@item
-First
-@item
-Second
-@item
-Third
-@end enumerate
-
-and:
-
-@enumerate
-@item
-One
-@item
-Two
-@item
-Three
-@end enumerate
-
-Loose using tabs:
-
-@enumerate
-@item
-First
-
-@item
-Second
-
-@item
-Third
-
-@end enumerate
-
-and using spaces:
-
-@enumerate
-@item
-One
-
-@item
-Two
-
-@item
-Three
-
-@end enumerate
-
-Multiple paragraphs:
-
-@enumerate
-@item
-Item 1, graf one.
-
-Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
-
-@item
-Item 2.
-
-@item
-Item 3.
-
-@end enumerate
-
-@node Nested
-@section Nested
-@anchor{#nested}
-@itemize
-@item
-Tab
-@itemize
-@item
-Tab
-@itemize
-@item
-Tab
-@end itemize
-
-@end itemize
-
-@end itemize
-
-Here's another:
-
-@enumerate
-@item
-First
-@item
-Second:
-@itemize
-@item
-Fee
-@item
-Fie
-@item
-Foe
-@end itemize
-
-@item
-Third
-@end enumerate
-
-Same thing but with paragraphs:
-
-@enumerate
-@item
-First
-
-@item
-Second:
-
-@itemize
-@item
-Fee
-@item
-Fie
-@item
-Foe
-@end itemize
-
-@item
-Third
-
-@end enumerate
-
-@node Tabs and spaces
-@section Tabs and spaces
-@anchor{#tabs-and-spaces}
-@itemize
-@item
-this is a list item indented with tabs
-
-@item
-this is a list item indented with spaces
-
-@itemize
-@item
-this is an example list item indented with tabs
-
-@item
-this is an example list item indented with spaces
-
-@end itemize
-
-@end itemize
-
-@node Fancy list markers
-@section Fancy list markers
-@anchor{#fancy-list-markers}
-@enumerate 2
-@item
-begins with 2
-@item
-and now 3
-
-with a continuation
-
-@enumerate 4
-@item
-sublist with roman numerals, starting with 4
-@item
-more items
-@enumerate A
-@item
-a subsublist
-@item
-a subsublist
-@end enumerate
-
-@end enumerate
-
-@end enumerate
-
-Nesting:
-
-@enumerate A
-@item
-Upper Alpha
-@enumerate
-@item
-Upper Roman.
-@enumerate 6
-@item
-Decimal start with 6
-@enumerate c
-@item
-Lower alpha with paren
-@end enumerate
-
-@end enumerate
-
-@end enumerate
-
-@end enumerate
-
-Autonumbering:
-
-@enumerate
-@item
-Autonumber.
-@item
-More.
-@enumerate
-@item
-Nested.
-@end enumerate
-
-@end enumerate
-
-Should not be a list item:
-
-M.A.@ 2007
-
-B. Williams
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Definition Lists
-@chapter Definition Lists
-@anchor{#definition-lists}
-Tight using spaces:
-
-@table @asis
-@item apple
-
-red fruit
-@item orange
-
-orange fruit
-@item banana
-
-yellow fruit
-@end table
-
-Tight using tabs:
-
-@table @asis
-@item apple
-
-red fruit
-@item orange
-
-orange fruit
-@item banana
-
-yellow fruit
-@end table
-
-Loose:
-
-@table @asis
-@item apple
-
-red fruit
-
-@item orange
-
-orange fruit
-
-@item banana
-
-yellow fruit
-
-@end table
-
-Multiple blocks with italics:
-
-@table @asis
-@item @emph{apple}
-
-red fruit
-
-contains seeds, crisp, pleasant to taste
-
-@item @emph{orange}
-
-orange fruit
-
-@verbatim
-{ orange code block }
-@end verbatim
-
-@quotation
-orange block quote
-@end quotation
-@end table
-
-Multiple definitions, tight:
-
-@table @asis
-@item apple
-
-red fruit
-computer
-@item orange
-
-orange fruit
-bank
-@end table
-
-Multiple definitions, loose:
-
-@table @asis
-@item apple
-
-red fruit
-
-computer
-
-@item orange
-
-orange fruit
-
-bank
-
-@end table
-
-Blank line after term, indented marker, alternate markers:
-
-@table @asis
-@item apple
-
-red fruit
-
-computer
-
-@item orange
-
-orange fruit
-
-@enumerate
-@item
-sublist
-@item
-sublist
-@end enumerate
-
-@end table
-
-@node HTML Blocks
-@chapter HTML Blocks
-@anchor{#html-blocks}
-Simple block on one line:
-
-foo
-And nested without indentation:
-
-foo
-bar
-Interpreted markdown in a table:
-
-This is @emph{emphasized}
-And this is @strong{strong}
-Here's a simple block:
-
-foo
-This should be a code block, though:
-
-@verbatim
-<div>
- foo
-</div>
-@end verbatim
-
-As should this:
-
-@verbatim
-<div>foo</div>
-@end verbatim
-
-Now, nested:
-
-foo
-This should just be an HTML comment:
-
-Multiline:
-
-Code block:
-
-@verbatim
-<!-- Comment -->
-@end verbatim
-
-Just plain comment, with trailing spaces on the line:
-
-Code:
-
-@verbatim
-<hr />
-@end verbatim
-
-Hr's:
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Inline Markup
-@chapter Inline Markup
-@anchor{#inline-markup}
-This is @emph{emphasized}, and so @emph{is this}.
-
-This is @strong{strong}, and so @strong{is this}.
-
-An @emph{@uref{/url,emphasized link}}.
-
-@strong{@emph{This is strong and em.}}
-
-So is @strong{@emph{this}} word.
-
-@strong{@emph{This is strong and em.}}
-
-So is @strong{@emph{this}} word.
-
-This is code: @code{>}, @code{$}, @code{\}, @code{\$}, @code{<html>}.
-
-@textstrikeout{This is @emph{strikeout}.}
-
-Superscripts: a@textsuperscript{bc}d a@textsuperscript{@emph{hello}}
-a@textsuperscript{hello@ there}.
-
-Subscripts: H@textsubscript{2}O, H@textsubscript{23}O,
-H@textsubscript{many@ of@ them}O.
-
-These should not be superscripts or subscripts, because of the unescaped
-spaces: a^b c^d, a~b c~d.
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Smart quotes ellipses dashes
-@chapter Smart quotes, ellipses, dashes
-@anchor{#smart-quotes-ellipses-dashes}
-``Hello,'' said the spider. ```Shelob' is my name.''
-
-`A', `B', and `C' are letters.
-
-`Oak,' `elm,' and `beech' are names of trees. So is `pine.'
-
-`He said, ``I want to go.''' Were you alive in the 70's?
-
-Here is some quoted `@code{code}' and a
-``@uref{http://example.com/?foo=1&bar=2,quoted link}''.
-
-Some dashes: one---two --- three---four --- five.
-
-Dashes between numbers: 5--7, 255--66, 1987--1999.
-
-Ellipses@dots{}and@dots{}and@dots{}.
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node LaTeX
-@chapter LaTeX
-@anchor{#latex}
-@itemize
-@item
-@tex
-\cite[22-23]{smith.1899}
-@end tex
-@item
-@math{2+2=4}
-@item
-@math{x \in y}
-@item
-@math{\alpha \wedge \omega}
-@item
-@math{223}
-@item
-@math{p}-Tree
-@item
-Here's some display math:
-@math{\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}}
-@item
-Here's one that has a line break in it: @math{\alpha + \omega \times x^2}.
-@end itemize
-
-These shouldn't be math:
-
-@itemize
-@item
-To get the famous equation, write @code{$e = mc^2$}.
-@item
-$22,000 is a @emph{lot} of money. So is $34,000. (It worked if ``lot'' is
-emphasized.)
-@item
-Shoes ($20) and socks ($5).
-@item
-Escaped @code{$}: $73 @emph{this should be emphasized} 23$.
-@end itemize
-
-Here's a LaTeX table:
-
-@tex
-\begin{tabular}{|l|l|}\hline
-Animal & Number \\ \hline
-Dog & 2 \\
-Cat & 1 \\ \hline
-\end{tabular}
-@end tex
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Special Characters
-@chapter Special Characters
-@anchor{#special-characters}
-Here is some unicode:
-
-@itemize
-@item
-I hat: Î
-@item
-o umlaut: ö
-@item
-section: §
-@item
-set membership: ∈
-@item
-copyright: ©
-@end itemize
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: _
-
-Left brace: @{
-
-Right brace: @}
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Links
-@chapter Links
-@anchor{#links}
-@menu
-* Explicit::
-* Reference::
-* With ampersands::
-* Autolinks::
-@end menu
-
-@node Explicit
-@section Explicit
-@anchor{#explicit}
-Just a @uref{/url/,URL}.
-
-@uref{/url/,URL and title}.
-
-@uref{/url/,URL and title}.
-
-@uref{/url/,URL and title}.
-
-@uref{/url/,URL and title}
-
-@uref{/url/,URL and title}
-
-@uref{/url/with_underscore,with_underscore}
-
-@uref{mailto:nobody@@nowhere.net,Email link}
-
-@uref{,Empty}.
-
-@node Reference
-@section Reference
-@anchor{#reference}
-Foo @uref{/url/,bar}.
-
-Foo @uref{/url/,bar}.
-
-Foo @uref{/url/,bar}.
-
-With @uref{/url/,embedded [brackets]}.
-
-@uref{/url/,b} by itself should be a link.
-
-Indented @uref{/url,once}.
-
-Indented @uref{/url,twice}.
-
-Indented @uref{/url,thrice}.
-
-This should [not][] be a link.
-
-@verbatim
-[not]: /url
-@end verbatim
-
-Foo @uref{/url/,bar}.
-
-Foo @uref{/url/,biz}.
-
-@node With ampersands
-@section With ampersands
-@anchor{#with-ampersands}
-Here's a @uref{http://example.com/?foo=1&bar=2,link with an ampersand in the
-URL}.
-
-Here's a link with an amersand in the link text: @uref{http://att.com/,AT&T}.
-
-Here's an @uref{/script?foo=1&bar=2,inline link}.
-
-Here's an @uref{/script?foo=1&bar=2,inline link in pointy braces}.
-
-@node Autolinks
-@section Autolinks
-@anchor{#autolinks}
-With an ampersand: @url{http://example.com/?foo=1&bar=2}
-
-@itemize
-@item
-In a list?
-@item
-@url{http://example.com/}
-@item
-It should.
-@end itemize
-
-An e-mail address: @uref{mailto:nobody@@nowhere.net,nobody@@nowhere.net}
-
-@quotation
-Blockquoted: @url{http://example.com/}
-@end quotation
-Auto-links should not occur here: @code{<http://example.com/>}
-
-@verbatim
-or here: <http://example.com/>
-@end verbatim
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Images
-@chapter Images
-@anchor{#images}
-From ``Voyage dans la Lune'' by Georges Melies (1902):
-
-@float
-@image{lalune,,,lalune,jpg}
-@caption{lalune}
-@end float
-
-Here is a movie @image{movie,,,movie,jpg} icon.
-
-@iftex
-@bigskip@hrule@bigskip
-@end iftex
-@ifnottex
-------------------------------------------------------------------------
-@end ifnottex
-
-@node Footnotes
-@chapter Footnotes
-@anchor{#footnotes}
-Here is a footnote reference,@footnote{Here is the footnote. It can go
-anywhere after the footnote reference. It need not be placed at the end of the
-document.} and another.@footnote{Here's the long note. This one contains
-multiple blocks.
-
-Subsequent blocks are indented to show that they belong to the footnote (as
-with list items).
-
-@verbatim
- { <code> }
-@end verbatim
-
-If you want, you can indent every line, but you can also be lazy and just
-indent the first line of each block.} This should @emph{not} be a footnote
-reference, because it contains a space.[^my note] Here is an inline
-note.@footnote{This is @emph{easier} to type. Inline notes may contain
-@uref{http://google.com,links} and @code{]} verbatim characters, as well as
-[bracketed text].}
-
-@quotation
-Notes can go in quotes.@footnote{In quote.}
-@end quotation
-@enumerate
-@item
-And in list items.@footnote{In list.}
-@end enumerate
-
-This paragraph should not be part of the note, as it is not indented.
-
-@bye
diff --git a/tests/writer.textile b/tests/writer.textile
deleted file mode 100644
index 293418ed5..000000000
--- a/tests/writer.textile
+++ /dev/null
@@ -1,723 +0,0 @@
-This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.
-
-<hr />
-
-h1(#headers). Headers
-
-h2(#level-2-with-an-embedded-link). Level 2 with an "embedded link":/url
-
-h3(#level-3-with-emphasis). Level 3 with _emphasis_
-
-h4(#level-4). Level 4
-
-h5(#level-5). Level 5
-
-h1(#level-1). Level 1
-
-h2(#level-2-with-emphasis). Level 2 with _emphasis_
-
-h3(#level-3). Level 3
-
-with no blank line
-
-h2(#level-2). Level 2
-
-with no blank line
-
-<hr />
-
-h1(#paragraphs). Paragraphs
-
-Here's a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard&#45;wrapped line in the middle of a paragraph looked like a list item.
-
-Here's one with a bullet. &#42; criminey.
-
-There should be a hard line break
-here.
-
-<hr />
-
-h1(#block-quotes). Block Quotes
-
-E&#45;mail style:
-
-bq. This is a block quote. It is pretty short.
-
-
-
-<blockquote>
-
-Code in a block quote:
-
-bc. sub status {
- print "working";
-}
-
-
-A list:
-
-# item one
-# item two
-
-Nested block quotes:
-
-bq. nested
-
-
-
-bq. nested
-
-
-
-</blockquote>
-
-This should not be a block quote: 2 &gt; 1.
-
-And a following paragraph.
-
-<hr />
-
-h1(#code-blocks). Code Blocks
-
-Code:
-
-<pre>
----- (should be four hyphens)
-
-sub status {
- print &quot;working&quot;;
-}
-
-this code block is indented by one tab
-</pre>
-
-And:
-
-<pre>
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \&gt; \[ \{
-</pre>
-
-<hr />
-
-h1(#lists). Lists
-
-h2(#unordered). Unordered
-
-Asterisks tight:
-
-* asterisk 1
-* asterisk 2
-* asterisk 3
-
-Asterisks loose:
-
-* asterisk 1
-* asterisk 2
-* asterisk 3
-
-Pluses tight:
-
-* Plus 1
-* Plus 2
-* Plus 3
-
-Pluses loose:
-
-* Plus 1
-* Plus 2
-* Plus 3
-
-Minuses tight:
-
-* Minus 1
-* Minus 2
-* Minus 3
-
-Minuses loose:
-
-* Minus 1
-* Minus 2
-* Minus 3
-
-h2(#ordered). Ordered
-
-Tight:
-
-# First
-# Second
-# Third
-
-and:
-
-# One
-# Two
-# Three
-
-Loose using tabs:
-
-# First
-# Second
-# Third
-
-and using spaces:
-
-# One
-# Two
-# Three
-
-Multiple paragraphs:
-
-<ol style="list-style-type: decimal;">
-<li><p>Item 1, graf one.</p>
-<p>Item 1. graf two. The quick brown fox jumped over the lazy dog's back.</p></li>
-<li><p>Item 2.</p></li>
-<li><p>Item 3.</p></li>
-</ol>
-
-h2(#nested). Nested
-
-* Tab
-** Tab
-*** Tab
-
-Here's another:
-
-# First
-# Second:
-#* Fee
-#* Fie
-#* Foe
-# Third
-
-Same thing but with paragraphs:
-
-# First
-# Second:
-#* Fee
-#* Fie
-#* Foe
-# Third
-
-h2(#tabs-and-spaces). Tabs and spaces
-
-* this is a list item indented with tabs
-* this is a list item indented with spaces
-** this is an example list item indented with tabs
-** this is an example list item indented with spaces
-
-h2(#fancy-list-markers). Fancy list markers
-
-<ol start="2" style="list-style-type: decimal;">
-<li>begins with 2</li>
-<li><p>and now 3</p>
-<p>with a continuation</p>
-<ol start="4" style="list-style-type: lower-roman;">
-<li>sublist with roman numerals, starting with 4</li>
-<li>more items
-<ol style="list-style-type: upper-alpha;">
-<li>a subsublist</li>
-<li>a subsublist</li>
-</ol>
-</li>
-</ol>
-</li>
-</ol>
-
-Nesting:
-
-<ol style="list-style-type: upper-alpha;">
-<li>Upper Alpha
-<ol style="list-style-type: upper-roman;">
-<li>Upper Roman.
-<ol start="6" style="list-style-type: decimal;">
-<li>Decimal start with 6
-<ol start="3" style="list-style-type: lower-alpha;">
-<li>Lower alpha with paren</li>
-</ol>
-</li>
-</ol>
-</li>
-</ol>
-</li>
-</ol>
-
-Autonumbering:
-
-# Autonumber.
-# More.
-## Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-<hr />
-
-h1(#definition-lists). Definition Lists
-
-Tight using spaces:
-
-<dl>
-<dt>apple</dt>
-<dd>red fruit</dd>
-<dt>orange</dt>
-<dd>orange fruit</dd>
-<dt>banana</dt>
-<dd>yellow fruit</dd>
-</dl>
-
-Tight using tabs:
-
-<dl>
-<dt>apple</dt>
-<dd>red fruit</dd>
-<dt>orange</dt>
-<dd>orange fruit</dd>
-<dt>banana</dt>
-<dd>yellow fruit</dd>
-</dl>
-
-Loose:
-
-<dl>
-<dt>apple</dt>
-<dd><p>red fruit</p></dd>
-<dt>orange</dt>
-<dd><p>orange fruit</p></dd>
-<dt>banana</dt>
-<dd><p>yellow fruit</p></dd>
-</dl>
-
-Multiple blocks with italics:
-
-<dl>
-<dt>_apple_</dt>
-<dd><p>red fruit</p>
-<p>contains seeds, crisp, pleasant to taste</p></dd>
-<dt>_orange_</dt>
-<dd><p>orange fruit</p>
-bc. { orange code block }
-
-
-bq. <p>orange block quote</p>
-
-</dd>
-</dl>
-
-Multiple definitions, tight:
-
-<dl>
-<dt>apple</dt>
-<dd>red fruit</dd>
-<dd>computer</dd>
-<dt>orange</dt>
-<dd>orange fruit</dd>
-<dd>bank</dd>
-</dl>
-
-Multiple definitions, loose:
-
-<dl>
-<dt>apple</dt>
-<dd><p>red fruit</p></dd>
-<dd><p>computer</p></dd>
-<dt>orange</dt>
-<dd><p>orange fruit</p></dd>
-<dd><p>bank</p></dd>
-</dl>
-
-Blank line after term, indented marker, alternate markers:
-
-<dl>
-<dt>apple</dt>
-<dd><p>red fruit</p></dd>
-<dd><p>computer</p></dd>
-<dt>orange</dt>
-<dd><p>orange fruit</p>
-<ol style="list-style-type: decimal;">
-<li>sublist</li>
-<li>sublist</li>
-</ol>
-</dd>
-</dl>
-
-h1(#html-blocks). HTML Blocks
-
-Simple block on one line:
-
-<div>
-
-foo
-
-</div>
-
-And nested without indentation:
-
-<div>
-
-<div>
-
-<div>
-
-foo
-
-
-</div>
-
-
-</div>
-
-<div>
-
-bar
-
-</div>
-
-
-</div>
-
-Interpreted markdown in a table:
-
-<table>
-<tr>
-<td>
-This is _emphasized_
-</td>
-<td>
-And this is *strong*
-</td>
-</tr>
-</table>
-<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
-Here's a simple block:
-
-<div>
-
-foo
-
-
-</div>
-
-This should be a code block, though:
-
-bc. <div>
- foo
-</div>
-
-
-As should this:
-
-bc. <div>foo</div>
-
-
-Now, nested:
-
-<div>
-
-<div>
-
-<div>
-
-foo
-
-</div>
-
-
-</div>
-
-
-</div>
-
-This should just be an HTML comment:
-
-<!-- Comment -->
-Multiline:
-
-<!--
-Blah
-Blah
--->
-<!--
- This is another comment.
--->
-Code block:
-
-bc. <!-- Comment -->
-
-
-Just plain comment, with trailing spaces on the line:
-
-<!-- foo -->
-Code:
-
-bc. <hr />
-
-
-Hr's:
-
-<hr>
-<hr />
-<hr />
-<hr>
-<hr />
-<hr />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar" />
-<hr class="foo" id="bar">
-<hr />
-
-h1(#inline-markup). Inline Markup
-
-This is _emphasized_, and so _is this_.
-
-This is *strong*, and so *is this*.
-
-An _"emphasized link":/url_.
-
-*_This is strong and em._*
-
-So is *_this_* word.
-
-*_This is strong and em._*
-
-So is *_this_* word.
-
-This is code: @>@, @$@, @\@, @\$@, @<html>@.
-
--This is _strikeout_.-
-
-Superscripts: a[^bc^]d a[^_hello_^] a[^hello there^].
-
-Subscripts: H[~2~]O, H[~23~]O, H[~many of them~]O.
-
-These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
-
-<hr />
-
-h1(#smart-quotes-ellipses-dashes). Smart quotes, ellipses, dashes
-
-"Hello," said the spider. "'Shelob' is my name."
-
-'A', 'B', and 'C' are letters.
-
-'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
-
-'He said, "I want to go."' Were you alive in the 70's?
-
-Here is some quoted '@code@' and a ""quoted link":http://example.com/?foo=1&bar=2".
-
-Some dashes: one -- two -- three -- four -- five.
-
-Dashes between numbers: 5 - 7, 255 - 66, 1987 - 1999.
-
-Ellipses...and...and....
-
-<hr />
-
-h1(#latex). LaTeX
-
-*
-* <span class="math">2+2=4</math>
-* <span class="math">x \in y</math>
-* <span class="math">\alpha \wedge \omega</math>
-* <span class="math">223</math>
-* <span class="math">p</math>&#45;Tree
-* Here's some display math: <span class="math">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</math>
-* Here's one that has a line break in it: <span class="math">\alpha + \omega \times x^2</math>.
-
-These shouldn't be math:
-
-* To get the famous equation, write @$e = mc^2$@.
-* $22,000 is a _lot_ of money. So is $34,000. (It worked if "lot" is emphasized.)
-* Shoes ($20) and socks ($5).
-* Escaped @$@: $73 _this should be emphasized_ 23$.
-
-Here's a LaTeX table:
-
-
-<hr />
-
-h1(#special-characters). Special Characters
-
-Here is some unicode:
-
-* I hat: Î
-* o umlaut: ö
-* section: §
-* set membership: ∈
-* copyright: ©
-
-AT&amp;T has an ampersand in their name.
-
-AT&amp;T is another way to write it.
-
-This &amp; that.
-
-4 &lt; 5.
-
-6 &gt; 5.
-
-Backslash: \
-
-Backtick: `
-
-Asterisk: &#42;
-
-Underscore: &#95;
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater&#45;than: &gt;
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: &#43;
-
-Minus: &#45;
-
-<hr />
-
-h1(#links). Links
-
-h2(#explicit). Explicit
-
-Just a "URL":/url/.
-
-"URL and title":/url/.
-
-"URL and title":/url/.
-
-"URL and title":/url/.
-
-"URL and title":/url/
-
-"URL and title":/url/
-
-"with&#95;underscore":/url/with_underscore
-
-"Email link":mailto:nobody@nowhere.net
-
-"Empty":.
-
-h2(#reference). Reference
-
-Foo "bar":/url/.
-
-Foo "bar":/url/.
-
-Foo "bar":/url/.
-
-With "embedded [brackets]":/url/.
-
-"b":/url/ by itself should be a link.
-
-Indented "once":/url.
-
-Indented "twice":/url.
-
-Indented "thrice":/url.
-
-This should [not][] be a link.
-
-bc. [not]: /url
-
-
-Foo "bar":/url/.
-
-Foo "biz":/url/.
-
-h2(#with-ampersands). With ampersands
-
-Here's a "link with an ampersand in the URL":http://example.com/?foo=1&bar=2.
-
-Here's a link with an amersand in the link text: "AT&amp;T":http://att.com/.
-
-Here's an "inline link":/script?foo=1&bar=2.
-
-Here's an "inline link in pointy braces":/script?foo=1&bar=2.
-
-h2(#autolinks). Autolinks
-
-With an ampersand: "$":http://example.com/?foo=1&bar=2
-
-* In a list?
-* "$":http://example.com/
-* It should.
-
-An e&#45;mail address: "nobody&#64;nowhere.net":mailto:nobody@nowhere.net
-
-bq. Blockquoted: "$":http://example.com/
-
-
-
-Auto&#45;links should not occur here: @<http://example.com/>@
-
-bc. or here: <http://example.com/>
-
-
-<hr />
-
-h1(#images). Images
-
-From "Voyage dans la Lune" by Georges Melies (1902):
-
-!lalune.jpg(Voyage dans la Lune)!
-lalune
-
-Here is a movie !movie.jpg(movie)! icon.
-
-<hr />
-
-h1(#footnotes). Footnotes
-
-Here is a footnote reference,[1] and another.[2] This should _not_ be a footnote reference, because it contains a space.[^my note] Here is an inline note.[3]
-
-bq. Notes can go in quotes.[4]
-
-
-
-# And in list items.[5]
-
-This paragraph should not be part of the note, as it is not indented.
-
-
-fn1. Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
-
-
-fn2. Here's the long note. This one contains multiple blocks.
-
-Subsequent blocks are indented to show that they belong to the footnote (as with list items).
-
-bc. { <code> }
-
-
-If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
-
-
-fn3. This is _easier_ to type. Inline notes may contain "links":http://google.com and @]@ verbatim characters, as well as [bracketed text].
-
-
-fn4. In quote.
-
-
-fn5. In list.
diff --git a/tests/writer.zimwiki b/tests/writer.zimwiki
deleted file mode 100644
index 848ca955e..000000000
--- a/tests/writer.zimwiki
+++ /dev/null
@@ -1,627 +0,0 @@
-Content-Type: text/x-zim-wiki
-Wiki-Format: zim 0.4
-
-This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.
-
-
-----
-
-====== Headers ======
-
-===== Level 2 with an embedded link =====
-
-==== Level 3 with emphasis ====
-
-=== Level 4 ===
-
-== Level 5 ==
-
-====== Level 1 ======
-
-===== Level 2 with emphasis =====
-
-==== Level 3 ====
-
-with no blank line
-
-===== Level 2 =====
-
-with no blank line
-
-
-----
-
-====== Paragraphs ======
-
-Here’s a regular paragraph.
-
-In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
-
-Here’s one with a bullet. * criminey.
-
-There should be a hard line break
-here.
-
-
-----
-
-====== Block Quotes ======
-
-E-mail style:
-
-> This is a block quote. It is pretty short.
-
-> Code in a block quote:
->
-> '''
-> sub status {
-> print "working";
-> }
-> '''
->
-> A list:
->
-> 1. item one
-> 1. item two
->
-> Nested block quotes:
->
-> > nested
->
-> > nested
-
-This should not be a block quote: 2 > 1.
-
-And a following paragraph.
-
-
-----
-
-====== Code Blocks ======
-
-Code:
-
-'''
----- (should be four hyphens)
-
-sub status {
- print "working";
-}
-
-this code block is indented by one tab
-'''
-
-And:
-
-'''
- this code block is indented by two tabs
-
-These should not be escaped: \$ \\ \> \[ \{
-'''
-
-
-----
-
-====== Lists ======
-
-===== Unordered =====
-
-Asterisks tight:
-
- * asterisk 1
- * asterisk 2
- * asterisk 3
-
-Asterisks loose:
-
- * asterisk 1
- * asterisk 2
- * asterisk 3
-
-Pluses tight:
-
- * Plus 1
- * Plus 2
- * Plus 3
-
-Pluses loose:
-
- * Plus 1
- * Plus 2
- * Plus 3
-
-Minuses tight:
-
- * Minus 1
- * Minus 2
- * Minus 3
-
-Minuses loose:
-
- * Minus 1
- * Minus 2
- * Minus 3
-
-===== Ordered =====
-
-Tight:
-
- 1. First
- 1. Second
- 1. Third
-
-and:
-
- 1. One
- 1. Two
- 1. Three
-
-Loose using tabs:
-
- 1. First
- 1. Second
- 1. Third
-
-and using spaces:
-
- 1. One
- 1. Two
- 1. Three
-
-Multiple paragraphs:
-
- 1. Item 1, graf one.
-Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
- 1. Item 2.
- 1. Item 3.
-
-===== Nested =====
-
- * Tab
- * Tab
- * Tab
-
-Here’s another:
-
- 1. First
- 1. Second:
- * Fee
- * Fie
- * Foe
- 1. Third
-
-Same thing but with paragraphs:
-
- 1. First
- 1. Second:
- * Fee
- * Fie
- * Foe
- 1. Third
-
-===== Tabs and spaces =====
-
- * this is a list item indented with tabs
- * this is a list item indented with spaces
- * this is an example list item indented with tabs
- * this is an example list item indented with spaces
-
-===== Fancy list markers =====
-
- 1. begins with 2
- 1. and now 3
-with a continuation
- 1. sublist with roman numerals, starting with 4
- 1. more items
- 1. a subsublist
- 1. a subsublist
-
-Nesting:
-
- 1. Upper Alpha
- 1. Upper Roman.
- 1. Decimal start with 6
- 1. Lower alpha with paren
-
-Autonumbering:
-
- 1. Autonumber.
- 1. More.
- 1. Nested.
-
-Should not be a list item:
-
-M.A. 2007
-
-B. Williams
-
-
-----
-
-====== Definition Lists ======
-
-Tight using spaces:
-
-* **apple** red fruit
-* **orange** orange fruit
-* **banana** yellow fruit
-Tight using tabs:
-
-* **apple** red fruit
-* **orange** orange fruit
-* **banana** yellow fruit
-Loose:
-
-* **apple** red fruit
-
-* **orange** orange fruit
-
-* **banana** yellow fruit
-
-Multiple blocks with italics:
-
-* **//apple//** red fruit
-
-contains seeds, crisp, pleasant to taste
-
-* **//orange//** orange fruit
-
-'''
-{ orange code block }
-'''
-
-> orange block quote
-
-Multiple definitions, tight:
-
-* **apple** red fruitcomputer
-* **orange** orange fruitbank
-Multiple definitions, loose:
-
-* **apple** red fruit
-computer
-
-* **orange** orange fruit
-bank
-
-Blank line after term, indented marker, alternate markers:
-
-* **apple** red fruit
-computer
-
-* **orange** orange fruit
-
- 1. sublist
- 1. sublist
-
-====== HTML Blocks ======
-
-Simple block on one line:
-
-foo
-
-And nested without indentation:
-
-foo
-
-
-
-bar
-
-
-Interpreted markdown in a table:
-
-
-
-
-This is //emphasized//
-
-
-And this is **strong**
-
-
-
-
-Here’s a simple block:
-
-foo
-
-
-This should be a code block, though:
-
-'''
-<div>
- foo
-</div>
-'''
-
-As should this:
-
-'''
-<div>foo</div>
-'''
-
-Now, nested:
-
-foo
-
-
-
-This should just be an HTML comment:
-
-
-Multiline:
-
-
-
-Code block:
-
-'''
-<!-- Comment -->
-'''
-
-Just plain comment, with trailing spaces on the line:
-
-
-Code:
-
-'''
-<hr />
-'''
-
-Hr’s:
-
-
-
-
-
-
-
-
-
-
-
-----
-
-====== Inline Markup ======
-
-This is //emphasized//, and so //is this//.
-
-This is **strong**, and so **is this**.
-
-An //[[url|emphasized link]]//.
-
-**//This is strong and em.//**
-
-So is **//this//** word.
-
-**//This is strong and em.//**
-
-So is **//this//** word.
-
-This is code: ''>'', ''$'', ''\'', ''\$'', ''<html>''.
-
-~~This is //strikeout//.~~
-
-Superscripts: a^{bc}d a^{//hello//} a^{hello there}.
-
-Subscripts: H_{2}O, H_{23}O, H_{many of them}O.
-
-These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
-
-
-----
-
-====== Smart quotes, ellipses, dashes ======
-
-“Hello,” said the spider. “‘Shelob’ is my name.”
-
-‘A’, ‘B’, and ‘C’ are letters.
-
-‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’
-
-‘He said, “I want to go.”’ Were you alive in the 70’s?
-
-Here is some quoted ‘''code''’ and a “[[http://example.com/?foo=1&bar=2|quoted link]]”.
-
-Some dashes: one—two — three—four — five.
-
-Dashes between numbers: 5–7, 255–66, 1987–1999.
-
-Ellipses…and…and….
-
-
-----
-
-====== LaTeX ======
-
- *
- * $2+2=4$
- * $x \in y$
- * $\alpha \wedge \omega$
- * $223$
- * $p$-Tree
- * Here’s some display math: $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
- * Here’s one that has a line break in it: $\alpha + \omega \times x^2$.
-
-These shouldn’t be math:
-
- * To get the famous equation, write ''$e = mc^2$''.
- * $22,000 is a //lot// of money. So is $34,000. (It worked if “lot” is emphasized.)
- * Shoes ($20) and socks ($5).
- * Escaped ''$'': $73 //this should be emphasized// 23$.
-
-Here’s a LaTeX table:
-
-
-
-----
-
-====== Special Characters ======
-
-Here is some unicode:
-
- * I hat: Î
- * o umlaut: ö
- * section: §
- * set membership: ∈
- * copyright: ©
-
-AT&T has an ampersand in their name.
-
-AT&T is another way to write it.
-
-This & that.
-
-4 < 5.
-
-6 > 5.
-
-Backslash: \
-
-Backtick: `
-
-Asterisk: *
-
-Underscore: _
-
-Left brace: {
-
-Right brace: }
-
-Left bracket: [
-
-Right bracket: ]
-
-Left paren: (
-
-Right paren: )
-
-Greater-than: >
-
-Hash: #
-
-Period: .
-
-Bang: !
-
-Plus: +
-
-Minus: -
-
-
-----
-
-====== Links ======
-
-===== Explicit =====
-
-Just a [[url/|URL]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]].
-
-[[url/|URL and title]]
-
-[[url/|URL and title]]
-
-[[url/with_underscore|with_underscore]]
-
-[[mailto:nobody@nowhere.net|Email link]]
-
-[[|Empty]].
-
-===== Reference =====
-
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
-With [[url/|embedded [brackets]]].
-
-[[url/|b]] by itself should be a link.
-
-Indented [[url|once]].
-
-Indented [[url|twice]].
-
-Indented [[url|thrice]].
-
-This should [not][] be a link.
-
-'''
-[not]: /url
-'''
-
-Foo [[url/|bar]].
-
-Foo [[url/|biz]].
-
-===== With ampersands =====
-
-Here’s a [[http://example.com/?foo=1&bar=2|link with an ampersand in the URL]].
-
-Here’s a link with an amersand in the link text: [[http://att.com/|AT&T]].
-
-Here’s an [[script?foo=1&bar=2|inline link]].
-
-Here’s an [[script?foo=1&bar=2|inline link in pointy braces]].
-
-===== Autolinks =====
-
-With an ampersand: http://example.com/?foo=1&bar=2
-
- * In a list?
- * http://example.com/
- * It should.
-
-An e-mail address: <nobody@nowhere.net>
-
-> Blockquoted: http://example.com/
-
-Auto-links should not occur here: ''<http://example.com/>''
-
-'''
-or here: <http://example.com/>
-'''
-
-
-----
-
-====== Images ======
-
-From “Voyage dans la Lune” by Georges Melies (1902):
-
-{{:lalune.jpg|Voyage dans la Lune lalune}}
-
-Here is a movie {{:movie.jpg|movie}} icon.
-
-
-----
-
-====== Footnotes ======
-
-Here is a footnote reference,((Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
-)) and another.((Here’s the long note. This one contains multiple blocks.
-
-Subsequent blocks are indented to show that they belong to the footnote (as with list items).
-
-'''
- { <code> }
-'''
-
-If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
-)) This should //not// be a footnote reference, because it contains a space.[^my note] Here is an inline note.((This is //easier// to type. Inline notes may contain [[http://google.com|links]] and '']'' verbatim characters, as well as [bracketed text].
-))
-
-> Notes can go in quotes.((In quote.
-> ))
-
- 1. And in list items.((In list.))
-
-This paragraph should not be part of the note, as it is not indented.
diff --git a/tests/writers-lang-and-dir.context b/tests/writers-lang-and-dir.context
deleted file mode 100644
index 66dab9ead..000000000
--- a/tests/writers-lang-and-dir.context
+++ /dev/null
@@ -1,109 +0,0 @@
-% Enable hyperlinks
-\setupinteraction
- [state=start,
- style=,
- color=,
- contrastcolor=]
-% make chapter, section bookmarks visible when opening document
-\placebookmarks[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][chapter, section]
-\setupinteractionscreen[option=bookmark]
-\setuptagging[state=start]
-
-% use microtypography
-\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
-\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
-\setupalign[hz,hanging]
-\setupitaliccorrection[global, always]
-\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
-\usemodule[simplefonts]
-\setmainfontfallback[DejaVu Serif][range={greekandcoptic, greekextended}, force=yes, rscale=auto]
-\setupwhitespace[medium]
-
-\setuphead[chapter] [style=\tfd,header=empty]
-\setuphead[section] [style=\tfc]
-\setuphead[subsection] [style=\tfb]
-\setuphead[subsubsection] [style=\bf]
-\setuphead[subsubsubsection] [style=\sc]
-\setuphead[subsubsubsubsection][style=\it]
-
-\setuphead[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][number=no]
-
-\definedescription
- [description]
- [headstyle=bold, style=normal, location=hanging, width=broad, margin=1cm, alternative=hanging]
-
-\setupitemize[autointro] % prevent orphan list intro
-\setupitemize[indentnext=no]
-
-\setupfloat[figure][default={here,nonumber}]
-\setupfloat[table][default={here,nonumber}]
-
-\setupthinrules[width=15em] % width of horizontal rules
-
-
-\starttext
-
-\section[empty-divs-and-spans]{Empty Divs and Spans}
-
-Some text and
-
-div contents
-
-and more text.
-
-Next paragraph with a span and a word-thatincludesaspanright?
-
-\section[directionality]{Directionality}
-
-Some text and
-
-\startalignment[righttoleft]
-rtl div contents
-
-\stopalignment
-
-and more text.
-
-\startalignment[lefttoright]
-and a ltr div. with a {\righttoleft rtl span}.
-
-\stopalignment
-
-Next paragraph with a {\righttoleft rtl span} and a
-word-that-includesa{\lefttoright ltrspan}right?
-
-\section[languages]{Languages}
-
-Some text and
-
-\start\language[de]
-German div contents
-
-\stop
-
-and more text.
-
-Next paragraph with a \start\language[en-gb]British span\stop and a
-word-that-includesa\start\language[de-ch]Swiss German span\stop right?
-
-Some \start\language[es]Spanish text\stop .
-
-\section[combined]{Combined}
-
-Some text and
-
-\start\language[fr]
-\startalignment[righttoleft]
-French rtl div contents
-
-\stopalignment
-\stop
-
-and more text.
-
-Next paragraph with a \start\language[en-gb]{\lefttoright British ltr
-span}\stop and a
-word-that-includesa\start\language[de-ch]{\lefttoright Swiss German ltr
-span}\stop right?
-
-\stoptext
diff --git a/tests/writers-lang-and-dir.latex b/tests/writers-lang-and-dir.latex
deleted file mode 100644
index f79984feb..000000000
--- a/tests/writers-lang-and-dir.latex
+++ /dev/null
@@ -1,153 +0,0 @@
-\documentclass[english,]{article}
-\usepackage{lmodern}
-\usepackage{amssymb,amsmath}
-\usepackage{ifxetex,ifluatex}
-\usepackage{fixltx2e} % provides \textsubscript
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[T1]{fontenc}
- \usepackage[utf8]{inputenc}
-\else % if luatex or xelatex
- \ifxetex
- \usepackage{mathspec}
- \else
- \usepackage{fontspec}
- \fi
- \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
-\fi
-% use upquote if available, for straight quotes in verbatim environments
-\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
-% use microtype if available
-\IfFileExists{microtype.sty}{%
-\usepackage[]{microtype}
-\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
-}{}
-\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
-\usepackage[unicode=true]{hyperref}
-\hypersetup{
- pdfborder={0 0 0},
- breaklinks=true}
-\urlstyle{same} % don't use monospace font for urls
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[shorthands=off,ngerman,british,nswissgerman,spanish,french,main=english]{babel}
- \newcommand{\textgerman}[2][]{\foreignlanguage{ngerman}{#2}}
- \newenvironment{german}[2][]{\begin{otherlanguage}{ngerman}}{\end{otherlanguage}}
- \newcommand{\textenglish}[2][]{\foreignlanguage{british}{#2}}
- \newenvironment{english}[2][]{\begin{otherlanguage}{british}}{\end{otherlanguage}}
- \let\oritextspanish\textspanish
- \AddBabelHook{spanish}{beforeextras}{\renewcommand{\textspanish}{\oritextspanish}}
- \AddBabelHook{spanish}{afterextras}{\renewcommand{\textspanish}[2][]{\foreignlanguage{spanish}{##2}}}
- \newcommand{\textfrench}[2][]{\foreignlanguage{french}{#2}}
- \newenvironment{french}[2][]{\begin{otherlanguage}{french}}{\end{otherlanguage}}
-\else
- \usepackage{polyglossia}
- \setmainlanguage[]{english}
- \setotherlanguage[]{german}
- \setotherlanguage[variant=british]{english}
- \setotherlanguage[variant=swiss]{german}
- \setotherlanguage[]{spanish}
- \setotherlanguage[]{french}
-\fi
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
-\setlength{\emergencystretch}{3em} % prevent overfull lines
-\providecommand{\tightlist}{%
- \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-\setcounter{secnumdepth}{0}
-% Redefines (sub)paragraphs to behave more like sections
-\ifx\paragraph\undefined\else
-\let\oldparagraph\paragraph
-\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
-\fi
-\ifx\subparagraph\undefined\else
-\let\oldsubparagraph\subparagraph
-\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
-\fi
-\ifxetex
- % load bidi as late as possible as it modifies e.g. graphicx
- \usepackage{bidi}
- \fi
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \TeXXeTstate=1
- \newcommand{\RL}[1]{\beginR #1\endR}
- \newcommand{\LR}[1]{\beginL #1\endL}
- \newenvironment{RTL}{\beginR}{\endR}
- \newenvironment{LTR}{\beginL}{\endL}
-\fi
-
-% set default figure placement to htbp
-\makeatletter
-\def\fps@figure{htbp}
-\makeatother
-
-
-\date{}
-
-\begin{document}
-
-\section{Empty Divs and Spans}\label{empty-divs-and-spans}
-
-Some text and
-
-div contents
-
-and more text.
-
-Next paragraph with a {span} and a word-thatincludesa{span}right?
-
-\section{Directionality}\label{directionality}
-
-Some text and
-
-\begin{RTL}
-rtl div contents
-\end{RTL}
-
-and more text.
-
-\begin{LTR}
-and a ltr div. with a \RL{rtl span}.
-\end{LTR}
-
-Next paragraph with a \RL{rtl span} and a
-word-that-includesa\LR{ltrspan}right?
-
-\section{Languages}\label{languages}
-
-Some text and
-
-\begin{german}
-
-German div contents
-
-\end{german}
-
-and more text.
-
-Next paragraph with a \textenglish[variant=british]{British span} and a
-word-that-includesa\textgerman[variant=swiss]{Swiss German span}right?
-
-Some \textspanish{Spanish text}.
-
-\section{Combined}\label{combined}
-
-Some text and
-
-\begin{RTL}
-\begin{french}
-
-French rtl div contents
-
-\end{french}
-\end{RTL}
-
-and more text.
-
-Next paragraph with a \LR{\textenglish[variant=british]{British ltr
-span}} and a word-that-includesa\LR{\textgerman[variant=swiss]{Swiss
-German ltr span}}right?
-
-\end{document}
diff --git a/trypandoc/Makefile b/trypandoc/Makefile
index b53758d7f..f5f6046b1 100644
--- a/trypandoc/Makefile
+++ b/trypandoc/Makefile
@@ -1,7 +1,7 @@
CGIBIN=/home/website/cgi-bin
-TRYPANDOC=/home/website/html/pandoc/try/
+TRYPANDOC=/home/website/pandoc.org/try/
CGI=${CGIBIN}/trypandoc
-BIN=../.cabal-sandbox/bin/trypandoc
+BIN=/home/jgm/.local/bin/trypandoc
install: ${CGI} ${TRYPANDOC}/index.html
diff --git a/trypandoc/index.html b/trypandoc/index.html
index d9674793b..944683d48 100644
--- a/trypandoc/index.html
+++ b/trypandoc/index.html
@@ -78,21 +78,28 @@ $(document).ready(function() {
from
</label>
<select id="from">
+ <option value="commonmark">CommonMark</option>
+ <option value="creole">Creole</option>
<option value="docbook">DocBook</option>
+ <option value="gfm">GitHub-Flavored Markdown</option>
<option value="haddock">Haddock markup</option>
<option value="html">HTML</option>
<option value="latex">LaTeX</option>
<option value="markdown" selected>Markdown (pandoc)</option>
- <option value="markdown_strict">Markdown (strict)</option>
+ <option value="markdown_mmd">MultiMarkdown</option>
<option value="markdown_phpextra">Markdown (PHP Markdown Extra)</option>
- <option value="markdown_github">Markdown (GitHub)</option>
+ <option value="markdown_strict">Markdown (strict)</option>
<option value="mediawiki">MediaWiki</option>
- <option value="markdown_mmd">MultiMarkdown</option>
+ <option value="muse">Muse</option>
+ <option value="native">Native (Pandoc AST)</option>
<option value="opml">OPML</option>
<option value="org">Org Mode</option>
<option value="rst">reStructuredText</option>
- <option value="textile">Textile</option>
<option value="t2t">Txt2Tags</option>
+ <option value="textile">Textile</option>
+ <option value="tikiwiki">TikiWiki</option>
+ <option value="twiki">TWiki</option>
+ <option value="vimwiki">Vimwiki</option>
</select>
<br/>
<textarea id="text" maxlength="3000" rows="15"></textarea>
@@ -102,33 +109,44 @@ $(document).ready(function() {
to
</label>
<select id="to">
+ <option value="S5">S5</option>
<option value="asciidoc">AsciiDoc</option>
+ <option value="beamer">LaTeX Beamer</option>
+ <option value="commonmark">CommonMark</option>
<option value="context">ConTeXt</option>
- <option value="docbook">DocBook</option>
+ <option value="docbook4">DocBook v4</option>
+ <option value="docbook5">DocBook v5</option>
<option value="dokuwiki">DokuWiki</option>
<option value="dzslides">DZSlides</option>
- <option value="man">Groff man</option>
- <option value="html" selected>HTML</option>
+ <option value="dzslides">dzslides</option>
+ <option value="gfm">GitHub-Flavored Markdown</option>
+ <option value="haddock">Haddock markup</option>
+ <option value="html4" selected>HTML 4</option>
<option value="html5">HTML 5</option>
<option value="icml">ICML</option>
+ <option value="json">JSON</option>
<option value="latex">LaTeX</option>
- <option value="beamer">LaTeX Beamer</option>
+ <option value="man">Groff man</option>
+ <option value="ms">Groff ms</option>
<option value="markdown">Markdown (pandoc)</option>
- <option value="markdown_strict">Markdown (strict)</option>
- <option value="markdown_phpextra">Markdown (PHP Markdown Extra)</option>
- <option value="markdown_github">Markdown (GitHub)</option>
<option value="markdown_mmd">MultiMarkdown</option>
- <option value="rst">reStructuredText</option>
- <option value="textile">Textile</option>
+ <option value="markdown_phpextra">Markdown (PHP Markdown Extra)</option>
+ <option value="markdown_strict">Markdown (strict)</option>
<option value="mediawiki">MediaWiki</option>
- <option value="org">Org Mode</option>
+ <option value="muse">Muse</option>
+ <option value="native">Native (Pandoc AST)</option>
<option value="opendocument">OpenDocument</option>
<option value="opml">OPML</option>
+ <option value="org">Org Mode</option>
+ <option value="plain">Plain text</option>
+ <option value="revealjs">reveal.js</option>
+ <option value="rst">reStructuredText</option>
<option value="rtf">RTF</option>
- <option value="S5">S5</option>
<option value="slideous">Slideous</option>
<option value="slidy">Slidy</option>
<option value="texinfo">Texinfo</option>
+ <option value="textile">Textile</option>
+ <option value="zimwiki">ZimWiki</option>
</select>
<br/>
<pre id="results"></pre>
diff --git a/trypandoc/trypandoc.hs b/trypandoc/trypandoc.hs
index 2fcfe35e7..5a4828877 100644
--- a/trypandoc/trypandoc.hs
+++ b/trypandoc/trypandoc.hs
@@ -3,12 +3,15 @@ module Main where
import Network.Wai.Handler.CGI
import Network.Wai
import Control.Applicative ((<$>))
-import Data.Maybe (mapMaybe, fromMaybe)
+import Data.Maybe (fromMaybe)
import Network.HTTP.Types.Status (status200)
import Network.HTTP.Types.Header (hContentType)
import Network.HTTP.Types.URI (queryToQueryText)
import Text.Pandoc
-import Text.Pandoc.Error (PandocError)
+import Text.Pandoc.Writers.Math (defaultMathJaxURL)
+import Text.Pandoc.Highlighting (pygments)
+import Text.Pandoc.Readers (getReader, Reader(..))
+import Text.Pandoc.Writers (getWriter, Writer(..))
import Text.Pandoc.Shared (tabFilter)
import Data.Aeson
import qualified Data.Text as T
@@ -25,12 +28,18 @@ app req respond = do
text <- getParam "text" >>= checkLength . fromMaybe T.empty
fromFormat <- fromMaybe "" <$> getParam "from"
toFormat <- fromMaybe "" <$> getParam "to"
- reader <- maybe (error $ "could not find reader for " ++ T.unpack fromFormat) return
- $ lookup fromFormat fromFormats
- let writer = maybe (error $ "could not find writer for " ++ T.unpack toFormat) id
- $ lookup toFormat toFormats
- let result = case reader $ tabFilter 4 $ T.unpack text of
- Right doc -> T.pack $ writer doc
+ let reader = case getReader (T.unpack fromFormat) of
+ Right (TextReader r, es) -> r readerOpts{
+ readerExtensions = es }
+ _ -> error $ "could not find reader for "
+ ++ T.unpack fromFormat
+ let writer = case getWriter (T.unpack toFormat) of
+ Right (TextWriter w, es) -> w writerOpts{
+ writerExtensions = es }
+ _ -> error $ "could not find writer for " ++
+ T.unpack toFormat
+ let result = case runPure $ reader (tabFilter 4 text) >>= writer of
+ Right s -> s
Left err -> error (show err)
let output = encode $ object [ T.pack "html" .= result
, T.pack "name" .=
@@ -49,53 +58,9 @@ checkLength t =
writerOpts :: WriterOptions
writerOpts = def { writerReferenceLinks = True,
writerEmailObfuscation = NoObfuscation,
- writerHTMLMathMethod = MathJax "http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML",
- writerHighlight = True }
+ writerHTMLMathMethod = MathJax (defaultMathJaxURL ++
+ "MathJax.js?config=TeX-AMS_CHTML-full"),
+ writerHighlightStyle = Just pygments }
readerOpts :: ReaderOptions
-readerOpts = def { readerParseRaw = True,
- readerSmart = True }
-
-fromFormats :: [(Text, String -> Either PandocError Pandoc)]
-fromFormats = [
- ("native" , readNative)
- ,("json" , Text.Pandoc.readJSON readerOpts)
- ,("markdown" , readMarkdown readerOpts)
- ,("markdown_strict" , readMarkdown readerOpts{
- readerExtensions = strictExtensions,
- readerSmart = False })
- ,("markdown_phpextra" , readMarkdown readerOpts{
- readerExtensions = phpMarkdownExtraExtensions })
- ,("markdown_github" , readMarkdown readerOpts{
- readerExtensions = githubMarkdownExtensions })
- ,("markdown_mmd", readMarkdown readerOpts{
- readerExtensions = multimarkdownExtensions })
- ,("rst" , readRST readerOpts)
- ,("mediawiki" , readMediaWiki readerOpts)
- ,("docbook" , readDocBook readerOpts)
- ,("opml" , readOPML readerOpts)
- ,("t2t" , readTxt2TagsNoMacros readerOpts)
- ,("org" , readOrg readerOpts)
- ,("textile" , readTextile readerOpts) -- TODO : textile+lhs
- ,("html" , readHtml readerOpts)
- ,("latex" , readLaTeX readerOpts)
- ,("haddock" , readHaddock readerOpts)
- ]
-
-toFormats :: [(Text, Pandoc -> String)]
-toFormats = mapMaybe (\(x,y) ->
- case y of
- PureStringWriter w -> Just (T.pack x, w writerOpts{
- writerExtensions =
- case x of
- "markdown_strict" -> strictExtensions
- "markdown_phpextra" -> phpMarkdownExtraExtensions
- "markdown_mmd" -> multimarkdownExtensions
- "markdown_github" -> githubMarkdownExtensions
- _ -> pandocExtensions
- })
- _ ->
- case x of
- "rtf" -> Just (T.pack x, writeRTF writerOpts)
- _ -> Nothing) writers
-
+readerOpts = def