git.iko.soy/typeable/pandoc
on master help sign in
Merge remote-tracking branch 'jgm/master' into dokuwiki
commit717e16660d1ee83f690b35d0aa9b60c8ac9d6b61 authorClare Macrae <github@cfmacrae.fastmail.co.uk> dateSun 29 Jun 2014, 19:22 (12 years ago) parentfccfc84ce69021
269 files changed+18085−14621
.editorconfig+16 .gitignore+5−1 .travis.yml+26−5 CONTRIBUTING.md+3 COPYRIGHT+15−47 INSTALL+66−24 Interact.hs+4 Makefile−48 README+404−149 RELEASE-CHECKLIST+2 Setup.hs+25−3 benchmark/benchmark-pandoc.hs+19−2 changelog+1405−44 data/MathMLinHTML.js+10−10 data/default.csl−458 data/epub.css+1−20 data/reference.docx data/reference.odt data/s5/default/blank.gif data/s5/default/bodybg.gif data/s5/default/framing.css−23 data/s5/default/iepngfix.htc−42 data/s5/default/opera.css−7 data/s5/default/outline.css−15 data/s5/default/pretty.css−86 data/s5/default/print.css−24 data/s5/default/s5-core.css−9 data/s5/default/slides.css−3 data/s5/default/slides.js−553 data/sample.lua+17−5 data/slideous/slideous.css−95 data/slideous/slideous.js−321 data/slidy/graphics/fold-dim.gif data/slidy/graphics/fold.gif data/slidy/graphics/nofold-dim.gif data/slidy/graphics/unfold-dim.gif data/slidy/graphics/unfold.gif data/slidy/scripts/slidy.js−3016 data/slidy/styles/slidy.css−405 github-upload.sh+18 googlecode-upload.sh+1−1 make_osx_package.sh+49−25 man/make-pandoc-man-pages.hs+1 osx-resources/InstallationCheck → osx/osx-resources/InstallationCheck osx-resources/InstallationCheck.strings → osx/osx-resources/InstallationCheck.strings osx/uninstall-pandoc.pl+79 pandoc.cabal+104−131 pandoc.hs+231−124 src/Text/Pandoc.hs+86−106 src/Text/Pandoc/Asciify.hs+2−2 src/Text/Pandoc/Biblio.hs−187 src/Text/Pandoc/Compat/Monoid.hs+20 src/Text/Pandoc/Compat/TagSoupEntity.hs+15 src/Text/Pandoc/Highlighting.hs+8−3 src/Text/Pandoc/ImageSize.hs+258−9 src/Text/Pandoc/MIME.hs+16−4 src/Text/Pandoc/Options.hs+18−11 src/Text/Pandoc/PDF.hs+88−47 src/Text/Pandoc/Parsing.hs+187−51 src/Text/Pandoc/Pretty.hs+14−6 src/Text/Pandoc/Process.hs+104 src/Text/Pandoc/Readers/DocBook.hs+90−50 src/Text/Pandoc/Readers/Docx.hs+489 src/Text/Pandoc/Readers/Docx/Lists.hs+227 src/Text/Pandoc/Readers/Docx/Parse.hs+596 src/Text/Pandoc/Readers/Docx/Reducible.hs+181 src/Text/Pandoc/Readers/HTML.hs+214−129 src/Text/Pandoc/Readers/Haddock.hs+118−21 src/Text/Pandoc/Readers/Haddock/Lex.x−171 src/Text/Pandoc/Readers/Haddock/Parse.y−178 src/Text/Pandoc/Readers/LaTeX.hs+455−264 src/Text/Pandoc/Readers/Markdown.hs+264−236 src/Text/Pandoc/Readers/MediaWiki.hs+79−28 src/Text/Pandoc/Readers/Native.hs+2−2 src/Text/Pandoc/Readers/OPML.hs+1−1 src/Text/Pandoc/Readers/Org.hs+1379 src/Text/Pandoc/Readers/RST.hs+126−37 src/Text/Pandoc/Readers/TeXMath.hs+22−88 src/Text/Pandoc/Readers/Textile.hs+203−161 src/Text/Pandoc/SelfContained.hs+18−15 src/Text/Pandoc/Shared.hs+137−47 src/Text/Pandoc/Slides.hs+8−3 src/Text/Pandoc/Templates.hs+48−40 src/Text/Pandoc/UTF8.hs+4−4 src/Text/Pandoc/UUID.hs+2−2 src/Text/Pandoc/Writers/AsciiDoc.hs+14−6 src/Text/Pandoc/Writers/ConTeXt.hs+15−19 src/Text/Pandoc/Writers/Custom.hs+16−3 src/Text/Pandoc/Writers/Docbook.hs+43−21 src/Text/Pandoc/Writers/Docx.hs+199−126 src/Text/Pandoc/Writers/EPUB.hs+780−138 src/Text/Pandoc/Writers/FB2.hs+11−6 src/Text/Pandoc/Writers/HTML.hs+105−53 src/Text/Pandoc/Writers/Haddock.hs+346 src/Text/Pandoc/Writers/ICML.hs+525 src/Text/Pandoc/Writers/LaTeX.hs+263−126 src/Text/Pandoc/Writers/Man.hs+14−9 src/Text/Pandoc/Writers/Markdown.hs+107−61 src/Text/Pandoc/Writers/MediaWiki.hs+60−53 src/Text/Pandoc/Writers/Native.hs+2−2 src/Text/Pandoc/Writers/ODT.hs+63−22 src/Text/Pandoc/Writers/OPML.hs+2−2 src/Text/Pandoc/Writers/OpenDocument.hs+43−22 src/Text/Pandoc/Writers/Org.hs+15−4 src/Text/Pandoc/Writers/RST.hs+34−15 src/Text/Pandoc/Writers/RTF.hs+18−13 src/Text/Pandoc/Writers/Shared.hs+48−4 src/Text/Pandoc/Writers/Texinfo.hs+21−17 src/Text/Pandoc/Writers/Textile.hs+19−11 src/Text/Pandoc/XML.hs+3−3 tests/MarkdownTest_1.0.3/MarkdownTest.pl−176 tests/MarkdownTest_1.0.3/Tests/Amps and angle encoding.html−17 tests/MarkdownTest_1.0.3/Tests/Amps and angle encoding.text−21 tests/MarkdownTest_1.0.3/Tests/Auto links.html−18 tests/MarkdownTest_1.0.3/Tests/Auto links.text−13 tests/MarkdownTest_1.0.3/Tests/Backslash escapes.html−118 tests/MarkdownTest_1.0.3/Tests/Backslash escapes.text−120 tests/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.html−15 tests/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.text−11 tests/MarkdownTest_1.0.3/Tests/Code Blocks.html−18 tests/MarkdownTest_1.0.3/Tests/Code Blocks.text−14 tests/MarkdownTest_1.0.3/Tests/Code Spans.html−6 tests/MarkdownTest_1.0.3/Tests/Code Spans.text−6 tests/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.html−8 tests/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.text−8 tests/MarkdownTest_1.0.3/Tests/Horizontal rules.html−71 tests/MarkdownTest_1.0.3/Tests/Horizontal rules.text−67 tests/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).html−15 tests/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).text−15 tests/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).html−72 tests/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).text−69 tests/MarkdownTest_1.0.3/Tests/Inline HTML comments.html−13 tests/MarkdownTest_1.0.3/Tests/Inline HTML comments.text−13 tests/MarkdownTest_1.0.3/Tests/Links, inline style.html−11 tests/MarkdownTest_1.0.3/Tests/Links, inline style.text−12 tests/MarkdownTest_1.0.3/Tests/Links, reference style.html−52 tests/MarkdownTest_1.0.3/Tests/Links, reference style.text−71 tests/MarkdownTest_1.0.3/Tests/Links, shortcut references.html−9 tests/MarkdownTest_1.0.3/Tests/Links, shortcut references.text−20 tests/MarkdownTest_1.0.3/Tests/Literal quotes in titles.html−3 tests/MarkdownTest_1.0.3/Tests/Literal quotes in titles.text−7 tests/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.html−314 tests/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.text−306 tests/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.html−942 tests/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.text−888 tests/MarkdownTest_1.0.3/Tests/Nested blockquotes.html−9 tests/MarkdownTest_1.0.3/Tests/Nested blockquotes.text−5 tests/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.html−148 tests/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.text−131 tests/MarkdownTest_1.0.3/Tests/Strong and em together.html−7 tests/MarkdownTest_1.0.3/Tests/Strong and em together.text−7 tests/MarkdownTest_1.0.3/Tests/Tabs.html−25 tests/MarkdownTest_1.0.3/Tests/Tabs.text−21 tests/MarkdownTest_1.0.3/Tests/Tidyness.html−8 tests/MarkdownTest_1.0.3/Tests/Tidyness.text−5 tests/Tests/Arbitrary.hs+9−10 tests/Tests/Old.hs+13−20 tests/Tests/Readers/Docx.hs+160 tests/Tests/Readers/LaTeX.hs+31−24 tests/Tests/Readers/Markdown.hs+20−3 tests/Tests/Readers/Org.hs+994 tests/Tests/Walk.hs+47 tests/Tests/Writers/AsciiDoc.hs+37 tests/Tests/Writers/Docbook.hs+229 tests/Tests/Writers/HTML.hs+1−4 tests/Tests/Writers/LaTeX.hs+31−1 tests/Tests/Writers/Markdown.hs+4 tests/biblio.bib−26 tests/chicago-author-date.csl−458 tests/docbook-reader.docbook+10−8 tests/docx.block_quotes.docx tests/docx.block_quotes_parse_indent.native+8 tests/docx.codeblock.docx tests/docx.codeblock.native+3 tests/docx.deep_normalize.docx tests/docx.deep_normalize.native+6 tests/docx.definition_list.docx tests/docx.definition_list.native+7 tests/docx.headers.docx tests/docx.headers.native+5 tests/docx.image.docx tests/docx.image_no_embed.native+2 tests/docx.inline_code.docx tests/docx.inline_code.native+1 tests/docx.inline_formatting.docx tests/docx.inline_formatting.native+5 tests/docx.links.docx tests/docx.links.native+6 tests/docx.lists.docx tests/docx.lists.native+18 tests/docx.normalize.docx tests/docx.normalize.native+2 tests/docx.notes.docx tests/docx.notes.native+2 tests/docx.tables.docx tests/docx.tables.native+24 tests/docx.tabs.docx tests/docx.tabs.native+2 tests/docx.track_changes_deletion.docx tests/docx.track_changes_deletion_accept.native+1 tests/docx.track_changes_deletion_all.native+1 tests/docx.track_changes_deletion_reject.native+1 tests/docx.track_changes_insertion.docx tests/docx.track_changes_insertion_accept.native+1 tests/docx.track_changes_insertion_all.native+1 tests/docx.track_changes_insertion_reject.native+1 tests/docx.trailing_spaces_in_formatting.docx tests/docx.trailing_spaces_in_formatting.native+1 tests/docx.unicode.docx tests/docx.unicode.native+1 tests/haddock-reader.haddock+10−10 tests/haddock-reader.native+8−8 tests/html-reader.html+24 tests/html-reader.native+87−71 tests/ieee.csl−302 tests/latex-reader.native+35−35 tests/lhs-test.html+2−2 tests/lhs-test.html+lhs+2−2 tests/lhs-test.latex+5−6 tests/lhs-test.latex+lhs+4−5 tests/lhs-test.markdown+2−2 tests/lhs-test.native+1−1 tests/markdown-citations.chicago-author-date.txt−45 tests/markdown-citations.ieee.txt−45 tests/markdown-citations.mhra.txt−63 tests/markdown-citations.native+17 tests/markdown-reader-more.native+12−7 tests/markdown-reader-more.txt+12 tests/mediawiki-reader.native+49−43 tests/mediawiki-reader.wiki+9−2 tests/mhra.csl−399 tests/opml-reader.native+1−1 tests/pipe-tables.native+9−1 tests/pipe-tables.txt+10 tests/rst-reader.native+43−33 tests/rst-reader.rst+24 tests/tables.asciidoc+4−7 tests/tables.context+7−7 tests/tables.haddock+77 tests/tables.html+6 tests/tables.icml+748 tests/tables.latex+77−77 tests/tables.mediawiki+125−191 tests/tables.rtf+92−92 tests/test-pandoc.hs+15−1 tests/testsuite.native+13−23 tests/testsuite.txt+6−6 tests/textile-reader.native+83−84 tests/textile-reader.textile+3−3 tests/writer.context+8−7 tests/writer.docbook+57−67 tests/writer.fb2+1−1 tests/writer.haddock+660 tests/writer.html+7−13 tests/writer.icml+3023 tests/writer.latex+9−19 tests/writer.man+1−1 tests/writer.markdown+23−6 tests/writer.mediawiki+20−8 tests/writer.native+13−23 tests/writer.opendocument+88−75 tests/writer.opml+6−6 tests/writer.org+31−6 tests/writer.plain+5 tests/writer.rst+30−5 tests/writer.rtf+1−1 tests/writer.textile+26−5 windows/make-windows-installer.bat+11−9 windows/pandoc.wxs+12−1
.editorconfignew file+16
@@ -0,0 +1,16 @@
1+root = true
2+
3+[*]
4+charset = utf-8
5+end_of_line = lf
6+indent_style = space
7+indent_size = 2
8+insert_final_newline = true
9+trim_trailing_whitespace = true
10+
11+[*.{markdown,md}]
12+trim_trailing_whitespace = false
13+
14+[tests/*]
15+insert_final_newline = false
16+trim_trailing_whitespace = false
.gitignore+5−1
@@ -1,15 +1,19 @@
1+*~
12dist/*
23README.*
34!README.Debian
45INSTALL.*
56.configure-stamp
7+.cabal-sandbox
8+cabal.sandbox.config
9+pandoc.cabal.orig
610man/man?/*.1
711man/man?/*.5
812man/man?/*.html
913*.diff
10−pandoc.cabal.orig
1114*.o
1215*.hi
16+*.pyc
1317/COPYING.rtf
1418/COPYRIGHT.txt
1519/cabal-dev/
.travis.yml+26−5
@@ -1,7 +1,28 @@
1−language: haskell
1+# NB: don't set `language: haskell` here
2+
3+# The following enables several GHC versions to be tested; often it's enough to test only against the last release in a major GHC version. Feel free to omit lines listings versions you don't need/want testing for.
4+env:
5+# - GHCVER=6.12.3
6+ - GHCVER=7.4.2
7+ - GHCVER=7.6.3
8+ - GHCVER=7.8.2 # see note about Alex/Happy
9+# - GHCVER=head # see section about GHC HEAD snapshots
10+
11+# Note: the distinction between `before_install` and `install` is not important.
212before_install:
3− - git submodule update --init --recursive
13+ - travis_retry sudo add-apt-repository -y ppa:hvr/ghc
14+ - travis_retry sudo apt-get update
15+ - travis_retry sudo apt-get install cabal-install-1.18 ghc-$GHCVER
16+ - export PATH=/opt/ghc/$GHCVER/bin:$PATH
17+
418install:
5− - cabal update
6− - cabal install --enable-tests
7−script: cabal configure --enable-tests && cabal build && cabal test
19+ - cabal-1.18 update
20+# - git clone https://github.com/jgm/pandoc-types && cd pandoc-types && cabal-1.18 install && cd ..
21+ - cabal-1.18 install --only-dependencies --enable-tests
22+
23+# Here starts the actual work to be performed for the package under test; any command which exits with a non-zero exit code causes the build to fail.
24+script:
25+ - cabal-1.18 configure --enable-tests -v2 # -v2 provides useful information for debugging
26+ - cabal-1.18 build --ghc-options=-Werror # this builds all libraries and executables (including tests/benchmarks)
27+ - cabal-1.18 test
28+ - cabal-1.18 check
CONTRIBUTING.md+3
@@ -60,6 +60,8 @@ Please follow these guidelines:
60603. Follow the stylistic conventions you find in the existing
6161 pandoc code. Use spaces, not tabs, and wrap code to 80 columns.
6262 Always include type signatures for top-level functions.
63+ Consider installing [EditorConfig], this will help you to follow the
64+ coding style prevalent in pandoc.
6365
64664. Your code should compile without warnings (`-Wall` clean).
6567
@@ -177,5 +179,6 @@ The library is structured as follows:
177179[issue tracker]: https://github.com/jgm/pandoc/issues
178180[User's Guide]: http://johnmacfarlane.net/pandoc/README.html
179181[FAQs]: http://johnmacfarlane.net/pandoc/faqs.html
182+[EditorConfig]: http://editorconfig.org/
180183[Haskell platform]: http://www.haskell.org/platform/
181184[hsb2hs]: http://hackage.haskell.org/package/hsb2hs
COPYRIGHT+15−47
@@ -1,5 +1,5 @@
11Pandoc
2−Copyright (C) 2006-2013 John MacFarlane <jgm at berkeley dot edu>
2+Copyright (C) 2006-2014 John MacFarlane <jgm at berkeley dot edu>
33
44This code is released under the [GPL], version 2 or later:
55
@@ -33,33 +33,34 @@ licenses.
3333
3434----------------------------------------------------------------------
3535src/Text/Pandoc/Writers/Texinfo.hs
36−Copyright (C) 2008-2010 John MacFarlane and Peter Wang
36+Copyright (C) 2008-2014 John MacFarlane and Peter Wang
3737
38−Released under the GPL.
38+Released under the GNU General Public License version 2 or later.
3939
4040----------------------------------------------------------------------
4141src/Text/Pandoc/Writers/OpenDocument.hs
42−Copyright (C) 2008-2010 Andrea Rossato and John MacFarlane
42+Copyright (C) 2008-2014 Andrea Rossato and John MacFarlane
4343
44−Released under the GPL.
44+Released under the GNU General Public License version 2 or later.
4545
4646----------------------------------------------------------------------
4747src/Text/Pandoc/Writers/Org.hs
48−Copyright (C) 2010 Puneeth Chaganti
48+Copyright (C) 2010-2014 Puneeth Chaganti and JohnMacFarlane
4949
50−Released under the GPL.
50+Released under the GNU General Public License version 2 or later.
5151
5252----------------------------------------------------------------------
5353src/Text/Pandoc/Readers/Textile.hs
54−Copyright (C) 2010 Paul Rivier
54+Copyright (C) 2010-2014 Paul Rivier and John MacFarlane
5555
56−Released under the GPL.
56+Released under the GNU General Public License version 2 or later.
5757
5858----------------------------------------------------------------------
59−src/Text/Pandoc/Biblio.hs
60−Copyright (C) 2008-2010 Andrea Rossato
59+src/Text/Pandoc/Readers/Org.hs
60+tests/Tests/Readers/Org.hs
61+Copyright (C) 2014 Albert Krewinkel
6162
62−Released under the GPL.
63+Released under the GNU General Public License version 2 or later.
6364
6465----------------------------------------------------------------------
6566data/LaTeXMathML.js
@@ -67,46 +68,13 @@ Adapted by Jeff Knisely and Douglas Woodall from
6768ASCIIMathML.js v. 1.4.7
6869Copyright (C) 2005 Peter Jipsen
6970
70−Released under the GPL.
71+Released under the GNU General Public License version 2 or later.
7172
7273----------------------------------------------------------------------
73−data/MathMLInHTML.js
74+data/MathMLinHTML.js
7475Copyright (C) 2004 Peter Jipsen http://www.chapman.edu/~jipsen
7576
7677Released under the GNU General Public License version 2 or later.
77−See the GNU General Public License
78−(at http://www.gnu.org/copyleft/gpl.html) for more details.
79−
80−----------------------------------------------------------------------
81−s5/default
82−S5 slides.js and css files
83−by Eric A. Meyer
84−<http://meyerweb.com/eric/tools/s5
85−
86−Released under an explicit Public Domain License
87−
88−----------------------------------------------------------------------
89−slidy/default
90−Slidy javascript and CSS
91−by Dave Raggett
92−http://www.w3.org/Talks/Tools/Slidy2
93−
94−Released under W3C document and software licenses
95−
96−----------------------------------------------------------------------
97−slideous/default
98−Slideous javascript and CSS
99−by Stefan Gössner
100−http://goessner.net/
101−
102−Released under Creative Commons GNU LGPL License
103−
104−------------------------------------------------------------------------
105−windows/modpath.iss
106−Copyright (c) 2007 Jared Breland
107−http://legroom.net/software
108−
109−Released under the GPL.
11078
11179------------------------------------------------------------------------
11280The dzslides template contains javascript and CSS from Paul Rouget's
INSTALL+66−24
@@ -3,15 +3,22 @@
33These instructions explain how to install pandoc from source.
44Binary packages or ports of pandoc are available for freebsd
55and several linux distributions, so check your package manager.
6−There is also a Windows installer.
6+There are also binary installers for Windows and Mac OS X.
7+
8+If you are installing the development version from github, see also:
9+https://github.com/jgm/pandoc/wiki/Installing-the-development-version-of-pandoc
710
811Quick install
912-------------
1013
11141. Install the [Haskell platform]. This will give you [GHC] and
12−the [cabal-install] build tool.
15+ the [cabal-install] build tool.
16+
17+2. Update your package database:
18+
19+ cabal update
1320
14−2. Use `cabal` to install pandoc and its dependencies:
21+3. Use `cabal` to install pandoc and its dependencies:
1522
1623 cabal install pandoc
1724
@@ -23,16 +30,47 @@ the [cabal-install] build tool.
2330
2431 cabal install
2532
26−3. Make sure the `$CABALDIR/bin` directory is in your path. You should
27−now be able to run `pandoc`:
33+ Note: If you obtained the source from the git repository (rather
34+ than a release tarball), you'll need to do
35+
36+ git submodule update --init
37+
38+ to fetch the contents of `data/templates` before `cabal install`.
39+
40+4. Make sure the `$CABALDIR/bin` directory is in your path. You should
41+ now be able to run `pandoc`:
2842
2943 pandoc --help
3044
31−4. Make sure the `$CABALDIR/share/man/man1` directory is in your `MANPATH`.
32−You should now be able to access the `pandoc` man page:
45+ [Not sure where `$CABALDIR` is?](http://www.haskell.org/haskellwiki/Cabal-Install#The_cabal-install_configuration_file)
46+
47+5. Make sure the `$CABALDIR/share/man/man1` directory is in your `MANPATH`.
48+ You should now be able to access the `pandoc` man page:
3349
3450 man pandoc
3551
52+6. If you want to process citations with pandoc, you will also need to
53+ install a separate package, `pandoc-citeproc`. This can be installed
54+ using cabal:
55+
56+ cabal install pandoc-citeproc
57+
58+ By default `pandoc-citeproc` uses the "i;unicode-casemap" method
59+ to sort bibliography entries (RFC 5051). If you would like to
60+ use the locale-sensitive unicode collation algorithm instead,
61+ specify the `unicode_collation` flag:
62+
63+ cabal install pandoc-citeproc -funicode_collation
64+
65+ Note that this requires the `text-icu` library, which in turn
66+ depends on the C library `icu4c`. Installation directions
67+ vary by platform. Here is how it might work on OSX with homebrew:
68+
69+ brew install icu4c
70+ cabal install --extra-lib-dirs=/usr/local/Cellar/icu4c/51.1/lib \
71+ --extra-include-dirs=/usr/local/Cellar/icu4c/51.1/include \
72+ -funicode_collation text-icu pandoc-citeproc
73+
3674[GHC]: http://www.haskell.org/ghc/
3775[Haskell platform]: http://hackage.haskell.org/platform/
3876[cabal-install]: http://hackage.haskell.org/trac/hackage/wiki/CabalInstall
@@ -43,14 +81,19 @@ Custom install
4381This is a step-by-step procedure that offers maximal control
4482over the build and installation. Most users should use the
4583quick install, but this information may be of use to packagers.
46−For more details, see the [Cabal User's Guide].
84+For more details, see the [Cabal User's Guide]. These instructions
85+assume that the pandoc source directory is your working directory.
4786
48871. Install dependencies: in addition to the [Haskell platform],
49−you will need [zip-archive], [blaze-html], and [highlighting-kate].
88+ you will need a number of additional libraries. You can install
89+ them all with
90+
91+ cabal update
92+ cabal install --only-dependencies
5093
51942. Configure:
5295
53− runghc Setup.hs configure --prefix=DIR --bindir=DIR --libdir=DIR \
96+ cabal configure --prefix=DIR --bindir=DIR --libdir=DIR \
5497 --datadir=DIR --libsubdir=DIR --datasubdir=DIR --docdir=DIR \
5598 --htmldir=DIR --program-prefix=PREFIX --program-suffix=SUFFIX \
5699 --mandir=DIR --flags=FLAGSPEC
@@ -62,26 +105,33 @@ you will need [zip-archive], [blaze-html], and [highlighting-kate].
62105 preceded by a `-` (to force the flag to `false`), and separated
63106 by spaces. Pandoc's flags include:
64107
65− - `blaze_html_0_5`: Use blaze-html >= 0.5 (default yes)
66− - `embed_data_files`: embed all data files into the binary (default no)
108+ - `embed_data_files`: embed all data files into the binary (default no).
109+ This is helpful if you want to create a relocatable binary.
110+ Note: if this option is selected, you need to install the
111+ `hsb2hs` preprocessor:
112+
113+ cabal install hsb2hs
114+
115+ - `https`: enable support for downloading resources over https
116+ (using the `http-client` and `http-client-tls` libraries).
67117
681183. Build:
69119
70− runghc Setup.hs build
120+ cabal build
71121
721224. Build API documentation:
73123
74− runghc Setup.hs haddock --html-location=URL --hyperlink-source
124+ cabal haddock --html-location=URL --hyperlink-source
75125
761265. Copy the files:
77127
78− runghc Setup.hs copy --destdir=PATH
128+ cabal copy --destdir=PATH
79129
80130 The default destdir is `/`.
81131
821326. Register pandoc as a GHC package:
83133
84− runghc Setup.hs register
134+ cabal register
85135
86136 Package managers may want to use the `--gen-script` option to
87137 generate a script that can be run to register the package at
@@ -107,7 +157,6 @@ you please.
107157[blaze-html]: http://hackage.haskell.org/package/blaze-html
108158[Cabal User's Guide]: http://www.haskell.org/cabal/release/latest/doc/users-guide/builders.html#setup-configure-paths
109159
110−
111160Running tests
112161-------------
113162
@@ -116,13 +165,6 @@ To build the tests:
116165
117166 cabal configure --enable-tests && cabal build
118167
119−Note: If you obtained the source via git, you should first do
120−
121− git submodule update --init data/templates
122−
123−to populate the templates subdirectory. (You can skip this step
124−if you obtained the source from a release tarball.)
125−
126168To run the tests:
127169
128170 cabal test
Interact.hs+4
@@ -9,6 +9,10 @@
99
1010-- You must have first done a 'cabal configure' or 'cabal install'
1111
12+-- Note: Interact.hs doesn't work with Cabal >= 1.18. I recommend
13+-- using cabal sandboxes and the new 'cabal repl' command if you are
14+-- using a recent version.
15+
1216import System.Process
1317import Distribution.Simple.LocalBuildInfo
1418import Distribution.Package
Makefiledeleted−48
@@ -1,48 +0,0 @@
1−# This Makefile is for development only. It requires cabal-dev.
2−# To get started, do 'make prep' and then 'make' or 'make quick'.
3−
4−.PHONY: prep submodules all quick bench clean veryclean install sdist
5−
6−all:
7− cabal-dev configure --enable-tests --enable-benchmarks && cabal-dev build
8−
9−prof:
10− cabal-dev configure --disable-tests --enable-library-profiling --enable-executable-profiling && cabal-dev build
11−
12−prep: submodules pandoc-types citeproc-hs
13− (cabal-dev --version || (cabal update && cabal install cabal-dev)) && \
14− cabal-dev update && \
15− cabal-dev install-deps --enable-library-profiling --enable-tests --enable-benchmarks
16−
17−submodules:
18− git submodule update --init
19−
20−quick:
21− cabal-dev configure --enable-tests --disable-optimization && cabal-dev build
22−
23−relocatable:
24− cabal-dev configure -fembed_data_files && cabal-dev build
25−
26−bench:
27− cabal-dev configure --enable-benchmarks && cabal-dev build
28−
29−sdist:
30− dist/setup/setup sdist
31− # cabal sdist won't work, see https://github.com/haskell/cabal/issues/403
32−
33−clean:
34− cabal-dev clean
35−
36−veryclean: clean
37− cabal-dev clean && rm -rf pandoc-types citeproc-hs
38−
39−pandoc-types:
40− git clone https://github.com/jgm/pandoc-types && \
41− cabal-dev add-source pandoc-types
42−
43−citeproc-hs: pandoc-types
44− darcs get --lazy http://gorgias.mine.nu/repos/citeproc-hs && \
45− cabal-dev add-source citeproc-hs
46−
47−install:
48− cabal-dev install --enable-tests --enable-benchmarks
README+404−149
@@ -1,6 +1,6 @@
11% Pandoc User's Guide
22% John MacFarlane
3−% January 19, 2013
3+% May 16, 2014
44
55Synopsis
66========
@@ -13,14 +13,15 @@ Description
1313Pandoc is a [Haskell] library for converting from one markup format to
1414another, and a command-line tool that uses this library. It can read
1515[markdown] and (subsets of) [Textile], [reStructuredText], [HTML],
16−[LaTeX], [MediaWiki markup], [Haddock markup], [OPML], and [DocBook]; and
17−it can write plain text, [markdown], [reStructuredText], [XHTML], [HTML 5],
18−[LaTeX] (including [beamer] slide shows), [ConTeXt], [RTF], [OPML], [DocBook],
16+[LaTeX], [MediaWiki markup], [Haddock markup], [OPML], [Emacs
17+Org-mode], [DocBook], and [Word docx]; and it can write plain text,
18+[markdown], [reStructuredText], [XHTML], [HTML 5], [LaTeX] (including
19+[beamer] slide shows), [ConTeXt], [RTF], [OPML], [DocBook],
1920[OpenDocument], [ODT], [Word docx], [GNU Texinfo], [MediaWiki markup],
20−[EPUB] (v2 or v3), [FictionBook2], [Textile], [groff man] pages, [Emacs
21−Org-Mode], [AsciiDoc], and [Slidy], [Slideous], [DZSlides], [reveal.js]
22−or [S5] HTML slide shows. It can also produce [PDF] output on systems
23−where LaTeX is installed.
21+[Haddock markup], [EPUB] (v2 or v3), [FictionBook2], [Textile],
22+[groff man] pages, [Emacs Org-Mode], [AsciiDoc], [InDesign ICML],
23+and [Slidy], [Slideous], [DZSlides], [reveal.js] or [S5] HTML slide shows.
24+It can also produce [PDF] output on systems where LaTeX is installed.
2425
2526Pandoc's enhanced version of markdown includes syntax for footnotes,
2627tables, flexible ordered lists, definition lists, fenced code blocks,
@@ -108,7 +109,7 @@ to PDF:
108109Production of a PDF requires that a LaTeX engine be installed (see
109110`--latex-engine`, below), and assumes that the following LaTeX packages are
110111available: `amssymb`, `amsmath`, `ifxetex`, `ifluatex`, `listings` (if the
111−`--listings` option is used), `fancyvrb`, `longtable`, `url`,
112+`--listings` option is used), `fancyvrb`, `longtable`, `booktabs`, `url`,
112113`graphicx`, `hyperref`, `ulem`, `babel` (if the `lang` variable is set),
113114`fontspec` (if `xelatex` or `lualatex` is used as the LaTeX engine), `xltxtra`
114115and `xunicode` (if `xelatex` is used).
@@ -143,14 +144,14 @@ General options
143144 `markdown_phpextra` (PHP Markdown Extra extended markdown),
144145 `markdown_github` (github extended markdown),
145146 `textile` (Textile), `rst` (reStructuredText), `html` (HTML),
146− `docbook` (DocBook), `opml` (OPML), `mediawiki` (MediaWiki markup),
147− `haddock` (Haddock markup), or `latex` (LaTeX).
148− If `+lhs` is appended to `markdown`, `rst`, `latex`, or `html`,
149− the input will be treated as literate Haskell source:
150− see [Literate Haskell support](#literate-haskell-support), below.
151− Markdown syntax extensions can be individually enabled or disabled
152− by appending `+EXTENSION` or `-EXTENSION` to the format name.
153− So, for example, `markdown_strict+footnotes+definition_lists`
147+ `docbook` (DocBook), `opml` (OPML), `org` (Emacs Org-mode),
148+ `mediawiki` (MediaWiki markup), `haddock` (Haddock markup), or
149+ `latex` (LaTeX). If `+lhs` is appended to `markdown`, `rst`,
150+ `latex`, or `html`, the input will be treated as literate Haskell
151+ source: see [Literate Haskell support](#literate-haskell-support),
152+ below. Markdown syntax extensions can be individually enabled or
153+ disabled by appending `+EXTENSION` or `-EXTENSION` to the format
154+ name. So, for example, `markdown_strict+footnotes+definition_lists`
154155 is strict markdown with footnotes and definition lists enabled,
155156 and `markdown-pipe_tables+hard_line_breaks` is pandoc's markdown
156157 without pipe tables and with hard line breaks. See [Pandoc's
@@ -168,22 +169,22 @@ General options
168169 `context` (ConTeXt), `man` (groff man), `mediawiki` (MediaWiki markup),
169170 `textile` (Textile), `org` (Emacs Org-Mode), `texinfo` (GNU Texinfo),
170171 `opml` (OPML), `docbook` (DocBook), `opendocument` (OpenDocument), `odt`
171− (OpenOffice text document), `docx` (Word docx),
172− `rtf` (rich text format), `epub` (EPUB v2 book), `epub3`
173− (EPUB v3), `fb2` (FictionBook2 e-book), `asciidoc` (AsciiDoc), `slidy`
174− (Slidy HTML and javascript slide show), `slideous` (Slideous HTML and
175− javascript slide show), `dzslides` (DZSlides HTML5 + javascript slide
176− show), `revealjs` (reveal.js HTML5 + javascript slide show), `s5`
177− (S5 HTML and javascript slide show), or the path of a custom
178− lua writer (see [Custom writers](#custom-writers), below). Note that
179− `odt`, `epub`, and `epub3` output will not be directed to *stdout*; an
180− output filename must be specified using the `-o/--output` option. If
181− `+lhs` is appended to `markdown`, `rst`, `latex`, `beamer`, `html`, or
182− `html5`, the output will be rendered as literate Haskell source: see
183− [Literate Haskell support](#literate-haskell-support), below. Markdown
184− syntax extensions can be individually enabled or disabled by appending
185− `+EXTENSION` or `-EXTENSION` to the format name, as described above
186− under `-f`.
172+ (OpenOffice text document), `docx` (Word docx), `haddock` (Haddock
173+ markup), `rtf` (rich text format), `epub` (EPUB v2 book), `epub3`
174+ (EPUB v3), `fb2` (FictionBook2 e-book), `asciidoc` (AsciiDoc),
175+ `icml` (InDesign ICML), `slidy` (Slidy HTML and javascript slide show),
176+ `slideous` (Slideous HTML and javascript slide show), `dzslides`
177+ (DZSlides HTML5 + javascript slide show), `revealjs` (reveal.js
178+ HTML5 + javascript slide show), `s5` (S5 HTML and javascript slide show),
179+ or the path of a custom lua writer (see [Custom writers](#custom-writers),
180+ below). Note that `odt`, `epub`, and `epub3` output will not be directed
181+ to *stdout*; an output filename must be specified using the `-o/--output`
182+ option. If `+lhs` is appended to `markdown`, `rst`, `latex`, `beamer`,
183+ `html`, or `html5`, the output will be rendered as literate Haskell
184+ source: see [Literate Haskell support](#literate-haskell-support), below.
185+ Markdown syntax extensions can be individually enabled or disabled by
186+ appending `+EXTENSION` or `-EXTENSION` to the format name, as described
187+ above under `-f`.
187188
188189`-o` *FILE*, `--output=`*FILE*
189190: Write output to *FILE* instead of *stdout*. If *FILE* is
@@ -259,6 +260,42 @@ Reader options
259260 require different kinds of images. Currently this option only affects
260261 the markdown and LaTeX readers.
261262
263+`--filter=`*EXECUTABLE*
264+: Specify an executable to be used as a filter transforming the
265+ Pandoc AST after the input is parsed and before the output is
266+ written. The executable should read JSON from stdin and write
267+ JSON to stdout. The JSON must be formatted like pandoc's own
268+ JSON input and output. The name of the output format will be
269+ passed to the filter as the first argument. Hence,
270+
271+ pandoc --filter ./caps.py -t latex
272+
273+ is equivalent to
274+
275+ pandoc -t json | ./caps.py latex | pandoc -f json -t latex
276+
277+ The latter form may be useful for debugging filters.
278+
279+ Filters may be written in any language. `Text.Pandoc.JSON`
280+ exports `toJSONFilter` to facilitate writing filters in Haskell.
281+ Those who would prefer to write filters in python can use the
282+ module `pandocfilters`, installable from PyPI. See
283+ <http://github.com/jgm/pandocfilters> for the module and several
284+ examples. Note that the *EXECUTABLE* will be sought in the user's
285+ `PATH`, and not in the working directory, if no directory is
286+ provided. If you want to run a script in the working directory,
287+ preface the filename with `./`.
288+
289+`-M` *KEY[=VAL]*, `--metadata=`*KEY[:VAL]*
290+: Set the metadata field *KEY* to the value *VAL*. A value specified
291+ on the command line overrides a value specified in the document.
292+ Values will be parsed as YAML boolean or string values. If no value is
293+ specified, the value will be treated as Boolean true. Like
294+ `--variable`, `--metadata` causes template variables to be set.
295+ But unlike `--variable`, `--metadata` affects the metadata of the
296+ underlying document (which is accessible from filters and may be
297+ printed in some output formats).
298+
262299`--normalize`
263300: Normalize the document after reading: merge adjacent
264301 `Str` or `Emph` elements, for example, and remove repeated `Space`s.
@@ -271,6 +308,17 @@ Reader options
271308`--tab-stop=`*NUMBER*
272309: Specify the number of spaces per tab (default is 4).
273310
311+`--track-changes=`*accept|reject|all*
312+: Specifies what to do with insertions and deletions produced by the MS
313+ Word "track-changes" feature. *accept* (the default), inserts all
314+ insertions, and ignores all deletions. *reject* inserts all
315+ deletions and ignores insertions. *all* puts in both insertions
316+ and deletions, wrapped in spans with `insertion` and `deletion`
317+ classes, respectively. The author and time of change is
318+ included. *all* is useful for scripting: only accepting changes
319+ from a certain reviewer, say, or before a certain date. This
320+ option only affects the Docx reader.
321+
274322General writer options
275323----------------------
276324
@@ -303,9 +351,8 @@ General writer options
303351: Print the default template for an output *FORMAT*. (See `-t`
304352 for a list of possible *FORMAT*s.)
305353
306−`--print-sample-lua-writer`
307−: Print a sample lua custom writer (see [Custom writers](#custom-writers),
308− below.
354+`--print-default-data-file=`*FILE*
355+: Print a default data file.
309356
310357`--no-wrap`
311358: Disable text wrapping in output. By default, text is wrapped
@@ -318,7 +365,7 @@ General writer options
318365: Include an automatically generated table of contents (or, in
319366 the case of `latex`, `context`, and `rst`, an instruction to create
320367 one) in the output document. This option has no effect on `man`,
321− `docbook`, `slidy`, `slideous`, or `s5` output.
368+ `docbook`, `slidy`, `slideous`, `s5`, `docx`, or `odt` output.
322369
323370`--toc-depth=`*NUMBER*
324371: Specify the number of section levels to include in the table
@@ -399,8 +446,8 @@ Options affecting specific writers
399446`--chapters`
400447: Treat top-level headers as chapters in LaTeX, ConTeXt, and DocBook
401448 output. When the LaTeX template uses the report, book, or
402− memoir class, this option is implied. If `--beamer` is used,
403− top-level headers will become `\part{..}`.
449+ memoir class, this option is implied. If `beamer` is the output
450+ format, top-level headers will become `\part{..}`.
404451
405452`-N`, `--number-sections`
406453: Number section headings in LaTeX, ConTeXt, HTML, or EPUB output.
@@ -471,7 +518,7 @@ Options affecting specific writers
471518
472519`-c` *URL*, `--css=`*URL*
473520: Link to a CSS style sheet. This option can be be used repeatedly to
474− include multiple files. They will be included in the order specified.
521+ include multiple files. They will be included in the order specified.
475522
476523`--reference-odt=`*FILE*
477524: Use the specified file as a style reference in producing an ODT.
@@ -487,7 +534,8 @@ Options affecting specific writers
487534: Use the specified file as a style reference in producing a docx file.
488535 For best results, the reference docx should be a modified version
489536 of a docx file produced using pandoc. The contents of the reference docx
490− are ignored, but its stylesheets are used in the new docx. If no
537+ are ignored, but its stylesheets and document properties (including
538+ margins, page size, header, and footer) are used in the new docx. If no
491539 reference docx is specified on the command line, pandoc will look
492540 for a file `reference.docx` in the user data directory (see
493541 `--data-dir`). If this is not found either, sensible defaults will be
@@ -506,7 +554,9 @@ Options affecting specific writers
506554
507555`--epub-cover-image=`*FILE*
508556: Use the specified image as the EPUB cover. It is recommended
509− that the image be less than 1000px in width and height.
557+ that the image be less than 1000px in width and height. Note that
558+ in a markdown source document you can also specify `cover-image`
559+ in a YAML metadata block (see [EPUB Metadata], below).
510560
511561`--epub-metadata=`*FILE*
512562: Look in the specified XML file for metadata for the EPUB.
@@ -525,6 +575,10 @@ Options affecting specific writers
525575 id="BookId">` (a randomly generated UUID). Any of these may be
526576 overridden by elements in the metadata file.
527577
578+ Note: if the source document is markdown, a YAML metadata block
579+ in the document can be used instead. See below under
580+ [EPUB Metadata].
581+
528582`--epub-embed-font=`*FILE*
529583: Embed the specified font in the EPUB. This option can be repeated
530584 to embed multiple fonts. To use embedded fonts, you
@@ -575,58 +629,32 @@ Citation rendering
575629------------------
576630
577631`--bibliography=`*FILE*
578−: Specify bibliography database to be used in resolving
579− citations. The database type will be determined from the
580− extension of *FILE*, which may be `.mods` (MODS format),
581− `.bib` (BibLaTeX format, which will normally work for BibTeX
582− files as well), `.bibtex` (BibTeX format),
583− `.ris` (RIS format), `.enl` (EndNote format),
584− `.xml` (EndNote XML format), `.wos` (ISI format),
585− `.medline` (MEDLINE format), `.copac` (Copac format),
586− or `.json` (citeproc JSON). If you want to use multiple
587− bibliographies, just use this option repeatedly.
632+: Set the `bibliography` field in the document's metadata to *FILE*,
633+ overriding any value set in the metadata, and process citations
634+ using `pandoc-citeproc`. (This is equivalent to
635+ `--metadata bibliography=FILE --filter pandoc-citeproc`.)
588636
589637`--csl=`*FILE*
590−: Specify [CSL] style to be used in formatting citations and
591− the bibliography. If *FILE* is not found, pandoc will look
592− for it in
593−
594− $HOME/.csl
595−
596− in unix,
597−
598− C:\Documents And Settings\USERNAME\Application Data\csl
599−
600− in Windows XP, and
601−
602− C:\Users\USERNAME\AppData\Roaming\csl
603−
604− in Windows 7. If the `--csl` option is not specified, pandoc
605− will use a default style: either `default.csl` in the
606− user data directory (see `--data-dir`), or, if that is
607− not present, the Chicago author-date style.
638+: Set the `csl` field in the document's metadata to *FILE*,
639+ overriding any value set in the metadata. (This is equivalent to
640+ `--metadata csl=FILE`.)
608641
609642`--citation-abbreviations=`*FILE*
610−: Specify a file containing abbreviations for journal titles and
611− other bibliographic fields (indicated by setting `form="short"`
612− in the CSL node for the field). The format is described at
613− <http://citationstylist.org/2011/10/19/abbreviations-for-zotero-test-release/>.
614− Here is a short example:
615−
616− { "default": {
617− "container-title": {
618− "Lloyd's Law Reports": "Lloyd's Rep",
619− "Estates Gazette": "EG",
620− "Scots Law Times": "SLT"
621− }
622− }
623− }
643+: Set the `citation-abbreviations` field in the document's metadata to
644+ *FILE*, overriding any value set in the metadata. (This is equivalent to
645+ `--metadata citation-abbreviations=FILE`.)
624646
625647`--natbib`
626−: Use natbib for citations in LaTeX output.
648+: Use natbib for citations in LaTeX output. This option is not for use
649+ with the `pandoc-citeproc` filter or with PDF output. It is intended for
650+ use in producing a LaTeX file that can be processed with pdflatex and
651+ bibtex.
627652
628653`--biblatex`
629−: Use biblatex for citations in LaTeX output.
654+: Use biblatex for citations in LaTeX output. This option is not for use
655+ with the `pandoc-citeproc` filter or with PDF output. It is intended for
656+ use in producing a LaTeX file that can be processed with pdflatex and
657+ bibtex or biber.
630658
631659Math rendering in HTML
632660----------------------
@@ -755,29 +783,41 @@ as `title`, `author`, and `date`) as well as the following:
755783: base URL for Slidy documents (defaults to
756784 `http://www.w3.org/Talks/Tools/Slidy2`)
757785`slideous-url`
758−: base URL for Slideous documents (defaults to `default`)
786+: base URL for Slideous documents (defaults to `slideous`)
759787`s5-url`
760−: base URL for S5 documents (defaults to `ui/default`)
788+: base URL for S5 documents (defaults to `s5/default`)
761789`revealjs-url`
762790: base URL for reveal.js documents (defaults to `reveal.js`)
763791`theme`
764−: reveal.js theme
792+: reveal.js or LaTeX beamer theme
765793`transition`
766794: reveal.js transition
767795`fontsize`
768796: font size (10pt, 11pt, 12pt) for LaTeX documents
769797`documentclass`
770798: document class for LaTeX documents
799+`classoption`
800+: option for LaTeX documentclass, e.g. `oneside`; may be repeated
801+ for multiple options
771802`geometry`
772803: options for LaTeX `geometry` class, e.g. `margin=1in`;
773804 may be repeated for multiple options
805+`linestretch`
806+: adjusts line spacing (requires the `setspace` package)
807+`fontfamily`
808+: font package to use for LaTeX documents (with pdflatex):
809+ TeXLive has `bookman` (Bookman), `utopia` or `fourier` (Utopia),
810+ `fouriernc` (New Century Schoolbook), `times` or `txfonts` (Times),
811+ `mathpazo` or `pxfonts` or `mathpple` (Palatino),
812+ `libertine` (Linux Libertine), `arev` (Arev Sans),
813+ and the default `lmodern`, among others.
774814`mainfont`, `sansfont`, `monofont`, `mathfont`
775815: fonts for LaTeX documents (works only with xelatex
776816 and lualatex)
777−`theme`
778−: theme for LaTeX beamer documents
779817`colortheme`
780818: colortheme for LaTeX beamer documents
819+`fonttheme`
820+: fonttheme for LaTeX beamer documents
781821`linkcolor`
782822: color for internal links in LaTeX documents (`red`, `green`,
783823 `magenta`, `cyan`, `blue`, `black`)
@@ -787,6 +827,10 @@ as `title`, `author`, and `date`) as well as the following:
787827: color for citation links in LaTeX documents
788828`links-as-notes`
789829: causes links to be printed as footnotes in LaTeX documents
830+`biblio-style`
831+: bibliography style in LaTeX, when used with `--natbib`
832+`biblio-files`
833+: bibliography files to use in LaTeX, with `--natbib` or `--biblatex`
790834`section`
791835: section number in man pages
792836`header`
@@ -880,6 +924,9 @@ If you need a hard line break, put two or more spaces at the end of a line.
880924**Extension: `escaped_line_breaks`**
881925
882926A backslash followed by a newline is also a hard line break.
927+Note: in multiline and grid table cells, this is the only way
928+to create a hard line break, since trailing spaces in the cells
929+are ignored.
883930
884931Headers
885932-------
@@ -889,7 +936,7 @@ There are two kinds of headers, Setext and atx.
889936### Setext-style headers ###
890937
891938A setext-style header is a line of text "underlined" with a row of `=` signs
892−(for a level one header) of `-` signs (for a level two header):
939+(for a level one header) or `-` signs (for a level two header):
893940
894941 A level-one header
895942 ==================
@@ -936,10 +983,8 @@ of the line containing the header text:
936983
937984 {#identifier .class .class key=value key=value}
938985
939−Although this syntax allows assignment of classes and key/value attributes,
940−only identifiers currently have any affect in the writers (and only in some
941−writers: HTML, LaTeX, ConTeXt, Textile, AsciiDoc). Thus, for example,
942−the following headers will all be assigned the identifier `foo`:
986+Thus, for example, the following headers will all be assigned the identifier
987+`foo`:
943988
944989 # My header {#foo}
945990
@@ -950,6 +995,12 @@ the following headers will all be assigned the identifier `foo`:
950995
951996(This syntax is compatible with [PHP Markdown Extra].)
952997
998+Note that although this syntax allows assignment of classes and key/value
999+attributes, writers generally don't use all of this information. Identifiers,
1000+classes, and key/value attributes are used in HTML and HTML-based formats such
1001+as EPUB and slidy. Identifiers are used for labels and link anchors in the
1002+LaTeX, ConTeXt, Textile, and AsciiDoc writers.
1003+
9531004Headers with the class `unnumbered` will not be numbered, even if
9541005`--number-sections` is specified. A single hyphen (`-`) in an attribute
9551006context is equivalent to `.unnumbered`, and preferable in non-English
@@ -968,6 +1019,7 @@ automatically assigned a unique identifier based on the header text.
9681019To derive the identifier from the header text,
9691020
9701021 - Remove all formatting, links, etc.
1022+ - Remove all footnotes.
9711023 - Remove all punctuation, except underscores, hyphens, and periods.
9721024 - Replace all spaces and newlines with hyphens.
9731025 - Convert all alphabetic characters to lowercase.
@@ -1262,7 +1314,7 @@ one tab:
12621314 + pears
12631315 + peaches
12641316 * vegetables
1265− + brocolli
1317+ + broccoli
12661318 + chard
12671319
12681320As noted above, markdown allows you to write list items "lazily," instead of
@@ -1337,6 +1389,12 @@ capital letter with a period, by at least two spaces.[^2]
13371389
13381390 (C\) 2007 Joe Smith
13391391
1392+The `fancy_lists` extension also allows '`#`' to be used as an
1393+ordered list marker in place of a numeral:
1394+
1395+ #. one
1396+ #. two
1397+
13401398**Extension: `startnum`**
13411399
13421400Pandoc also pays attention to the type of list marker used, and to the
@@ -1779,14 +1837,21 @@ YAML metadata block
17791837
17801838**Extension: `yaml_metadata_block`**
17811839
1782−If the file begins with a YAML object, delimited by a line of three
1783−hyphens (`---`) at the top and a line of three hyphens (`---`) or three
1784−dots (`...`) at the bottom, metadata will be taken from the fields
1785−of the YAML object. Metadata can contain lists and objects (nested
1786−arbitrarily), but all string scalars will be interpreted as markdown.
1840+A YAML metadata block is a valid YAML object, delimited by a line of three
1841+hyphens (`---`) at the top and a line of three hyphens (`---`) or three dots
1842+(`...`) at the bottom. A YAML metadata block may occur anywhere in the
1843+document, but if it is not at the beginning, it must be preceded by a blank
1844+line.
1845+
1846+Metadata will be taken from the fields of the YAML object and added to any
1847+existing document metadata. Metadata can contain lists and objects (nested
1848+arbitrarily), but all string scalars will be interpreted as markdown. Fields
1849+with names ending in an underscore will be ignored by pandoc. (They may be
1850+given a role by external processors.)
17871851
1788−Fields with names ending in an underscore will be ignored by
1789−pandoc. (They may be given a role by external processors.)
1852+A document may contain multiple metadata blocks. The metadata fields will
1853+be combined through a *left-biased union*: if two metadata blocks attempt
1854+to set the same field, the value from the first block will be taken.
17901855
17911856Note that YAML escaping rules must be followed. Thus, for example,
17921857if a title contains a colon, it must be quoted. The pipe character
@@ -1794,27 +1859,39 @@ if a title contains a colon, it must be quoted. The pipe character
17941859literally, without need for escaping. This form is necessary
17951860when the field contains blank lines:
17961861
1797− ---
1798− title: 'This is the title: it contains a colon'
1799− author:
1800− - name: Author One
1801− affiliation: University of Somewhere
1802− - name: Author Two
1803− affiliation: University of Nowhere
1804− tags: [nothing, nothingness]
1805− abstract: |
1806− This is the abstract.
1807−
1808− It consists of two paragraphs.
1809− ...
1810−
1811−Template variables will be set from the metadata. Thus, for example,
1812−in writing HTML, the variable `abstract` will be set to the HTML
1862+ ---
1863+ title: 'This is the title: it contains a colon'
1864+ author:
1865+ - name: Author One
1866+ affiliation: University of Somewhere
1867+ - name: Author Two
1868+ affiliation: University of Nowhere
1869+ tags: [nothing, nothingness]
1870+ abstract: |
1871+ This is the abstract.
1872+
1873+ It consists of two paragraphs.
1874+ ...
1875+
1876+Template variables will be set automatically from the metadata. Thus, for
1877+example, in writing HTML, the variable `abstract` will be set to the HTML
18131878equivalent of the markdown in the `abstract` field:
18141879
18151880 <p>This is the abstract.</p>
18161881 <p>It consists of two paragraphs.</p>
18171882
1883+Note: The `author` variable in the default templates expects a simple list or
1884+string. To use the structured authors in the example, you would need a
1885+custom template. For example:
1886+
1887+ $for(author)$
1888+ $if(author.name)$
1889+ $author.name$$if(author.affiliation)$ ($author.affiliation$)$endif$
1890+ $else$
1891+ $author$
1892+ $endif$
1893+ $endfor$
1894+
18181895
18191896Backslash escapes
18201897-----------------
@@ -1954,6 +2031,14 @@ Attributes can be attached to verbatim text, just as with
19542031
19552032 `<$>`{.haskell}
19562033
2034+### Small caps ###
2035+
2036+To write small caps, you can use an HTML span tag:
2037+
2038+ <span style="font-variant:small-caps;">Small caps</span>
2039+
2040+This will work in all output formats that support small caps.
2041+
19572042Math
19582043----
19592044
@@ -2063,7 +2148,7 @@ Raw HTML
20632148
20642149Markdown allows you to insert raw HTML (or DocBook) anywhere in a document
20652150(except verbatim contexts, where `<`, `>`, and `&` are interpreted
2066−literally). (Techncially this is not an extension, since standard
2151+literally). (Technically this is not an extension, since standard
20672152markdown allows it, but it has been made an extension so that it can
20682153be disabled if desired.)
20692154
@@ -2335,9 +2420,14 @@ Citations
23352420
23362421**Extension: `citations`**
23372422
2338−Pandoc can automatically generate citations and a bibliography in a number of
2339−styles (using Andrea Rossato's `hs-citeproc`). In order to use this feature,
2340−you will need a bibliographic database in one of the following formats:
2423+Using an external filter, `pandoc-citeproc`, pandoc can automatically generate
2424+citations and a bibliography in a number of styles. Basic usage is
2425+
2426+ pandoc --filter pandoc-citeproc myinput.txt
2427+
2428+In order to use this feature, you will need to specify a bibliography file
2429+using the `bibliography` metadata field in a YAML metadata section.
2430+The bibliography may have any of these formats:
23412431
23422432 Format File extension
23432433 ------------ --------------
@@ -2355,23 +2445,47 @@ you will need a bibliographic database in one of the following formats:
23552445Note that `.bib` can generally be used with both BibTeX and BibLaTeX
23562446files, but you can use `.bibtex` to force BibTeX.
23572447
2358−You will need to specify the bibliography file using the `--bibliography`
2359−command-line option (which may be repeated if you have several
2360−bibliographies).
2448+Alternatively you can use a `references` field in the document's YAML
2449+metadata. This should include an array of YAML-encoded references,
2450+for example:
23612451
2362−By default, pandoc will use a Chicago author-date format for citations
2363−and references. To use another style, you will need to use the
2364−`--csl` option to specify a [CSL] 1.0 style file. A primer on
2365−creating and modifying CSL styles can be found at
2366−<http://citationstyles.org/downloads/primer.html>.
2367−A repository of CSL styles can be found at
2368−<https://github.com/citation-style-language/styles>.
2369−See also <http://zotero.org/styles> for easy browsing.
2452+ ---
2453+ references:
2454+ - id: fenner2012a
2455+ title: One-click science marketing
2456+ author:
2457+ - family: Fenner
2458+ given: Martin
2459+ container-title: Nature Materials
2460+ volume: 11
2461+ URL: 'http://dx.doi.org/10.1038/nmat3283'
2462+ DOI: 10.1038/nmat3283
2463+ issue: 4
2464+ publisher: Nature Publishing Group
2465+ page: 261-263
2466+ type: article-journal
2467+ issued:
2468+ year: 2012
2469+ month: 3
2470+ ...
2471+
2472+(The program `mods2yaml`, which comes with `pandoc-citeproc`, can help produce
2473+these from a MODS reference collection.)
2474+
2475+By default, `pandoc-citeproc` will use a Chicago author-date format for
2476+citations and references. To use another style, you will need to specify
2477+a [CSL] 1.0 style file in the `csl` metadata field. A primer on creating and
2478+modifying CSL styles can be found at
2479+<http://citationstyles.org/downloads/primer.html>. A repository of CSL styles
2480+can be found at <https://github.com/citation-style-language/styles>. See also
2481+<http://zotero.org/styles> for easy browsing.
23702482
23712483Citations go inside square brackets and are separated by semicolons.
23722484Each citation must have a key, composed of '@' + the citation
23732485identifier from the database, and may optionally have a prefix,
2374−a locator, and a suffix. Here are some examples:
2486+a locator, and a suffix. The citation key must begin with a letter
2487+or `_`, and may contain alphanumerics, `_`, and internal punctuation
2488+characters (`:.#$%&-+?<>~/`). Here are some examples:
23752489
23762490 Blah blah [see @doe99, pp. 33-35; also @smith04, ch. 1].
23772491
@@ -2399,7 +2513,24 @@ document with an appropriate header:
23992513
24002514 # References
24012515
2402−The bibliography will be inserted after this header.
2516+The bibliography will be inserted after this header. Note that
2517+the `unnumbered` class will be added to this header, so that the
2518+section will not be numbered.
2519+
2520+If you want to include items in the bibliography without actually
2521+citing them in the body text, you can define a dummy `nocite` metadata
2522+field and put the citations there:
2523+
2524+ ---
2525+ nocite: |
2526+ @item1, @item2
2527+ ...
2528+
2529+ @item3
2530+
2531+In this example, the document will contain a citation for `item3`
2532+only, but the bibliography will contain entries for `item1`, `item2`, and
2533+`item3`.
24032534
24042535Non-pandoc extensions
24052536---------------------
@@ -2409,10 +2540,20 @@ in pandoc, but may be enabled by adding `+EXTENSION` to the format
24092540name, where `EXTENSION` is the name of the extension. Thus, for
24102541example, `markdown+hard_line_breaks` is markdown with hard line breaks.
24112542
2543+**Extension: `lists_without_preceding_blankline`**\
2544+Allow a list to occur right after a paragraph, with no intervening
2545+blank space.
2546+
24122547**Extension: `hard_line_breaks`**\
24132548Causes all newlines within a paragraph to be interpreted as hard line
24142549breaks instead of spaces.
24152550
2551+**Extension: `ignore_line_breaks`**\
2552+Causes newlines within a paragraph to be ignored, rather than being
2553+treated as spaces or as hard line breaks. This option is intended for
2554+use with East Asian languages where spaces are not used between words,
2555+but text is divided into lines for readability.
2556+
24162557**Extension: `tex_math_single_backslash`**\
24172558Causes anything between `\(` and `\)` to be interpreted as inline
24182559TeX math, and anything between `\[` and `\]` to be interpreted
@@ -2439,10 +2580,9 @@ the document, for example:
24392580 Comment: This is a sample mmd title block, with
24402581 a field spanning multiple lines.
24412582
2442−See the MultiMarkdown documentation for details. Note that only title,
2443−author, and date are recognized; other fields are simply ignored by
2444−pandoc. If `pandoc_title_block` or `yaml_metadata_block` is enabled,
2445−it will take precedence over `mmd_title_block`.
2583+See the MultiMarkdown documentation for details. If `pandoc_title_block` or
2584+`yaml_metadata_block` is enabled, it will take precedence over
2585+`mmd_title_block`.
24462586
24472587 [MultiMarkdown]: http://fletcherpenney.net/multimarkdown/
24482588
@@ -2500,6 +2640,20 @@ variants are supported:
25002640`markdown_strict` (Markdown.pl)
25012641: `raw_html`
25022642
2643+Extensions with formats other than markdown
2644+-------------------------------------------
2645+
2646+Some of the extensions discussed above can be used with formats
2647+other than markdown:
2648+
2649+* `auto_identifiers` can be used with `latex`, `rst`, `mediawiki`,
2650+ and `textile` input (and is used by default).
2651+
2652+* `tex_math_dollars`, `tex_math_single_backslash`, and
2653+ `tex_math_double_backslash` can be used with `html` input.
2654+ (This is handy for reading web pages formatted using MathJax,
2655+ for example.)
2656+
25032657Producing slide shows with Pandoc
25042658=================================
25052659
@@ -2625,9 +2779,8 @@ a single document.
26252779Inserting pauses
26262780----------------
26272781
2628−In reveal.js and beamer slide shows, you can add "pauses" within
2629−a slide by including a paragraph containing three dots, separated
2630−by spaces:
2782+You can add "pauses" within a slide by including a paragraph containing
2783+three dots, separated by spaces:
26312784
26322785 # Slide with a pause
26332786
@@ -2663,11 +2816,109 @@ using the `-V` option:
26632816
26642817 pandoc -t beamer habits.txt -V theme:Warsaw -o habits.pdf
26652818
2819+Note that header attributes will turn into slide attributes
2820+(on a `<div>` or `<section>`) in HTML slide formats, allowing you
2821+to style individual slides. In Beamer, the only header attribute
2822+that affects slides is the `allowframebreaks` class, which sets the
2823+`allowframebreaks` option, causing multiple slides to be created
2824+if the content overfills the frame. This is recommended especially for
2825+bibliographies:
2826+
2827+ # References {.allowframebreaks}
2828+
2829+Speaker notes
2830+-------------
2831+
2832+reveal.js has good support for speaker notes. You can add notes to your
2833+markdown document thus:
2834+
2835+ <div class="notes">
2836+ This is my note.
2837+
2838+ - It can contain markdown
2839+ - like this list
2840+
2841+ </div>
2842+
2843+To show the notes window, press `s` while viewing the presentation.
2844+Notes are not yet supported for other slide formats, but the notes
2845+will not appear on the slides themselves.
2846+
2847+EPUB Metadata
2848+=============
2849+
2850+EPUB metadata may be specified using the `--epub-metadata` option, but
2851+if the source document is markdown, it is better to use a YAML metadata
2852+block. Here is an example:
2853+
2854+ ---
2855+ title:
2856+ - type: main
2857+ text: My Book
2858+ - type: subtitle
2859+ text: An investigation of metadata
2860+ creator:
2861+ - role: author
2862+ text: John Smith
2863+ - role: editor
2864+ text: Sarah Jones
2865+ identifier:
2866+ - scheme: DOI
2867+ text: doi:10.234234.234/33
2868+ publisher: My Press
2869+ rights: (c) 2007 John Smith, CC BY-NC
2870+ ...
2871+
2872+The following fields are recognized:
2873+
2874+`identifier`
2875+ ~ Either a string value or an object with fields `text` and
2876+ `scheme`. Valid values for `scheme` are `ISBN-10`,
2877+ `GTIN-13`, `UPC`, `ISMN-10`, `DOI`, `LCCN`, `GTIN-14`,
2878+ `ISBN-13`, `Legal deposit number`, `URN`, `OCLC`,
2879+ `ISMN-13`, `ISBN-A`, `JP`, `OLCC`.
2880+`title`
2881+ ~ Either a string value, or an object with fields `file-as` and
2882+ `type`, or a list of such objects. Valid values for `type` are
2883+ `main`, `subtitle`, `short`, `collection`, `edition`, `extended`.
2884+`creator`
2885+ ~ Either a string value, or an object with fields `role`, `file-as`,
2886+ and `text`, or a list of such objects. Valid values for `role` are
2887+ [marc relators](http://www.loc.gov/marc/relators/relaterm.html), but
2888+ pandoc will attempt to translate the human-readable versions
2889+ (like "author" and "editor") to the appropriate marc relators.
2890+`contributor`
2891+ ~ Same format as `creator`.
2892+`date`
2893+ ~ A string value in `YYYY-MM-DD` format. (Only the year is necessary.)
2894+ Pandoc will attempt to convert other common date formats.
2895+`language`
2896+ ~ A string value in [RFC5646] format. Pandoc will default to the local
2897+ language if nothing is specified.
2898+`subject`
2899+ ~ A string value or a list of such values.
2900+`description`
2901+ ~ A string value.
2902+`type`
2903+ ~ A string value.
2904+`format`
2905+ ~ A string value.
2906+`relation`
2907+ ~ A string value.
2908+`coverage`
2909+ ~ A string value.
2910+`rights`
2911+ ~ A string value.
2912+`cover-image`
2913+ ~ A string value (path to cover image).
2914+`stylesheet`
2915+ ~ A string value (path to CSS stylesheet).
2916+
26662917Literate Haskell support
26672918========================
26682919
26692920If you append `+lhs` (or `+literate_haskell`) to an appropriate input or output
2670−format (`markdown`, `mardkown_strict`, `rst`, or `latex` for input or output;
2921+format (`markdown`, `markdown_strict`, `rst`, or `latex` for input or output;
26712922`beamer`, `html` or `html5` for output only), pandoc will treat the document as
26722923literate Haskell source. This means that
26732924
@@ -2724,7 +2975,7 @@ Creating a custom writer requires writing a lua function for each
27242975possible element in a pandoc document. To get a documented example
27252976which you can modify according to your needs, do
27262977
2727− pandoc --print-sample-lua-writer
2978+ pandoc --print-default-data-file sample.lua
27282979
27292980Authors
27302981=======
@@ -2738,7 +2989,9 @@ Puneeth Chaganti, Paul Rivier, rodja.trappe, Bradley Kuhn, thsutton,
27382989Nathan Gass, Jonathan Daugherty, Jérémy Bobbio, Justin Bogner, qerub,
27392990Christopher Sawicki, Kelsey Hightower, Masayoshi Takahashi, Antoine
27402991Latter, Ralf Stephan, Eric Seidel, B. Scott Michel, Gavin Beatty,
2741−Sergey Astanin, Arlo O'Keeffe, Denis Laxalde, Brent Yorgey.
2992+Sergey Astanin, Arlo O'Keeffe, Denis Laxalde, Brent Yorgey, David Lazar,
2993+Jamie F. Olson, Matthew Pickering, Albert Krewinkel, mb21, Jesse
2994+Rosenthal.
27422995
27432996[markdown]: http://daringfireball.net/projects/markdown/
27442997[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
@@ -2772,5 +3025,7 @@ Sergey Astanin, Arlo O'Keeffe, Denis Laxalde, Brent Yorgey.
27723025[PDF]: http://www.adobe.com/pdf/
27733026[reveal.js]: http://lab.hakim.se/reveal-js/
27743027[FictionBook2]: http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1
2775−[lua]: TODO
2776−
3028+[lua]: http://www.lua.org
3029+[marc relators]: http://www.loc.gov/marc/relators/relaterm.html
3030+[RFC5646]: http://tools.ietf.org/html/rfc5646
3031+[InDesign ICML]: https://www.adobe.com/content/dam/Adobe/en/devnet/indesign/cs55-docs/IDML/idml-specification.pdf
RELEASE-CHECKLIST+2
@@ -16,6 +16,8 @@ _ Upload to Google Code (googlecode-upload.sh)
1616
1717_ Go to Google code and deprecate the old versions
1818
19+- Add release on github (and upload files)
20+
1921_ Upload to HackageDB
2022
2123_ Update website, including short description of changes
Setup.hs+25−3
@@ -1,16 +1,34 @@
11{-# LANGUAGE CPP #-}
2+{-
3+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
4+
5+This program is free software; you can redistribute it and/or modify
6+it under the terms of the GNU General Public License as published by
7+the Free Software Foundation; either version 2 of the License, or
8+(at your option) any later version.
9+
10+This program is distributed in the hope that it will be useful,
11+but WITHOUT ANY WARRANTY; without even the implied warranty of
12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+GNU General Public License for more details.
14+
15+You should have received a copy of the GNU General Public License
16+along with this program; if not, write to the Free Software
17+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+-}
219
320import Distribution.Simple
421import Distribution.Simple.PreProcess
522import Distribution.Simple.Setup
6− (copyDest, copyVerbosity, fromFlag, installVerbosity, BuildFlags(..))
23+ (copyDest, copyVerbosity, fromFlag, installVerbosity, BuildFlags(..),
24+ TestFlags(..))
725import Distribution.PackageDescription (PackageDescription(..), Executable(..))
826import Distribution.Simple.LocalBuildInfo
927 (LocalBuildInfo(..), absoluteInstallDirs)
1028import Distribution.Verbosity ( Verbosity, silent )
11−import Distribution.Simple.InstallDirs (mandir, CopyDest (NoCopyDest))
29+import Distribution.Simple.InstallDirs (mandir, CopyDest (NoCopyDest), toPathTemplate)
1230import Distribution.Simple.Utils (installOrdinaryFiles, info)
13−import Prelude hiding (catch)
31+import Distribution.Simple.Test (test)
1432import System.Process ( rawSystem )
1533import System.FilePath ( (</>) )
1634import System.Directory ( findExecutable )
@@ -20,6 +38,10 @@ main :: IO ()
2038main = do
2139 defaultMainWithHooks $ simpleUserHooks {
2240 postBuild = makeManPages
41+ , testHook = \pkg lbi _ flags ->
42+ -- pass build directory as first argument to test program
43+ test pkg lbi flags{ testOptions =
44+ toPathTemplate (buildDir lbi) : testOptions flags }
2345 , postCopy = \ _ flags pkg lbi ->
2446 installManpages pkg lbi (fromFlag $ copyVerbosity flags)
2547 (fromFlag $ copyDest flags)
benchmark/benchmark-pandoc.hs+19−2
@@ -1,3 +1,20 @@
1+{-
2+Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
3+
4+This program is free software; you can redistribute it and/or modify
5+it under the terms of the GNU General Public License as published by
6+the Free Software Foundation; either version 2 of the License, or
7+(at your option) any later version.
8+
9+This program is distributed in the hope that it will be useful,
10+but WITHOUT ANY WARRANTY; without even the implied warranty of
11+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+GNU General Public License for more details.
13+
14+You should have received a copy of the GNU General Public License
15+along with this program; if not, write to the Free Software
16+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+-}
118import Text.Pandoc
219import Criterion.Main
320import Criterion.Config
@@ -31,8 +48,8 @@ main = do
3148 inp2 <- readFile "tests/testsuite.txt"
3249 let opts = def{ readerSmart = True }
3350 let doc = readMarkdown opts $ inp ++ unlines (drop 3 $ lines inp2)
34− let readerBs = map (readerBench doc) readers
51+ let readerBs = map (readerBench doc)
52+ $ filter (\(n,_) -> n /="haddock") readers
3553 let writers' = [(n,w) | (n, PureStringWriter w) <- writers]
3654 defaultMainWith conf (return ()) $
3755 map (writerBench doc) writers' ++ readerBs
38−
changelog+1405−44
@@ -1,3 +1,1364 @@
1+pandoc (1.12.4.2)
2+
3+ * Require highlighting-kate >= 0.5.8. Fixes a performance regression.
4+
5+ * Shared: `addMetaValue` now behaves slightly differently:
6+ if both the new and old values are lists, it concatenates their
7+ contents to form a new list.
8+
9+ * LaTeX reader:
10+
11+ + Set `bibliography` in metadata from `\bibliography` or
12+ `\addbibresource` command.
13+ + Don't error on `%foo` with no trailing newline.
14+
15+ * Org reader:
16+
17+ + Support code block headers (`#+BEGIN_SRC ...`) (Albert Krewinkel).
18+ + Fix parsing of blank lines within blocks (Albert Krewinkel).
19+ + Support pandoc citation extension (Albert Krewinkel). This can
20+ be turned off by specifying `org-citations` as the input format.
21+
22+ * Markdown reader:
23+
24+ + `citeKey` moved to `Text.Pandoc.Parsing` so it can be used by
25+ other readers (Albert Krewinkel).
26+
27+ * `Text.Pandoc.Parsing`:
28+
29+ + Added `citeKey` (see above).
30+ + Added `HasLastStrPosition` type class and `updateLastStrPos`
31+ and `notAfterString` functions.
32+
33+ * Updated copyright notices (Albert Krewinkel).
34+
35+ * Added default.icml to data files so it installs with the package.
36+
37+ * OSX package:
38+
39+ + The binary is now built with options to ensure that it can be
40+ used with OSX 10.6+.
41+ + Moved OSX package materials to osx directory.
42+ + Added OSX package uninstall script, included in the zip container
43+ (thanks to Daniel T. Staal).
44+
45+pandoc (1.12.4)
46+
47+ * Made it possible to run filters that aren't executable (#1096).
48+ Pandoc first tries to find the executable (searching the path
49+ if path isn't given). If it fails, but the file exists and has
50+ a `.py`, `.pl`, `.rb`, `.hs`, or `.php` extension, pandoc runs the filter
51+ using the appropriate interpreter. This should make it easier to
52+ use filters on Windows, and make it more convenient for everyone.
53+
54+ * Added Emacs org-mode reader (Albert Krewinkel).
55+
56+ * Added InDesign ICML Writer (mb21).
57+
58+ * MediaWiki reader:
59+
60+ + Accept image links in more languages (Jaime Marquínez Ferrándiz).
61+ + Fixed bug in certain nested lists (#1213). If a level 2 list was
62+ followed by a level 1 list, the first item of the level 1 list
63+ would be lost.
64+ + Handle table rows containing just an HTML comment (#1230).
65+
66+ * LaTeX reader:
67+
68+ + Give better location information on errors, pointing to line
69+ numbers within included files (#1274).
70+ + LaTeX reader: Better handling of `table` environment (#1204).
71+ Positioning options no longer rendered verbatim.
72+ + Better handling of figure and table with caption (#1204).
73+ + Handle `@{}` and `p{length}` in tabular. The length is not actually
74+ recorded, but at least we get a table (#1180).
75+ + Properly handle `\nocite`. It now adds a `nocite` metadata
76+ field. Citations there will appear in the bibliography but not
77+ in the text (unless you explicitly put a `$nocite$` variable
78+ in your template).
79+
80+ * Markdown reader:
81+
82+ + Ensure that whole numbers in YAML metadata are rendered without
83+ decimal points. (This became necessary with changes to aeson
84+ and yaml libraries. aeson >= 0.7 and yaml >= 0.8.8.2 are now required.)
85+ + Fixed regression on line breaks in strict mode (#1203).
86+ + Small efficiency improvements.
87+ + Improved parsing of nested `div`s. Formerly a closing `div` tag
88+ would be missed if it came right after other block-level tags.
89+ + Avoid backtracking when closing `</div>` not found.
90+ + Fixed bug in reference link parsing in `markdown_mmd`.
91+ + Fixed a bug in list parsing (#1154). When reading a raw list
92+ item, we now strip off up to 4 spaces.
93+ + Fixed parsing of empty reference link definitions (#1186).
94+ + Made one-column pipe tables work (#1218).
95+
96+ * Textile reader:
97+
98+ + Better support for attributes. Instead of being ignored, attributes
99+ are now parsed and included in Span inlines. The output will be a bit
100+ different from stock textile: e.g. for `*(foo)hi*`, we'll get
101+ `<em><span class="foo">hi</span></em>` instead of
102+ `<em class="foo">hi</em>`. But at least the data is not lost.
103+ + Improved treatment of HTML spans (%) (#1115).
104+ + Improved link parsing. In particular we now pick up on attributes.
105+ Since pandoc links can't have attributes, we enclose the whole link in
106+ a span if there are attributes (#1008).
107+ + Implemented correct parsing rules for inline markup (#1175, Matthew
108+ Pickering).
109+ + Use Builder (Matthew Pickering).
110+
111+ * DocBook reader:
112+
113+ + Better treatment of `formalpara`. We now emit the title (if present)
114+ as a separate paragraph with boldface text (#1215).
115+ + Set metadata `author` not `authors`.
116+ + Added recognition of `authorgroup` and `releaseinfo` elements (#1214,
117+ Matthew Pickering).
118+ + Converted current meta information parsing in DocBook to a more
119+ extensible version which is aware of the more recent meta
120+ representation (Matthew Pickering).
121+
122+ * HTML reader:
123+
124+ + Require tagsoup 0.13.1, to fix a bug with parsing of script tags
125+ (#1248).
126+ + Treat processing instructions & declarations as block. Previously
127+ these were treated as inline, and included in paragraph tags in HTML
128+ or DocBook output, which is generally not what is wanted (#1233).
129+ + Updated `closes` with rules from HTML5 spec.
130+ + Use Builder (Matthew Pickering, #1162).
131+
132+ * RST reader:
133+
134+ + Remove duplicate `http` in PEP links (Albert Krewinkel).
135+ + Make rst figures true figures (#1168, CasperVector)
136+ + Enhanced Pandoc's support for rST roles (Merijn Verstaaten).
137+ rST parser now supports: all built-in rST roles, new role definition,
138+ role inheritance, though with some limitations.
139+ + Use `author` rather than `authors` in metadata.
140+ + Better handling of directives. We now correctly handle field
141+ lists that are indented more than three spaces. We treat an
142+ `aafig` directive as a code block with attributes, so it can be
143+ processed in a filter (#1212).
144+
145+ * LaTeX writer:
146+
147+ + Mark span contents with label if span has an ID (Albert Krewinkel).
148+ + Made `--toc-depth` work well with books in latex/pdf output (#1210).
149+ + Handle line breaks in simple table cells (#1217).
150+ + Workaround for level 4-5 headers in quotes. These previously produced
151+ invalid LaTeX: `\paragraph` or `\subparagraph` in a `quote` environment.
152+ This adds an `mbox{}` in these contexts to work around the problem.
153+ See <http://tex.stackexchange.com/a/169833/22451> (#1221).
154+ + Use `\/` to avoid en-dash ligature instead of `-{}-` (Vaclav Zeman).
155+ This is to fix LuaLaTeX output. The `-{}-` sequence does not avoid the
156+ ligature with LuaLaTeX but `\/` does.
157+ + Fixed string escaping in `hyperref` and `hyperdef` (#1130).
158+
159+ * ConTeXt writer: Improved autolinks (#1270).
160+
161+ * DocBook writer:
162+
163+ + Improve handling of hard line breaks in Docbook writer
164+ (Neil Mayhew). Use a `<literallayout>` for the entire paragraph, not
165+ just for the newline character.
166+ + Don't let line breaks inside footnotes influence the enclosing
167+ paragraph (Neil Mayhew).
168+ + Distinguish tight and loose lists in DocBook output, using
169+ `spacing="compact"` (Neil Mayhew, #1250).
170+
171+ * Docx writer: When needed files are not present in the user's
172+ `reference.docx`, fall back on the versions in the `reference.docx`
173+ in pandoc's data files. This fixes a bug that occurs when a
174+ `reference.docx` saved by LibreOffice is used. (#1185)
175+
176+ * EPUB writer:
177+
178+ + Include extension in epub ids. This fixes a problem with duplicate
179+ extensions for fonts and images with the same base name but different
180+ extensions (#1254).
181+ + Handle files linked in raw `img` tags (#1170).
182+ + Handle media in `audio` source tags (#1170).
183+ Note that we now use a `media` directory rather than `images`.
184+ + Incorporate files linked in `video` tags (#1170). `src` and `poster`
185+ will both be incorporated into `content.opf` and the epub container.
186+
187+ * HTML writer:
188+
189+ + Add colgroup around col tags (#877). Also affects EPUB writer.
190+ + Fixed bug with unnumbered section headings. Unnumbered section
191+ headings (with class `unnumbered`) were getting numbers.
192+ + Improved detection of image links. Previously image links with
193+ queries were not recognized, causing `<embed>` to be used instead
194+ of `<img>`.
195+
196+ * Man writer: Ensure that terms in definition lists aren't line wrapped
197+ (#1195).
198+
199+ * Markdown writer:
200+
201+ + Use proper escapes to avoid unwanted lists (#980). Previously we used
202+ 0-width spaces, an ugly hack.
203+ + Use longer backtick fences if needed (#1206). If the content contains a
204+ backtick fence and there are attributes, make sure longer fences are
205+ used to delimit the code. Note: This works well in pandoc, but github
206+ markdown is more limited, and will interpret the first string of three
207+ or more backticks as ending the code block.
208+
209+ * RST writer: Avoid stack overflow with certain tables (#1197).
210+
211+ * RTF writer: Fixed table cells containing paragraphs.
212+
213+ * Custom writer:
214+
215+ + Correctly handle UTF-8 in custom lua scripts (#1189).
216+ + Fix bugs with lua scripts with mixed-case filenames and
217+ paths containing `+` or `-` (#1267). Note that `getWriter`
218+ in `Text.Pandoc` no longer returns a custom writer on input
219+ `foo.lua`.
220+
221+ * AsciiDoc writer: Handle multiblock and empty table cells
222+ (#1245, #1246). Added tests.
223+
224+ * `Text.Pandoc.Options`: Added `readerTrace` to `ReaderOptions`
225+
226+ * `Text.Pandoc.Shared`:
227+
228+ + Added `compactify'DL` (formerly in markdown reader) (Albert Krewinkel).
229+ + Fixed bug in `toRomanNumeral`: numbers ending with '9' would
230+ be rendered as Roman numerals ending with 'IXIV' (#1249). Thanks to
231+ Jesse Rosenthal.
232+ + `openURL`: set proxy with value of http_proxy env variable (#1211).
233+ Note: proxies with non-root paths are not supported, due to
234+ limitations in `http-conduit`.
235+
236+ * `Text.Pandoc.PDF`:
237+
238+ + Ensure that temp directories deleted on Windows (#1192). The PDF is
239+ now read as a strict bytestring, ensuring that process ownership will
240+ be terminated, so the temp directory can be deleted.
241+ + Use `/` as path separators in a few places, even on Windows.
242+ This seems to be necessary for texlive (#1151, thanks to Tim Lin).
243+ + Use `;` for `TEXINPUTS` separator on Windows (#1151).
244+ + Changes to error reporting, to handle non-UTF8 error output.
245+
246+ * `Text.Pandoc.Templates`:
247+
248+ + Removed unneeded datatype context (Merijn Verstraaten).
249+
250+ + YAML objects resolve to "true" in conditionals (#1133).
251+ Note: If `address` is a YAML object and you just have `$address$`
252+ in your template, the word `true` will appear, which may be
253+ unexpected. (Previously nothing would appear.)
254+
255+ * `Text.Pandoc.SelfContained`: Handle `poster` attribute in `video`
256+ tags (#1188).
257+
258+ * `Text.Pandoc.Parsing`:
259+
260+ + Made `F` an instance of Applicative (#1138).
261+ + Added `stateCaption`.
262+ + Added `HasMacros`, simplified other typeclasses.
263+ Removed `updateHeaderMap`, `setHeaderMap`, `getHeaderMap`,
264+ `updateIdentifierList`, `setIdentifierList`, `getIdentifierList`.
265+ + Changed the smart punctuation parser to return `Inlines`
266+ rather than `Inline` (Matthew Pickering).
267+ + Changed `HasReaderOptions`, `HasHeaderMap`, `HasIdentifierList`
268+ from typeclasses of monads to typeclasses of states. This simplifies
269+ the instance definitions and provides more flexibility. Generalized
270+ type of `getOption` and added a default definition. Removed
271+ `askReaderOption`. Added `extractReaderOption`. Added
272+ `extractHeaderMap` and `updateHeaderMap` in `HasHeaderMap`.
273+ Gave default definitions for `getHeaderMap`, `putHeaderMap`,
274+ `modifyHeaderMap`. Added `extractIdentifierList` and
275+ `updateIdentifierList` in `HasIdentifierList`. Gave defaults
276+ for `getIdentifierList`, `putIdentifierList`, and
277+ `modifyIdentifierList`. The ultimate goal here is to allow different
278+ parsers to use their own, tailored parser states (instead of
279+ `ParserState`) while still using shared functions.
280+
281+ * Template changes:
282+
283+ + LaTeX template: Use `fontenc` package only with `pdflatex` (#1164).
284+ + LaTeX template: Add `linestretch` and `fontfamily` variables.
285+ + LaTeX template: Conditionalize author and date commands.
286+ + Beamer template: Consistent styles for figure and table captions
287+ (aaronwolen).
288+ + LaTeX and beamer template: Adjust widths correctly for oversized
289+ images. Use `\setkeys{Gin}{}` to set appropriate defaults for
290+ `\includegraphics` (Yihui Xie, Garrick Aden-Buie). Load
291+ `upquote` only after `fontenc` (Yihui Xie).
292+ + Beamer template: Added caption package (#1200).
293+ + Beamer template: changes for better unicode handling (KarolS).
294+ + DocBook template: use `authorgroup` if there are authors.
295+ + revealjs template: Move `include-after` to end (certainlyakey).
296+ + revealjs template: Fixed PDF print function (#1220, kevinkenan).
297+
298+ * Bumped version bounds of dependencies.
299+
300+ * Added a `--trace` command line option, for debugging backtracking
301+ bugs. So far this only works with the markdown reader.
302+
303+ * MathMLinHTML: Fixed deprecation warning (#362, gwern, Albert Krewinkel).
304+
305+ * Updated travis script to test with multiple GHC versions.
306+
307+ * Force failure of a Travis build if GHC produces warnings (Albert
308+ Krewinkel).
309+
310+ * Add `.editorconfig` (Albert Krewinkel).
311+ See <http://editorconfig.org/> for details.
312+
313+ * Give more useful error message if '-t pdf' is specified (#1155).
314+
315+ * Added `Cite`, `SmallCaps` to `Arbitrary` instance (#1269).
316+
317+ * Allow `html4` as a synonym of `html` as a reader (it already works
318+ as a writer).
319+
320+ * README:
321+
322+ + Added an explanation of how to use YAML metadata to
323+ force items to appear in the bibliography without citations in
324+ the text (like LaTeX `\nocite`).
325+ + Added note to `--bibtex/--natbib`: not for use in making PDF
326+ (#1194, thanks to nahoj).
327+ + Added explanatory notes about `--natbib` and `--biblatex`.
328+ + Added specification of legal syntax for citation keys.
329+ + Fixed variable defaults documentation (Albert Krewinkel).
330+
331+ * Removed copyright statements for files that have been removed
332+ (Albert Krewinkel).
333+
334+ * Moved some doc files from `data-files` to `extra-source-files` (#1123).
335+ They aren't needed at runtime. We keep README and COPYRIGHT in data
336+ to ensure that they'll be available on all systems on which pandoc
337+ is installed.
338+
339+ * Use cabal sandboxes in Windows build script.
340+
341+pandoc (1.12.3.3)
342+
343+ * To changes to source; recompiled tarball with latest alex and
344+ happy, so they will work with GHC 7.8.
345+
346+pandoc (1.12.3.2)
347+
348+ * Bumped version bounds for blaze-html, blaze-markup.
349+
350+ * ImageSize: Avoid use of lookAhead, which is not in binary >= 0.6
351+ (#1124).
352+
353+ * Fixed mediawiki ordered list parsing (#1122).
354+
355+ * HTML reader: Fixed bug reading inline math with `$$` (#225).
356+
357+ * Added support for LaTeX style literate Haskell code blocks in rST
358+ (Merijn Verstraaten).
359+
360+pandoc (1.12.3.1)
361+
362+ * Relaxed version constraint on binary, allowing the use of binary 0.5.
363+
364+pandoc (1.12.3)
365+
366+ * The `--bibliography` option now sets the `biblio-files` variable.
367+ So, if you're using `--natbib` or `--biblatex`, you can just use
368+ `--bibliography=foo.bib` instead of `-V bibliofiles=foo`.
369+
370+ * Don't run pandoc-citeproc filter if `--bibliography` is
371+ used together with `--natbib` or `--biblatex` (Florian Eitel).
372+
373+ * Template changes:
374+
375+ + Updated beamer template to include booktabs.
376+ + Added `abstract` variable to LaTeX template.
377+ + Put `header-includes` after `title` in LaTeX template (#908).
378+ + Allow use of `\includegraphics[size]` in beamer.
379+ This just required porting a macro definition from the default
380+ LaTeX template to the default beamer template.
381+
382+ * `reference.docx`: Include `FootnoteText` style.
383+ Otherwise Word ignores the style, even when specified in the `pPr`.
384+ (#901)
385+
386+ * `reference.odt`: Tidied `styles.xml`.
387+
388+ * Relaxed version bounds for dependencies.
389+
390+ * Added `withSocketsDo` around http conduit code in `openURL`,
391+ so it works on Windows (#1080).
392+
393+ * Added `Cite` function to `sample.lua`.
394+
395+ * Markdown reader:
396+
397+ + Fixed regression in title blocks (#1089).
398+ If author field was empty, date was being ignored.
399+ + Allow backslash-newline hard line breaks in grid and
400+ multiline table cells.
401+ + Citation keys may now start with underscores, and may contain
402+ underscores adjacent to internal punctuation.
403+
404+ * LaTeX reader:
405+
406+ + Add support for `Verb` macro (jrnold) (#1090).
407+ + Support babel-style quoting: `` "`..."' ``.
408+
409+ * Properly handle script blocks in strict mode. (That is,
410+ `markdown-markdown_in_html_blocks`.) Previously a spurious
411+ `<p>` tag was being added (#1093).
412+
413+ * Docbook reader: Avoid failure if `tbody` contains no `tr` or `row`
414+ elements.
415+
416+ * LaTeX writer:
417+
418+ + Factored out function for table cell creation.
419+ + Better treatment of footnotes in tables.
420+ Notes now appear in the regular sequence, rather than in the
421+ table cell. (This was a regression in 1.10.)
422+
423+ * HTML reader: Parse name/content pairs from meta tags as metadata.
424+ Closes #1106.
425+
426+ * Moved `fixDisplayMath` from Docx writer to `Writer.Shared`.
427+
428+ * OpenDocument writer: Fixed `RawInline`, `RawBlock` so they don't escape.
429+
430+ * ODT writer: Use mathml for proper rendering of formulas.
431+ Note: LibreOffice's support for this seems a bit buggy. But
432+ it should be better than what we had before.
433+
434+ * RST writer: Ensure no blank line after def in definition list (#992).
435+
436+ * Markdown writer: Don't use tilde code blocks with braced attributes in
437+ `markdown_github` output. A consequence of this change is that the
438+ backtick form will be preferred in general if both are enabled. That
439+ is good, as it is much more widespread than the tilde form. (#1084)
440+
441+ * Docx writer: Fixed problem with some modified reference docx files.
442+ Include `word/_rels/settings.xml.rels` if it exists, as well as other
443+ `rels` files besides the ones pandoc generates explicitly.
444+
445+ * HTML writer:
446+
447+ + With `--toc`, headers no longer link to themselves (#1081).
448+ + Omit footnotes from TOC entries. Otherwise we get doubled
449+ footnotes when headers have notes!
450+
451+ * EPUB writer:
452+
453+ + Avoid duplicate notes when headings contain notes.
454+ This arose because the headings are copied into the metadata
455+ "title" field, and the note gets rendered twice. We strip the
456+ note now before putting the heading in "title".
457+ + Strip out footnotes from toc entries.
458+ + Fixed bug with `--epub-stylesheet`. Now the contents of
459+ `writerEpubStylesheet` (set by `--epub-stylesheet`)
460+ should again work, and take precedence over a stylesheet specified
461+ in the metadata.
462+
463+ * `Text.Pandoc.Pretty`: Added `nestle`. API change.
464+
465+ * `Text.Pandoc.MIME`: Added `wmf`, `emf`.
466+
467+ * `Text.Pandoc.Shared`: `fetchItem` now handles image URLs beginning
468+ with `//`.
469+
470+ * `Text.Pandoc.ImageSize`: Parse EXIF format JPEGs. Previously
471+ we could only get size information for JFIF format, which led
472+ to squished images in Word documents. Closes #976.
473+
474+ * Removed old `MarkdownTest_1.0.3` directory (#1104).
475+
476+pandoc (1.12.2.1)
477+
478+ * Markdown reader: Fixed regression in list parser, involving
479+ continuation lines containing raw HTML (or even verbatim raw HTML).
480+
481+pandoc (1.12.2)
482+
483+ * Metadata may now be included in YAML blocks in a markdown document.
484+ For example,
485+
486+ ---
487+ title:
488+ - type: main
489+ text: My Book
490+ - type: subtitle
491+ text: An investigation of metadata
492+ creator:
493+ - role: author
494+ text: John Smith
495+ - role: editor
496+ text: Sarah Jones
497+ identifier:
498+ - scheme: DOI
499+ text: doi:10.234234.234/33
500+ publisher: My Press
501+ rights: (c) 2007 John Smith, CC BY-NC
502+ cover-image: img/mypic.jpg
503+ ...
504+
505+ Metadata may still be provided using `--epub-metadata`; it will
506+ be merged with the metadata in YAML blocks.
507+
508+ * EPUB writer:
509+
510+ + `meta` tags are now used instead of `opf` attributes for EPUB3.
511+ + Insert "svg" property as needed in opf (EPUB 3).
512+ + Simplify `imageTypeOf` using `getMimeType`.
513+ + Add properties attribute to `cover-image` item for EPUB 3.
514+ + Don't include node for `cover.xhtml` if no cover!
515+ + Ensure that same identifier is used throughout (#1044).
516+ If an identifier is given in metadata, we use that; otherwise
517+ we generate a random uuid.
518+ + Add cover reference to guide element (EPUB 2) (Shaun Attfield).
519+ Fixes an issue with Calibre putting the cover at the end of the book
520+ if the spine has `linear="no"`. Apparently this is best practice
521+ for other converters as well:
522+ <http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.6>.
523+ + Allow `stylesheet` in metadata. The value is a path to the stylesheet.
524+ + Allow partial dates: `YYYY`, `YYYY-MM`.
525+
526+ * Markdown writer: Fix rendering of tight sublists (#1050).
527+ Previously a spurious blank line was included after a tight sublist.
528+
529+ * ODT writer: Add `draw:name` attribute to `draw:frame` elements (#1069).
530+ This is reported to be necessary to avoid an error from recent
531+ versions of Libre Office when files contain more than one image
532+ Thanks to wmanley for reporting and diagnosing the problem.
533+
534+ * ConTeXt writer: Don't hardcode figure/table placement and numbering.
535+ Instead, let this be set in the template, using `\setupfloat`.
536+ Thanks to on4aa and Aditya Mahajan for the suggestion (#1067).
537+
538+ * Implemented CSL flipflopping spans in DOCX, LaTeX, and HTML writers.
539+
540+ * Fixed bug with markdown intraword emphasis. Closes #1066.
541+
542+ * Docbook writer: Hierarchicalize block content in metadata.
543+ Previously headers just disappeared from block-level metadata
544+ when it was used in templates. Now we apply the 'hierarchicalize'
545+ transformation. Note that a block headed by a level-2 header will
546+ turn into a `<sect1>` element.
547+
548+ * OpenDocument writer: Skip raw HTML (#1035).
549+ Previously it was erroneously included as verbatim text.
550+
551+ * HTML/EPUB writer, footnotes: Put `<sup>` tag inside `<a>` tags.
552+ This allows better control of formatting, since the `<a>`
553+ tags have a distinguishing class (#1049).
554+
555+ * Docx writer:
556+
557+ + Use mime type info returned by fetchItem.
558+ + Fixed core metadata (#1046).
559+ Don't create empty date nodes if no date given.
560+ Don't create multiple `dc:creator` nodes; instead separate by
561+ semicolons.
562+ + Fix URL for core-properties in `_rels/.rels` (#1046).
563+
564+ * Plain writer: don't print `<span>` tags.
565+
566+ * LaTeX writer:
567+
568+ + Fix definition lists with internal links in terms (#1032).
569+ This fix puts braces around a term that contains an internal
570+ link, to avoid problems with square brackets.
571+ + Properly escape pdftitle, pdfauthor (#1059).
572+ + Use booktabs package for tables (thanks to Jose Luis Duran).
573+
574+ * Updated beamer template. Now references should work properly
575+ (in a slide) when `--biblatex` or `--natbib` is used.
576+
577+ * LaTeX reader:
578+
579+ + Parse contents of curly quotes or matched `"` as quotes.
580+ + Support `\textnormal` as span with class `nodecor`.
581+ This is needed for pandoc-citeproc.
582+ + Improved citation parsing. This fixes a run-time error that occured
583+ with `\citet{}` (empty list of keys). It also ensures that empty keys
584+ don't get produced.
585+
586+ * MediaWiki reader: Add automatic header identifiers.
587+
588+ * HTML reader:
589+
590+ + Use pandoc `Div` and `Span` for raw `<div>`, `<span>` when
591+ `--parse-raw`.
592+ + Recognize `svg` tags as block level content (thanks to MinRK).
593+ + Parse LaTeX math if appropriate options are set.
594+
595+ * Markdown reader:
596+
597+ + Yaml block must start immediately after `---`. If there's a blank
598+ line after `---`, we interpreted it as a horizontal rule.
599+ + Correctly handle empty bullet list items.
600+ + Stop parsing "list lines" when we hit a block tag.
601+ This fixes exponential slowdown in certain input, e.g.
602+ a series of lists followed by `</div>`.
603+
604+ * Slides: Preserve `<div class="references">` in references slide.
605+
606+ * `Text.Pandoc.Writer.Shared`:
607+
608+ + Fixed bug in `tagWithAttrs`. A space was omitted before key-value
609+ attributes, leading to invalid HTML.
610+ + `normalizeDate`: Allow dates with year only (thanks to Shaun Attfield).
611+ + Fixed bug in `openURL` with `data:` URIs. Previously the base-64
612+ encoded bytestring was returned. We now decode it so it's a proper
613+ image!
614+
615+ * DocBook reader: Handle numerical attributes starting with decimal.
616+ Also use `safeRead` instead of `read`.
617+
618+ * `Text.Pandoc.Parsing`:
619+
620+ + Generalized type of `registerHeader`, using new type classes
621+ `HasReadeOptions`, `HasIdentifierList`, `HasHeaderMap`.
622+ These allow certain common functions to be reused
623+ even in parsers that use custom state (instead of `ParserState`),
624+ such as the MediaWiki reader.
625+ + Moved inlineMath, displayMath from Markdown reader to Parsing.
626+ Generalize their types and export them from Parsing. (API change.)
627+
628+ * `Text.Pandoc.Readers.TexMath`: Export `readTeXMath'`, which attends
629+ to display/inline. Deprecate `readTeXMath`, and use `readTeXMath'`
630+ in all the writers. Require `texmath >= 0.6.5.2`.
631+
632+ * `Text.Pandoc.MIME`:
633+
634+ + Add entry for `jfif`.
635+ + In looking up extensions, drop the encoding info.
636+ E.g. for 'image/jpg;base64' we should lookup 'image/jpg'.
637+
638+ * Templates: Changed how array variables are resolved. Previously if
639+ `foo` is an array (which might be because multiple values were set on
640+ the command line), `$foo$` would resolve to the concatenation of the
641+ elements of foo. This is rarely useful behavior. It has been changed
642+ so that the first value is rendered. Of course, you can still iterate
643+ over the values using `$for(foo)$`. This has the result that you can
644+ override earlier settings using `-V` by putting new values later on the
645+ command line, which is useful for many purposes.
646+
647+ * `Text.Pandoc`: Don't default to `pandocExtensions` for all writers.
648+
649+ * Allow "epub2" as synonym for "epub", "html4" for "html".
650+
651+ * Don't look for slidy files in data files with `--self-contained`.
652+
653+ * Allow `https:` command line arguments to be downloaded.
654+
655+ * Fixed `make_osx_package.sh` so data files embedded in `pandoc-citeproc`.
656+
657+pandoc (1.12.1)
658+
659+ * `Text.Pandoc.Definition`: Changed default JSON serialization format.
660+ Instead of `{"Str": "foo"}`, for example, we now have `{"t": "Str",
661+ "c": "foo"}`. This new format is easier to work with outside of Haskell.
662+ Incidentally, "t" stands for "tag", "c" for "contents".
663+
664+ * MediaWiki reader: Trim contents of `<math>` tags, to avoid problems
665+ when converting to markdown (#1027).
666+
667+ * LaTeX reader:
668+
669+ + Ensure that preamble doesn't contribute to the text of
670+ the document.
671+ + Fixed character escaping in \url{}. Previously `\~` wasn't handled
672+ properly, among others.
673+ + Parse `{groups}` as `Span`. This is needed for accurate conversion of
674+ bibtex titles, since we need to know what was protected from
675+ titlecase conversions.
676+
677+ * LaTeX writer:
678+
679+ + Specially escape non-ascii characters in labels.
680+ Otherwise we can get compile errors and other bugs when
681+ compiled with pdflatex (#1007). Thanks to begemotv2718 for the fix.
682+ + Add link anchors for code blocks with identifiers (#1025).
683+
684+ * Throughout the code, use `isURI` instead of `isAbsoluteURI`.
685+ It allows fragments identifiers.
686+
687+ * Slide formats:
688+
689+ + A Div element with class "notes" is treated as speaker
690+ notes. Currently beamer goes to `\note{}`, revealjs to
691+ `<aside class="notes">`, and the notes are simply suppressed in
692+ other formats (#925).
693+ + Fixed `. . .` (pause) on HTML slide formats. Closes #1029.
694+ The old version caused a pause to be inserted before the first
695+ material on a slide. This has been fixed.
696+ + Removed data files for s5, slideous, slidy.
697+ Users of s5 and slideous will have to download the needed
698+ files, as has been documented for some time in the README.
699+ By default, slidy code will be sought on the web, as before.
700+
701+ * HTML writer: Insert command to typeset mathjax only in slideous output
702+ (#966, #1012).
703+
704+ * RST writer: Skip spaces after display math. Otherwise we get indentation
705+ problems, and part of the next paragraph may be rendered as part of the
706+ math.
707+
708+ * OpenDocument writer: Fix formatting of strikeout code (#995),
709+ thanks to wilx. don't use `font-face-decls` variable.
710+
711+ * Fixed test suite so it works with cabal sandboxes.
712+
713+pandoc (1.12.0.2)
714+
715+ * Removed `stringable` dependency.
716+
717+pandoc (1.12.0.1)
718+
719+ * Allow `--metadata` to be repeated for the same key to form a list.
720+ This also has the effect that `--bibliography` can be repeated,
721+ as before.
722+
723+ * Handle boolean values in `--metadata`. Note that anything not parseable
724+ as a YAML boolean or string is treated as a literal string.
725+ You can get a string value with "yes", or any of the strings interpretable
726+ as booleans, by quoting it:
727+
728+ -M boolvalue=yes -M stringvalue='"yes"'
729+
730+ * LaTeX writer: Don't print references if `--natbib` or `--biblatex`
731+ option used.
732+
733+ * DOCX writer: Add `settings.xml` to the zip container. Fixes a bug
734+ in which docx files could not be read by some versions of Word
735+ and LibreOffice (#990).
736+
737+ * Fixed a regression involving slide shows with bibliographies.
738+ The Div container around references messed up the procedure for carving
739+ a document into slides. So we now remove the surrounding Div in
740+ `prepSlides`.
741+
742+ * More informative error message when a filter is not found in path.
743+
744+ * Depend on pandoc-types 1.12.1. This provide `ToJSONFilter`
745+ instances for `Data a => a -> [a]` and `Data a => a -> IO [a]`.
746+
747+ * Don't use unicode_collation in building OSX package:
748+ it adds something like 50MB of dependencies to the package.
749+
750+ * Declare alex and happy as build-tools (#986).
751+
752+pandoc (1.12)
753+
754+ [new features]
755+
756+ * Much more flexible metadata, including arbitrary fields and structured
757+ values. Metadata can be specified flexibly in pandoc markdown using
758+ YAML metadata blocks, which may occur anywhere in the document:
759+
760+ ---
761+ title: Here is my title.
762+ abstract: |
763+ This is the abstract.
764+
765+ 1. It can contain
766+ 2. block content
767+ and *inline markup*
768+
769+ tags: [cat, dog, animal]
770+ ...
771+
772+ Metadata fields automatically populate template variables.
773+
774+ * Added `opml` (OPML) as input and output format. The `_note` attribute,
775+ used in OmniOutliner and supported by multimarkdown, is supported.
776+ We treat the contents as markdown blocks under a section header.
777+
778+ * Added `haddock` (Haddock markup) as input format (David Lazar).
779+
780+ * Added `revealjs` output format, for reveal.js HTML 5 slide shows.
781+ (Thanks to Jamie F. Olson for the initial patch.)
782+ Nested vertical stacks are used for hierarchical structure.
783+ Results for more than one level of nesting may be odd.
784+
785+ * Custom writers can now be written in lua.
786+
787+ pandoc -t data/sample.lua
788+
789+ will load the script sample.lua and use it as a custom writer.
790+ (For a sample, do `pandoc --print-default-data-file sample.lua`.)
791+ Note that pandoc embeds a lua interpreter, so lua need not be
792+ installed separately.
793+
794+ * New `--filter/-F` option to make it easier to run "filters"
795+ (Pandoc AST transformations that operate on JSON serializations).
796+ Filters are always passed the name of the output format, so their
797+ behavior can be tailored to it. The repository
798+ <https://github.com/jgm/pandocfilters> contains
799+ a python module for writing pandoc filters in python, with
800+ a number of examples.
801+
802+ * Added `--metadata/-M` option.
803+ This is like `--variable/-V`, but actually adds to metadata, not
804+ just variables.
805+
806+ * Added `--print-default-data-file` option, which allows printing
807+ of any of pandoc's data files. (For example,
808+ `pandoc --print-default-data-file reference.odt` will print
809+ `reference.odt`.)
810+
811+ * Added syntax for "pauses" in slide shows:
812+
813+ This gives
814+
815+ . . .
816+
817+ me pause.
818+
819+ * New markdown extensions:
820+
821+ + `ignore_line_breaks`: causes intra-paragraph line breaks to be ignored,
822+ rather than being treated as hard line breaks or spaces. This is useful
823+ for some East Asian languages, where spaces aren't used between words,
824+ but text is separated into lines for readability.
825+ + `yaml_metadata_block`: Parse YAML metadata blocks. (Default.)
826+ + `ascii_identifiers`: This will force `auto_identifiers` to use ASCII
827+ only. (Default for `markdown_github`.) (#807)
828+ + `lists_without_preceding_blankline`: Allow lists to start without
829+ preceding blank space. (Default for `markdown_github`.) (#972)
830+
831+ [behavior changes]
832+
833+ * `--toc-level` no longer implies `--toc`.
834+ Reason: EPUB users who don't want a visible TOC may still want
835+ to set the TOC level for in the book navigation.
836+
837+ * `--help` now prints in and out formats in alphabetical order, and
838+ says something about PDF output (#720).
839+
840+ * `--self-contained` now returns less verbose output (telling you
841+ which URLs it is fetching, but not giving the full header). In
842+ addition, there are better error messages when fetching a URL fails.
843+
844+ * Citation support is no longer baked in to core pandoc. Users who
845+ need citations will need to install and use a separate filter
846+ (`--filter pandoc-citeproc`). This filter will take `bibliography`,
847+ `csl`, and `citation-abbreviations` from the metadata, though it
848+ may still be specified on the command line as before.
849+
850+ * A `Cite` element is now created in parsing markdown whether or not
851+ there is a matching reference.
852+
853+ * The `pandoc-citeproc` script will put the bibliography at the
854+ end of the document, as before. However, it will be put inside a `Div`
855+ element with class "references", allowing users some control
856+ over the styling of references. A final header, if any, will
857+ be included in the `Div`.
858+
859+ * The markdown writer will not print a bibliography if the
860+ `citations` extension is enabled. (If the citations are formatted
861+ as markdown citations, it is redundant to have a bibliography,
862+ since one will be generated automatically.)
863+
864+ * Previously we used to store the directory of the first input file,
865+ even if it was local, and used this as a base directory for finding
866+ images in ODT, EPUB, Docx, and PDF. This has been confusing to many
867+ users. So we now look for images relative to the current
868+ working directory, even if the first file argument is in another
869+ directory. Note that this change may break some existing workflows.
870+ If you have been assuming that relative links will be interpreted
871+ relative to the directory of the first file argument, you'll need
872+ to make that the current directory before running pandoc. (#942)
873+
874+ * Better error reporting in some readers, due to changes in `readWith`:
875+ the line in which the error occured is printed, with a caret pointing
876+ to the column.
877+
878+ * All slide formats now support incremental slide view for definition lists.
879+
880+ * Parse `\(..\)` and `\[..\]` as math in MediaWiki reader.
881+ Parse `:<math>...</math>` as display math. These notations are used with
882+ the MathJax MediaWiki extension.
883+
884+ * All writers: template variables are set automatically from metadata
885+ fields. However, variables specified on the command line with
886+ `--variable` will completely shadow metadata fields.
887+
888+ * If `--variable` is used to set many variables with the same name,
889+ a list is created.
890+
891+ * Man writer: The `title`, `section`, `header`, and `footer` can now
892+ all be set individually in metadata. The `description` variable has been
893+ removed. Quotes have been added so that spaces are allowed in the
894+ title. If you have a title that begins
895+
896+ COMMAND(1) footer here | header here
897+
898+ pandoc will still parse it into a title, section, header, and
899+ footer. But you can also specify these elements explicitly (#885).
900+
901+ * Markdown reader
902+
903+ + Added support for YAML metadata blocks, which can come anywhere
904+ in the document (not just at the beginning). A document can contain
905+ multiple YAML metadata blocks.
906+ + HTML span and div tags are parsed as pandoc Span and Div elements.
907+
908+ * Markdown writer
909+
910+ + Allow simple tables to be printed as grid tables,
911+ if other table options are disabled. This means you can do
912+ `pandoc -t markdown-pipe_tables-simple_tables-multiline_tables`
913+ and all tables will render as grid tables.
914+ + Support YAML title block (render fields in alphabetical order
915+ to make output predictable).
916+
917+ [API changes]
918+
919+ * `Meta` in `Text.Pandoc.Definition` has been changed to allow
920+ structured metadata. (Note: existing code that pattern-matches
921+ on `Meta` will have to be revised.) Metadata can now contain
922+ indefinitely many fields, with content that can be a string,
923+ a Boolean, a list of `Inline` elements, a list of `Block`
924+ elements, or a map or list of these.
925+
926+ * A new generic block container (`Div`) has been added to `Block`,
927+ and a generic inline container (`Span`) has been added to `Inline`.
928+ These can take attributes. They will render in HTML, Textile,
929+ MediaWiki, Org, RST and and Markdown (with `markdown_in_html`
930+ extension) as HTML `<div>` and `<span>` elements; in other formats
931+ they will simply pass through their contents. But they can be
932+ targeted by scripts.
933+
934+ * `Format` is now a newtype, not an alias for String.
935+ Equality comparisons are case-insensitive.
936+
937+ * Added `Text.Pandoc.Walk`, which exports hand-written tree-walking
938+ functions that are much faster than the SYB functions from
939+ `Text.Pandoc.Generic`. These functions are now used where possible
940+ in pandoc's code. (`Tests.Walk` verifies that `walk` and `query`
941+ match the generic traversals `bottomUp` and `queryWith`.)
942+
943+ * Added `Text.Pandoc.JSON`, which provides `ToJSON` and `FromJSON`
944+ instances for the basic pandoc types. They use GHC generics and
945+ should be faster than the old JSON serialization using
946+ `Data.Aeson.Generic`.
947+
948+ * Added `Text.Pandoc.Process`, exporting `pipeProcess`.
949+ This is a souped-up version of `readProcessWithErrorcode` that
950+ uses lazy bytestrings instead of strings and allows setting
951+ environment variables. (Used in `Text.Pandoc.PDF`.)
952+
953+ * New module `Text.Pandoc.Readers.OPML`.
954+
955+ * New module `Text.Pandoc.Writers.OPML`.
956+
957+ * New module `Text.Pandoc.Readers.Haddock` (David Lazar).
958+ This is based on Haddock's own lexer/parser.
959+
960+ * New module `Text.Pandoc.Writers.Custom`.
961+
962+ * In `Text.Pandoc.Shared`, `openURL` and `fetchItem` now return an
963+ Either, for better error handling.
964+
965+ * Made `stringify` polymorphic in `Text.Pandoc.Shared`.
966+
967+ * Removed `stripTags` from `Text.Pandoc.XML`.
968+
969+ * `Text.Pandoc.Templates`:
970+
971+ + Simplified `Template` type to a newtype.
972+ + Removed `Empty`.
973+ + Changed type of `renderTemplate`: it now takes a JSON context
974+ and a compiled template.
975+ + Export `compileTemplate`.
976+ + Export `renderTemplate'` that takes a string instead of a compiled
977+ template.
978+ + Export `varListToJSON`.
979+
980+ * `Text.Pandoc.PDF` exports `makePDF` instead of `tex2pdf`.
981+
982+ * `Text.Pandoc`:
983+
984+ + Made `toJsonFilter` an alias for `toJSONFilter` from `Text.Pandoc.JSON`.
985+ + Removed `ToJsonFilter` typeclass. `ToJSONFilter` from
986+ `Text.Pandoc.JSON` should be used instead. (Compiling against
987+ pandoc-types instead of pandoc will also produce smaller executables.)
988+ * Removed the deprecated `jsonFilter` function.
989+ + Added `readJSON`, `writeJSON` to the API (#817).
990+
991+ * `Text.Pandoc.Options`:
992+
993+ + Added `Ext_lists_without_preceding_blankline`,
994+ `Ext_ascii_identifiers`, `Ext_ignore_line_breaks`,
995+ `Ext_yaml_metadataBlock` to `Extension`.
996+ + Changed `writerSourceDirectory` to `writerSourceURL` and changed the
997+ type to a `Maybe`. `writerSourceURL` is set to 'Just url' when the
998+ first command-line argument is an absolute URL. (So, relative links
999+ will be resolved in relation to the first page.) Otherwise, 'Nothing'.
1000+ + All bibliography-related fields have been removed from
1001+ `ReaderOptions` and `WriterOptions`: `writerBiblioFiles`,
1002+ `readerReferences`, `readerCitationStyle`.
1003+
1004+ * The `Text.Pandoc.Biblio` module has been removed. Users of the
1005+ pandoc library who want citation support will need to use
1006+ `Text.CSL.Pandoc` from `pandoc-citeproc`.
1007+
1008+
1009+ [bug fixes]
1010+
1011+ * In markdown, don't autolink a bare URI that is followed by `</a>`
1012+ (#937).
1013+
1014+ * `Text.Pandoc.Shared`
1015+
1016+ + `openURL` now follows redirects (#701), properly handles `data:`
1017+ URIs, and prints diagnostic output to stderr rather than stdout.
1018+ + `readDefaultDataFile`: normalize the paths. This fixes bugs in
1019+ `--self-contained` on pandoc compiled with `embed_data_files` (#833).
1020+ + Fixed `readDefaultDataFile` so it works on Windows.
1021+ + Better error messages for `readDefaultDataFile`. Instead of
1022+ listing the last path tried, which can confuse people who are
1023+ using `--self-contained`, so now we just list the data file name.
1024+ + URL-escape pipe characters. Even though these are legal, `Network.URI`
1025+ doesn't regard them as legal in URLs. So we escape them first (#535).
1026+
1027+ * Mathjax in HTML slide shows: include explicit "Typeset" call.
1028+ This seems to be needed for some formats (e.g. slideous) and won't
1029+ hurt in others (#966).
1030+
1031+ * `Text.Pandoc.PDF`
1032+
1033+ + On Windows, create temdir in working directory, since the system
1034+ temp directory path may contain tildes, which can cause
1035+ problems in LaTeX (#777).
1036+ + Put temporary output directory in `TEXINPUTS` (see #917).
1037+ + `makePDF` tries to download images that are not found locally,
1038+ if the first argument is a URL (#917).
1039+ + If compiling with `pdflatex` yields an encoding error, offer
1040+ the suggestion to use `--latex-engine=xelatex`.
1041+
1042+ * Produce automatic header identifiers in parsing textile, RST,
1043+ and LaTeX, unless `auto_identifiers` extension is disabled (#967).
1044+
1045+ * `Text.Pandoc.SelfContained`: Strip off fragment, query of relative URL
1046+ before treating as a filename. This fixes `--self-contained` when used
1047+ with CSS files that include web fonts using the method described here:
1048+ <http://paulirish.com/2009/bulletproof-font-face-implementation-syntax/>
1049+ (#739). Handle `src` in `embed`, `audio`, `source`, `input` tags.
1050+
1051+ * `Text.Pandoc.Parsing`: `uri` parser no longer treats punctuation before
1052+ percent-encoding, or a `+` character, as final punctuation.
1053+
1054+ * `Text.Pandoc.ImageSize`: Handle EPS (#903). This change will make
1055+ EPS images properly sized on conversion to Word.
1056+
1057+ * Slidy: Use slidy.js rather than slidy.js.gz.
1058+ Reason: some browsers have trouble with the gzipped js file,
1059+ at least on the local file system (#795).
1060+
1061+ * Markdown reader
1062+
1063+ + Properly handle blank line at beginning of input (#882).
1064+ + Fixed bug in unmatched reference links. The input
1065+ `[*infile*] [*outfile*]` was getting improperly parsed:
1066+ "infile" was emphasized, but "*outfile*" was literal (#883).
1067+ + Allow internal `+` in citation identifiers (#856).
1068+ + Allow `.` or `)` after `#` in ATX headers if no `fancy_lists`.
1069+ + Do not generate blank title, author, or date metadata elements.
1070+ Leave these out entirely if they aren't present.
1071+ + Allow backtick code blocks not to be preceded by blank line (#975).
1072+
1073+ * Textile reader:
1074+
1075+ + Correctly handle entities.
1076+ + Improved handling of `<pre>` blocks (#927). Remove internal HTML tags
1077+ in code blocks, rather than printing them verbatim. Parse attributes
1078+ on `<pre>` tag for code blocks.
1079+
1080+ * HTML reader: Handle non-simple tables (#893). Column widths are read from
1081+ `col` tags if present, otherwise divided equally.
1082+
1083+ * LaTeX reader
1084+
1085+ + Support alltt environment (#892).
1086+ + Support `\textasciitilde`, `\textasciicircum` (#810).
1087+ + Treat `\textsl` as emphasized text reader (#850).
1088+ + Skip positional options after `\begin{figure}`.
1089+ + Support `\v{}` for hacek (#926).
1090+ + Don't add spurious ", " to citation suffixes.
1091+ This is added when needed in pandoc-citeproc.
1092+ + Allow spaces in alignment spec in tables, e.g. `{ l r c }`.
1093+ + Improved support for accented characters (thanks to Scott Morrison).
1094+ + Parse label after section command and set id (#951).
1095+
1096+ * RST reader:
1097+
1098+ + Don't insert paragraphs where docutils doesn't.
1099+ `rst2html` doesn't add `<p>` tags to list items (even when they are
1100+ separated by blank lines) unless there are multiple paragraphs in the
1101+ list. This commit changes the RST reader to conform more closely to
1102+ what docutils does (#880).
1103+ + Improved metadata. Treat initial field list as metadata when
1104+ standalone specified. Previously ALL fields "title", "author",
1105+ "date" in field lists were treated as metadata, even if not at
1106+ the beginning. Use `subtitle` metadata field for subtitle.
1107+ + Fixed 'authors' metadata parsing in reST. Semicolons separate
1108+ different authors.
1109+
1110+ * MediaWiki reader
1111+
1112+ + Allow space before table rows.
1113+ + Fixed regression for `<ref>URL</ref>`.
1114+ `<` is no longer allowed in URLs, according to the uri parser
1115+ in `Text.Pandoc.Parsing`. Added a test case.
1116+ + Correctly handle indented preformatted text without preceding
1117+ or following blank line.
1118+ + Fixed `|` links inside table cells. Improved attribute parsing.
1119+ + Skip attributes on table rows. Previously we just crashed if
1120+ rows had attributes, now we ignore them.
1121+ + Ignore attributes on headers.
1122+ + Allow `Image:` for images (#971).
1123+ + Parse an image with caption in a paragraph by itself as a figure.
1124+
1125+ * LaTeX writer
1126+
1127+ + Don't use ligatures in escaping inline code.
1128+ + Fixed footnote numbers in LaTeX/PDF tables. This fixes a bug
1129+ wherein notes were numbered incorrectly in tables (#827).
1130+ + Always create labels for sections. Previously the labels were only
1131+ created when there were links to the section in the document (#871).
1132+ + Stop escaping `|` in LaTeX math.
1133+ This caused problems with array environments (#891).
1134+ + Change `\` to `/` in paths. `/` works even on Windows in LaTeX.
1135+ `\` will cause major problems if unescaped.
1136+ + Write id for code block to label attribute in LaTeX when listings
1137+ is used (thanks to Florian Eitel).
1138+ + Scale LaTeX tables so they don't exceed columnwidth.
1139+ + Avoid problem with footnotes in unnumbered headers (#940).
1140+
1141+ * Beamer writer: when creating beamer slides, add `allowframebreaks` option
1142+ to the slide if it is one of the header classes. It is recommended
1143+ that your bibliography slide have this attribute:
1144+
1145+ # References {.allowframebreaks}
1146+
1147+ This causes multiple slides to be created if necessary, depending
1148+ on the length of the bibliography.
1149+
1150+ * ConTeXt writer: Properly handle tables without captions. The old output
1151+ only worked in MkII. This should work in MkIV as well (#837).
1152+
1153+ * MediaWiki writer: Use native mediawiki tables instead of HTML (#720).
1154+
1155+ * HTML writer:
1156+
1157+ + Fixed `--no-highlight` (Alexander Kondratskiy).
1158+ + Don't convert to lowercase in email obfuscation (#839).
1159+ + Ensure proper escaping in `<title>` and `<meta>` fields.
1160+
1161+ * AsciiDoc writer:
1162+
1163+ + Support `--atx-headers` (Max Rydahl Andersen).
1164+ + Don't print empty identifier blocks `([[]])` on headers (Max
1165+ Rydahl Andersen).
1166+
1167+ * ODT writer:
1168+
1169+ + Fixing wrong numbered-list indentation in open document format
1170+ (Alexander Kondratskiy) (#369).
1171+ + `reference.odt`: Added pandoc as "generator" in `meta.xml`.
1172+ + Minor changes for ODF 1.2 conformance (#939). We leave the
1173+ nonconforming `contextual-spacing` attribute, which is provided by
1174+ LibreOffice itself and seems well supported.
1175+
1176+ * Docx writer:
1177+
1178+ + Fixed rendering of display math in lists.
1179+ In 1.11 and 1.11.1, display math in lists rendered as a new list
1180+ item. Now it always appears centered, just as outside of lists,
1181+ and in proper display math style, no matter how far indented the
1182+ containing list item is (#784).
1183+ + Use `w:br` with `w:type` `textWrapping` for linebreaks.
1184+ Previously we used `w:cr` (#873).
1185+ + Use Compact style for Plain block elements, to
1186+ differentiate between tight and loose lists (#775).
1187+ + Ignore most components of `reference.docx`.
1188+ We take the `word/styles.xml`, `docProps/app.xml`,
1189+ `word/theme/theme1.xml`, and `word/fontTable.xml` from
1190+ `reference.docx`, ignoring everything else. This should help
1191+ with the corruption problems caused when different versions of
1192+ Word resave the reference.docx and reorganize things.
1193+ + Made `--no-highlight` work properly.
1194+
1195+ * EPUB writer
1196+
1197+ + Don't add `dc:creator` tags if present in EPUB metadata.
1198+ + Add `id="toc-title"` to `h1` in `nav.xhtml` (#799).
1199+ + Don't put blank title page in reading sequence.
1200+ Set `linear="no"` if no title block. Addresses #797.
1201+ + Download webtex images and include as data URLs.
1202+ This allows you to use `--webtex` in creating EPUBs.
1203+ Math with `--webtex` is automatically made self-contained.
1204+ + In `data/epub.css`, removed highlighting styles (which
1205+ are no longer needed, since styles are added by the HTML
1206+ writer according to `--highlighting-style`). Simplified
1207+ margin fields.
1208+ + If resource not found, skip it, as in Docx writer (#916).
1209+
1210+ * RTF writer:
1211+
1212+ + Properly handle characters above the 0000-FFFF range.
1213+ Uses surrogate pairs. Thanks to Hiromi Ishii for the patch.
1214+ + Fixed regression with RTF table of contents.
1215+ + Only autolink absolute URIs. This fixes a regression, #830.
1216+
1217+ * Markdown writer:
1218+
1219+ + Only autolink absolute URIs. This fixes a regression, #830.
1220+ + Don't wrap attributes in fenced code blocks.
1221+ + Write full metadata in MMD style title blocks.
1222+ + Put multiple authors on separate lines in pandoc titleblock.
1223+ Also, don't wrap long author entries, as new lines get treated
1224+ as new authors.
1225+
1226+ * `Text.Pandoc.Templates`:
1227+
1228+ + Fixed bug retrieving default template for markdown variants.
1229+ + Templates can now contain "record lookups" in variables;
1230+ for example, `author.institution` will retrieve the `institution`
1231+ field of the `author` variable.
1232+ + More consistent behavior of `$for$`. When `foo` is not a list,
1233+ `$for(foo)$...$endfor$` should behave like $if(foo)$...$endif$.
1234+ So if `foo` resolves to "", no output should be produced.
1235+ See pandoc-templates#39.
1236+
1237+ * Citation processing improvements (now part of pandoc-citeproc):
1238+
1239+ + Fixed `endWithPunct` The new version correctly sees a sentence
1240+ ending in '.)' as ending with punctuation. This fixes a bug which
1241+ led such sentences to receive an extra period at the end: '.).'.
1242+ Thanks to Steve Petersen for reporting.
1243+ + Don't interfere with Notes that aren't citation notes.
1244+ This fixes a bug in which notes not generated from citations were
1245+ being altered (e.g. first letter capitalized) (#898).
1246+ + Only capitalize footnote citations when they have a prefix.
1247+ + Changes in suffix parsing. A suffix beginning with a digit gets 'p'
1248+ inserted before it before passing to citeproc-hs, so that bare numbers
1249+ are treated as page numbers by default. A suffix not beginning with
1250+ punctuation has a space added at the beginning (rather than a comma and
1251+ space, as was done before for not-author-in-text citations).
1252+ The result is that `\citep[23]{item1}` in LaTeX will be interpreted
1253+ properly, with '23' treated as a locator of type 'page'.
1254+ + Many improvements to citation rendering, due to fixes in citeproc-hs
1255+ (thanks to Andrea Rossato).
1256+ + Warnings are issued for undefined citations, which are rendered
1257+ as `???`.
1258+ + Fixed hanging behavior when locale files cannot be found.
1259+
1260+ [template changes]
1261+
1262+ * DocBook: Use DocBook 4.5 doctype.
1263+
1264+ * Org: '#+TITLE:' is inserted before the title.
1265+ Previously the writer did this.
1266+
1267+ * LaTeX: Changes to make mathfont work with xelatex.
1268+ We need the mathspec library, not just fontspec, for this.
1269+ We also need to set options for setmathfont (#734).
1270+
1271+ * LaTeX: Use `tex-ansi` mapping for `monofont`.
1272+ This ensures that straight quotes appear as straight, rather than
1273+ being treated as curly. See #889.
1274+
1275+ * Made `\includegraphics` more flexible in LaTeX template.
1276+ Now it can be used with options, if needed. Thanks to Bernhard Weichel.
1277+
1278+ * LaTeX/Beamer: Added `classoption` variable.
1279+ This is intended for class options like `oneside`; it may
1280+ be repeated with different options. (Thanks to Oliver Matthews.)
1281+
1282+ * Beamer: Added `fonttheme` variable. (Thanks to Luis Osa.)
1283+
1284+ * LaTeX: Added `biblio-style` variable (#920).
1285+
1286+ * DZSlides: title attribute on title section.
1287+
1288+ * HTML5: add meta tag to allow scaling by user (Erik Evenson)
1289+
1290+ [under-the-hood improvements]
1291+
1292+ * Markdown reader:Improved strong/emph parsing, using the strategy of
1293+ <https://github.com/jgm/Markdown>. The new parsing algorithm requires
1294+ no backtracking, and no keeping track of nesting levels. It will give
1295+ different results in some edge cases, but these should not affect normal
1296+ uses.
1297+
1298+ * Added `Text.Pandoc.Compat.Monoid`.
1299+ This allows pandoc to compile with `base` < 4.5, where `Data.Monoid`
1300+ doesn't export `<>`. Thanks to Dirk Ullirch for the patch.
1301+
1302+ * Added `Text.Pandoc.Compat.TagSoupEntity`.
1303+ This allows pandoc to compile with `tagsoup` 0.13.x.
1304+ Thanks to Dirk Ullrich for the patch.
1305+
1306+ * Most of `Text.Pandoc.Readers.TeXMath` has been moved to the
1307+ `texmath` module (0.6.4). (This allows `pandoc-citeproc` to
1308+ handle simple math in bibliography fields.)
1309+
1310+ * Added `Text.Pandoc.Writers.Shared` for shared functions used
1311+ only in writers. `metaToJSON` is used in writers to create a
1312+ JSON object for use in the templates from the pandoc metadata
1313+ and variables. `getField`, `setField`, and `defField` are
1314+ for working with JSON template contexts.
1315+
1316+ * Added `Text.Pandoc.Asciify` utility module.
1317+ This exports functions to create ASCII-only versions of identifiers.
1318+
1319+ * `Text.Pandoc.Parsing`
1320+
1321+ + Generalized state type on `readWith` (API change).
1322+ + Specialize readWith to `String` input. (API change).
1323+ + In `ParserState`, replace `stateTitle`, `stateAuthors`, `stateDate`
1324+ with `stateMeta` and `stateMeta'`.
1325+
1326+ * `Text.Pandoc.UTF8`: use strict bytestrings in reading. The use of lazy
1327+ bytestrings seemed to cause problems using pandoc on 64-bit Windows
1328+ 7/8 (#874).
1329+
1330+ * Factored out `registerHeader` from markdown reader, added to
1331+ `Text.Pandoc.Parsing`.
1332+
1333+ * Removed `blaze_html_0_5` flag, require `blaze-html` >= 0.5.
1334+ Reason: < 0.5 does not provide a monoid instance for Attribute,
1335+ which is now needed by the HTML writer (#803).
1336+
1337+ * Added `http-conduit` flag, which allows fetching https resources.
1338+ It also brings in a large number of dependencies (`http-conduit`
1339+ and its dependencies), which is why for now it is an optional flag
1340+ (#820).
1341+
1342+ * Added CONTRIBUTING.md.
1343+
1344+ * Improved INSTALL instructions.
1345+
1346+ * `make-windows-installer.bat`: Removed explicit paths for executables.
1347+
1348+ * `aeson` is now used instead of `json` for JSON.
1349+
1350+ * Set default stack size to 16M. This is needed for some large
1351+ conversions, esp. if pandoc is compiled with 64-bit ghc.
1352+
1353+ * Various small documentation improvements.
1354+ Thanks to achalddave and drothlis for patches.
1355+
1356+ * Removed comment that chokes recent versions of CPP (#933).
1357+
1358+ * Removed support for GHC version < 7.2, since pandoc-types now
1359+ requires at least GHC 7.2 for GHC generics.
1360+
1361+
11362pandoc (1.11.1)
21363
31364 * Markdown reader:
@@ -10,7 +1371,7 @@ pandoc (1.11.1)
101371 paragraphs. The unmatched quotes now get turned into literal
111372 left double quotes. (No `Quoted` inline is generated, however.)
121373 Closes #99 (again).
13−
1374+
141375 * HTML writer: Fixed numbering mismatch between TOC and sections.
151376 `--number-offset` now affects TOC numbering as well
161377 as section numbering, as it should have all along. Closes #789.
@@ -45,7 +1406,7 @@ pandoc (1.11)
451406 * Added `--number-offset` option. (See README for description.)
461407
471408 * Added `--default-image-extension` option. (See README for description.)
48−
1409+
491410 * `--number-sections` behavior change: headers with class `unnumbered`
501411 will not be numbered.
511412
@@ -96,7 +1457,7 @@ pandoc (1.11)
961457 + Better support for Verbatim and minted environments. Closes #763.
971458
981459 * Markdown reader:
99−
1460+
1001461 + `-` in an attribute context = `.unnumbered`. The point of this
1011462 is to provide a way to specify unnumbered headers in non-English
1021463 documents.
@@ -122,7 +1483,7 @@ pandoc (1.11)
1221483 Closes #723.
1231484
1241485 * Textile reader:
125−
1486+
1261487 + Handle attributes on headers.
1271488
1281489 * LaTeX reader:
@@ -155,7 +1516,7 @@ pandoc (1.11)
1551516 `unnumbered` class.
1561517
1571518 * Textile writer:
158−
1519+
1591520 + Support header attributes.
1601521
1611522 * Markdown writer:
@@ -169,11 +1530,11 @@ pandoc (1.11)
1691530 use `pandoc -t markdown-citations`.
1701531
1711532 * RST writer:
172−
1533+
1731534 + Support `:number-lines:` in code blocks.
1741535
1751536 * Docx writer:
176−
1537+
1771538 + Better treatment of display math. Display math inside a
1781539 paragraph is now put in a separate paragraph, so it will render
1791540 properly (centered and without extra blank lines around it).
@@ -191,7 +1552,7 @@ pandoc (1.11)
1911552 edited. Closes #414.
1921553
1931554 * EPUB writer:
194−
1555+
1951556 + Fix section numbering. Previously the numbering restarted from 1
1961557 in each chapter (with `--number-sections`), though the numbers in
1971558 the table of contents were correct.
@@ -214,7 +1575,7 @@ pandoc (1.11)
2141575 section number.
2151576
2161577 * `Text.Pandoc.Pretty`:
217−
1578+
2181579 + Fixed `chomp` so it works inside `Prefixed` elements.
2191580 + Changed `Show` instance so it is better for debugging.
2201581
@@ -284,7 +1645,7 @@ pandoc (1.10.1)
2841645 Thanks to Nick Bart for the suggestion of using @{}.
2851646
2861647 * `Text.Pandoc.Parsing`:
287−
1648+
2881649 + More efficient version of `anyLine`.
2891650 + Type of `macro` has changed; the parser now returns `Blocks`
2901651 instead of `Block`.
@@ -307,7 +1668,7 @@ pandoc (1.10.0.5)
3071668 Thanks to Andrew Lee for pointing out the bug.
3081669
3091670 * Markdown reader: Fixed regressions in fenced code blocks. Closes #722.
310−
1671+
3111672 + Tilde code fences can again take a bare language string
3121673 (`~~~ haskell`), not just curly-bracketed attributes
3131674 (`~~~ {.haskell}`).
@@ -338,7 +1699,7 @@ pandoc (1.10.0.5)
3381699 `hsb2hs`.
3391700
3401701 * Changes to `make-windows-installer.bat`.
341−
1702+
3421703 + Exit batch file if any of the cabal-dev installs fail.
3431704 + There's no longer any need to reinstall `highlighting-kate`.
3441705 + Don't start with a `cabal update`; leave that to the user.
@@ -1090,19 +2451,19 @@ pandoc (1.9.4.2)
10902451 checks for the base version that intelligibly enable encoding/decoding
10912452 when needed. Fixes a bug with multilingual filenames when pandoc was
10922453 compiled with ghc 7.4 (#540).
1093−
2454+
10942455 * Don't generate an empty H1 after hrule slide breaks.
10952456 We now use a slide-level header with contents `[Str "\0"]` to mark
10962457 an hrule break. This avoids creation of an empty H1 in these
10972458 contexts. Closes #484.
1098−
2459+
10992460 * Docbook reader: Added support for "bold" emphasis. Thanks to mb21.
1100−
2461+
11012462 * In make_osx_package.sh, ensure citeproc-hs is built with the
11022463 embed_data_files flag.
1103−
2464+
11042465 * MediaWiki writer: Avoid extra blank lines after sublists (Gavin Beatty).
1105−
2466+
11062467 * ConTeXt writer: Don't escape `&`, `^`, `<`, `>`, `_`,
11072468 simplified escapes for `}` and `{` to `\{` and `\}` (Aditya Mahajan).
11082469
@@ -1113,7 +2474,7 @@ pandoc (1.9.4.2)
11132474
11142475 * Added some missing exports and tests to the cabal file
11152476 (Alexander V Vershilov).
1116−
2477+
11172478 * Compile with `-rtsopts` and `-threaded` by default.
11182479
11192480pandoc (1.9.4.1)
@@ -1131,7 +2492,7 @@ pandoc (1.9.4.1)
11312492 + Use microtype if available.
11322493
11332494 * Biblio:
1134−
2495+
11352496 + Add comma to beginning of bare suffix, e.g. `@item1 [50]`.
11362497 Motivation: `@item1 [50]` should be as close as possible to
11372498 `[@item1, 50]`.
@@ -1435,12 +2796,12 @@ pandoc (1.9.1.1)
14352796pandoc (1.9.1)
14362797
14372798 * LaTeX reader:
1438−
2799+
14392800 + Fixed regression in 1.9; properly handle escaped $ in latex math.
14402801 + Put LaTeX verse environments in blockquotes.
14412802
14422803 * Markdown reader:
1443−
2804+
14442805 + Limit nesting of strong/emph. This avoids exponential lookahead
14452806 in parasitic cases, like `a**a*a**a*a**a*a**a*a**a*a**a*a**a*a**`.
14462807 + Improved attributes syntax (inn code blocks/spans):
@@ -1659,7 +3020,7 @@ pandoc (1.9)
16593020 </sidebar>
16603021
16613022 will not be wrapped in `<para>` tags.
1662−
3023+
16633024 * The LaTeX parser has been completely rewritten; it is now much more
16643025 accurate, robust, and extensible. However, there are two important
16653026 changes in how it treats unknown LaTeX. (1) Previously, unknown
@@ -2835,7 +4196,7 @@ pandoc (1.5.1.1)
28354196
28364197 [ John MacFarlane ]
28374198
2838− * Fixed uniqueIdent in Shared so that header identifiers work as
4199+ * Fixed uniqueIdent in Shared so that header identifiers work as
28394200 advertized in the README and are are valid XHTML names.
28404201
28414202pandoc (1.5.1)
@@ -4077,7 +5438,7 @@ pandoc (0.46) unstable; urgency=low
40775438 HTML reader now uses rawHtmlBlock', which excludes </html> and </body>,
40785439 since these are handled in parseHtml. (Resolves Issue #38.)
40795440
4080− + Fixed bug (emph parser was looking for <IT> tag, not <I>).
5441+ + Fixed bug (emph parser was looking for `<IT>` tag, not `<I>`).
40815442
40825443 + Don't interpret contents of style tags as markdown.
40835444 (Resolves Issue #40.)
@@ -4162,15 +5523,15 @@ pandoc (0.45) unstable; urgency=low
41625523 + readTeXMath is now used for default HTML output in HTML, S5, RTF,
41635524 and Docbook, if no other method for displaying math in HTML is
41645525 specified. Enclosing $'s are no longer printed by default.
4165− + By default, math is put inside <span class="math">. This way it can be
5526+ + By default, math is put inside `<span class="math">`. This way it can be
41665527 distinguished from the surrounding text, e.g. put in a different
41675528 font.
41685529
41695530 * New --gladtex and --mimetex options for display of math in HTML:
41705531
4171− + If --gladtex is specified, math is output between <eq> tags, so
5532+ + If --gladtex is specified, math is output between `<eq>` tags, so
41725533 it can be processed by gladTeX.
4173− + If --mimetex is specified, math is put in <img> tags with a link
5534+ + If --mimetex is specified, math is put in `<img>` tags with a link
41745535 to the mimetex CGI script (or any other script that takes TeX math
41755536 as input and outputs an image). The URL of the script may be
41765537 specified, but defaults to /cgi-bin/mimetex.cgi.
@@ -4184,13 +5545,13 @@ pandoc (0.45) unstable; urgency=low
41845545 + Fixed bug: parser for minimized attributes should not swallow
41855546 trailing spaces.
41865547 + Simplified HTML attribute parsing.
4187− + Changed parsing of code blocks in HTML reader: <code> tag is no
4188− longer needed. <pre> suffices. All HTML tags in the code block
5548+ + Changed parsing of code blocks in HTML reader: `<code>` tag is no
5549+ longer needed. `<pre>` suffices. All HTML tags in the code block
41895550 (e.g. for syntax highlighting) are skipped, because they are not
4190− portable to other output formats. A <code>...</code> block not
4191− surrounded by <pre> now counts as inline HTML, not a code block.
5551+ portable to other output formats. A `<code>...</code>` block not
5552+ surrounded by `<pre>` now counts as inline HTML, not a code block.
41925553 + Remove just one leading and one trailing newline from contents of
4193− <pre>...</pre> in codeBlock parser.
5554+ `<pre>...</pre>` in codeBlock parser.
41945555
41955556 * Markdown reader:
41965557
@@ -4512,8 +5873,8 @@ pandoc (0.43) unstable; urgency=low
45125873 end code block with a nonindented line.)
45135874 + Changed definition of 'emph': italics with '_' must not
45145875 be followed by an alphanumeric character. This is to help
4515− prevent interpretation of e.g. [LC_TYPE]: my_type as
4516− '[LC<em>TYPE]:my</em>type'.
5876+ prevent interpretation of e.g. `[LC_TYPE]: my_type` as
5877+ `[LC<em>TYPE]:my</em>type`.
45175878 + Improved Markdown.pl-compatibility in referenceLink: the two parts
45185879 of a reference-style link may be separated by one space, but not
45195880 more... [a] [link], [not] [a link].
@@ -4521,7 +5882,7 @@ pandoc (0.43) unstable; urgency=low
45215882 Markdown.pl: the marker for the end of the code section is a clump
45225883 of the same number of `'s with which the section began, followed
45235884 by a non-` character. So, for example,
4524− ` h ``` i ` -> <code>h ``` i</code>.
5885+ ` h ``` i ` -> `<code>h ``` i</code>`.
45255886 + Split 'title' into 'linkTitle' and 'referenceTitle', since the
45265887 rules are slightly different.
45275888 + Rewrote 'para' for greater efficiency.
@@ -4628,7 +5989,7 @@ pandoc (0.41) unstable; urgency=low
46285989 [ John MacFarlane ]
46295990
46305991 * Fixed bugs in HTML reader:
4631− + Skip material at end *only if* </html> is present (previously,
5992+ + Skip material at end *only if* `</html>` is present (previously,
46325993 only part of the document would be parsed if an error was
46335994 found; now a proper error message is given).
46345995 + Added new constant eitherBlockOrInline with elements that may
@@ -4837,9 +6198,9 @@ pandoc (0.4) unstable; urgency=low
48376198 may cause documents to be parsed differently. Users should take
48386199 care in upgrading.
48396200 + Changed autoLink parsing to conform better to Markdown.pl's
4840− behavior. <google.com> is not treated as a link, but
4841− <http://google.com>, <ftp://google.com>, and <mailto:google@google.com>
4842− are.
6201+ behavior. `<google.com>` is not treated as a link, but
6202+ `<http://google.com>`, `<ftp://google.com>`, and
6203+ `<mailto:google@google.com>` are.
48436204 + Cleaned up handling of embedded quotes in link titles. Now these are
48446205 stored as a '"' character, not as '&quot;'.
48456206 + Use lookAhead parser for the 'first pass' (looking for reference keys),
@@ -4903,7 +6264,7 @@ pandoc (0.4) unstable; urgency=low
49036264 been removed, since they are written programatically. This change
49046265 introduces a new dependency on the xhtml package.
49056266 + Fixed two bugs in email obfuscation involving improper escaping
4906− of '&' in the <noscript> section and in --strict mode. Resolves
6267+ of '&' in the `<noscript>` section and in `--strict` mode. Resolves
49076268 Issue #9.
49086269 + Fixed another bug in email obfuscation: If the text to be obfuscated
49096270 contains an entity, this needs to be decoded before obfuscation.
@@ -4935,8 +6296,8 @@ pandoc (0.4) unstable; urgency=low
49356296 + Links in markdown output are now printed as inline links by default,
49366297 rather than reference links. A --reference-links option has been added
49376298 that forces links to be printed as reference links. Resolves Issue #4.
4938− + Use autolinks when possible. Instead of [site.com](site.com),
4939− use <site.com>.
6299+ + Use autolinks when possible. Instead of `[site.com](site.com)`,
6300+ use `<site.com>`.
49406301
49416302 * LaTeX writer:
49426303
@@ -5152,7 +6513,7 @@ pandoc (0.3) unstable; urgency=low
51526513 only non-alphanumeric characters can be escaped. Strict mode
51536514 follows Markdown.pl in only allowing a select group of punctuation
51546515 characters to be escaped.
5155− + Modified HTML reader to skip a newline following a <br> tag.
6516+ + Modified HTML reader to skip a newline following a `<br>` tag.
51566517 Otherwise the newline will be treated as a space at the beginning
51576518 of the next line.
51586519
@@ -5182,7 +6543,7 @@ pandoc (0.3) unstable; urgency=low
51826543 * Moved handling of "smart typography" from the writers to the Markdown
51836544 and LaTeX readers. This allows great simplification of the writers
51846545 and more accurate smart quotes, dashes, and ellipses. DocBook can
5185− now use '<quote>'. The '--smart' option now toggles an option in
6546+ now use `<quote>`. The '--smart' option now toggles an option in
51866547 the parser state rather than a writer option. Several new kinds
51876548 of inline elements have been added: Quoted, Ellipses, Apostrophe,
51886549 EmDash, EnDash.
data/MathMLinHTML.js+10−10
@@ -1,4 +1,4 @@
1−/*
1+/*
22March 19, 2004 MathHTML (c) Peter Jipsen http://www.chapman.edu/~jipsen
33Released under the GNU General Public License version 2 or later.
44See the GNU General Public License (at http://www.gnu.org/copyleft/gpl.html)
@@ -7,15 +7,15 @@ for more details.
77
88function convertMath(node) {// for Gecko
99 if (node.nodeType==1) {
10− var newnode =
10+ var newnode =
1111 document.createElementNS("http://www.w3.org/1998/Math/MathML",
1212 node.nodeName.toLowerCase());
1313 for(var i=0; i < node.attributes.length; i++)
1414 newnode.setAttribute(node.attributes[i].nodeName,
15− node.attributes[i].nodeValue);
15+ node.attributes[i].value);
1616 for (var i=0; i<node.childNodes.length; i++) {
1717 var st = node.childNodes[i].nodeValue;
18− if (st==null || st.slice(0,1)!=" " && st.slice(0,1)!="\n")
18+ if (st==null || st.slice(0,1)!=" " && st.slice(0,1)!="\n")
1919 newnode.appendChild(convertMath(node.childNodes[i]));
2020 }
2121 return newnode;
@@ -37,14 +37,14 @@ function convert() {
3737 if (st=="#text") str += node.nodeValue;
3838 else {
3939 str += (st.slice(0,1)=="/" ? "</m:"+st.slice(1) : "<m:"+st);
40− if (st.slice(0,1)!="/")
40+ if (st.slice(0,1)!="/")
4141 for(var j=0; j < node.attributes.length; j++)
42− if (node.attributes[j].nodeValue!="italic" &&
43− node.attributes[j].nodeValue!="" &&
44− node.attributes[j].nodeValue!="inherit" &&
45− node.attributes[j].nodeValue!=undefined)
42+ if (node.attributes[j].value!="italic" &&
43+ node.attributes[j].value!="" &&
44+ node.attributes[j].value!="inherit" &&
45+ node.attributes[j].value!=undefined)
4646 str += " "+node.attributes[j].nodeName+"="+
47− "\""+node.attributes[j].nodeValue+"\"";
47+ "\""+node.attributes[j].value+"\"";
4848 str += ">";
4949 }
5050 node = node.nextSibling;
data/default.csldeleted−458
@@ -1,458 +0,0 @@
1−<?xml version="1.0" encoding="utf-8"?>
2−<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="never">
3− <info>
4− <title>Chicago Manual of Style (author-date)</title>
5− <id>http://www.zotero.org/styles/chicago-author-date</id>
6− <link href="http://www.zotero.org/styles/chicago-author-date" rel="self"/>
7− <link href="http://www.chicagomanualofstyle.org/tools_citationguide.html" rel="documentation"/>
8− <author>
9− <name>Julian Onions</name>
10− <email>julian.onions@gmail.com</email>
11− </author>
12− <contributor>
13− <name>Sebastian Karcher</name>
14− </contributor>
15− <contributor>
16− <name>Richard Karnesky</name>
17− <email>karnesky+zotero@gmail.com</email>
18− <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
19− </contributor>
20− <category citation-format="author-date"/>
21− <category field="generic-base"/>
22− <summary>The author-date variant of the Chicago style</summary>
23− <updated>2013-03-28T05:37:10+00:00</updated>
24− <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
25− </info>
26− <locale>
27− <terms>
28− <term name="editor" form="verb-short">ed.</term>
29− <term name="container-author" form="verb">by</term>
30− <term name="translator" form="verb-short">trans.</term>
31− <term name="translator" form="short">trans.</term>
32− </terms>
33− </locale>
34− <macro name="secondary-contributors">
35− <choose>
36− <if type="chapter paper-conference" match="none">
37− <group delimiter=". ">
38− <names variable="editor translator">
39− <label form="verb" text-case="capitalize-first" suffix=" " plural="never"/>
40− <name and="text" delimiter=", "/>
41− </names>
42− </group>
43− </if>
44− </choose>
45− </macro>
46− <macro name="container-contributors">
47− <choose>
48− <if type="chapter paper-conference" match="any">
49− <group prefix=", " delimiter=", ">
50− <names variable="container-author editor" delimiter=", ">
51− <label form="verb" suffix=" " plural="never"/>
52− <name and="text" delimiter=", "/>
53− </names>
54− </group>
55− </if>
56− </choose>
57− </macro>
58− <macro name="editor">
59− <names variable="editor">
60− <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
61− <label form="short" prefix=", "/>
62− </names>
63− </macro>
64− <macro name="translator">
65− <names variable="translator">
66− <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
67− <label form="short" prefix=", " plural="never"/>
68− </names>
69− </macro>
70− <macro name="recipient">
71− <choose>
72− <if type="personal_communication">
73− <choose>
74− <if variable="genre">
75− <text variable="genre" text-case="capitalize-first"/>
76− </if>
77− <else>
78− <text term="letter" text-case="capitalize-first"/>
79− </else>
80− </choose>
81− </if>
82− </choose>
83− <names variable="recipient" delimiter=", ">
84− <label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
85− <name and="text" delimiter=", "/>
86− </names>
87− </macro>
88− <macro name="contributors">
89− <names variable="author">
90− <name and="text" name-as-sort-order="first" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
91− <label form="short" plural="never" prefix=", "/>
92− <substitute>
93− <names variable="editor"/>
94− <names variable="translator"/>
95− <text macro="title"/>
96− </substitute>
97− </names>
98− <text macro="recipient"/>
99− </macro>
100− <macro name="contributors-short">
101− <names variable="author">
102− <name form="short" and="text" delimiter=", " initialize-with=". "/>
103− <substitute>
104− <names variable="editor"/>
105− <names variable="translator"/>
106− <text macro="title"/>
107− </substitute>
108− </names>
109− </macro>
110− <macro name="interviewer">
111− <names variable="interviewer" delimiter=", ">
112− <label form="verb" prefix=" " text-case="capitalize-first" suffix=" "/>
113− <name and="text" delimiter=", "/>
114− </names>
115− </macro>
116− <macro name="archive">
117− <group delimiter=". ">
118− <text variable="archive_location" text-case="capitalize-first"/>
119− <text variable="archive"/>
120− <text variable="archive-place"/>
121− </group>
122− </macro>
123− <macro name="access">
124− <group delimiter=". ">
125− <choose>
126− <if type="graphic report" match="any">
127− <text macro="archive"/>
128− </if>
129− <else-if type="article-magazine article-newspaper bill book chapter graphic legal_case legislation motion_picture paper-conference report song thesis" match="none">
130− <text macro="archive"/>
131− </else-if>
132− </choose>
133− <text variable="DOI" prefix="doi:"/>
134− <choose>
135− <if variable="DOI issued" match="none">
136− <choose>
137− <if variable="URL accessed" match="all">
138− <group delimiter=" ">
139− <text term="accessed" text-case="capitalize-first"/>
140− <date variable="accessed" delimiter=" ">
141− <date-part name="month"/>
142− <date-part name="day"/>
143− </date>
144− </group>
145− </if>
146− </choose>
147− </if>
148− <else-if type="webpage">
149− <date variable="issued" delimiter=" ">
150− <date-part name="month"/>
151− <date-part name="day"/>
152− </date>
153− </else-if>
154− </choose>
155− <choose>
156− <if type="legal_case" match="none">
157− <text variable="URL"/>
158− </if>
159− </choose>
160− </group>
161− </macro>
162− <macro name="title">
163− <choose>
164− <if variable="title" match="none">
165− <choose>
166− <if type="personal_communication" match="none">
167− <text variable="genre" text-case="capitalize-first"/>
168− </if>
169− </choose>
170− </if>
171− <else-if type="bill book graphic legal_case legislation motion_picture song" match="any">
172− <text variable="title" text-case="title" font-style="italic"/>
173− </else-if>
174− <else>
175− <text variable="title" text-case="title" quotes="true"/>
176− </else>
177− </choose>
178− </macro>
179− <macro name="edition">
180− <choose>
181− <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
182− <choose>
183− <if is-numeric="edition">
184− <group delimiter=" " prefix=". ">
185− <number variable="edition" form="ordinal"/>
186− <text term="edition" form="short" strip-periods="true"/>
187− </group>
188− </if>
189− <else>
190− <text variable="edition" prefix=". "/>
191− </else>
192− </choose>
193− </if>
194− <else-if type="chapter paper-conference" match="any">
195− <choose>
196− <if is-numeric="edition">
197− <group delimiter=" " prefix=", ">
198− <number variable="edition" form="ordinal"/>
199− <text term="edition" form="short"/>
200− </group>
201− </if>
202− <else>
203− <text variable="edition" prefix=", "/>
204− </else>
205− </choose>
206− </else-if>
207− </choose>
208− </macro>
209− <macro name="locators">
210− <choose>
211− <if type="article-journal">
212− <text variable="volume" prefix=" "/>
213− <text variable="issue" prefix=" (" suffix=")"/>
214− </if>
215− <else-if type="legal_case">
216− <text variable="volume" prefix=", "/>
217− <text variable="container-title" prefix=" "/>
218− <text variable="page" prefix=" "/>
219− </else-if>
220− <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
221− <group prefix=". " delimiter=". ">
222− <group>
223− <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
224− <number variable="volume" form="numeric"/>
225− </group>
226− <group>
227− <number variable="number-of-volumes" form="numeric"/>
228− <text term="volume" form="short" prefix=" " plural="true"/>
229− </group>
230− </group>
231− </else-if>
232− <else-if type="chapter paper-conference" match="any">
233− <choose>
234− <if variable="page" match="none">
235− <group prefix=". ">
236− <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
237− <number variable="volume" form="numeric"/>
238− </group>
239− </if>
240− </choose>
241− </else-if>
242− </choose>
243− </macro>
244− <macro name="locators-chapter">
245− <choose>
246− <if type="chapter paper-conference" match="any">
247− <choose>
248− <if variable="page">
249− <group prefix=", ">
250− <text variable="volume" suffix=":"/>
251− <text variable="page"/>
252− </group>
253− </if>
254− </choose>
255− </if>
256− </choose>
257− </macro>
258− <macro name="locators-article">
259− <choose>
260− <if type="article-newspaper">
261− <group prefix=", " delimiter=", ">
262− <group>
263− <text variable="edition" suffix=" "/>
264− <text term="edition" prefix=" "/>
265− </group>
266− <group>
267− <text term="section" form="short" suffix=" "/>
268− <text variable="section"/>
269− </group>
270− </group>
271− </if>
272− <else-if type="article-journal">
273− <text variable="page" prefix=": "/>
274− </else-if>
275− </choose>
276− </macro>
277− <macro name="point-locators">
278− <choose>
279− <if variable="locator">
280− <choose>
281− <if locator="page" match="none">
282− <choose>
283− <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
284− <choose>
285− <if variable="volume">
286− <group>
287− <text term="volume" form="short" suffix=" "/>
288− <number variable="volume" form="numeric"/>
289− <label variable="locator" form="short" prefix=", " suffix=" "/>
290− </group>
291− </if>
292− <else>
293− <label variable="locator" form="short" suffix=" "/>
294− </else>
295− </choose>
296− </if>
297− <else>
298− <label variable="locator" form="short" suffix=" "/>
299− </else>
300− </choose>
301− </if>
302− <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
303− <number variable="volume" form="numeric" suffix=":"/>
304− </else-if>
305− </choose>
306− <text variable="locator"/>
307− </if>
308− </choose>
309− </macro>
310− <macro name="container-prefix">
311− <text term="in" text-case="capitalize-first"/>
312− </macro>
313− <macro name="container-title">
314− <choose>
315− <if type="chapter paper-conference" match="any">
316− <text macro="container-prefix" suffix=" "/>
317− </if>
318− </choose>
319− <choose>
320− <if type="legal_case" match="none">
321− <text variable="container-title" text-case="title" font-style="italic"/>
322− </if>
323− </choose>
324− </macro>
325− <macro name="publisher">
326− <group delimiter=": ">
327− <text variable="publisher-place"/>
328− <text variable="publisher"/>
329− </group>
330− </macro>
331− <macro name="date">
332− <choose>
333− <if variable="issued">
334− <date variable="issued">
335− <date-part name="year"/>
336− </date>
337− </if>
338− <else-if variable="accessed">
339− <date variable="accessed">
340− <date-part name="year"/>
341− </date>
342− </else-if>
343− </choose>
344− </macro>
345− <macro name="day-month">
346− <date variable="issued">
347− <date-part name="month"/>
348− <date-part name="day" prefix=" "/>
349− </date>
350− </macro>
351− <macro name="collection-title">
352− <text variable="collection-title" text-case="title"/>
353− <text variable="collection-number" prefix=" "/>
354− </macro>
355− <macro name="event">
356− <group>
357− <text term="presented at" suffix=" "/>
358− <text variable="event"/>
359− </group>
360− </macro>
361− <macro name="description">
362− <choose>
363− <if type="interview">
364− <group delimiter=". ">
365− <text macro="interviewer"/>
366− <text variable="medium" text-case="capitalize-first"/>
367− </group>
368− </if>
369− <else>
370− <text variable="medium" text-case="capitalize-first" prefix=". "/>
371− </else>
372− </choose>
373− <choose>
374− <if variable="title" match="none"/>
375− <else-if type="thesis"/>
376− <else>
377− <group delimiter=" " prefix=". ">
378− <text variable="genre" text-case="capitalize-first"/>
379− <choose>
380− <if type="report">
381− <text variable="number"/>
382− </if>
383− </choose>
384− </group>
385− </else>
386− </choose>
387− <!--This is for computer programs only. Localization new to 1.0.1, so may be missing in many locales-->
388− <group delimiter=" " prefix=" (" suffix=")">
389− <text term="version"/>
390− <text variable="version"/>
391− </group>
392− </macro>
393− <macro name="issue">
394− <choose>
395− <if type="article-journal">
396− <text macro="day-month" prefix=" (" suffix=")"/>
397− </if>
398− <else-if type="legal_case">
399− <text variable="authority" prefix=". "/>
400− </else-if>
401− <else-if type="speech">
402− <group prefix=" " delimiter=", ">
403− <text macro="event"/>
404− <text macro="day-month"/>
405− <text variable="event-place"/>
406− </group>
407− </else-if>
408− <else-if type="article-newspaper article-magazine" match="any">
409− <text macro="day-month" prefix=", "/>
410− </else-if>
411− <else>
412− <group prefix=". " delimiter=", ">
413− <choose>
414− <if type="thesis">
415− <text variable="genre" text-case="capitalize-first"/>
416− </if>
417− </choose>
418− <text macro="publisher"/>
419− </group>
420− </else>
421− </choose>
422− </macro>
423− <citation et-al-min="4" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" givenname-disambiguation-rule="primary-name">
424− <layout prefix="(" suffix=")" delimiter="; ">
425− <group delimiter=", ">
426− <group delimiter=" ">
427− <text macro="contributors-short"/>
428− <text macro="date"/>
429− </group>
430− <text macro="point-locators"/>
431− </group>
432− </layout>
433− </citation>
434− <bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" subsequent-author-substitute="&#8212;&#8212;&#8212;" entry-spacing="0">
435− <sort>
436− <key macro="contributors"/>
437− <key variable="issued"/>
438− </sort>
439− <layout suffix=".">
440− <group delimiter=". ">
441− <text macro="contributors"/>
442− <text macro="date"/>
443− <text macro="title"/>
444− </group>
445− <text macro="description"/>
446− <text macro="secondary-contributors" prefix=". "/>
447− <text macro="container-title" prefix=". "/>
448− <text macro="container-contributors"/>
449− <text macro="edition"/>
450− <text macro="locators-chapter"/>
451− <text macro="locators"/>
452− <text macro="collection-title" prefix=". "/>
453− <text macro="issue"/>
454− <text macro="locators-article"/>
455− <text macro="access" prefix=". "/>
456− </layout>
457− </bibliography>
458−</style>
data/epub.css+1−20
@@ -1,5 +1,5 @@
11/* This defines styles and classes used in the book */
2−body { margin-left: 5%; margin-right: 5%; margin-top: 5%; margin-bottom: 5%; text-align: justify; font-size: medium; }
2+body { margin: 5%; text-align: justify; font-size: medium; }
33code { font-family: monospace; }
44h1 { text-align: left; }
55h2 { text-align: left; }
@@ -12,22 +12,3 @@ h2.author { }
1212h3.date { }
1313ol.toc { padding: 0; margin-left: 1em; }
1414ol.toc li { list-style-type: none; margin: 0; padding: 0; }
15−/* For source-code highlighting */
16−table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode, table.sourceCode pre
17− { margin: 0; padding: 0; border: 0; vertical-align: baseline; border: none; }
18−td.lineNumbers { border-right: 1px solid #AAAAAA; text-align: right; color: #AAAAAA; padding-right: 5px; padding-left: 5px; }
19−td.sourceCode { padding-left: 5px; }
20−pre.sourceCode { }
21−code.sourceCode span.kw { color: #007020; font-weight: bold; }
22−code.sourceCode span.dt { color: #902000; }
23−code.sourceCode span.dv { color: #40a070; }
24−code.sourceCode span.bn { color: #40a070; }
25−code.sourceCode span.fl { color: #40a070; }
26−code.sourceCode span.ch { color: #4070a0; }
27−code.sourceCode span.st { color: #4070a0; }
28−code.sourceCode span.co { color: #60a0b0; font-style: italic; }
29−code.sourceCode span.ot { color: #007020; }
30−code.sourceCode span.al { color: red; font-weight: bold; }
31−code.sourceCode span.fu { color: #06287e; }
32−code.sourceCode span.re { }
33−code.sourceCode span.er { color: red; font-weight: bold; }
data/reference.docx

Binary file not shown.

data/reference.odt

Binary file not shown.

data/s5/default/blank.gifdeleted

Binary file not shown.

data/s5/default/bodybg.gifdeleted

Binary file not shown.

data/s5/default/framing.cssdeleted−23
@@ -1,23 +0,0 @@
1−/* The following styles size, place, and layer the slide components.
2− Edit these if you want to change the overall slide layout.
3− The commented lines can be uncommented (and modified, if necessary)
4− to help you with the rearrangement process. */
5−
6−/* target = 1024x768 */
7−
8−div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
9−div#header {top: 0; height: 3em; z-index: 1;}
10−div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
11−.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2; list-style: none;}
12−div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
13−div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
14− margin: 0;}
15−#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; z-index: 10;}
16−html>body #currentSlide {position: fixed;}
17−
18−/*
19−div#header {background: #FCC;}
20−div#footer {background: #CCF;}
21−div#controls {background: #BBD;}
22−div#currentSlide {background: #FFC;}
23−*/
data/s5/default/iepngfix.htcdeleted−42
@@ -1,42 +0,0 @@
1−<public:component>
2−<public:attach event="onpropertychange" onevent="doFix()" />
3−
4−<script>
5−
6−// IE5.5+ PNG Alpha Fix v1.0 by Angus Turnbull http://www.twinhelix.com
7−// Free usage permitted as long as this notice remains intact.
8−
9−// This must be a path to a blank image. That's all the configuration you need here.
10−var blankImg = 'ui/default/blank.gif';
11−
12−var f = 'DXImageTransform.Microsoft.AlphaImageLoader';
13−
14−function filt(s, m) {
15− if (filters[f]) {
16− filters[f].enabled = s ? true : false;
17− if (s) with (filters[f]) { src = s; sizingMethod = m }
18− } else if (s) style.filter = 'progid:'+f+'(src="'+s+'",sizingMethod="'+m+'")';
19−}
20−
21−function doFix() {
22− if ((parseFloat(navigator.userAgent.match(/MSIE (\S+)/)[1]) < 5.5) ||
23− (event && !/(background|src)/.test(event.propertyName))) return;
24−
25− if (tagName == 'IMG') {
26− if ((/\.png$/i).test(src)) {
27− filt(src, 'image'); // was 'scale'
28− src = blankImg;
29− } else if (src.indexOf(blankImg) < 0) filt();
30− } else if (style.backgroundImage) {
31− if (style.backgroundImage.match(/^url[("']+(.*\.png)[)"']+$/i)) {
32− var s = RegExp.$1;
33− style.backgroundImage = '';
34− filt(s, 'crop');
35− } else filt();
36− }
37−}
38−
39−doFix();
40−
41−</script>
42−</public:component>
data/s5/default/opera.cssdeleted−7
@@ -1,7 +0,0 @@
1−/* DO NOT CHANGE THESE unless you really want to break Opera Show */
2−.slide {
3− visibility: visible !important;
4− position: static !important;
5− page-break-before: always;
6−}
7−#slide0 {page-break-before: avoid;}
data/s5/default/outline.cssdeleted−15
@@ -1,15 +0,0 @@
1−/* don't change this unless you want the layout stuff to show up in the outline view! */
2−
3−.layout div, #footer *, #controlForm * {display: none;}
4−#footer, #controls, #controlForm, #navLinks, #toggle {
5− display: block; visibility: visible; margin: 0; padding: 0;}
6−#toggle {float: right; padding: 0.5em;}
7−html>body #toggle {position: fixed; top: 0; right: 0;}
8−
9−/* making the outline look pretty-ish */
10−
11−#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;}
12−#slide0 h1 {padding-top: 1.5em;}
13−.slide h1 {margin: 1.5em 0 0; padding-top: 0.25em;
14− border-top: 1px solid #888; border-bottom: 1px solid #AAA;}
15−#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;}
data/s5/default/pretty.cssdeleted−86
@@ -1,86 +0,0 @@
1−/* Following are the presentation styles -- edit away! */
2−
3−body {background: #FFF url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2em;}
4−:link, :visited {text-decoration: none; color: #00C;}
5−#controls :active {color: #88A !important;}
6−#controls :focus {outline: 1px dotted #227;}
7−h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
8−ul, pre {margin: 0; line-height: 1em;}
9−html, body {margin: 0; padding: 0;}
10−
11−blockquote, q {font-style: italic;}
12−blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;}
13−blockquote p {margin: 0;}
14−blockquote i {font-style: normal;}
15−blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;}
16−blockquote b i {font-style: italic;}
17−
18−kbd {font-weight: bold; font-size: 1em;}
19−sup {font-size: smaller; line-height: 1px;}
20−
21−.slide code {padding: 2px 0.25em; font-weight: bold; color: #533;}
22−.slide code.bad, code del {color: red;}
23−.slide code.old {color: silver;}
24−.slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;}
25−.slide pre code {display: block;}
26−.slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;}
27−.slide li {margin-top: 0.75em; margin-right: 0;}
28−.slide ul ul {line-height: 1;}
29−.slide ul ul li {margin: .2em; font-size: 85%; list-style: square;}
30−.slide img.leader {display: block; margin: 0 auto;}
31−
32−div#header, div#footer {background: #005; color: #AAB;
33− font-family: Verdana, Helvetica, sans-serif;}
34−div#header {background: #005 url(bodybg.gif) -16px 0 no-repeat;
35− line-height: 1px;}
36−div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;}
37−#footer h1, #footer h2 {display: block; padding: 0 1em;}
38−#footer h2 {font-style: italic;}
39−
40−div.long {font-size: 0.75em;}
41−.slide h1 {position: absolute; top: 0.7em; left: 87px; z-index: 1;
42− margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap;
43− font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize;
44− color: #DDE; background: #005;}
45−.slide h3 {font-size: 130%;}
46−h1 abbr {font-variant: small-caps;}
47−
48−div#controls {position: absolute; left: 50%; bottom: 0;
49− width: 50%;
50− text-align: right; font: bold 0.9em Verdana, Helvetica, sans-serif;}
51−html>body div#controls {position: fixed; padding: 0 0 1em 0;
52− top: auto;}
53−div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
54− margin: 0; padding: 0;}
55−#controls #navLinks a {padding: 0; margin: 0 0.5em;
56− background: #005; border: none; color: #779;
57− cursor: pointer;}
58−#controls #navList {height: 1em;}
59−#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; background: #DDD; color: #227;}
60−
61−#currentSlide {text-align: center; font-size: 0.5em; color: #449;}
62−
63−#slide0 {padding-top: 3.5em; font-size: 90%;}
64−#slide0 h1 {position: static; margin: 1em 0 0; padding: 0;
65− font: bold 2em Helvetica, sans-serif; white-space: normal;
66− color: #000; background: transparent;}
67−#slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 0.25em;}
68−#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
69−#slide0 h4 {margin-top: 0; font-size: 1em;}
70−
71−ul.urls {list-style: none; display: inline; margin: 0;}
72−.urls li {display: inline; margin: 0;}
73−.note {display: none;}
74−.external {border-bottom: 1px dotted gray;}
75−html>body .external {border-bottom: none;}
76−.external:after {content: " \274F"; font-size: smaller; color: #77B;}
77−
78−.incremental, .incremental *, .incremental *:after {color: #DDE; visibility: visible;}
79−img.incremental {visibility: hidden;}
80−.slide .current {color: #B02;}
81−
82−
83−/* diagnostics
84−
85−li:after {content: " [" attr(class) "]"; color: #F88;}
86−*/
data/s5/default/print.cssdeleted−24
@@ -1,24 +0,0 @@
1−/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */
2−.slide, ul {page-break-inside: avoid; visibility: visible !important;}
3−h1 {page-break-after: avoid;}
4−
5−body {font-size: 12pt; background: white;}
6−* {color: black;}
7−
8−#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;}
9−#slide0 h3 {margin: 0; padding: 0;}
10−#slide0 h4 {margin: 0 0 0.5em; padding: 0;}
11−#slide0 {margin-bottom: 3em;}
12−
13−h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;}
14−.extra {background: transparent !important;}
15−div.extra, pre.extra, .example {font-size: 10pt; color: #333;}
16−ul.extra a {font-weight: bold;}
17−p.example {display: none;}
18−
19−#header {display: none;}
20−#footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;}
21−#footer h2, #controls {display: none;}
22−
23−/* The following rule keeps the layout stuff out of print. Remove at your own risk! */
24−.layout, .layout * {display: none !important;}
data/s5/default/s5-core.cssdeleted−9
@@ -1,9 +0,0 @@
1−/* Do not edit or override these styles! The system will likely break if you do. */
2−
3−div#header, div#footer, div#controls, .slide {position: absolute;}
4−html>body div#header, html>body div#footer,
5− html>body div#controls, html>body .slide {position: fixed;}
6−.handout {display: none;}
7−.layout {display: block;}
8−.slide, .hideme, .incremental {visibility: hidden;}
9−#slide0 {visibility: visible;}
data/s5/default/slides.cssdeleted−3
@@ -1,3 +0,0 @@
1−@import url(s5-core.css); /* required to make the slide show run at all */
2−@import url(framing.css); /* sets basic placement and size of slide components */
3−@import url(pretty.css); /* stuff that makes the slides look better than blah */
data/s5/default/slides.jsdeleted−553
@@ -1,553 +0,0 @@
1−// S5 v1.1 slides.js -- released into the Public Domain
2−//
3−// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information
4−// about all the wonderful and talented contributors to this code!
5−
6−var undef;
7−var slideCSS = '';
8−var snum = 0;
9−var smax = 1;
10−var incpos = 0;
11−var number = undef;
12−var s5mode = true;
13−var defaultView = 'slideshow';
14−var controlVis = 'visible';
15−
16−var isIE = navigator.appName == 'Microsoft Internet Explorer' && navigator.userAgent.indexOf('Opera') < 1 ? 1 : 0;
17−var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0;
18−var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0;
19−
20−function hasClass(object, className) {
21− if (!object.className) return false;
22− return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1);
23−}
24−
25−function hasValue(object, value) {
26− if (!object) return false;
27− return (object.search('(^|\\s)' + value + '(\\s|$)') != -1);
28−}
29−
30−function removeClass(object,className) {
31− if (!object) return;
32− object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2);
33−}
34−
35−function addClass(object,className) {
36− if (!object || hasClass(object, className)) return;
37− if (object.className) {
38− object.className += ' '+className;
39− } else {
40− object.className = className;
41− }
42−}
43−
44−function GetElementsWithClassName(elementName,className) {
45− var allElements = document.getElementsByTagName(elementName);
46− var elemColl = new Array();
47− for (var i = 0; i< allElements.length; i++) {
48− if (hasClass(allElements[i], className)) {
49− elemColl[elemColl.length] = allElements[i];
50− }
51− }
52− return elemColl;
53−}
54−
55−function isParentOrSelf(element, id) {
56− if (element == null || element.nodeName=='BODY') return false;
57− else if (element.id == id) return true;
58− else return isParentOrSelf(element.parentNode, id);
59−}
60−
61−function nodeValue(node) {
62− var result = "";
63− if (node.nodeType == 1) {
64− var children = node.childNodes;
65− for (var i = 0; i < children.length; ++i) {
66− result += nodeValue(children[i]);
67− }
68− }
69− else if (node.nodeType == 3) {
70− result = node.nodeValue;
71− }
72− return(result);
73−}
74−
75−function slideLabel() {
76− var slideColl = GetElementsWithClassName('*','slide');
77− var list = document.getElementById('jumplist');
78− smax = slideColl.length;
79− for (var n = 0; n < smax; n++) {
80− var obj = slideColl[n];
81−
82− var did = 'slide' + n.toString();
83− obj.setAttribute('id',did);
84− if (isOp) continue;
85−
86− var otext = '';
87− var menu = obj.firstChild;
88− if (!menu) continue; // to cope with empty slides
89− while (menu && menu.nodeType == 3) {
90− menu = menu.nextSibling;
91− }
92− if (!menu) continue; // to cope with slides with only text nodes
93−
94− var menunodes = menu.childNodes;
95− for (var o = 0; o < menunodes.length; o++) {
96− otext += nodeValue(menunodes[o]);
97− }
98− list.options[list.length] = new Option(n + ' : ' + otext, n);
99− }
100−}
101−
102−function currentSlide() {
103− var cs;
104− if (document.getElementById) {
105− cs = document.getElementById('currentSlide');
106− } else {
107− cs = document.currentSlide;
108− }
109− cs.innerHTML = '<span id="csHere">' + snum + '<\/span> ' +
110− '<span id="csSep">\/<\/span> ' +
111− '<span id="csTotal">' + (smax-1) + '<\/span>';
112− if (snum == 0) {
113− cs.style.visibility = 'hidden';
114− } else {
115− cs.style.visibility = 'visible';
116− }
117−}
118−
119−function go(step) {
120− if (document.getElementById('slideProj').disabled || step == 0) return;
121− var jl = document.getElementById('jumplist');
122− var cid = 'slide' + snum;
123− var ce = document.getElementById(cid);
124− if (incrementals[snum].length > 0) {
125− for (var i = 0; i < incrementals[snum].length; i++) {
126− removeClass(incrementals[snum][i], 'current');
127− removeClass(incrementals[snum][i], 'incremental');
128− }
129− }
130− if (step != 'j') {
131− snum += step;
132− lmax = smax - 1;
133− if (snum > lmax) snum = lmax;
134− if (snum < 0) snum = 0;
135− } else
136− snum = parseInt(jl.value);
137− var nid = 'slide' + snum;
138− var ne = document.getElementById(nid);
139− if (!ne) {
140− ne = document.getElementById('slide0');
141− snum = 0;
142− }
143− if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;}
144− if (incrementals[snum].length > 0 && incpos == 0) {
145− for (var i = 0; i < incrementals[snum].length; i++) {
146− if (hasClass(incrementals[snum][i], 'current'))
147− incpos = i + 1;
148− else
149− addClass(incrementals[snum][i], 'incremental');
150− }
151− }
152− if (incrementals[snum].length > 0 && incpos > 0)
153− addClass(incrementals[snum][incpos - 1], 'current');
154− ce.style.visibility = 'hidden';
155− ne.style.visibility = 'visible';
156− jl.selectedIndex = snum;
157− currentSlide();
158− number = 0;
159−}
160−
161−function goTo(target) {
162− if (target >= smax || target == snum) return;
163− go(target - snum);
164−}
165−
166−function subgo(step) {
167− if (step > 0) {
168− removeClass(incrementals[snum][incpos - 1],'current');
169− removeClass(incrementals[snum][incpos], 'incremental');
170− addClass(incrementals[snum][incpos],'current');
171− incpos++;
172− } else {
173− incpos--;
174− removeClass(incrementals[snum][incpos],'current');
175− addClass(incrementals[snum][incpos], 'incremental');
176− addClass(incrementals[snum][incpos - 1],'current');
177− }
178−}
179−
180−function toggle() {
181− var slideColl = GetElementsWithClassName('*','slide');
182− var slides = document.getElementById('slideProj');
183− var outline = document.getElementById('outlineStyle');
184− if (!slides.disabled) {
185− slides.disabled = true;
186− outline.disabled = false;
187− s5mode = false;
188− fontSize('1em');
189− for (var n = 0; n < smax; n++) {
190− var slide = slideColl[n];
191− slide.style.visibility = 'visible';
192− }
193− } else {
194− slides.disabled = false;
195− outline.disabled = true;
196− s5mode = true;
197− fontScale();
198− for (var n = 0; n < smax; n++) {
199− var slide = slideColl[n];
200− slide.style.visibility = 'hidden';
201− }
202− slideColl[snum].style.visibility = 'visible';
203− }
204−}
205−
206−function showHide(action) {
207− var obj = GetElementsWithClassName('*','hideme')[0];
208− switch (action) {
209− case 's': obj.style.visibility = 'visible'; break;
210− case 'h': obj.style.visibility = 'hidden'; break;
211− case 'k':
212− if (obj.style.visibility != 'visible') {
213− obj.style.visibility = 'visible';
214− } else {
215− obj.style.visibility = 'hidden';
216− }
217− break;
218− }
219−}
220−
221−// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/)
222−function keys(key) {
223− if (!key) {
224− key = event;
225− key.which = key.keyCode;
226− }
227− if (key.which == 84) {
228− toggle();
229− return;
230− }
231− if (s5mode) {
232− switch (key.which) {
233− case 10: // return
234− case 13: // enter
235− if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
236− if (key.target && isParentOrSelf(key.target, 'controls')) return;
237− if(number != undef) {
238− goTo(number);
239− break;
240− }
241− case 32: // spacebar
242− case 34: // page down
243− case 39: // rightkey
244− case 40: // downkey
245− if(number != undef) {
246− go(number);
247− } else if (!incrementals[snum] || incpos >= incrementals[snum].length) {
248− go(1);
249− } else {
250− subgo(1);
251− }
252− break;
253− case 33: // page up
254− case 37: // leftkey
255− case 38: // upkey
256− if(number != undef) {
257− go(-1 * number);
258− } else if (!incrementals[snum] || incpos <= 0) {
259− go(-1);
260− } else {
261− subgo(-1);
262− }
263− break;
264− case 36: // home
265− goTo(0);
266− break;
267− case 35: // end
268− goTo(smax-1);
269− break;
270− case 67: // c
271− showHide('k');
272− break;
273− }
274− if (key.which < 48 || key.which > 57) {
275− number = undef;
276− } else {
277− if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
278− if (key.target && isParentOrSelf(key.target, 'controls')) return;
279− number = (((number != undef) ? number : 0) * 10) + (key.which - 48);
280− }
281− }
282− return false;
283−}
284−
285−function clicker(e) {
286− number = undef;
287− var target;
288− if (window.event) {
289− target = window.event.srcElement;
290− e = window.event;
291− } else target = e.target;
292− if (target.getAttribute('href') != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object')) return true;
293− if (!e.which || e.which == 1) {
294− if (!incrementals[snum] || incpos >= incrementals[snum].length) {
295− go(1);
296− } else {
297− subgo(1);
298− }
299− }
300−}
301−
302−function findSlide(hash) {
303− var target = null;
304− var slides = GetElementsWithClassName('*','slide');
305− for (var i = 0; i < slides.length; i++) {
306− var targetSlide = slides[i];
307− if ( (targetSlide.name && targetSlide.name == hash)
308− || (targetSlide.id && targetSlide.id == hash) ) {
309− target = targetSlide;
310− break;
311− }
312− }
313− while(target != null && target.nodeName != 'BODY') {
314− if (hasClass(target, 'slide')) {
315− return parseInt(target.id.slice(5));
316− }
317− target = target.parentNode;
318− }
319− return null;
320−}
321−
322−function slideJump() {
323− if (window.location.hash == null) return;
324− var sregex = /^#slide(\d+)$/;
325− var matches = sregex.exec(window.location.hash);
326− var dest = null;
327− if (matches != null) {
328− dest = parseInt(matches[1]);
329− } else {
330− dest = findSlide(window.location.hash.slice(1));
331− }
332− if (dest != null)
333− go(dest - snum);
334−}
335−
336−function fixLinks() {
337− var thisUri = window.location.href;
338− thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length);
339− var aelements = document.getElementsByTagName('A');
340− for (var i = 0; i < aelements.length; i++) {
341− var a = aelements[i].href;
342− var slideID = a.match('\#slide[0-9]{1,2}');
343− if ((slideID) && (slideID[0].slice(0,1) == '#')) {
344− var dest = findSlide(slideID[0].slice(1));
345− if (dest != null) {
346− if (aelements[i].addEventListener) {
347− aelements[i].addEventListener("click", new Function("e",
348− "if (document.getElementById('slideProj').disabled) return;" +
349− "go("+dest+" - snum); " +
350− "if (e.preventDefault) e.preventDefault();"), true);
351− } else if (aelements[i].attachEvent) {
352− aelements[i].attachEvent("onclick", new Function("",
353− "if (document.getElementById('slideProj').disabled) return;" +
354− "go("+dest+" - snum); " +
355− "event.returnValue = false;"));
356− }
357− }
358− }
359− }
360−}
361−
362−function externalLinks() {
363− if (!document.getElementsByTagName) return;
364− var anchors = document.getElementsByTagName('a');
365− for (var i=0; i<anchors.length; i++) {
366− var anchor = anchors[i];
367− if (anchor.getAttribute('href') && hasValue(anchor.rel, 'external')) {
368− anchor.target = '_blank';
369− addClass(anchor,'external');
370− }
371− }
372−}
373−
374−function createControls() {
375− var controlsDiv = document.getElementById("controls");
376− if (!controlsDiv) return;
377− var hider = ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';
378− var hideDiv, hideList = '';
379− if (controlVis == 'hidden') {
380− hideDiv = hider;
381− } else {
382− hideList = hider;
383− }
384− controlsDiv.innerHTML = '<form action="#" id="controlForm"' + hideDiv + '>' +
385− '<div id="navLinks">' +
386− '<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;<\/a>' +
387− '<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;<\/a>' +
388− '<a accesskey="x" id="next" href="javascript:go(1);">&raquo;<\/a>' +
389− '<div id="navList"' + hideList + '><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>' +
390− '<\/div><\/form>';
391− if (controlVis == 'hidden') {
392− var hidden = document.getElementById('navLinks');
393− } else {
394− var hidden = document.getElementById('jumplist');
395− }
396− addClass(hidden,'hideme');
397−}
398−
399−function fontScale() { // causes layout problems in FireFox that get fixed if browser's Reload is used; same may be true of other Gecko-based browsers
400− if (!s5mode) return false;
401− var vScale = 22; // both yield 32 (after rounding) at 1024x768
402− var hScale = 32; // perhaps should auto-calculate based on theme's declared value?
403− if (window.innerHeight) {
404− var vSize = window.innerHeight;
405− var hSize = window.innerWidth;
406− } else if (document.documentElement.clientHeight) {
407− var vSize = document.documentElement.clientHeight;
408− var hSize = document.documentElement.clientWidth;
409− } else if (document.body.clientHeight) {
410− var vSize = document.body.clientHeight;
411− var hSize = document.body.clientWidth;
412− } else {
413− var vSize = 700; // assuming 1024x768, minus chrome and such
414− var hSize = 1024; // these do not account for kiosk mode or Opera Show
415− }
416− var newSize = Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));
417− fontSize(newSize + 'px');
418− if (isGe) { // hack to counter incremental reflow bugs
419− var obj = document.getElementsByTagName('body')[0];
420− obj.style.display = 'none';
421− obj.style.display = 'block';
422− }
423−}
424−
425−function fontSize(value) {
426− if (!(s5ss = document.getElementById('s5ss'))) {
427− if (!isIE) {
428− document.getElementsByTagName('head')[0].appendChild(s5ss = document.createElement('style'));
429− s5ss.setAttribute('media','screen, projection');
430− s5ss.setAttribute('id','s5ss');
431− } else {
432− document.createStyleSheet();
433− document.s5ss = document.styleSheets[document.styleSheets.length - 1];
434− }
435− }
436− if (!isIE) {
437− while (s5ss.lastChild) s5ss.removeChild(s5ss.lastChild);
438− s5ss.appendChild(document.createTextNode('body {font-size: ' + value + ' !important;}'));
439− } else {
440− document.s5ss.addRule('body','font-size: ' + value + ' !important;');
441− }
442−}
443−
444−function notOperaFix() {
445− slideCSS = document.getElementById('slideProj').href;
446− var slides = document.getElementById('slideProj');
447− var outline = document.getElementById('outlineStyle');
448− slides.setAttribute('media','screen');
449− outline.disabled = true;
450− if (isGe) {
451− slides.setAttribute('href','null'); // Gecko fix
452− slides.setAttribute('href',slideCSS); // Gecko fix
453− }
454− if (isIE && document.styleSheets && document.styleSheets[0]) {
455− document.styleSheets[0].addRule('img', 'behavior: url(ui/default/iepngfix.htc)');
456− document.styleSheets[0].addRule('div', 'behavior: url(ui/default/iepngfix.htc)');
457− document.styleSheets[0].addRule('.slide', 'behavior: url(ui/default/iepngfix.htc)');
458− }
459−}
460−
461−function getIncrementals(obj) {
462− var incrementals = new Array();
463− if (!obj)
464− return incrementals;
465− var children = obj.childNodes;
466− for (var i = 0; i < children.length; i++) {
467− var child = children[i];
468− if (hasClass(child, 'incremental')) {
469− if (child.nodeName == 'OL' || child.nodeName == 'UL') {
470− removeClass(child, 'incremental');
471− for (var j = 0; j < child.childNodes.length; j++) {
472− if (child.childNodes[j].nodeType == 1) {
473− addClass(child.childNodes[j], 'incremental');
474− }
475− }
476− } else {
477− incrementals[incrementals.length] = child;
478− removeClass(child,'incremental');
479− }
480− }
481− if (hasClass(child, 'show-first')) {
482− if (child.nodeName == 'OL' || child.nodeName == 'UL') {
483− removeClass(child, 'show-first');
484− if (child.childNodes[isGe].nodeType == 1) {
485− removeClass(child.childNodes[isGe], 'incremental');
486− }
487− } else {
488− incrementals[incrementals.length] = child;
489− }
490− }
491− incrementals = incrementals.concat(getIncrementals(child));
492− }
493− return incrementals;
494−}
495−
496−function createIncrementals() {
497− var incrementals = new Array();
498− for (var i = 0; i < smax; i++) {
499− incrementals[i] = getIncrementals(document.getElementById('slide'+i));
500− }
501− return incrementals;
502−}
503−
504−function defaultCheck() {
505− var allMetas = document.getElementsByTagName('meta');
506− for (var i = 0; i< allMetas.length; i++) {
507− if (allMetas[i].name == 'defaultView') {
508− defaultView = allMetas[i].content;
509− }
510− if (allMetas[i].name == 'controlVis') {
511− controlVis = allMetas[i].content;
512− }
513− }
514−}
515−
516−// Key trap fix, new function body for trap()
517−function trap(e) {
518− if (!e) {
519− e = event;
520− e.which = e.keyCode;
521− }
522− try {
523− modifierKey = e.ctrlKey || e.altKey || e.metaKey;
524− }
525− catch(e) {
526− modifierKey = false;
527− }
528− return modifierKey || e.which == 0;
529−}
530−
531−function startup() {
532− defaultCheck();
533− if (!isOp)
534− createControls();
535− slideLabel();
536− fixLinks();
537− externalLinks();
538− fontScale();
539− if (!isOp) {
540− notOperaFix();
541− incrementals = createIncrementals();
542− slideJump();
543− if (defaultView == 'outline') {
544− toggle();
545− }
546− document.onkeyup = keys;
547− document.onkeypress = trap;
548− document.onclick = clicker;
549− }
550−}
551−
552−window.onload = startup;
553−window.onresize = function(){setTimeout('fontScale()', 50);}
data/sample.lua+17−5
@@ -77,16 +77,16 @@ function Doc(body, metadata, variables)
7777 add('<!DOCTYPE html>')
7878 add('<html>')
7979 add('<head>')
80− add('<title>' .. metadata.title .. '</title>')
80+ add('<title>' .. (metadata['title'] or '') .. '</title>')
8181 add('</head>')
8282 add('<body>')
83− if title ~= "" then
84− add('<h1 class="title">' .. metadata.title .. '</h1>')
83+ if metadata['title'] and metadata['title'] ~= "" then
84+ add('<h1 class="title">' .. metadata['title'] .. '</h1>')
8585 end
86− for _, author in pairs(metadata.author) do
86+ for _, author in pairs(metadata['author'] or {}) do
8787 add('<h2 class="author">' .. author .. '</h2>')
8888 end
89− if date ~= "" then
89+ if metadata['date'] and metadata['date'] ~= "" then
9090 add('<h3 class="date">' .. metadata.date .. '</h3>')
9191 end
9292 add(body)
@@ -177,6 +177,14 @@ function Note(s)
177177 '"><sup>' .. num .. '</sup></a>'
178178end
179179
180+function Span(s, attr)
181+ return "<span" .. attributes(attr) .. ">" .. s .. "</span>"
182+end
183+
184+function Cite(s)
185+ return "<span class=\"cite\">" .. s .. "</span>"
186+end
187+
180188function Plain(s)
181189 return s
182190end
@@ -299,6 +307,10 @@ function Table(caption, aligns, widths, headers, rows)
299307 return table.concat(buffer,'\n')
300308end
301309
310+function Div(s, attr)
311+ return "<div" .. attributes(attr) .. ">\n" .. s .. "</div>"
312+end
313+
302314-- The following code will produce runtime warnings when you haven't defined
303315-- all of the functions you need for the custom writer, so it's useful
304316-- to include when you're working on a writer.
data/slideous/slideous.cssdeleted−95
@@ -1,95 +0,0 @@
1−/* This work is licensed under Creative Commons GNU LGPL License.
2−
3− License: http://creativecommons.org/licenses/LGPL/2.1/
4− Version: 1.0
5−
6− Author: Stefan Goessner/2005
7− Web: http://goessner.net/
8−*/
9−@media screen, projection {
10−body {
11− background-color: #e3eee7;
12− padding: 0;
13− margin: 0;
14− color: #132;
15− border-color: #678;
16− font-size: 125%;
17−}
18−#statusbar {
19− display: none;
20− position: absolute; z-index: 10;
21− top: auto; bottom: 0; left: 0; right: 0;
22− height: 2em;
23− background-color: #f0fff8;
24− color: #132;
25− font-size: 75%;
26− padding: 0.5em 0.5em 0 2px;
27− border-top: solid 1px #000;
28−}
29−#statusbar button, #tocbox {
30− cursor: pointer;
31− color: #031;
32− background-color: #e0eee7;
33− margin: 1px;
34− padding: 0 0.5em;
35− border: inset 1px black;
36−}
37−#statusbar button:hover, #tocbox:hover {
38− color: #031;
39− background-color: #c0ccc6;
40− border: outset 1px black;
41−}
42−#tocbox {
43− width: 15em;
44−}
45−#eos {
46− visibility: hidden;
47− color: #021;
48− background-color: #fffafa;
49− border: inset 1px black;
50− font-size: 120%;
51−}
52−div.slide {
53− display: block;
54− margin: 0 0 2em 0;
55− padding: 0 150px;
56−}
57−
58−div.slide h1 {
59− background: #a0aaa4;
60− color: #f0fff8;
61− padding: 0 0.5em 0 0.5em;
62− margin: 0 -150px;
63− font-size: 120%;
64− border-bottom: solid 1px black;
65−}
66−
67−div.slide h1:before { content: "# "; }
68−div.handout { display: block; }
69−
70−body>#statusbar { /* ie6 hack for fixing the statusbar - in quirks mode */
71− position: fixed; /* thanks to Anne van Kesteren and Arthur Steiner */
72−} /* see http://limpid.nl/lab/css/fixed/footer */
73−* html body {
74− overflow: hidden;
75−}
76−* html div.slide {
77− height: 100%;
78− padding-bottom: 2em;
79− overflow: auto;
80−} /* end ie6-hack */
81−
82−} /* @media screen, projection */
83−
84−@media print {
85−body {
86− color: black;
87− font-family: sans-serif;
88− font-size: 11pt;
89−}
90−
91−#statusbar { display: none; }
92−div.slide { page-break-after: always; }
93−div.handout { display: block; }
94−
95−} /* @media print */
data/slideous/slideous.jsdeleted−321
@@ -1,321 +0,0 @@
1−/* This work is licensed under Creative Commons GNU LGPL License.
2−
3− License: http://creativecommons.org/licenses/LGPL/2.1/
4−
5− Author: Stefan Goessner/2005-2006
6− Web: http://goessner.net/
7−*/
8−var Slideous = {
9− version: 1.0,
10− // == user customisable ===
11− clickables: { a: true, button: true, img: true, input: true, object: true, textarea: true, select: true, option: true },
12− incrementables: { blockquote: { filter: "self, parent" },
13− dd: { filter: "self, parent" },
14− dt: { filter: "self, parent" },
15− h2: { filter: "self, parent" },
16− h3: { filter: "self, parent" },
17− h4: { filter: "self, parent" },
18− h5: { filter: "self, parent" },
19− h6: { filter: "self, parent" },
20− li: { filter: "self, parent" },
21− p: { filter: "self" },
22− pre: { filter: "self" },
23− img: { filter: "self, parent" },
24− object: { filter: "self, parent" },
25− table: { filter: "self, parent" },
26− td: { filter: "self, parent" },
27− th: { filter: "self, parent" },
28− tr: { filter: "parent, grandparent" }
29− },
30− autoincrementables: { ol: true, ul: true, dl: true },
31− autoincrement: false,
32− statusbar: true,
33− navbuttons: { incfontbutton: function(){Slideous.changefontsize(+Slideous.fontdelta);},
34− decfontbutton: function(){Slideous.changefontsize(-Slideous.fontdelta);},
35− contentbutton: function(){Slideous.gotoslide(Slideous.tocidx(), true, true);},
36− homebutton: function(){Slideous.gotoslide(1, true, true);},
37− prevslidebutton: function(){Slideous.previous(false);},
38− previtembutton: function(){Slideous.previous(true);},
39− nextitembutton: function(){Slideous.next(true);},
40− nextslidebutton: function(){Slideous.next(false);},
41− endbutton: function(){Slideous.gotoslide(Slideous.count,true,true);} },
42− fontsize: 125, // in percent, corresponding to body.font-size in css file
43− fontdelta: 5, // increase/decrease fontsize by this value
44− mousesensitive: true,
45− tocidx: 0,
46− tocitems: { toc: "<li><a href=\"#s{\$slideidx}\">{\$slidetitle}</a></li>",
47− tocbox: "<option value=\"#s{\$slideidx}\" title=\"{\$slidetitle}\">{\$slidetitle}</option>" },
48− keydown: function(evt) {
49− evt = evt || window.event;
50− var key = evt.keyCode || evt.which;
51− if (key && !evt.ctrlKey && !evt.altKey) {
52− switch (key) {
53− case 33: // page up ... previous slide
54− Slideous.previous(false); evt.cancel = !Slideous.showall; break;
55− case 37: // left arrow ... previous item
56− Slideous.previous(true); evt.cancel = !Slideous.showall; break;
57− case 32: // space bar
58− case 39: // right arrow
59− Slideous.next(true); evt.cancel = !Slideous.showall; break;
60− case 13: // carriage return ... next slide
61− case 34: // page down
62− Slideous.next(false); evt.cancel = !Slideous.showall; break;
63− case 35: // end ... last slide (not recognised by opera)
64− Slideous.gotoslide(Slideous.count, true, true); evt.cancel = !Slideous.showall; break;
65− case 36: // home ... first slide (not recognised by opera)
66− Slideous.gotoslide(1, true, true); evt.cancel = !Slideous.showall; break;
67− case 65: // A ... show All
68− case 80: // P ... Print mode
69− Slideous.toggleshowall(!Slideous.showall); evt.cancel = true; break;
70− case 67: // C ... goto contents
71− Slideous.gotoslide(Slideous.tocidx, true, true); evt.cancel = true; break;
72− case 77: // M ... toggle mouse sensitivity
73− Slideous.mousenavigation(Slideous.mousesensitive = !Slideous.mousesensitive); evt.cancel = true; break;
74− case 83: // S ... toggle statusbar
75− Slideous.togglestatusbar(); evt.cancel = true; break;
76− case 61: // + ... increase fontsize
77− case 107:
78− Slideous.changefontsize(+Slideous.fontdelta); evt.cancel = true; break;
79− case 109: // - ... decrease fontsize
80− Slideous.changefontsize(-Slideous.fontdelta); evt.cancel = true; break;
81− default: break;
82− }
83− if (evt.cancel) evt.returnValue = false;
84− }
85− return !evt.cancel;
86− },
87−
88− // == program logic ===
89− count: 0, // # of slides ..
90− curidx: 0, // current slide index ..
91− mousedownpos: null, // last mouse down position ..
92− contentselected: false, // indicates content selection ..
93− showall: true,
94− init: function() {
95− Slideous.curidx = 1;
96− Slideous.importproperties();
97− Slideous.registerslides();
98− document.body.innerHTML = Slideous.injectproperties(document.body.innerHTML);
99− Slideous.buildtocs();
100− Slideous.registeranchors();
101− Slideous.toggleshowall(false);
102− Slideous.updatestatus();
103− document.body.style.fontSize = Slideous.fontsize+"%";
104− document.getElementById("s1").style.display = "block";
105− document.onkeydown = Slideous.keydown;
106− Slideous.mousenavigation(Slideous.mousesensitive);
107− Slideous.registerbuttons();
108− if (window.location.hash)
109− Slideous.gotoslide(window.location.hash.substr(2), true, true);
110− },
111− registerslides: function() {
112− var div = document.getElementsByTagName("div");
113− Slideous.count = 0;
114− for (var i in div)
115− if (Slideous.hasclass(div[i], "slide"))
116− div[i].setAttribute("id", "s"+(++Slideous.count));
117− },
118− registeranchors: function() {
119− var a = document.getElementsByTagName("a"),
120− loc = (window.location.hostname+window.location.pathname).replace(/\\/g, "/");
121− for (var i in a) {
122− if (a[i].href && a[i].href.indexOf(loc) >= 0 && a[i].href.lastIndexOf("#") >= 0) {
123− a[i].href = "javascript:Slideous.gotoslide(" + a[i].href.substr(a[i].href.lastIndexOf("#")+2)+",true,true)";
124− }
125− }
126− },
127− registerbuttons: function() {
128− var button;
129− for (var b in Slideous.navbuttons)
130− if (button = document.getElementById(b))
131− button.onclick = Slideous.navbuttons[b];
132− },
133− importproperties: function() { // from html meta section ..
134− var meta = document.getElementsByTagName("meta"), elem;
135− for (var i in meta)
136− if (meta[i].attributes && meta[i].attributes["name"] && meta[i].attributes["name"].value in Slideous)
137− switch (typeof(Slideous[meta[i].attributes["name"].value])) {
138− case "number": Slideous[meta[i].attributes["name"].value] = parseInt(meta[i].attributes["content"].value); break;
139− case "boolean": Slideous[meta[i].attributes["name"].value] = meta[i].attributes["content"].value == "true" ? true : false; break;
140− default: Slideous[meta[i].attributes["name"].value] = meta[i].attributes["content"].value; break;
141− }
142− },
143− injectproperties: function(str) {
144− var meta = document.getElementsByTagName("meta"), elem;
145− for (var i in meta) {
146− if (meta[i].attributes && meta[i].attributes["name"])
147− str = str.replace(new RegExp("{\\$"+meta[i].attributes["name"].value+"}","g"), meta[i].attributes["content"].value);
148− }
149− return str = str.replace(/{\$generator}/g, "Slideous")
150− .replace(/{\$version}/g, Slideous.version)
151− .replace(/{\$title}/g, document.title)
152− .replace(/{\$slidecount}/g, Slideous.count);
153− },
154− buildtocs: function() {
155− var toc = document.getElementById("toc"), list = "",
156− tocbox = document.getElementById("tocbox");
157− if (toc) {
158− for (var i=0; i<Slideous.count; i++)
159− list += Slideous.tocitems.toc.replace(/{\$slideidx}/g, i+1).replace(/{\$slidetitle}/, document.getElementById("s"+(i+1)).getElementsByTagName("h1")[0].innerHTML);
160− toc.innerHTML = list;
161− while (toc && !Slideous.hasclass(toc, "slide")) toc = toc.parentNode;
162− if (toc) Slideous.tocidx = toc.getAttribute("id").substr(1);
163− }
164− if (tocbox) {
165− tocbox.innerHTML = "";
166− for (var i=0; i<Slideous.count; i++)
167− tocbox.options[tocbox.length] = new Option((i+1)+". "+document.getElementById("s"+(i+1)).getElementsByTagName("h1")[0].innerHTML, "#s"+(i+1));
168− tocbox.onchange = function() { Slideous.gotoslide(this.selectedIndex+1, true, true); };
169− }
170− },
171− next: function(deep) {
172− if (!Slideous.showall) {
173− var slide = document.getElementById("s"+Slideous.curidx),
174− item = Slideous.firstitem(slide, Slideous.isitemhidden);
175− if (deep) { // next item
176− if (item)
177− Slideous.displayitem(item, true);
178− else
179− Slideous.gotoslide(Slideous.curidx+1, false, false);
180− }
181− else if (item) // complete slide ..
182− while (item = Slideous.firstitem(slide, Slideous.isitemhidden))
183− Slideous.displayitem(item, true);
184− else // next slide
185− Slideous.gotoslide(Slideous.curidx+1, true, false);
186− Slideous.updatestatus();
187− }
188− },
189− previous: function(deep) {
190− if (!Slideous.showall) {
191− var slide = document.getElementById("s"+Slideous.curidx);
192− if (deep) {
193− var item = Slideous.lastitem(slide, Slideous.isitemvisible);
194− if (item)
195− Slideous.displayitem(item, false);
196− else
197− Slideous.gotoslide(Slideous.curidx-1, true, false);
198− }
199− else
200− Slideous.gotoslide(Slideous.curidx-1, true, false);
201− Slideous.updatestatus();
202− }
203− },
204− gotoslide: function(i, showitems, updatestatus) {
205− if (!Slideous.showall && i > 0 && i <= Slideous.count && i != Slideous.curidx) {
206− document.getElementById("s"+Slideous.curidx).style.display = "none";
207− var slide = document.getElementById("s"+(Slideous.curidx=i)), item;
208− while (item = Slideous.firstitem(slide, showitems ? Slideous.isitemhidden : Slideous.isitemvisible))
209− Slideous.displayitem(item, showitems);
210− slide.style.display = "block";
211− if (updatestatus)
212− Slideous.updatestatus();
213− }
214− },
215− firstitem: function(root, filter) {
216− var found = filter(root);
217− for (var node=root.firstChild; node!=null && !found; node = node.nextSibling)
218− found = Slideous.firstitem(node, filter);
219− return found;
220− },
221− lastitem: function(root, filter) {
222− var found = null;
223− for (var node=root.lastChild; node!=null && !found; node = node.previousSibling)
224− found = Slideous.lastitem(node, filter);
225− return found || filter(root);
226− },
227− isitem: function(node, visible) {
228− var nodename;
229− return node && node.nodeType == 1 // elements only ..
230− && (nodename=node.nodeName.toLowerCase()) in Slideous.incrementables
231− && ( Slideous.incrementables[nodename].filter.match("\\bself\\b") && (Slideous.hasclass(node, "incremental") || (Slideous.autoincrement && nodename in Slideous.autoincrementables))
232− || Slideous.incrementables[nodename].filter.match("\\bparent\\b") && (Slideous.hasclass(node.parentNode, "incremental") || (Slideous.autoincrement && node.parentNode.nodeName.toLowerCase() in Slideous.autoincrementables))
233− || Slideous.incrementables[nodename].filter.match("\\bgrandparent\\b") && (Slideous.hasclass(node.parentNode.parentNode, "incremental") || (Slideous.autoincrement && node.parentNode.parentNode.nodeName.toLowerCase() in Slideous.autoincrementables))
234− )
235− && (visible ? (node.style.visibility != "hidden")
236− : (node.style.visibility == "hidden"))
237− ? node : null;
238− },
239− isitemvisible: function(node) { return Slideous.isitem(node, true); },
240− isitemhidden: function(node) { return Slideous.isitem(node, false); },
241− displayitem: function(item, show) {
242− if (item) item.style.visibility = (show ? "visible" : "hidden");
243− },
244− updatestatus: function() {
245− if (Slideous.statusbar) {
246− var eos = document.getElementById("eos"),
247− idx = document.getElementById("slideidx"),
248− tocbox = document.getElementById("tocbox");
249− if (eos)
250− eos.style.visibility = Slideous.firstitem(document.getElementById("s"+Slideous.curidx), Slideous.isitemhidden) != null
251− ? "visible" : "hidden";
252− if (idx)
253− idx.innerHTML = Slideous.curidx;
254− if (tocbox)
255− tocbox.selectedIndex = Slideous.curidx-1;
256− }
257− },
258− changefontsize: function(delta) {
259− document.body.style.fontSize = (Slideous.fontsize+=delta)+"%";
260− },
261− togglestatusbar: function() {
262− document.getElementById("statusbar").style.display = (Slideous.statusbar = !Slideous.statusbar) ? "block" : "none";
263− },
264− toggleshowall: function(showall) {
265− var slide, item;
266− for (var i=0; i<Slideous.count; i++) {
267− slide = document.getElementById("s"+(i+1));
268− slide.style.display = showall ? "block" : "none";
269− while (item = Slideous.firstitem(slide, showall ? Slideous.isitemhidden : Slideous.isitemvisible))
270− Slideous.displayitem(item, showall);
271− var divs = slide.getElementsByTagName("div");
272− for (var j in divs)
273− if (Slideous.hasclass(divs[j], "handout"))
274− divs[j].style.display = showall ? "block" : "none";
275− }
276− if (!showall)
277− document.getElementById("s"+Slideous.curidx).style.display = "block";
278− if (Slideous.statusbar)
279− document.getElementById("statusbar").style.display = showall ? "none" : "block";
280− Slideous.showall = showall;
281− },
282− hasclass: function(elem, classname) {
283− var classattr = null;
284− return (classattr=(elem.attributes && elem.attributes["class"]))
285− && classattr.nodeValue.match("\\b"+classname+"\\b");
286− },
287− selectedcontent: function() {
288− return window.getSelection ? window.getSelection().toString()
289− : document.getSelection ? document.getSelection()
290− : document.selection ? document.selection.createRange().text
291− : "";
292− },
293− mousenavigation: function(on) {
294− if (on) {
295− document.onmousedown = Slideous.mousedown;
296− document.onmouseup = Slideous.mouseup;
297− }
298− else
299− document.onmousedown = document.onmouseup = null;
300− },
301− mousepos: function(e) {
302− return e.pageX ? {x: e.pageX, y: e.pageY}
303− : {x: e.x+document.body.scrollLeft, y: e.y+document.body.scrollTop};
304− },
305− mousedown: function(evt) {
306− evt = evt||window.event;
307− Slideous.mousedownpos = Slideous.mousepos(evt);
308− Slideous.contentselected = !!Slideous.selectedcontent() || ((evt.target || evt.srcElement).nodeName.toLowerCase() in Slideous.clickables);
309− return true;
310− },
311− mouseup: function(evt) {
312− evt = evt||window.event;
313− var pos = Slideous.mousepos(evt);
314− if (pos.x == Slideous.mousedownpos.x && pos.y == Slideous.mousedownpos.y && !Slideous.contentselected) {
315− Slideous.next(true);
316− return evt.returnValue = !(evt.cancel = true);
317− }
318− return false;
319− }
320−};
321−window.onload = Slideous.init;
data/slidy/graphics/fold-dim.gifdeleted

Binary file not shown.

data/slidy/graphics/fold.gifdeleted

Binary file not shown.

data/slidy/graphics/nofold-dim.gifdeleted

Binary file not shown.

data/slidy/graphics/unfold-dim.gifdeleted

Binary file not shown.

data/slidy/graphics/unfold.gifdeleted

Binary file not shown.

data/slidy/scripts/slidy.jsdeleted−3016
@@ -1,3016 +0,0 @@
1−/* slidy.js
2−
3− Copyright (c) 2005-2011 W3C (MIT, ERCIM, Keio), All Rights Reserved.
4− W3C liability, trademark, document use and software licensing
5− rules apply, see:
6−
7− http://www.w3.org/Consortium/Legal/copyright-documents
8− http://www.w3.org/Consortium/Legal/copyright-software
9−
10− Defines single name "w3c_slidy" in global namespace
11− Adds event handlers without trampling on any others
12−*/
13−
14−// the slidy object implementation
15−var w3c_slidy = {
16− // classify which kind of browser we're running under
17− ns_pos: (typeof window.pageYOffset!='undefined'),
18− khtml: ((navigator.userAgent).indexOf("KHTML") >= 0 ? true : false),
19− opera: ((navigator.userAgent).indexOf("Opera") >= 0 ? true : false),
20− ipad: ((navigator.userAgent).indexOf("iPad") >= 0 ? true : false),
21− iphone: ((navigator.userAgent).indexOf("iPhone") >= 0 ? true : false),
22− android: ((navigator.userAgent).indexOf("Android") >= 0 ? true : false),
23− ie: (typeof document.all != "undefined" && !this.opera),
24− ie6: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 6") != -1),
25− ie7: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 7") != -1),
26− ie8: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 8") != -1),
27− ie9: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 9") != -1),
28−
29− // data for swipe and double tap detection on touch screens
30− last_tap: 0,
31− prev_tap: 0,
32− start_x: 0,
33− start_y: 0,
34− delta_x: 0,
35− delta_y: 0,
36−
37− // are we running as XHTML? (doesn't work on Opera)
38− is_xhtml: /xml/.test(document.contentType),
39−
40− slide_number: 0, // integer slide count: 0, 1, 2, ...
41− slide_number_element: null, // element containing slide number
42− slides: [], // set to array of slide div's
43− notes: [], // set to array of handout div's
44− backgrounds: [], // set to array of background div's
45− toolbar: null, // element containing toolbar
46− title: null, // document title
47− last_shown: null, // last incrementally shown item
48− eos: null, // span element for end of slide indicator
49− toc: null, // table of contents
50− outline: null, // outline element with the focus
51− selected_text_len: 0, // length of drag selection on document
52− view_all: 0, // 1 to view all slides + handouts
53− want_toolbar: true, // user preference to show/hide toolbar
54− mouse_click_enabled: true, // enables left click for next slide
55− scroll_hack: 0, // IE work around for position: fixed
56− disable_slide_click: false, // used by clicked anchors
57−
58− lang: "en", // updated to language specified by html file
59−
60− help_anchor: null, // used for keyboard focus hack in showToolbar()
61− help_page: "http://www.w3.org/Talks/Tools/Slidy2/help/help.html",
62− help_text: "Navigate with mouse click, space bar, Cursor Left/Right, " +
63− "or Pg Up and Pg Dn. Use S and B to change font size.",
64−
65− size_index: 0,
66− size_adjustment: 0,
67− sizes: new Array("10pt", "12pt", "14pt", "16pt", "18pt", "20pt",
68− "22pt", "24pt", "26pt", "28pt", "30pt", "32pt"),
69−
70− // needed for efficient resizing
71− last_width: 0,
72− last_height: 0,
73−
74−
75− // Needed for cross browser support for relative width/height on
76− // object elements. The work around is to save width/height attributes
77− // and then to recompute absolute width/height dimensions on resizing
78− objects: [],
79−
80− // attach initialiation event handlers
81− set_up: function () {
82− var init = function() { w3c_slidy.init(); };
83− if (typeof window.addEventListener != "undefined")
84− window.addEventListener("load", init, false);
85− else
86− window.attachEvent("onload", init);
87− },
88−
89− hide_slides: function () {
90− if (document.body && !w3c_slidy.initialized)
91− document.body.style.visibility = "hidden";
92− else
93− setTimeout(w3c_slidy.hide_slides, 50);
94− },
95−
96− // hack to persuade IE to compute correct document height
97− // as needed for simulating fixed positioning of toolbar
98− ie_hack: function () {
99− window.resizeBy(0,-1);
100− window.resizeBy(0, 1);
101− },
102−
103− init: function () {
104− //alert("slidy starting test 10");
105− document.body.style.visibility = "visible";
106− this.init_localization();
107− this.add_toolbar();
108− this.wrap_implicit_slides();
109− this.collect_slides();
110− this.collect_notes();
111− this.collect_backgrounds();
112− this.objects = document.body.getElementsByTagName("object");
113− this.patch_anchors();
114− this.slide_number = this.find_slide_number(location.href);
115− window.offscreenbuffering = true;
116− this.size_adjustment = this.find_size_adjust();
117− this.time_left = this.find_duration();
118− this.hide_image_toolbar(); // suppress IE image toolbar popup
119− this.init_outliner(); // activate fold/unfold support
120− this.title = document.title;
121− this.keyboardless = (this.ipad||this.iphone||this.android);
122−
123− if (this.keyboardless)
124− {
125− w3c_slidy.remove_class(w3c_slidy.toolbar, "hidden")
126− this.want_toolbar = 0;
127− }
128−
129− // work around for opera bug
130− this.is_xhtml = (document.body.tagName == "BODY" ? false : true);
131−
132− if (this.slides.length > 0)
133− {
134− var slide = this.slides[this.slide_number];
135−
136− if (this.slide_number > 0)
137− {
138− this.set_visibility_all_incremental("visible");
139− this.last_shown = this.previous_incremental_item(null);
140− this.set_eos_status(true);
141− }
142− else
143− {
144− this.last_shown = null;
145− this.set_visibility_all_incremental("hidden");
146− this.set_eos_status(!this.next_incremental_item(this.last_shown));
147− }
148−
149− this.set_location();
150− this.add_class(this.slides[0], "first-slide");
151− w3c_slidy.show_slide(slide);
152− }
153−
154− this.toc = this.table_of_contents();
155−
156− this.add_initial_prompt();
157−
158− // bind event handlers without interfering with custom page scripts
159− // Tap events behave too weirdly to support clicks reliably on
160− // iPhone and iPad, so exclude these from click handler
161−
162− if (!this.keyboardless)
163− {
164− this.add_listener(document.body, "click", this.mouse_button_click);
165− this.add_listener(document.body, "mousedown", this.mouse_button_down);
166− }
167−
168− this.add_listener(document, "keydown", this.key_down);
169− this.add_listener(document, "keypress", this.key_press);
170− this.add_listener(window, "resize", this.resized);
171− this.add_listener(window, "scroll", this.scrolled);
172− this.add_listener(window, "unload", this.unloaded);
173−
174− //this.add_listener(document.body, "touchstart", this.touchstart);
175− //this.add_listener(document.body, "touchmove", this.touchmove);
176− //this.add_listener(document.body, "touchend", this.touchend);
177−
178− this.add_listener(document, "gesturechange", function ()
179− {
180− return false;
181− });
182−
183− this.attach_touch_handers(this.slides);
184−
185− // this seems to be a debugging hack
186− //if (!document.body.onclick)
187− // document.body.onclick = function () { };
188−
189− this.single_slide_view();
190−
191− //this.set_location();
192−
193− this.resized();
194−
195− if (this.ie7)
196− setTimeout(w3c_slidy.ie_hack, 100);
197−
198− this.show_toolbar();
199−
200− // for back button detection
201− setInterval(function () { w3c_slidy.check_location(); }, 200);
202− w3c_slidy.initialized = true;
203− },
204−
205− // create div element with links to each slide
206− table_of_contents: function () {
207− var toc = this.create_element("div");
208− this.add_class(toc, "slidy_toc hidden");
209− //toc.setAttribute("tabindex", "0");
210−
211− var heading = this.create_element("div");
212− this.add_class(heading, "toc-heading");
213− heading.innerHTML = this.localize("Table of Contents");
214−
215− toc.appendChild(heading);
216− var previous = null;
217−
218− for (var i = 0; i < this.slides.length; ++i)
219− {
220− var title = this.has_class(this.slides[i], "title");
221− var num = document.createTextNode((i + 1) + ". ");
222−
223− toc.appendChild(num);
224−
225− var a = this.create_element("a");
226− a.setAttribute("href", "#(" + (i+1) + ")");
227−
228− if (title)
229− this.add_class(a, "titleslide");
230−
231− var name = document.createTextNode(this.slide_name(i));
232− a.appendChild(name);
233− a.onclick = w3c_slidy.toc_click;
234− a.onkeydown = w3c_slidy.toc_key_down;
235− a.previous = previous;
236−
237− if (previous)
238− previous.next = a;
239−
240− toc.appendChild(a);
241−
242− if (i == 0)
243− toc.first = a;
244−
245− if (i < this.slides.length - 1)
246− {
247− var br = this.create_element("br");
248− toc.appendChild(br);
249− }
250−
251− previous = a;
252− }
253−
254− toc.focus = function () {
255− if (this.first)
256− this.first.focus();
257− }
258−
259− toc.onmouseup = w3c_slidy.mouse_button_up;
260−
261− toc.onclick = function (e) {
262− e||(e=window.event);
263−
264− if (w3c_slidy.selected_text_len <= 0)
265− w3c_slidy.hide_table_of_contents(true);
266−
267− w3c_slidy.stop_propagation(e);
268−
269− if (e.cancel != undefined)
270− e.cancel = true;
271−
272− if (e.returnValue != undefined)
273− e.returnValue = false;
274−
275− return false;
276− };
277−
278− document.body.insertBefore(toc, document.body.firstChild);
279− return toc;
280− },
281−
282− is_shown_toc: function () {
283− return !w3c_slidy.has_class(w3c_slidy.toc, "hidden");
284− },
285−
286− show_table_of_contents: function () {
287− w3c_slidy.remove_class(w3c_slidy.toc, "hidden");
288− var toc = w3c_slidy.toc;
289− toc.focus();
290−
291− if (w3c_slidy.ie7 && w3c_slidy.slide_number == 0)
292− setTimeout(w3c_slidy.ie_hack, 100);
293− },
294−
295− hide_table_of_contents: function (focus) {
296− w3c_slidy.add_class(w3c_slidy.toc, "hidden");
297−
298− if (focus && !w3c_slidy.opera &&
299− !w3c_slidy.has_class(w3c_slidy.toc, "hidden"))
300− w3c_slidy.help_anchor.focus();
301− },
302−
303− toggle_table_of_contents: function () {
304− if (w3c_slidy.is_shown_toc())
305− w3c_slidy.hide_table_of_contents(true);
306− else
307− w3c_slidy.show_table_of_contents();
308− },
309−
310− // called on clicking toc entry
311− toc_click: function (e) {
312− if (!e)
313− e = window.event;
314−
315− var target = w3c_slidy.get_target(e);
316−
317− if (target && target.nodeType == 1)
318− {
319− var uri = target.getAttribute("href");
320−
321− if (uri)
322− {
323− //alert("going to " + uri);
324− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
325− w3c_slidy.hide_slide(slide);
326− w3c_slidy.slide_number = w3c_slidy.find_slide_number(uri);
327− slide = w3c_slidy.slides[w3c_slidy.slide_number];
328− w3c_slidy.last_shown = null;
329− w3c_slidy.set_location();
330− w3c_slidy.set_visibility_all_incremental("hidden");
331− w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
332− w3c_slidy.show_slide(slide);
333− //target.focus();
334−
335− try
336− {
337− if (!w3c_slidy.opera)
338− w3c_slidy.help_anchor.focus();
339− }
340− catch (e)
341− {
342− }
343− }
344− }
345−
346− w3c_slidy.hide_table_of_contents(true);
347− if (w3c_slidy.ie7) w3c_slidy.ie_hack();
348− w3c_slidy.stop_propagation(e);
349− return w3c_slidy.cancel(e);
350− },
351−
352− // called onkeydown for toc entry
353− toc_key_down: function (event) {
354− var key;
355−
356− if (!event)
357− var event = window.event;
358−
359− // kludge around NS/IE differences
360− if (window.event)
361− key = window.event.keyCode;
362− else if (event.which)
363− key = event.which;
364− else
365− return true; // Yikes! unknown browser
366−
367− // ignore event if key value is zero
368− // as for alt on Opera and Konqueror
369− if (!key)
370− return true;
371−
372− // check for concurrent control/command/alt key
373− // but are these only present on mouse events?
374−
375− if (event.ctrlKey || event.altKey)
376− return true;
377−
378− if (key == 13)
379− {
380− var uri = this.getAttribute("href");
381−
382− if (uri)
383− {
384− //alert("going to " + uri);
385− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
386− w3c_slidy.hide_slide(slide);
387− w3c_slidy.slide_number = w3c_slidy.find_slide_number(uri);
388− slide = w3c_slidy.slides[w3c_slidy.slide_number];
389− w3c_slidy.last_shown = null;
390− w3c_slidy.set_location();
391− w3c_slidy.set_visibility_all_incremental("hidden");
392− w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
393− w3c_slidy.show_slide(slide);
394− //target.focus();
395−
396− try
397− {
398− if (!w3c_slidy.opera)
399− w3c_slidy.help_anchor.focus();
400− }
401− catch (e)
402− {
403− }
404− }
405−
406− w3c_slidy.hide_table_of_contents(true);
407−
408− if (self.ie7)
409− w3c_slidy.ie_hack();
410−
411− return w3c_slidy.cancel(event);
412− }
413−
414− if (key == 40 && this.next)
415− {
416− this.next.focus();
417− return w3c_slidy.cancel(event);
418− }
419−
420− if (key == 38 && this.previous)
421− {
422− this.previous.focus();
423− return w3c_slidy.cancel(event);
424− }
425−
426− return true;
427− },
428−
429− touchstart: function (e)
430− {
431− //e.preventDefault();
432− this.prev_tap = this.last_tap;
433− this.last_tap = (new Date).getTime();
434−
435− var tap_delay = this.last_tap - this.prev_tap;
436−
437− if (tap_delay <= 200)
438− {
439− // double tap
440− }
441−
442− var touch = e.touches[0];
443−
444− this.start_x = touch.pageX;
445− this.start_y = touch.pageY;
446− this.delta_x = this.delta_y = 0;
447− },
448−
449− touchmove: function (e)
450− {
451− //e.preventDefault();
452− var touch = e.touches[0];
453− this.delta_x = touch.pageX - this.start_x;
454− this.delta_y = touch.pageY - this.start_y;
455− },
456−
457− touchend: function (e)
458− {
459− //e.preventDefault();
460− var delay = (new Date).getTime() - this.last_tap;
461− var dx = this.delta_x;
462− var dy = this.delta_y;
463− var abs_dx = Math.abs(dx);
464− var abs_dy = Math.abs(dy);
465−
466− if (delay < 500 && (abs_dx > 100 || abs_dy > 100))
467− {
468− if (abs_dx > 0.5 * abs_dy)
469− {
470− if (dx < 0)
471− w3c_slidy.next_slide(true);
472− else
473− w3c_slidy.previous_slide(true);
474− }
475− else if (abs_dy > 2 * abs_dx)
476− {
477− w3c_slidy.toggle_table_of_contents();
478− }
479− }
480− },
481−
482− // ### OBSOLETE ###
483− before_print: function () {
484− this.show_all_slides();
485− this.hide_toolbar();
486− alert("before print");
487− },
488−
489− // ### OBSOLETE ###
490− after_print: function () {
491− if (!this.view_all)
492− {
493− this.single_slide_view();
494− this.show_toolbar();
495− }
496− alert("after print");
497− },
498−
499− // ### OBSOLETE ###
500− print_slides: function () {
501− this.before_print();
502− window.print();
503− this.after_print();
504− },
505−
506− // ### OBSOLETE ?? ###
507− toggle_view: function () {
508− if (this.view_all)
509− {
510− this.single_slide_view();
511− this.show_toolbar();
512− this.view_all = 0;
513− }
514− else
515− {
516− this.show_all_slides();
517− this.hide_toolbar();
518− this.view_all = 1;
519− }
520− },
521−
522− // prepare for printing ### OBSOLETE ###
523− show_all_slides: function () {
524− this.remove_class(document.body, "single_slide");
525− this.set_visibility_all_incremental("visible");
526− },
527−
528− // restore after printing ### OBSOLETE ###
529− single_slide_view: function () {
530− this.add_class(document.body, "single_slide");
531− this.set_visibility_all_incremental("visible");
532− this.last_shown = this.previous_incremental_item(null);
533− },
534−
535− // suppress IE's image toolbar pop up
536− hide_image_toolbar: function () {
537− if (!this.ns_pos)
538− {
539− var images = document.getElementsByTagName("IMG");
540−
541− for (var i = 0; i < images.length; ++i)
542− images[i].setAttribute("galleryimg", "no");
543− }
544− },
545−
546− unloaded: function (e) {
547− //alert("unloaded");
548− },
549−
550− // Safari and Konqueror don't yet support getComputedStyle()
551− // and they always reload page when location.href is updated
552− is_KHTML: function () {
553− var agent = navigator.userAgent;
554− return (agent.indexOf("KHTML") >= 0 ? true : false);
555− },
556−
557− // find slide name from first h1 element
558− // default to document title + slide number
559− slide_name: function (index) {
560− var name = null;
561− var slide = this.slides[index];
562−
563− var heading = this.find_heading(slide);
564−
565− if (heading)
566− name = this.extract_text(heading);
567−
568− if (!name)
569− name = this.title + "(" + (index + 1) + ")";
570−
571− name.replace(/\&/g, "&amp;");
572− name.replace(/\</g, "&lt;");
573− name.replace(/\>/g, "&gt;");
574−
575− return name;
576− },
577−
578− // find first h1 element in DOM tree
579− find_heading: function (node) {
580− if (!node || node.nodeType != 1)
581− return null;
582−
583− if (node.nodeName == "H1" || node.nodeName == "h1")
584− return node;
585−
586− var child = node.firstChild;
587−
588− while (child)
589− {
590− node = this.find_heading(child);
591−
592− if (node)
593− return node;
594−
595− child = child.nextSibling;
596− }
597−
598− return null;
599− },
600−
601− // recursively extract text from DOM tree
602− extract_text: function (node) {
603− if (!node)
604− return "";
605−
606− // text nodes
607− if (node.nodeType == 3)
608− return node.nodeValue;
609−
610− // elements
611− if (node.nodeType == 1)
612− {
613− node = node.firstChild;
614− var text = "";
615−
616− while (node)
617− {
618− text = text + this.extract_text(node);
619− node = node.nextSibling;
620− }
621−
622− return text;
623− }
624−
625− return "";
626− },
627−
628− // find copyright text from meta element
629− find_copyright: function () {
630− var name, content;
631− var meta = document.getElementsByTagName("meta");
632−
633− for (var i = 0; i < meta.length; ++i)
634− {
635− name = meta[i].getAttribute("name");
636− content = meta[i].getAttribute("content");
637−
638− if (name == "copyright")
639− return content;
640− }
641−
642− return null;
643− },
644−
645− find_size_adjust: function () {
646− var name, content, offset;
647− var meta = document.getElementsByTagName("meta");
648−
649− for (var i = 0; i < meta.length; ++i)
650− {
651− name = meta[i].getAttribute("name");
652− content = meta[i].getAttribute("content");
653−
654− if (name == "font-size-adjustment")
655− return 1 * content;
656− }
657−
658− return 1;
659− },
660−
661− // <meta name="duration" content="20" /> for 20 minutes
662− find_duration: function () {
663− var name, content, offset;
664− var meta = document.getElementsByTagName("meta");
665−
666− for (var i = 0; i < meta.length; ++i)
667− {
668− name = meta[i].getAttribute("name");
669− content = meta[i].getAttribute("content");
670−
671− if (name == "duration")
672− return 60000 * content;
673− }
674−
675− return null;
676− },
677−
678− replace_by_non_breaking_space: function (str) {
679− for (var i = 0; i < str.length; ++i)
680− str[i] = 160;
681− },
682−
683− // ### CHECK ME ### is use of "li" okay for text/html?
684− // for XHTML do we also need to specify namespace?
685− init_outliner: function () {
686− var items = document.getElementsByTagName("li");
687−
688− for (var i = 0; i < items.length; ++i)
689− {
690− var target = items[i];
691−
692− if (!this.has_class(target.parentNode, "outline"))
693− continue;
694−
695− target.onclick = this.outline_click;
696−/* ### more work needed for IE6
697− if (!this.ns_pos)
698− {
699− target.onmouseover = this.hover_outline;
700− target.onmouseout = this.unhover_outline;
701− }
702−*/
703− if (this.foldable(target))
704− {
705− target.foldable = true;
706− target.onfocus = function () {w3c_slidy.outline = this;};
707− target.onblur = function () {w3c_slidy.outline = null;};
708−
709− if (!target.getAttribute("tabindex"))
710− target.setAttribute("tabindex", "0");
711−
712− if (this.has_class(target, "expand"))
713− this.unfold(target);
714− else
715− this.fold(target);
716− }
717− else
718− {
719− this.add_class(target, "nofold");
720− target.visible = true;
721− target.foldable = false;
722− }
723− }
724− },
725−
726− foldable: function (item) {
727− if (!item || item.nodeType != 1)
728− return false;
729−
730− var node = item.firstChild;
731−
732− while (node)
733− {
734− if (node.nodeType == 1 && this.is_block(node))
735− return true;
736−
737− node = node.nextSibling;
738− }
739−
740− return false;
741− },
742−
743− // ### CHECK ME ### switch to add/remove "hidden" class
744− fold: function (item) {
745− if (item)
746− {
747− this.remove_class(item, "unfolded");
748− this.add_class(item, "folded");
749− }
750−
751− var node = item ? item.firstChild : null;
752−
753− while (node)
754− {
755− if (node.nodeType == 1 && this.is_block(node)) // element
756− {
757− w3c_slidy.add_class(node, "hidden");
758− }
759−
760− node = node.nextSibling;
761− }
762−
763− item.visible = false;
764− },
765−
766− // ### CHECK ME ### switch to add/remove "hidden" class
767− unfold: function (item) {
768− if (item)
769− {
770− this.add_class(item, "unfolded");
771− this.remove_class(item, "folded");
772− }
773−
774− var node = item ? item.firstChild : null;
775−
776− while (node)
777− {
778− if (node.nodeType == 1 && this.is_block(node)) // element
779− {
780− w3c_slidy.remove_class(node, "hidden");
781− }
782−
783− node = node.nextSibling;
784− }
785−
786− item.visible = true;
787− },
788−
789− outline_click: function (e) {
790− if (!e)
791− e = window.event;
792−
793− var rightclick = false;
794− var target = w3c_slidy.get_target(e);
795−
796− while (target && target.visible == undefined)
797− target = target.parentNode;
798−
799− if (!target)
800− return true;
801−
802− if (e.which)
803− rightclick = (e.which == 3);
804− else if (e.button)
805− rightclick = (e.button == 2);
806−
807− if (!rightclick && target.visible != undefined)
808− {
809− if (target.foldable)
810− {
811− if (target.visible)
812− w3c_slidy.fold(target);
813− else
814− w3c_slidy.unfold(target);
815− }
816−
817− w3c_slidy.stop_propagation(e);
818− e.cancel = true;
819− e.returnValue = false;
820− }
821−
822− return false;
823− },
824−
825− add_initial_prompt: function () {
826− var prompt = this.create_element("div");
827− prompt.setAttribute("class", "initial_prompt");
828−
829− var p1 = this.create_element("p");
830− prompt.appendChild(p1);
831− p1.setAttribute("class", "help");
832−
833− if (this.keyboardless)
834− p1.innerHTML = "swipe left to move to next slide";
835− else
836− p1.innerHTML = "Space, Right Arrow or swipe left to move to " +
837− "next slide, click help below for more details";
838−
839− this.add_listener(prompt, "click", function (e) {
840− document.body.removeChild(prompt);
841− w3c_slidy.stop_propagation(e);
842−
843− if (e.cancel != undefined)
844− e.cancel = true;
845−
846− if (e.returnValue != undefined)
847− e.returnValue = false;
848−
849− return false;
850− });
851−
852− document.body.appendChild(prompt);
853− this.initial_prompt = prompt;
854− setTimeout(function() {document.body.removeChild(prompt);}, 5000);
855− },
856−
857− add_toolbar: function () {
858− var counter, page;
859−
860− this.toolbar = this.create_element("div");
861− this.toolbar.setAttribute("class", "toolbar");
862−
863− // a reasonably behaved browser
864− if (this.ns_pos || !this.ie6)
865− {
866− var right = this.create_element("div");
867− right.setAttribute("style", "float: right; text-align: right");
868−
869− counter = this.create_element("span")
870− counter.innerHTML = this.localize("slide") + " n/m";
871− right.appendChild(counter);
872− this.toolbar.appendChild(right);
873−
874− var left = this.create_element("div");
875− left.setAttribute("style", "text-align: left");
876−
877− // global end of slide indicator
878− this.eos = this.create_element("span");
879− this.eos.innerHTML = "* ";
880− left.appendChild(this.eos);
881−
882− var help = this.create_element("a");
883− help.setAttribute("href", this.help_page);
884− help.setAttribute("title", this.localize(this.help_text));
885− help.innerHTML = this.localize("help?");
886− left.appendChild(help);
887− this.help_anchor = help; // save for focus hack
888−
889− var gap1 = document.createTextNode(" ");
890− left.appendChild(gap1);
891−
892− var contents = this.create_element("a");
893− contents.setAttribute("href", "javascript:w3c_slidy.toggle_table_of_contents()");
894− contents.setAttribute("title", this.localize("table of contents"));
895− contents.innerHTML = this.localize("contents?");
896− left.appendChild(contents);
897−
898− var gap2 = document.createTextNode(" ");
899− left.appendChild(gap2);
900−
901− var copyright = this.find_copyright();
902−
903− if (copyright)
904− {
905− var span = this.create_element("span");
906− span.className = "copyright";
907− span.innerHTML = copyright;
908− left.appendChild(span);
909− }
910−
911− this.toolbar.setAttribute("tabindex", "0");
912− this.toolbar.appendChild(left);
913− }
914− else // IE6 so need to work around its poor CSS support
915− {
916− this.toolbar.style.position = (this.ie7 ? "fixed" : "absolute");
917− this.toolbar.style.zIndex = "200";
918− this.toolbar.style.width = "99.9%";
919− this.toolbar.style.height = "1.2em";
920− this.toolbar.style.top = "auto";
921− this.toolbar.style.bottom = "0";
922− this.toolbar.style.left = "0";
923− this.toolbar.style.right = "0";
924− this.toolbar.style.textAlign = "left";
925− this.toolbar.style.fontSize = "60%";
926− this.toolbar.style.color = "red";
927− this.toolbar.borderWidth = 0;
928− this.toolbar.className = "toolbar";
929− this.toolbar.style.background = "rgb(240,240,240)";
930−
931− // would like to have help text left aligned
932− // and page counter right aligned, floating
933− // div's don't work, so instead use nested
934− // absolutely positioned div's.
935−
936− var sp = this.create_element("span");
937− sp.innerHTML = "&nbsp;&nbsp;*&nbsp;";
938− this.toolbar.appendChild(sp);
939− this.eos = sp; // end of slide indicator
940−
941− var help = this.create_element("a");
942− help.setAttribute("href", this.help_page);
943− help.setAttribute("title", this.localize(this.help_text));
944− help.innerHTML = this.localize("help?");
945− this.toolbar.appendChild(help);
946− this.help_anchor = help; // save for focus hack
947−
948− var gap1 = document.createTextNode(" ");
949− this.toolbar.appendChild(gap1);
950−
951− var contents = this.create_element("a");
952− contents.setAttribute("href", "javascript:toggleTableOfContents()");
953− contents.setAttribute("title", this.localize("table of contents".localize));
954− contents.innerHTML = this.localize("contents?");
955− this.toolbar.appendChild(contents);
956−
957− var gap2 = document.createTextNode(" ");
958− this.toolbar.appendChild(gap2);
959−
960− var copyright = this.find_copyright();
961−
962− if (copyright)
963− {
964− var span = this.create_element("span");
965− span.innerHTML = copyright;
966− span.style.color = "black";
967− span.style.marginLeft = "0.5em";
968− this.toolbar.appendChild(span);
969− }
970−
971− counter = this.create_element("div")
972− counter.style.position = "absolute";
973− counter.style.width = "auto"; //"20%";
974− counter.style.height = "1.2em";
975− counter.style.top = "auto";
976− counter.style.bottom = 0;
977− counter.style.right = "0";
978− counter.style.textAlign = "right";
979− counter.style.color = "red";
980− counter.style.background = "rgb(240,240,240)";
981−
982− counter.innerHTML = this.localize("slide") + " n/m";
983− this.toolbar.appendChild(counter);
984− }
985−
986− // ensure that click isn't passed through to the page
987− this.toolbar.onclick =
988− function (e) {
989− if (!e)
990− e = window.event;
991−
992− var target = e.target;
993−
994− if (!target && e.srcElement)
995− target = e.srcElement;
996−
997− // work around Safari bug
998− if (target && target.nodeType == 3)
999− target = target.parentNode;
1000−
1001− w3c_slidy.stop_propagation(e);
1002−
1003− if (target && target.nodeName.toLowerCase() != "a")
1004− w3c_slidy.mouse_button_click(e);
1005− };
1006−
1007− this.slide_number_element = counter;
1008− this.set_eos_status(false);
1009− document.body.appendChild(this.toolbar);
1010− },
1011−
1012− // wysiwyg editors make it hard to use div elements
1013− // e.g. amaya loses the div when you copy and paste
1014− // this function wraps div elements around implicit
1015− // slides which start with an h1 element and continue
1016− // up to the next heading or div element
1017− wrap_implicit_slides: function () {
1018− var i, heading, node, next, div;
1019− var headings = document.getElementsByTagName("h1");
1020−
1021− if (!headings)
1022− return;
1023−
1024− for (i = 0; i < headings.length; ++i)
1025− {
1026− heading = headings[i];
1027−
1028− if (heading.parentNode != document.body)
1029− continue;
1030−
1031− node = heading.nextSibling;
1032−
1033− div = document.createElement("div");
1034− this.add_class(div, "slide");
1035− document.body.replaceChild(div, heading);
1036− div.appendChild(heading);
1037−
1038− while (node)
1039− {
1040− if (node.nodeType == 1) // an element
1041− {
1042− if (node.nodeName == "H1" || node.nodeName == "h1")
1043− break;
1044−
1045− if (node.nodeName == "DIV" || node.nodeName == "div")
1046− {
1047− if (this.has_class(node, "slide"))
1048− break;
1049−
1050− if (this.has_class(node, "handout"))
1051− break;
1052− }
1053− }
1054−
1055− next = node.nextSibling;
1056− node = document.body.removeChild(node);
1057− div.appendChild(node);
1058− node = next;
1059− }
1060− }
1061− },
1062−
1063− attach_touch_handers: function(slides)
1064− {
1065− var i, slide;
1066−
1067− for (i = 0; i < slides.length; ++i)
1068− {
1069− slide = slides[i];
1070− this.add_listener(slide, "touchstart", this.touchstart);
1071− this.add_listener(slide, "touchmove", this.touchmove);
1072− this.add_listener(slide, "touchend", this.touchend);
1073− }
1074− },
1075−
1076−// return new array of all slides
1077− collect_slides: function () {
1078− var slides = new Array();
1079− var divs = document.body.getElementsByTagName("div");
1080−
1081− for (var i = 0; i < divs.length; ++i)
1082− {
1083− div = divs.item(i);
1084−
1085− if (this.has_class(div, "slide"))
1086− {
1087− // add slide to collection
1088− slides[slides.length] = div;
1089−
1090− // hide each slide as it is found
1091− this.add_class(div, "hidden");
1092−
1093− // add dummy <br/> at end for scrolling hack
1094− var node1 = document.createElement("br");
1095− div.appendChild(node1);
1096− var node2 = document.createElement("br");
1097− div.appendChild(node2);
1098− }
1099− else if (this.has_class(div, "background"))
1100− { // work around for Firefox SVG reload bug
1101− // which otherwise replaces 1st SVG graphic with 2nd
1102− div.style.display = "block";
1103− }
1104− }
1105−
1106− this.slides = slides;
1107− },
1108−
1109− // return new array of all <div class="handout">
1110− collect_notes: function () {
1111− var notes = new Array();
1112− var divs = document.body.getElementsByTagName("div");
1113−
1114− for (var i = 0; i < divs.length; ++i)
1115− {
1116− div = divs.item(i);
1117−
1118− if (this.has_class(div, "handout"))
1119− {
1120− // add note to collection
1121− notes[notes.length] = div;
1122−
1123− // and hide it
1124− this.add_class(div, "hidden");
1125− }
1126− }
1127−
1128− this.notes = notes;
1129− },
1130−
1131− // return new array of all <div class="background">
1132− // including named backgrounds e.g. class="background titlepage"
1133− collect_backgrounds: function () {
1134− var backgrounds = new Array();
1135− var divs = document.body.getElementsByTagName("div");
1136−
1137− for (var i = 0; i < divs.length; ++i)
1138− {
1139− div = divs.item(i);
1140−
1141− if (this.has_class(div, "background"))
1142− {
1143− // add background to collection
1144− backgrounds[backgrounds.length] = div;
1145−
1146− // and hide it
1147− this.add_class(div, "hidden");
1148− }
1149− }
1150−
1151− this.backgrounds = backgrounds;
1152− },
1153−
1154− // set click handlers on all anchors
1155− patch_anchors: function () {
1156− var self = w3c_slidy;
1157− var handler = function (event) {
1158− // compare this.href with location.href
1159− // for link to another slide in this doc
1160−
1161− if (self.page_address(this.href) == self.page_address(location.href))
1162− {
1163− // yes, so find new slide number
1164− var newslidenum = self.find_slide_number(this.href);
1165−
1166− if (newslidenum != self.slide_number)
1167− {
1168− var slide = self.slides[self.slide_number];
1169− self.hide_slide(slide);
1170− self.slide_number = newslidenum;
1171− slide = self.slides[self.slide_number];
1172− self.show_slide(slide);
1173− self.set_location();
1174− }
1175− }
1176− else
1177− w3c_slidy.stop_propagation(event);
1178−
1179−// else if (this.target == null)
1180−// location.href = this.href;
1181−
1182− this.blur();
1183− self.disable_slide_click = true;
1184− };
1185−
1186− var anchors = document.body.getElementsByTagName("a");
1187−
1188− for (var i = 0; i < anchors.length; ++i)
1189− {
1190− if (window.addEventListener)
1191− anchors[i].addEventListener("click", handler, false);
1192− else
1193− anchors[i].attachEvent("onclick", handler);
1194− }
1195− },
1196−
1197− // ### CHECK ME ### see which functions are invoked via setTimeout
1198− // either directly or indirectly for use of w3c_slidy vs this
1199− show_slide_number: function () {
1200− var timer = w3c_slidy.get_timer();
1201− w3c_slidy.slide_number_element.innerHTML = timer + w3c_slidy.localize("slide") + " " +
1202− (w3c_slidy.slide_number + 1) + "/" + w3c_slidy.slides.length;
1203− },
1204−
1205− // every 200mS check if the location has been changed as a
1206− // result of the user activating the Back button/menu item
1207− // doesn't work for Opera < 9.5
1208− check_location: function () {
1209− var hash = location.hash;
1210−
1211− if (w3c_slidy.slide_number > 0 && (hash == "" || hash == "#"))
1212− w3c_slidy.goto_slide(0);
1213− else if (hash.length > 2 && hash != "#("+(w3c_slidy.slide_number+1)+")")
1214− {
1215− var num = parseInt(location.hash.substr(2));
1216−
1217− if (!isNaN(num))
1218− w3c_slidy.goto_slide(num-1);
1219− }
1220−
1221− if (w3c_slidy.time_left && w3c_slidy.slide_number > 0)
1222− {
1223− w3c_slidy.show_slide_number();
1224−
1225− if (w3c_slidy.time_left > 0)
1226− w3c_slidy.time_left -= 200;
1227− }
1228− },
1229−
1230− get_timer: function () {
1231− var timer = "";
1232− if (w3c_slidy.time_left)
1233− {
1234− var mins, secs;
1235− secs = Math.floor(w3c_slidy.time_left/1000);
1236− mins = Math.floor(secs / 60);
1237− secs = secs % 60;
1238− timer = (mins ? mins+"m" : "") + secs + "s ";
1239− }
1240−
1241− return timer;
1242− },
1243−
1244− // this doesn't push location onto history stack for IE
1245− // for which a hidden iframe hack is needed: load page into
1246− // the iframe with script that set's parent's location.hash
1247− // but that won't work for standalone use unless we can
1248− // create the page dynamically via a javascript: URL
1249− // ### use history.pushState if available
1250− set_location: function () {
1251− var uri = w3c_slidy.page_address(location.href);
1252− var hash = "#(" + (w3c_slidy.slide_number+1) + ")";
1253−
1254− if (w3c_slidy.slide_number >= 0)
1255− uri = uri + hash;
1256−
1257− if (typeof(history.pushState) != "undefined")
1258− {
1259− document.title = w3c_slidy.title + " (" + (w3c_slidy.slide_number+1) + ")";
1260− history.pushState(0, document.title, hash);
1261− w3c_slidy.show_slide_number();
1262− return;
1263− }
1264−
1265− if (w3c_slidy.ie && (w3c_slidy.ie6 || w3c_slidy.ie7))
1266− w3c_slidy.push_hash(hash);
1267−
1268− if (uri != location.href) // && !khtml
1269− location.href = uri;
1270−
1271− if (this.khtml)
1272− hash = "(" + (w3c_slidy.slide_number+1) + ")";
1273−
1274− if (!this.ie && location.hash != hash && location.hash != "")
1275− location.hash = hash;
1276−
1277− document.title = w3c_slidy.title + " (" + (w3c_slidy.slide_number+1) + ")";
1278− w3c_slidy.show_slide_number();
1279− },
1280−
1281− page_address: function (uri) {
1282− var i = uri.indexOf("#");
1283−
1284− if (i < 0)
1285− i = uri.indexOf("%23");
1286−
1287− // check if anchor is entire page
1288−
1289− if (i < 0)
1290− return uri; // yes
1291−
1292− return uri.substr(0, i);
1293− },
1294−
1295− // only used for IE6 and IE7
1296− on_frame_loaded: function (hash) {
1297− location.hash = hash;
1298− var uri = w3c_slidy.page_address(location.href);
1299− location.href = uri + hash;
1300− },
1301−
1302− // history hack with thanks to Bertrand Le Roy
1303− push_hash: function (hash) {
1304− if (hash == "") hash = "#(1)";
1305− window.location.hash = hash;
1306−
1307− var doc = document.getElementById("historyFrame").contentWindow.document;
1308− doc.open("javascript:'<html></html>'");
1309− doc.write("<html><head><script type=\"text/javascript\">window.parent.w3c_slidy.on_frame_loaded('"+
1310− (hash) + "');</script></head><body>hello mum</body></html>");
1311− doc.close();
1312− },
1313−
1314− // find current slide based upon location
1315− // first find target anchor and then look
1316− // for associated div element enclosing it
1317− // finally map that to slide number
1318− find_slide_number: function (uri) {
1319− // first get anchor from page location
1320−
1321− var i = uri.indexOf("#");
1322−
1323− // check if anchor is entire page
1324− if (i < 0)
1325− return 0; // yes
1326−
1327− var anchor = unescape(uri.substr(i+1));
1328−
1329− // now use anchor as XML ID to find target
1330− var target = document.getElementById(anchor);
1331−
1332− if (!target)
1333− {
1334− // does anchor look like "(2)" for slide 2 ??
1335− // where first slide is (1)
1336− var re = /\((\d)+\)/;
1337−
1338− if (anchor.match(re))
1339− {
1340− var num = parseInt(anchor.substring(1, anchor.length-1));
1341−
1342− if (num > this.slides.length)
1343− num = 1;
1344−
1345− if (--num < 0)
1346− num = 0;
1347−
1348− return num;
1349− }
1350−
1351− // accept [2] for backwards compatibility
1352− re = /\[(\d)+\]/;
1353−
1354− if (anchor.match(re))
1355− {
1356− var num = parseInt(anchor.substring(1, anchor.length-1));
1357−
1358− if (num > this.slides.length)
1359− num = 1;
1360−
1361− if (--num < 0)
1362− num = 0;
1363−
1364− return num;
1365− }
1366−
1367− // oh dear unknown anchor
1368− return 0;
1369− }
1370−
1371− // search for enclosing slide
1372−
1373− while (true)
1374− {
1375− // browser coerces html elements to uppercase!
1376− if (target.nodeName.toLowerCase() == "div" &&
1377− this.has_class(target, "slide"))
1378− {
1379− // found the slide element
1380− break;
1381− }
1382−
1383− // otherwise try parent element if any
1384−
1385− target = target.parentNode;
1386−
1387− if (!target)
1388− {
1389− return 0; // no luck!
1390− }
1391− };
1392−
1393− for (i = 0; i < slides.length; ++i)
1394− {
1395− if (slides[i] == target)
1396− return i; // success
1397− }
1398−
1399− // oh dear still no luck
1400− return 0;
1401− },
1402−
1403− previous_slide: function (incremental) {
1404− if (!w3c_slidy.view_all)
1405− {
1406− var slide;
1407−
1408− if ((incremental || w3c_slidy.slide_number == 0) && w3c_slidy.last_shown != null)
1409− {
1410− w3c_slidy.last_shown = w3c_slidy.hide_previous_item(w3c_slidy.last_shown);
1411− w3c_slidy.set_eos_status(false);
1412− }
1413− else if (w3c_slidy.slide_number > 0)
1414− {
1415− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1416− w3c_slidy.hide_slide(slide);
1417−
1418− w3c_slidy.slide_number = w3c_slidy.slide_number - 1;
1419− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1420− w3c_slidy.set_visibility_all_incremental("visible");
1421− w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
1422− w3c_slidy.set_eos_status(true);
1423− w3c_slidy.show_slide(slide);
1424− }
1425−
1426− w3c_slidy.set_location();
1427−
1428− if (!w3c_slidy.ns_pos)
1429− w3c_slidy.refresh_toolbar(200);
1430− }
1431− },
1432−
1433− next_slide: function (incremental) {
1434− if (!w3c_slidy.view_all)
1435− {
1436− var slide, last = w3c_slidy.last_shown;
1437−
1438− if (incremental || w3c_slidy.slide_number == w3c_slidy.slides.length - 1)
1439− w3c_slidy.last_shown = w3c_slidy.reveal_next_item(w3c_slidy.last_shown);
1440−
1441− if ((!incremental || w3c_slidy.last_shown == null) &&
1442− w3c_slidy.slide_number < w3c_slidy.slides.length - 1)
1443− {
1444− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1445− w3c_slidy.hide_slide(slide);
1446−
1447− w3c_slidy.slide_number = w3c_slidy.slide_number + 1;
1448− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1449− w3c_slidy.last_shown = null;
1450− w3c_slidy.set_visibility_all_incremental("hidden");
1451− w3c_slidy.show_slide(slide);
1452− }
1453− else if (!w3c_slidy.last_shown)
1454− {
1455− if (last && incremental)
1456− w3c_slidy.last_shown = last;
1457− }
1458−
1459− w3c_slidy.set_location();
1460−
1461− w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
1462−
1463− if (!w3c_slidy.ns_pos)
1464− w3c_slidy.refresh_toolbar(200);
1465− }
1466− },
1467−
1468− // to first slide with nothing revealed
1469− // i.e. state at start of presentation
1470− first_slide: function () {
1471− if (!w3c_slidy.view_all)
1472− {
1473− var slide;
1474−
1475− if (w3c_slidy.slide_number != 0)
1476− {
1477− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1478− w3c_slidy.hide_slide(slide);
1479−
1480− w3c_slidy.slide_number = 0;
1481− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1482− w3c_slidy.last_shown = null;
1483− w3c_slidy.set_visibility_all_incremental("hidden");
1484− w3c_slidy.show_slide(slide);
1485− }
1486−
1487− w3c_slidy.set_eos_status(
1488− !w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
1489− w3c_slidy.set_location();
1490− }
1491− },
1492−
1493− // goto last slide with everything revealed
1494− // i.e. state at end of presentation
1495− last_slide: function () {
1496− if (!w3c_slidy.view_all)
1497− {
1498− var slide;
1499−
1500− w3c_slidy.last_shown = null; //revealNextItem(lastShown);
1501−
1502− if (w3c_slidy.last_shown == null &&
1503− w3c_slidy.slide_number < w3c_slidy.slides.length - 1)
1504− {
1505− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1506− w3c_slidy.hide_slide(slide);
1507− w3c_slidy.slide_number = w3c_slidy.slides.length - 1;
1508− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1509− w3c_slidy.set_visibility_all_incremental("visible");
1510− w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
1511−
1512− w3c_slidy.show_slide(slide);
1513− }
1514− else
1515− {
1516− w3c_slidy.set_visibility_all_incremental("visible");
1517− w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
1518− }
1519−
1520− w3c_slidy.set_eos_status(true);
1521− w3c_slidy.set_location();
1522− }
1523− },
1524−
1525−
1526− // ### check this and consider add/remove class
1527− set_eos_status: function (state) {
1528− if (this.eos)
1529− this.eos.style.color = (state ? "rgb(240,240,240)" : "red");
1530− },
1531−
1532− // first slide is 0
1533− goto_slide: function (num) {
1534− //alert("going to slide " + (num+1));
1535− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1536− w3c_slidy.hide_slide(slide);
1537− w3c_slidy.slide_number = num;
1538− slide = w3c_slidy.slides[w3c_slidy.slide_number];
1539− w3c_slidy.last_shown = null;
1540− w3c_slidy.set_visibility_all_incremental("hidden");
1541− w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
1542− document.title = w3c_slidy.title + " (" + (w3c_slidy.slide_number+1) + ")";
1543− w3c_slidy.show_slide(slide);
1544− w3c_slidy.show_slide_number();
1545− },
1546−
1547−
1548− show_slide: function (slide) {
1549− this.sync_background(slide);
1550− this.remove_class(slide, "hidden");
1551−
1552− // work around IE9 object rendering bug
1553− setTimeout("window.scrollTo(0,0);", 1);
1554− },
1555−
1556− hide_slide: function (slide) {
1557− this.add_class(slide, "hidden");
1558− },
1559−
1560− // show just the backgrounds pertinent to this slide
1561− // when slide background-color is transparent
1562− // this should now work with rgba color values
1563− sync_background: function (slide) {
1564− var background;
1565− var bgColor;
1566−
1567− if (slide.currentStyle)
1568− bgColor = slide.currentStyle["backgroundColor"];
1569− else if (document.defaultView)
1570− {
1571− var styles = document.defaultView.getComputedStyle(slide,null);
1572−
1573− if (styles)
1574− bgColor = styles.getPropertyValue("background-color");
1575− else // broken implementation probably due Safari or Konqueror
1576− {
1577− //alert("defective implementation of getComputedStyle()");
1578− bgColor = "transparent";
1579− }
1580− }
1581− else
1582− bgColor == "transparent";
1583−
1584− if (bgColor == "transparent" ||
1585− bgColor.indexOf("rgba") >= 0 ||
1586− bgColor.indexOf("opacity") >= 0)
1587− {
1588− var slideClass = this.get_class_list(slide);
1589−
1590− for (var i = 0; i < this.backgrounds.length; i++)
1591− {
1592− background = this.backgrounds[i];
1593−
1594− var bgClass = this.get_class_list(background);
1595−
1596− if (this.matching_background(slideClass, bgClass))
1597− this.remove_class(background, "hidden");
1598− else
1599− this.add_class(background, "hidden");
1600− }
1601− }
1602− else // forcibly hide all backgrounds
1603− this.hide_backgrounds();
1604− },
1605−
1606− hide_backgrounds: function () {
1607− for (var i = 0; i < this.backgrounds.length; i++)
1608− {
1609− background = this.backgrounds[i];
1610− this.add_class(background, "hidden");
1611− }
1612− },
1613−
1614− // compare classes for slide and background
1615− matching_background: function (slideClass, bgClass) {
1616− var i, count, pattern, result;
1617−
1618− // define pattern as regular expression
1619− pattern = /\w+/g;
1620−
1621− // check background class names
1622− result = bgClass.match(pattern);
1623−
1624− for (i = count = 0; i < result.length; i++)
1625− {
1626− if (result[i] == "hidden")
1627− continue;
1628−
1629− if (result[i] == "background")
1630− continue;
1631−
1632− ++count;
1633− }
1634−
1635− if (count == 0) // default match
1636− return true;
1637−
1638− // check for matches and place result in array
1639− result = slideClass.match(pattern);
1640−
1641− // now check if desired name is present for background
1642− for (i = count = 0; i < result.length; i++)
1643− {
1644− if (result[i] == "hidden")
1645− continue;
1646−
1647− if (this.has_token(bgClass, result[i]))
1648− return true;
1649− }
1650−
1651− return false;
1652− },
1653−
1654− resized: function () {
1655− var width = 0;
1656−
1657− if ( typeof( window.innerWidth ) == 'number' )
1658− width = window.innerWidth; // Non IE browser
1659− else if (document.documentElement && document.documentElement.clientWidth)
1660− width = document.documentElement.clientWidth; // IE6
1661− else if (document.body && document.body.clientWidth)
1662− width = document.body.clientWidth; // IE4
1663−
1664− var height = 0;
1665−
1666− if ( typeof( window.innerHeight ) == 'number' )
1667− height = window.innerHeight; // Non IE browser
1668− else if (document.documentElement && document.documentElement.clientHeight)
1669− height = document.documentElement.clientHeight; // IE6
1670− else if (document.body && document.body.clientHeight)
1671− height = document.body.clientHeight; // IE4
1672−
1673− if (height && (width/height > 1.05*1024/768))
1674− {
1675− width = height * 1024.0/768;
1676− }
1677−
1678− // IE fires onresize even when only font size is changed!
1679− // so we do a check to avoid blocking < and > actions
1680− if (width != w3c_slidy.last_width || height != w3c_slidy.last_height)
1681− {
1682− if (width >= 1100)
1683− w3c_slidy.size_index = 5; // 4
1684− else if (width >= 1000)
1685− w3c_slidy.size_index = 4; // 3
1686− else if (width >= 800)
1687− w3c_slidy.size_index = 3; // 2
1688− else if (width >= 600)
1689− w3c_slidy.size_index = 2; // 1
1690− else if (width)
1691− w3c_slidy.size_index = 0;
1692−
1693− // add in font size adjustment from meta element e.g.
1694− // <meta name="font-size-adjustment" content="-2" />
1695− // useful when slides have too much content ;-)
1696−
1697− if (0 <= w3c_slidy.size_index + w3c_slidy.size_adjustment &&
1698− w3c_slidy.size_index + w3c_slidy.size_adjustment < w3c_slidy.sizes.length)
1699− w3c_slidy.size_index = w3c_slidy.size_index + w3c_slidy.size_adjustment;
1700−
1701− // enables cross browser use of relative width/height
1702− // on object elements for use with SVG and Flash media
1703− w3c_slidy.adjust_object_dimensions(width, height);
1704−
1705− if (document.body.style.fontSize != w3c_slidy.sizes[w3c_slidy.size_index])
1706− {
1707− document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
1708− }
1709−
1710− w3c_slidy.last_width = width;
1711− w3c_slidy.last_height = height;
1712−
1713− // force reflow to work around Mozilla bug
1714− if (w3c_slidy.ns_pos)
1715− {
1716− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1717− w3c_slidy.hide_slide(slide);
1718− w3c_slidy.show_slide(slide);
1719− }
1720−
1721− // force correct positioning of toolbar
1722− w3c_slidy.refresh_toolbar(200);
1723− }
1724− },
1725−
1726− scrolled: function () {
1727− if (w3c_slidy.toolbar && !w3c_slidy.ns_pos && !w3c_slidy.ie7)
1728− {
1729− w3c_slidy.hack_offset = w3c_slidy.scroll_x_offset();
1730− // hide toolbar
1731− w3c_slidy.toolbar.style.display = "none";
1732−
1733− // make it reappear later
1734− if (w3c_slidy.scrollhack == 0 && !w3c_slidy.view_all)
1735− {
1736− setTimeout(function () {w3c_slidy.show_toolbar(); }, 1000);
1737− w3c_slidy.scrollhack = 1;
1738− }
1739− }
1740− },
1741−
1742− hide_toolbar: function () {
1743− w3c_slidy.add_class(w3c_slidy.toolbar, "hidden");
1744− window.focus();
1745− },
1746−
1747− // used to ensure IE refreshes toolbar in correct position
1748− refresh_toolbar: function (interval) {
1749− if (!w3c_slidy.ns_pos && !w3c_slidy.ie7)
1750− {
1751− w3c_slidy.hide_toolbar();
1752− setTimeout(function () {w3c_slidy.show_toolbar();}, interval);
1753− }
1754− },
1755−
1756− // restores toolbar after short delay
1757− show_toolbar: function () {
1758− if (w3c_slidy.want_toolbar)
1759− {
1760− w3c_slidy.toolbar.style.display = "block";
1761−
1762− if (!w3c_slidy.ns_pos)
1763− {
1764− // adjust position to allow for scrolling
1765− var xoffset = w3c_slidy.scroll_x_offset();
1766− w3c_slidy.toolbar.style.left = xoffset;
1767− w3c_slidy.toolbar.style.right = xoffset;
1768−
1769− // determine vertical scroll offset
1770− //var yoffset = scrollYOffset();
1771−
1772− // bottom is doc height - window height - scroll offset
1773− //var bottom = documentHeight() - lastHeight - yoffset
1774−
1775− //if (yoffset > 0 || documentHeight() > lastHeight)
1776− // bottom += 16; // allow for height of scrollbar
1777−
1778− w3c_slidy.toolbar.style.bottom = 0; //bottom;
1779− }
1780−
1781− w3c_slidy.remove_class(w3c_slidy.toolbar, "hidden");
1782− }
1783−
1784− w3c_slidy.scrollhack = 0;
1785−
1786−
1787− // set the keyboard focus to the help link on the
1788− // toolbar to ensure that document has the focus
1789− // IE doesn't always work with window.focus()
1790− // and this hack has benefit of Enter for help
1791−
1792− try
1793− {
1794− if (!w3c_slidy.opera)
1795− w3c_slidy.help_anchor.focus();
1796− }
1797− catch (e)
1798− {
1799− }
1800− },
1801−
1802−// invoked via F key
1803− toggle_toolbar: function () {
1804− if (!w3c_slidy.view_all)
1805− {
1806− if (w3c_slidy.has_class(w3c_slidy.toolbar, "hidden"))
1807− {
1808− w3c_slidy.remove_class(w3c_slidy.toolbar, "hidden")
1809− w3c_slidy.want_toolbar = 1;
1810− }
1811− else
1812− {
1813− w3c_slidy.add_class(w3c_slidy.toolbar, "hidden")
1814− w3c_slidy.want_toolbar = 0;
1815− }
1816− }
1817− },
1818−
1819− scroll_x_offset: function () {
1820− if (window.pageXOffset)
1821− return self.pageXOffset;
1822−
1823− if (document.documentElement &&
1824− document.documentElement.scrollLeft)
1825− return document.documentElement.scrollLeft;
1826−
1827− if (document.body)
1828− return document.body.scrollLeft;
1829−
1830− return 0;
1831− },
1832−
1833− scroll_y_offset: function () {
1834− if (window.pageYOffset)
1835− return self.pageYOffset;
1836−
1837− if (document.documentElement &&
1838− document.documentElement.scrollTop)
1839− return document.documentElement.scrollTop;
1840−
1841− if (document.body)
1842− return document.body.scrollTop;
1843−
1844− return 0;
1845− },
1846−
1847− // looking for a way to determine height of slide content
1848− // the slide itself is set to the height of the window
1849− optimize_font_size: function () {
1850− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1851−
1852− //var dh = documentHeight(); //getDocHeight(document);
1853− var dh = slide.scrollHeight;
1854− var wh = getWindowHeight();
1855− var u = 100 * dh / wh;
1856−
1857− alert("window utilization = " + u + "% (doc "
1858− + dh + " win " + wh + ")");
1859− },
1860−
1861− // from document object
1862− get_doc_height: function (doc) {
1863− if (!doc)
1864− doc = document;
1865−
1866− if (doc && doc.body && doc.body.offsetHeight)
1867− return doc.body.offsetHeight; // ns/gecko syntax
1868−
1869− if (doc && doc.body && doc.body.scrollHeight)
1870− return doc.body.scrollHeight;
1871−
1872− alert("couldn't determine document height");
1873− },
1874−
1875− get_window_height: function () {
1876− if ( typeof( window.innerHeight ) == 'number' )
1877− return window.innerHeight; // Non IE browser
1878−
1879− if (document.documentElement && document.documentElement.clientHeight)
1880− return document.documentElement.clientHeight; // IE6
1881−
1882− if (document.body && document.body.clientHeight)
1883− return document.body.clientHeight; // IE4
1884− },
1885−
1886− document_height: function () {
1887− var sh, oh;
1888−
1889− sh = document.body.scrollHeight;
1890− oh = document.body.offsetHeight;
1891−
1892− if (sh && oh)
1893− {
1894− return (sh > oh ? sh : oh);
1895− }
1896−
1897− // no idea!
1898− return 0;
1899− },
1900−
1901− smaller: function () {
1902− if (w3c_slidy.size_index > 0)
1903− {
1904− --w3c_slidy.size_index;
1905− }
1906−
1907− w3c_slidy.toolbar.style.display = "none";
1908− document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
1909− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1910− w3c_slidy.hide_slide(slide);
1911− w3c_slidy.show_slide(slide);
1912− setTimeout(function () {w3c_slidy.show_toolbar(); }, 50);
1913− },
1914−
1915− bigger: function () {
1916− if (w3c_slidy.size_index < w3c_slidy.sizes.length - 1)
1917− {
1918− ++w3c_slidy.size_index;
1919− }
1920−
1921− w3c_slidy.toolbar.style.display = "none";
1922− document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
1923− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1924− w3c_slidy.hide_slide(slide);
1925− w3c_slidy.show_slide(slide);
1926− setTimeout(function () {w3c_slidy.show_toolbar(); }, 50);
1927− },
1928−
1929− // enables cross browser use of relative width/height
1930− // on object elements for use with SVG and Flash media
1931− // with thanks to Ivan Herman for the suggestion
1932− adjust_object_dimensions: function (width, height) {
1933− for( var i = 0; i < w3c_slidy.objects.length; i++ )
1934− {
1935− var obj = this.objects[i];
1936− var mimeType = obj.getAttribute("type");
1937−
1938− if (mimeType == "image/svg+xml" || mimeType == "application/x-shockwave-flash")
1939− {
1940− if ( !obj.initialWidth )
1941− obj.initialWidth = obj.getAttribute("width");
1942−
1943− if ( !obj.initialHeight )
1944− obj.initialHeight = obj.getAttribute("height");
1945−
1946− if ( obj.initialWidth && obj.initialWidth.charAt(obj.initialWidth.length-1) == "%" )
1947− {
1948− var w = parseInt(obj.initialWidth.slice(0, obj.initialWidth.length-1));
1949− var newW = width * (w/100.0);
1950− obj.setAttribute("width",newW);
1951− }
1952−
1953− if ( obj.initialHeight &&
1954− obj.initialHeight.charAt(obj.initialHeight.length-1) == "%" )
1955− {
1956− var h = parseInt(obj.initialHeight.slice(0, obj.initialHeight.length-1));
1957− var newH = height * (h/100.0);
1958− obj.setAttribute("height", newH);
1959− }
1960− }
1961− }
1962− },
1963−
1964− // needed for Opera to inhibit default behavior
1965− // since Opera delivers keyPress even if keyDown
1966− // was cancelled
1967− key_press: function (event) {
1968− if (!event)
1969− event = window.event;
1970−
1971− if (!w3c_slidy.key_wanted)
1972− return w3c_slidy.cancel(event);
1973−
1974− return true;
1975− },
1976−
1977− // See e.g. http://www.quirksmode.org/js/events/keys.html for keycodes
1978− key_down: function (event) {
1979− var key, target, tag;
1980−
1981− w3c_slidy.key_wanted = true;
1982−
1983− if (!event)
1984− event = window.event;
1985−
1986− // kludge around NS/IE differences
1987− if (window.event)
1988− {
1989− key = window.event.keyCode;
1990− target = window.event.srcElement;
1991− }
1992− else if (event.which)
1993− {
1994− key = event.which;
1995− target = event.target;
1996− }
1997− else
1998− return true; // Yikes! unknown browser
1999−
2000− // ignore event if key value is zero
2001− // as for alt on Opera and Konqueror
2002− if (!key)
2003− return true;
2004−
2005− // avoid interfering with keystroke
2006− // behavior for non-slidy chrome elements
2007− if (!w3c_slidy.slidy_chrome(target) &&
2008− w3c_slidy.special_element(target))
2009− return true;
2010−
2011− // check for concurrent control/command/alt key
2012− // but are these only present on mouse events?
2013−
2014− if (event.ctrlKey || event.altKey || event.metaKey)
2015− return true;
2016−
2017− // dismiss table of contents if visible
2018− if (w3c_slidy.is_shown_toc() && key != 9 && key != 16 && key != 38 && key != 40)
2019− {
2020− w3c_slidy.hide_table_of_contents(true);
2021−
2022− if (key == 27 || key == 84 || key == 67)
2023− return w3c_slidy.cancel(event);
2024− }
2025−
2026− if (key == 34) // Page Down
2027− {
2028− if (w3c_slidy.view_all)
2029− return true;
2030−
2031− w3c_slidy.next_slide(false);
2032− return w3c_slidy.cancel(event);
2033− }
2034− else if (key == 33) // Page Up
2035− {
2036− if (w3c_slidy.view_all)
2037− return true;
2038−
2039− w3c_slidy.previous_slide(false);
2040− return w3c_slidy.cancel(event);
2041− }
2042− else if (key == 32) // space bar
2043− {
2044− w3c_slidy.next_slide(true);
2045− return w3c_slidy.cancel(event);
2046− }
2047− else if (key == 37) // Left arrow
2048− {
2049− w3c_slidy.previous_slide(!event.shiftKey);
2050− return w3c_slidy.cancel(event);
2051− }
2052− else if (key == 36) // Home
2053− {
2054− w3c_slidy.first_slide();
2055− return w3c_slidy.cancel(event);
2056− }
2057− else if (key == 35) // End
2058− {
2059− w3c_slidy.last_slide();
2060− return w3c_slidy.cancel(event);
2061− }
2062− else if (key == 39) // Right arrow
2063− {
2064− w3c_slidy.next_slide(!event.shiftKey);
2065− return w3c_slidy.cancel(event);
2066− }
2067− else if (key == 13) // Enter
2068− {
2069− if (w3c_slidy.outline)
2070− {
2071− if (w3c_slidy.outline.visible)
2072− w3c_slidy.fold(w3c_slidy.outline);
2073− else
2074− w3c_slidy.unfold(w3c_slidy.outline);
2075−
2076− return w3c_slidy.cancel(event);
2077− }
2078− }
2079− else if (key == 188) // < for smaller fonts
2080− {
2081− w3c_slidy.smaller();
2082− return w3c_slidy.cancel(event);
2083− }
2084− else if (key == 190) // > for larger fonts
2085− {
2086− w3c_slidy.bigger();
2087− return w3c_slidy.cancel(event);
2088− }
2089− else if (key == 189 || key == 109) // - for smaller fonts
2090− {
2091− w3c_slidy.smaller();
2092− return w3c_slidy.cancel(event);
2093− }
2094− else if (key == 187 || key == 191 || key == 107) // = + for larger fonts
2095− {
2096− w3c_slidy.bigger();
2097− return w3c_slidy.cancel(event);
2098− }
2099− else if (key == 83) // S for smaller fonts
2100− {
2101− w3c_slidy.smaller();
2102− return w3c_slidy.cancel(event);
2103− }
2104− else if (key == 66) // B for larger fonts
2105− {
2106− w3c_slidy.bigger();
2107− return w3c_slidy.cancel(event);
2108− }
2109− else if (key == 90) // Z for last slide
2110− {
2111− w3c_slidy.last_slide();
2112− return w3c_slidy.cancel(event);
2113− }
2114− else if (key == 70) // F for toggle toolbar
2115− {
2116− w3c_slidy.toggle_toolbar();
2117− return w3c_slidy.cancel(event);
2118− }
2119− else if (key == 65) // A for toggle view single/all slides
2120− {
2121− w3c_slidy.toggle_view();
2122− return w3c_slidy.cancel(event);
2123− }
2124− else if (key == 75) // toggle action of left click for next page
2125− {
2126− w3c_slidy.mouse_click_enabled = !w3c_slidy.mouse_click_enabled;
2127− var alert_msg = (w3c_slidy.mouse_click_enabled ?
2128− "enabled" : "disabled") + " mouse click advance";
2129−
2130− alert(w3c_slidy.localize(alert_msg));
2131− return w3c_slidy.cancel(event);
2132− }
2133− else if (key == 84 || key == 67) // T or C for table of contents
2134− {
2135− if (w3c_slidy.toc)
2136− w3c_slidy.toggle_table_of_contents();
2137−
2138− return w3c_slidy.cancel(event);
2139− }
2140− else if (key == 72) // H for help
2141− {
2142− window.location = w3c_slidy.help_page;
2143− return w3c_slidy.cancel(event);
2144− }
2145− //else alert("key code is "+ key);
2146−
2147− return true;
2148− },
2149−
2150− // safe for both text/html and application/xhtml+xml
2151− create_element: function (name) {
2152− if (this.xhtml && (typeof document.createElementNS != 'undefined'))
2153− return document.createElementNS("http://www.w3.org/1999/xhtml", name)
2154−
2155− return document.createElement(name);
2156− },
2157−
2158− get_element_style: function (elem, IEStyleProp, CSSStyleProp) {
2159− if (elem.currentStyle)
2160− {
2161− return elem.currentStyle[IEStyleProp];
2162− }
2163− else if (window.getComputedStyle)
2164− {
2165− var compStyle = window.getComputedStyle(elem, "");
2166− return compStyle.getPropertyValue(CSSStyleProp);
2167− }
2168− return "";
2169− },
2170−
2171− // the string str is a whitespace separated list of tokens
2172− // test if str contains a particular token, e.g. "slide"
2173− has_token: function (str, token) {
2174− if (str)
2175− {
2176− // define pattern as regular expression
2177− var pattern = /\w+/g;
2178−
2179− // check for matches
2180− // place result in array
2181− var result = str.match(pattern);
2182−
2183− // now check if desired token is present
2184− for (var i = 0; i < result.length; i++)
2185− {
2186− if (result[i] == token)
2187− return true;
2188− }
2189− }
2190−
2191− return false;
2192− },
2193−
2194− get_class_list: function (element) {
2195− if (typeof element.className != 'undefined')
2196− return element.className;
2197−
2198− return element.getAttribute("class");
2199− },
2200−
2201− has_class: function (element, name) {
2202− if (element.nodeType != 1)
2203− return false;
2204−
2205− var regexp = new RegExp("(^| )" + name + "\W*");
2206−
2207− if (typeof element.className != 'undefined')
2208− return regexp.test(element.className);
2209−
2210− return regexp.test(element.getAttribute("class"));
2211− },
2212−
2213− remove_class: function (element, name) {
2214− var regexp = new RegExp("(^| )" + name + "\W*");
2215− var clsval = "";
2216−
2217− if (typeof element.className != 'undefined')
2218− {
2219− clsval = element.className;
2220−
2221− if (clsval)
2222− {
2223− clsval = clsval.replace(regexp, "");
2224− element.className = clsval;
2225− }
2226− }
2227− else
2228− {
2229− clsval = element.getAttribute("class");
2230−
2231− if (clsval)
2232− {
2233− clsval = clsval.replace(regexp, "");
2234− element.setAttribute("class", clsval);
2235− }
2236− }
2237− },
2238−
2239− add_class: function (element, name) {
2240− if (!this.has_class(element, name))
2241− {
2242− if (typeof element.className != 'undefined')
2243− element.className += " " + name;
2244− else
2245− {
2246− var clsval = element.getAttribute("class");
2247− clsval = clsval ? clsval + " " + name : name;
2248− element.setAttribute("class", clsval);
2249− }
2250− }
2251− },
2252−
2253− // HTML elements that can be used with class="incremental"
2254− // note that you can also put the class on containers like
2255− // up, ol, dl, and div to make their contents appear
2256− // incrementally. Upper case is used since this is what
2257− // browsers report for HTML node names (text/html).
2258− incremental_elements: null,
2259− okay_for_incremental: function (name) {
2260− if (!this.incremental_elements)
2261− {
2262− var inclist = new Array();
2263− inclist["p"] = true;
2264− inclist["pre"] = true;
2265− inclist["li"] = true;
2266− inclist["blockquote"] = true;
2267− inclist["dt"] = true;
2268− inclist["dd"] = true;
2269− inclist["h2"] = true;
2270− inclist["h3"] = true;
2271− inclist["h4"] = true;
2272− inclist["h5"] = true;
2273− inclist["h6"] = true;
2274− inclist["span"] = true;
2275− inclist["address"] = true;
2276− inclist["table"] = true;
2277− inclist["tr"] = true;
2278− inclist["th"] = true;
2279− inclist["td"] = true;
2280− inclist["img"] = true;
2281− inclist["object"] = true;
2282− this.incremental_elements = inclist;
2283− }
2284− return this.incremental_elements[name.toLowerCase()];
2285− },
2286−
2287− next_incremental_item: function (node) {
2288− var br = this.is_xhtml ? "br" : "BR";
2289− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
2290−
2291− for (;;)
2292− {
2293− node = w3c_slidy.next_node(slide, node);
2294−
2295− if (node == null || node.parentNode == null)
2296− break;
2297−
2298− if (node.nodeType == 1) // ELEMENT
2299− {
2300− if (node.nodeName == br)
2301− continue;
2302−
2303− if (w3c_slidy.has_class(node, "incremental")
2304− && w3c_slidy.okay_for_incremental(node.nodeName))
2305− return node;
2306−
2307− if (w3c_slidy.has_class(node.parentNode, "incremental")
2308− && !w3c_slidy.has_class(node, "non-incremental"))
2309− return node;
2310− }
2311− }
2312−
2313− return node;
2314− },
2315−
2316− previous_incremental_item: function (node) {
2317− var br = this.is_xhtml ? "br" : "BR";
2318− var slide = w3c_slidy.slides[w3c_slidy.slide_number];
2319−
2320− for (;;)
2321− {
2322− node = w3c_slidy.previous_node(slide, node);
2323−
2324− if (node == null || node.parentNode == null)
2325− break;
2326−
2327− if (node.nodeType == 1)
2328− {
2329− if (node.nodeName == br)
2330− continue;
2331−
2332− if (w3c_slidy.has_class(node, "incremental")
2333− && w3c_slidy.okay_for_incremental(node.nodeName))
2334− return node;
2335−
2336− if (w3c_slidy.has_class(node.parentNode, "incremental")
2337− && !w3c_slidy.has_class(node, "non-incremental"))
2338− return node;
2339− }
2340− }
2341−
2342− return node;
2343− },
2344−
2345− // set visibility for all elements on current slide with
2346− // a parent element with attribute class="incremental"
2347− set_visibility_all_incremental: function (value) {
2348− var node = this.next_incremental_item(null);
2349−
2350− if (value == "hidden")
2351− {
2352− while (node)
2353− {
2354− w3c_slidy.add_class(node, "invisible");
2355− node = w3c_slidy.next_incremental_item(node);
2356− }
2357− }
2358− else // value == "visible"
2359− {
2360− while (node)
2361− {
2362− w3c_slidy.remove_class(node, "invisible");
2363− node = w3c_slidy.next_incremental_item(node);
2364− }
2365− }
2366− },
2367−
2368− // reveal the next hidden item on the slide
2369− // node is null or the node that was last revealed
2370− reveal_next_item: function (node) {
2371− node = w3c_slidy.next_incremental_item(node);
2372−
2373− if (node && node.nodeType == 1) // an element
2374− w3c_slidy.remove_class(node, "invisible");
2375−
2376− return node;
2377− },
2378−
2379− // exact inverse of revealNextItem(node)
2380− hide_previous_item: function (node) {
2381− if (node && node.nodeType == 1) // an element
2382− w3c_slidy.add_class(node, "invisible");
2383−
2384− return this.previous_incremental_item(node);
2385− },
2386−
2387− // left to right traversal of root's content
2388− next_node: function (root, node) {
2389− if (node == null)
2390− return root.firstChild;
2391−
2392− if (node.firstChild)
2393− return node.firstChild;
2394−
2395− if (node.nextSibling)
2396− return node.nextSibling;
2397−
2398− for (;;)
2399− {
2400− node = node.parentNode;
2401−
2402− if (!node || node == root)
2403− break;
2404−
2405− if (node && node.nextSibling)
2406− return node.nextSibling;
2407− }
2408−
2409− return null;
2410− },
2411−
2412− // right to left traversal of root's content
2413− previous_node: function (root, node) {
2414− if (node == null)
2415− {
2416− node = root.lastChild;
2417−
2418− if (node)
2419− {
2420− while (node.lastChild)
2421− node = node.lastChild;
2422− }
2423−
2424− return node;
2425− }
2426−
2427− if (node.previousSibling)
2428− {
2429− node = node.previousSibling;
2430−
2431− while (node.lastChild)
2432− node = node.lastChild;
2433−
2434− return node;
2435− }
2436−
2437− if (node.parentNode != root)
2438− return node.parentNode;
2439−
2440− return null;
2441− },
2442−
2443− previous_sibling_element: function (el) {
2444− el = el.previousSibling;
2445−
2446− while (el && el.nodeType != 1)
2447− el = el.previousSibling;
2448−
2449− return el;
2450− },
2451−
2452− next_sibling_element: function (el) {
2453− el = el.nextSibling;
2454−
2455− while (el && el.nodeType != 1)
2456− el = el.nextSibling;
2457−
2458− return el;
2459− },
2460−
2461− first_child_element: function (el) {
2462− var node;
2463−
2464− for (node = el.firstChild; node; node = node.nextSibling)
2465− {
2466− if (node.nodeType == 1)
2467− break;
2468− }
2469−
2470− return node;
2471− },
2472−
2473− first_tag: function (element, tag) {
2474− var node;
2475−
2476− if (!this.is_xhtml)
2477− tag = tag.toUpperCase();
2478−
2479− for (node = element.firstChild; node; node = node.nextSibling)
2480− {
2481− if (node.nodeType == 1 && node.nodeName == tag)
2482− break;
2483− }
2484−
2485− return node;
2486− },
2487−
2488− hide_selection: function () {
2489− if (window.getSelection) // Firefox, Chromium, Safari, Opera
2490− {
2491− var selection = window.getSelection();
2492−
2493− if (selection.rangeCount > 0)
2494− {
2495− var range = selection.getRangeAt(0);
2496− range.collapse (false);
2497− }
2498− }
2499− else // Internet Explorer
2500− {
2501− var textRange = document.selection.createRange ();
2502− textRange.collapse (false);
2503− }
2504− },
2505−
2506− get_selected_text: function () {
2507− try
2508− {
2509− if (window.getSelection)
2510− return window.getSelection().toString();
2511−
2512− if (document.getSelection)
2513− return document.getSelection().toString();
2514−
2515− if (document.selection)
2516− return document.selection.createRange().text;
2517− }
2518− catch (e)
2519− {
2520− }
2521−
2522− return "";
2523− },
2524−
2525− // make note of length of selected text
2526− // as this evaluates to zero in click event
2527− mouse_button_up: function (e) {
2528− w3c_slidy.selected_text_len = w3c_slidy.get_selected_text().length;
2529− },
2530−
2531− mouse_button_down: function (e) {
2532− w3c_slidy.selected_text_len = w3c_slidy.get_selected_text().length;
2533− w3c_slidy.mouse_x = e.clientX;
2534− w3c_slidy.mouse_y = e.clientY;
2535− },
2536−
2537− // right mouse button click is reserved for context menus
2538− // it is more reliable to detect rightclick than leftclick
2539− mouse_button_click: function (e) {
2540− if (!e)
2541− var e = window.event;
2542−
2543− if (Math.abs(e.clientX -w3c_slidy.mouse_x) +
2544− Math.abs(e.clientY -w3c_slidy.mouse_y) > 10)
2545− return true;
2546−
2547− if (w3c_slidy.selected_text_len > 0)
2548− return true;
2549−
2550− var rightclick = false;
2551− var leftclick = false;
2552− var middleclick = false;
2553− var target;
2554−
2555− if (!e)
2556− var e = window.event;
2557−
2558− if (e.target)
2559− target = e.target;
2560− else if (e.srcElement)
2561− target = e.srcElement;
2562−
2563− // work around Safari bug
2564− if (target.nodeType == 3)
2565− target = target.parentNode;
2566−
2567− if (e.which) // all browsers except IE
2568− {
2569− leftclick = (e.which == 1);
2570− middleclick = (e.which == 2);
2571− rightclick = (e.which == 3);
2572− }
2573− else if (e.button)
2574− {
2575− // Konqueror gives 1 for left, 4 for middle
2576− // IE6 gives 0 for left and not 1 as I expected
2577−
2578− if (e.button == 4)
2579− middleclick = true;
2580−
2581− // all browsers agree on 2 for right button
2582− rightclick = (e.button == 2);
2583− }
2584− else
2585− leftclick = true;
2586−
2587− if (w3c_slidy.selected_text_len > 0)
2588− {
2589− w3c_slidy.stop_propagation(e);
2590− e.cancel = true;
2591− e.returnValue = false;
2592− return false;
2593− }
2594−
2595− // dismiss table of contents
2596− w3c_slidy.hide_table_of_contents(false);
2597−
2598− // check if target is something that probably want's clicks
2599− // e.g. a, embed, object, input, textarea, select, option
2600− var tag = target.nodeName.toLowerCase();
2601−
2602− if (w3c_slidy.mouse_click_enabled && leftclick &&
2603− !w3c_slidy.special_element(target) &&
2604− !target.onclick)
2605− {
2606− w3c_slidy.next_slide(true);
2607− w3c_slidy.stop_propagation(e);
2608− e.cancel = true;
2609− e.returnValue = false;
2610− return false;
2611− }
2612−
2613− return true;
2614− },
2615−
2616− special_element: function (element) {
2617− if (this.has_class(element, "non-interactive"))
2618− return false;
2619−
2620− var tag = element.nodeName.toLowerCase();
2621−
2622− return element.onkeydown ||
2623− element.onclick ||
2624− tag == "a" ||
2625− tag == "embed" ||
2626− tag == "object" ||
2627− tag == "video" ||
2628− tag == "audio" ||
2629− tag == "svg" ||
2630− tag == "canvas" ||
2631− tag == "input" ||
2632− tag == "textarea" ||
2633− tag == "select" ||
2634− tag == "option";
2635− },
2636−
2637− slidy_chrome: function (el) {
2638− while (el)
2639− {
2640− if (el == w3c_slidy.toc ||
2641− el == w3c_slidy.toolbar ||
2642− w3c_slidy.has_class(el, "outline"))
2643− return true;
2644−
2645− el = el.parentNode;
2646− }
2647−
2648− return false;
2649− },
2650−
2651− get_key: function (e)
2652− {
2653− var key;
2654−
2655− // kludge around NS/IE differences
2656− if (typeof window.event != "undefined")
2657− key = window.event.keyCode;
2658− else if (e.which)
2659− key = e.which;
2660−
2661− return key;
2662− },
2663−
2664− get_target: function (e) {
2665− var target;
2666−
2667− if (!e)
2668− e = window.event;
2669−
2670− if (e.target)
2671− target = e.target;
2672− else if (e.srcElement)
2673− target = e.srcElement;
2674−
2675− if (target.nodeType != 1)
2676− target = target.parentNode;
2677−
2678− return target;
2679− },
2680−
2681− // does display property provide correct defaults?
2682− is_block: function (elem) {
2683− var tag = elem.nodeName.toLowerCase();
2684−
2685− return tag == "ol" || tag == "ul" || tag == "p" ||
2686− tag == "li" || tag == "table" || tag == "pre" ||
2687− tag == "h1" || tag == "h2" || tag == "h3" ||
2688− tag == "h4" || tag == "h5" || tag == "h6" ||
2689− tag == "blockquote" || tag == "address";
2690− },
2691−
2692− add_listener: function (element, event, handler) {
2693− if (window.addEventListener)
2694− element.addEventListener(event, handler, false);
2695− else
2696− element.attachEvent("on"+event, handler);
2697− },
2698−
2699− // used to prevent event propagation from field controls
2700− stop_propagation: function (event) {
2701− event = event ? event : window.event;
2702− event.cancelBubble = true; // for IE
2703−
2704− if (event.stopPropagation)
2705− event.stopPropagation();
2706−
2707− return true;
2708− },
2709−
2710− cancel: function (event) {
2711− if (event)
2712− {
2713− event.cancel = true;
2714− event.returnValue = false;
2715−
2716− if (event.preventDefault)
2717− event.preventDefault();
2718− }
2719−
2720− w3c_slidy.key_wanted = false;
2721− return false;
2722− },
2723−
2724−// for each language define an associative array
2725−// and also the help text which is longer
2726−
2727− strings_es: {
2728− "slide":"pág.",
2729− "help?":"Ayuda",
2730− "contents?":"Índice",
2731− "table of contents":"tabla de contenidos",
2732− "Table of Contents":"Tabla de Contenidos",
2733− "restart presentation":"Reiniciar presentación",
2734− "restart?":"Inicio"
2735− },
2736− help_es:
2737− "Utilice el ratón, barra espaciadora, teclas Izda/Dcha, " +
2738− "o Re pág y Av pág. Use S y B para cambiar el tamaño de fuente.",
2739−
2740− strings_ca: {
2741− "slide":"pàg..",
2742− "help?":"Ajuda",
2743− "contents?":"Índex",
2744− "table of contents":"taula de continguts",
2745− "Table of Contents":"Taula de Continguts",
2746− "restart presentation":"Reiniciar presentació",
2747− "restart?":"Inici"
2748− },
2749− help_ca:
2750− "Utilitzi el ratolí, barra espaiadora, tecles Esq./Dta. " +
2751− "o Re pàg y Av pàg. Usi S i B per canviar grandària de font.",
2752−
2753− strings_cs: {
2754− "slide":"snímek",
2755− "help?":"nápověda",
2756− "contents?":"obsah",
2757− "table of contents":"obsah prezentace",
2758− "Table of Contents":"Obsah prezentace",
2759− "restart presentation":"znovu spustit prezentaci",
2760− "restart?":"restart"
2761− },
2762− help_cs:
2763− "Prezentaci můžete procházet pomocí kliknutí myši, mezerníku, " +
2764− "šipek vlevo a vpravo nebo kláves PageUp a PageDown. Písmo se " +
2765− "dá zvětšit a zmenšit pomocí kláves B a S.",
2766−
2767− strings_nl: {
2768− "slide":"pagina",
2769− "help?":"Help?",
2770− "contents?":"Inhoud?",
2771− "table of contents":"inhoudsopgave",
2772− "Table of Contents":"Inhoudsopgave",
2773− "restart presentation":"herstart presentatie",
2774− "restart?":"Herstart?"
2775− },
2776− help_nl:
2777− "Navigeer d.m.v. het muis, spatiebar, Links/Rechts toetsen, " +
2778− "of PgUp en PgDn. Gebruik S en B om de karaktergrootte te veranderen.",
2779−
2780− strings_de: {
2781− "slide":"Seite",
2782− "help?":"Hilfe",
2783− "contents?":"Übersicht",
2784− "table of contents":"Inhaltsverzeichnis",
2785− "Table of Contents":"Inhaltsverzeichnis",
2786− "restart presentation":"Präsentation neu starten",
2787− "restart?":"Neustart"
2788− },
2789− help_de:
2790− "Benutzen Sie die Maus, Leerschlag, die Cursortasten links/rechts oder " +
2791− "Page up/Page Down zum Wechseln der Seiten und S und B für die Schriftgrösse.",
2792−
2793− strings_pl: {
2794− "slide":"slajd",
2795− "help?":"pomoc?",
2796− "contents?":"spis treści?",
2797− "table of contents":"spis treści",
2798− "Table of Contents":"Spis Treści",
2799− "restart presentation":"Restartuj prezentację",
2800− "restart?":"restart?"
2801− },
2802− help_pl:
2803− "Zmieniaj slajdy klikając myszą, naciskając spację, strzałki lewo/prawo" +
2804− "lub PgUp / PgDn. Użyj klawiszy S i B, aby zmienić rozmiar czczionki.",
2805−
2806− strings_fr: {
2807− "slide":"page",
2808− "help?":"Aide",
2809− "contents?":"Index",
2810− "table of contents":"table des matières",
2811− "Table of Contents":"Table des matières",
2812− "restart presentation":"Recommencer l'exposé",
2813− "restart?":"Début"
2814− },
2815− help_fr:
2816− "Naviguez avec la souris, la barre d'espace, les flèches " +
2817− "gauche/droite ou les touches Pg Up, Pg Dn. Utilisez " +
2818− "les touches S et B pour modifier la taille de la police.",
2819−
2820− strings_hu: {
2821− "slide":"oldal",
2822− "help?":"segítség",
2823− "contents?":"tartalom",
2824− "table of contents":"tartalomjegyzék",
2825− "Table of Contents":"Tartalomjegyzék",
2826− "restart presentation":"bemutató újraindítása",
2827− "restart?":"újraindítás"
2828− },
2829− help_hu:
2830− "Az oldalak közti lépkedéshez kattintson az egérrel, vagy " +
2831− "használja a szóköz, a bal, vagy a jobb nyíl, illetve a Page Down, " +
2832− "Page Up billentyűket. Az S és a B billentyűkkel változtathatja " +
2833− "a szöveg méretét.",
2834−
2835− strings_it: {
2836− "slide":"pag.",
2837− "help?":"Aiuto",
2838− "contents?":"Indice",
2839− "table of contents":"indice",
2840− "Table of Contents":"Indice",
2841− "restart presentation":"Ricominciare la presentazione",
2842− "restart?":"Inizio"
2843− },
2844− help_it:
2845− "Navigare con mouse, barra spazio, frecce sinistra/destra o " +
2846− "PgUp e PgDn. Usare S e B per cambiare la dimensione dei caratteri.",
2847−
2848− strings_el: {
2849− "slide":"σελίδα",
2850− "help?":"βοήθεια;",
2851− "contents?":"περιεχόμενα;",
2852− "table of contents":"πίνακας περιεχομένων",
2853− "Table of Contents":"Πίνακας Περιεχομένων",
2854− "restart presentation":"επανεκκίνηση παρουσίασης",
2855− "restart?":"επανεκκίνηση;"
2856− },
2857− help_el:
2858− "Πλοηγηθείτε με το κλίκ του ποντικιού, το space, τα βέλη αριστερά/δεξιά, " +
2859− "ή Page Up και Page Down. Χρησιμοποιήστε τα πλήκτρα S και B για να αλλάξετε " +
2860− "το μέγεθος της γραμματοσειράς.",
2861−
2862− strings_ja: {
2863− "slide":"スライド",
2864− "help?":"ヘルプ",
2865− "contents?":"目次",
2866− "table of contents":"目次を表示",
2867− "Table of Contents":"目次",
2868− "restart presentation":"最初から再生",
2869− "restart?":"最初から"
2870− },
2871− help_ja:
2872− "マウス左クリック ・ スペース ・ 左右キー " +
2873− "または Page Up ・ Page Downで操作, S ・ Bでフォントサイズ変更",
2874−
2875− strings_zh: {
2876− "slide":"幻灯片",
2877− "help?":"帮助?",
2878− "contents?":"内容?",
2879− "table of contents":"目录",
2880− "Table of Contents":"目录",
2881− "restart presentation":"重新启动展示",
2882− "restart?":"重新启动?"
2883− },
2884− help_zh:
2885− "用鼠标点击, 空格条, 左右箭头, Pg Up 和 Pg Dn 导航. " +
2886− "用 S, B 改变字体大小.",
2887−
2888− strings_ru: {
2889− "slide":"слайд",
2890− "help?":"помощь?",
2891− "contents?":"содержание?",
2892− "table of contents":"оглавление",
2893− "Table of Contents":"Оглавление",
2894− "restart presentation":"перезапустить презентацию",
2895− "restart?":"перезапуск?"
2896− },
2897− help_ru:
2898− "Перемещайтесь кликая мышкой, используя клавишу пробел, стрелки" +
2899− "влево/вправо или Pg Up и Pg Dn. Клавиши S и B меняют размер шрифта.",
2900−
2901− strings_sv: {
2902− "slide":"sida",
2903− "help?":"hjälp",
2904− "contents?":"innehåll",
2905− "table of contents":"innehållsförteckning",
2906− "Table of Contents":"Innehållsförteckning",
2907− "restart presentation":"visa presentationen från början",
2908− "restart?":"börja om"
2909− },
2910− help_sv:
2911− "Bläddra med ett klick med vänstra musknappen, mellanslagstangenten, " +
2912− "vänster- och högerpiltangenterna eller tangenterna Pg Up, Pg Dn. " +
2913− "Använd tangenterna S och B för att ändra textens storlek.",
2914−
2915− strings: { },
2916−
2917− localize: function (src) {
2918− if (src == "")
2919− return src;
2920−
2921− // try full language code, e.g. en-US
2922− var s, lookup = w3c_slidy.strings[w3c_slidy.lang];
2923−
2924− if (lookup)
2925− {
2926− s = lookup[src];
2927−
2928− if (s)
2929− return s;
2930− }
2931−
2932− // strip country code suffix, e.g.
2933− // try en if undefined for en-US
2934− var lg = w3c_slidy.lang.split("-");
2935−
2936− if (lg.length > 1)
2937− {
2938− lookup = w3c_slidy.strings[lg[0]];
2939−
2940− if (lookup)
2941− {
2942− s = lookup[src];
2943−
2944− if (s)
2945− return s;
2946− }
2947− }
2948−
2949− // otherwise string as is
2950− return src;
2951− },
2952−
2953− init_localization: function () {
2954− var i18n = w3c_slidy;
2955− var help_text = w3c_slidy.help_text;
2956−
2957− // each such language array is declared in the localize array
2958− // this is used as in w3c_slidy.localize("foo");
2959− this.strings = {
2960− "es":this.strings_es,
2961− "ca":this.strings_ca,
2962− "cs":this.strings_cs,
2963− "nl":this.strings_nl,
2964− "de":this.strings_de,
2965− "pl":this.strings_pl,
2966− "fr":this.strings_fr,
2967− "hu":this.strings_hu,
2968− "it":this.strings_it,
2969− "el":this.strings_el,
2970− "jp":this.strings_ja,
2971− "zh":this.strings_zh,
2972− "ru":this.strings_ru,
2973− "sv":this.strings_sv
2974− },
2975−
2976− i18n.strings_es[help_text] = i18n.help_es;
2977− i18n.strings_ca[help_text] = i18n.help_ca;
2978− i18n.strings_cs[help_text] = i18n.help_cs;
2979− i18n.strings_nl[help_text] = i18n.help_nl;
2980− i18n.strings_de[help_text] = i18n.help_de;
2981− i18n.strings_pl[help_text] = i18n.help_pl;
2982− i18n.strings_fr[help_text] = i18n.help_fr;
2983− i18n.strings_hu[help_text] = i18n.help_hu;
2984− i18n.strings_it[help_text] = i18n.help_it;
2985− i18n.strings_el[help_text] = i18n.help_el;
2986− i18n.strings_ja[help_text] = i18n.help_ja;
2987− i18n.strings_zh[help_text] = i18n.help_zh;
2988− i18n.strings_ru[help_text] = i18n.help_ru;
2989− i18n.strings_sv[help_text] = i18n.help_sv;
2990−
2991− w3c_slidy.lang = document.body.parentNode.getAttribute("lang");
2992−
2993− if (!w3c_slidy.lang)
2994− w3c_slidy.lang = document.body.parentNode.getAttribute("xml:lang");
2995−
2996− if (!w3c_slidy.lang)
2997− w3c_slidy.lang = "en";
2998− }
2999−};
3000−
3001−// hack for back button behavior
3002−if (w3c_slidy.ie6 || w3c_slidy.ie7)
3003−{
3004− document.write("<iframe id='historyFrame' " +
3005− "src='javascript:\"<html"+"></"+"html>\"' " +
3006− "height='1' width='1' " +
3007− "style='position:absolute;left:-800px'></iframe>");
3008−}
3009−
3010−// attach event listeners for initialization
3011−w3c_slidy.set_up();
3012−
3013−// hide the slides as soon as body element is available
3014−// to reduce annoying screen mess before the onload event
3015−setTimeout(w3c_slidy.hide_slides, 50);
3016−
data/slidy/styles/slidy.cssdeleted−405
@@ -1,405 +0,0 @@
1−/* slidy.css
2−
3− Copyright (c) 2005-2010 W3C (MIT, ERCIM, Keio), All Rights Reserved.
4− W3C liability, trademark, document use and software licensing
5− rules apply, see:
6−
7− http://www.w3.org/Consortium/Legal/copyright-documents
8− http://www.w3.org/Consortium/Legal/copyright-software
9−*/
10−body
11−{
12− margin: 0 0 0 0;
13− padding: 0 0 0 0;
14− width: 100%;
15− height: 100%;
16− color: black;
17− background-color: white;
18− font-family: "Gill Sans MT", "Gill Sans", GillSans, sans-serif;
19− font-size: 14pt;
20−}
21−
22−div.toolbar {
23− position: fixed; z-index: 200;
24− top: auto; bottom: 0; left: 0; right: 0;
25− height: 1.2em; text-align: right;
26− padding-left: 1em;
27− padding-right: 1em;
28− font-size: 60%;
29− color: red;
30− background-color: rgb(240,240,240);
31− border-top: solid 1px rgb(180,180,180);
32−}
33−
34−div.toolbar span.copyright {
35− color: black;
36− margin-left: 0.5em;
37−}
38−
39−div.initial_prompt {
40− position: absolute;
41− z-index: 1000;
42− bottom: 1.2em;
43− width: 100%;
44− background-color: rgb(200,200,200);
45− opacity: 0.35;
46− background-color: rgb(200,200,200, 0.35);
47− cursor: pointer;
48−}
49−
50−div.initial_prompt p.help {
51− text-align: center;
52−}
53−
54−div.initial_prompt p.close {
55− text-align: right;
56− font-style: italic;
57−}
58−
59−div.slidy_toc {
60− position: absolute;
61− z-index: 300;
62− width: 60%;
63− max-width: 30em;
64− height: 30em;
65− overflow: auto;
66− top: auto;
67− right: auto;
68− left: 4em;
69− bottom: 4em;
70− padding: 1em;
71− background: rgb(240,240,240);
72− border-style: solid;
73− border-width: 2px;
74− font-size: 60%;
75−}
76−
77−div.slidy_toc .toc_heading {
78− text-align: center;
79− width: 100%;
80− margin: 0;
81− margin-bottom: 1em;
82− border-bottom-style: solid;
83− border-bottom-color: rgb(180,180,180);
84− border-bottom-width: 1px;
85−}
86−
87−div.slide {
88− z-index: 20;
89− margin: 0 0 0 0;
90− padding-top: 0;
91− padding-bottom: 0;
92− padding-left: 20px;
93− padding-right: 20px;
94− border-width: 0;
95− clear: both;
96− top: 0;
97− bottom: 0;
98− left: 0;
99− right: 0;
100− line-height: 120%;
101− background-color: transparent;
102−}
103−
104−div.background {
105− display: none;
106−}
107−
108−div.handout {
109− margin-left: 20px;
110− margin-right: 20px;
111−}
112−
113−div.slide.titlepage {
114− text-align: center;
115−}
116−
117−div.slide.titlepage h1 {
118− padding-top: 10%;
119− margin-right: 0;
120−}
121−
122−div.slide h1 {
123− padding-left: 0;
124− padding-right: 20pt;
125− padding-top: 4pt;
126− padding-bottom: 4pt;
127− margin-top: 0;
128− margin-left: 0;
129− margin-right: 60pt;
130− margin-bottom: 0.5em;
131− display: block;
132− font-size: 160%;
133− line-height: 1.2em;
134− background: transparent;
135−}
136−
137−div.toc {
138− position: absolute;
139− top: auto;
140− bottom: 4em;
141− left: 4em;
142− right: auto;
143− width: 60%;
144− max-width: 30em;
145− height: 30em;
146− border: solid thin black;
147− padding: 1em;
148− background: rgb(240,240,240);
149− color: black;
150− z-index: 300;
151− overflow: auto;
152− display: block;
153− visibility: visible;
154−}
155−
156−div.toc-heading {
157− width: 100%;
158− border-bottom: solid 1px rgb(180,180,180);
159− margin-bottom: 1em;
160− text-align: center;
161−}
162−
163−img {
164− image-rendering: optimize-quality;
165−}
166−
167−pre {
168− font-size: 80%;
169− font-weight: bold;
170− line-height: 120%;
171− padding-top: 0.2em;
172− padding-bottom: 0.2em;
173− padding-left: 1em;
174− padding-right: 1em;
175− border-style: solid;
176− border-left-width: 1em;
177− border-top-width: thin;
178− border-right-width: thin;
179− border-bottom-width: thin;
180− border-color: #95ABD0;
181− color: #00428C;
182− background-color: #E4E5E7;
183−}
184−
185−li pre { margin-left: 0; }
186−
187−blockquote { font-style: italic }
188−
189−img { background-color: transparent }
190−
191−p.copyright { font-size: smaller }
192−
193−.center { text-align: center }
194−.footnote { font-size: smaller; margin-left: 2em; }
195−
196−a img { border-width: 0; border-style: none }
197−
198−a:visited { color: navy }
199−a:link { color: navy }
200−a:hover { color: red; text-decoration: underline }
201−a:active { color: red; text-decoration: underline }
202−
203−a {text-decoration: none}
204−.navbar a:link {color: white}
205−.navbar a:visited {color: yellow}
206−.navbar a:active {color: red}
207−.navbar a:hover {color: red}
208−
209−ul { list-style-type: square; }
210−ul ul { list-style-type: disc; }
211−ul ul ul { list-style-type: circle; }
212−ul ul ul ul { list-style-type: disc; }
213−li { margin-left: 0.5em; margin-top: 0.5em; }
214−li li { font-size: 85%; font-style: italic }
215−li li li { font-size: 85%; font-style: normal }
216−
217−div dt
218−{
219− margin-left: 0;
220− margin-top: 1em;
221− margin-bottom: 0.5em;
222− font-weight: bold;
223−}
224−div dd
225−{
226− margin-left: 2em;
227− margin-bottom: 0.5em;
228−}
229−
230−
231−p,pre,ul,ol,blockquote,h2,h3,h4,h5,h6,dl,table {
232− margin-left: 1em;
233− margin-right: 1em;
234−}
235−
236−p.subhead { font-weight: bold; margin-top: 2em; }
237−
238−.smaller { font-size: smaller }
239−.bigger { font-size: 130% }
240−
241−td,th { padding: 0.2em }
242−
243−ul {
244− margin: 0.5em 1.5em 0.5em 1.5em;
245− padding: 0;
246−}
247−
248−ol {
249− margin: 0.5em 1.5em 0.5em 1.5em;
250− padding: 0;
251−}
252−
253−ul { list-style-type: square; }
254−ul ul { list-style-type: disc; }
255−ul ul ul { list-style-type: circle; }
256−ul ul ul ul { list-style-type: disc; }
257−
258−ul li {
259− list-style: square;
260− margin: 0.1em 0em 0.6em 0;
261− padding: 0 0 0 0;
262− line-height: 140%;
263−}
264−
265−ol li {
266− margin: 0.1em 0em 0.6em 1.5em;
267− padding: 0 0 0 0px;
268− line-height: 140%;
269− list-style-type: decimal;
270−}
271−
272−li ul li {
273− font-size: 85%;
274− font-style: italic;
275− list-style-type: disc;
276− background: transparent;
277− padding: 0 0 0 0;
278−}
279−li li ul li {
280− font-size: 85%;
281− font-style: normal;
282− list-style-type: circle;
283− background: transparent;
284− padding: 0 0 0 0;
285−}
286−li li li ul li {
287− list-style-type: disc;
288− background: transparent;
289− padding: 0 0 0 0;
290−}
291−
292−li ol li {
293− list-style-type: decimal;
294−}
295−
296−
297−li li ol li {
298− list-style-type: decimal;
299−}
300−
301−/*
302− setting class="outline on ol or ul makes it behave as an
303− ouline list where blocklevel content in li elements is
304− hidden by default and can be expanded or collapsed with
305− mouse click. Set class="expand" on li to override default
306−*/
307−
308−ol.outline li:hover { cursor: pointer }
309−ol.outline li.nofold:hover { cursor: default }
310−
311−ul.outline li:hover { cursor: pointer }
312−ul.outline li.nofold:hover { cursor: default }
313−
314−ol.outline { list-style:decimal; }
315−ol.outline ol { list-style-type:lower-alpha }
316−
317−ol.outline li.nofold {
318− padding: 0 0 0 20px;
319− background: transparent url(../graphics/nofold-dim.gif) no-repeat 0px 0.5em;
320−}
321−ol.outline li.unfolded {
322− padding: 0 0 0 20px;
323− background: transparent url(../graphics/fold-dim.gif) no-repeat 0px 0.5em;
324−}
325−ol.outline li.folded {
326− padding: 0 0 0 20px;
327− background: transparent url(../graphics/unfold-dim.gif) no-repeat 0px 0.5em;
328−}
329−ol.outline li.unfolded:hover {
330− padding: 0 0 0 20px;
331− background: transparent url(../graphics/fold.gif) no-repeat 0px 0.5em;
332−}
333−ol.outline li.folded:hover {
334− padding: 0 0 0 20px;
335− background: transparent url(../graphics/unfold.gif) no-repeat 0px 0.5em;
336−}
337−
338−ul.outline li.nofold {
339− padding: 0 0 0 20px;
340− background: transparent url(../graphics/nofold-dim.gif) no-repeat 0px 0.5em;
341−}
342−ul.outline li.unfolded {
343− padding: 0 0 0 20px;
344− background: transparent url(../graphics/fold-dim.gif) no-repeat 0px 0.5em;
345−}
346−ul.outline li.folded {
347− padding: 0 0 0 20px;
348− background: transparent url(../graphics/unfold-dim.gif) no-repeat 0px 0.5em;
349−}
350−ul.outline li.unfolded:hover {
351− padding: 0 0 0 20px;
352− background: transparent url(../graphics/fold.gif) no-repeat 0px 0.5em;
353−}
354−ul.outline li.folded:hover {
355− padding: 0 0 0 20px;
356− background: transparent url(../graphics/unfold.gif) no-repeat 0px 0.5em;
357−}
358−
359−/* for slides with class "title" in table of contents */
360−a.titleslide { font-weight: bold; font-style: italic }
361−
362−/*
363− hide images for work around for save as bug
364− where browsers fail to save images used by CSS
365−*/
366−img.hidden { display: none; visibility: hidden }
367−div.initial_prompt { display: none; visibility: hidden }
368−
369− div.slide {
370− visibility: visible;
371− position: inherit;
372− }
373− div.handout {
374− border-top-style: solid;
375− border-top-width: thin;
376− border-top-color: black;
377− }
378−
379−@media screen {
380− .hidden { display: none; visibility: visible }
381−
382− div.slide.hidden { display: block; visibility: visible }
383− div.handout.hidden { display: block; visibility: visible }
384− div.background { display: none; visibility: hidden }
385− body.single_slide div.initial_prompt { display: block; visibility: visible }
386− body.single_slide div.background { display: block; visibility: visible }
387− body.single_slide div.background.hidden { display: none; visibility: hidden }
388− body.single_slide .invisible { visibility: hidden }
389− body.single_slide .hidden { display: none; visibility: hidden }
390− body.single_slide div.slide { position: absolute }
391− body.single_slide div.handout { display: none; visibility: hidden }
392−}
393−
394−@media print {
395− .hidden { display: block; visibility: visible }
396−
397− div.slide pre { font-size: 60%; padding-left: 0.5em; }
398− div.toolbar { display: none; visibility: hidden; }
399− div.slidy_toc { display: none; visibility: hidden; }
400− div.background { display: none; visibility: hidden; }
401− div.slide { page-break-before: always }
402− /* :first-child isn't reliable for print media */
403− div.slide.first-slide { page-break-before: avoid }
404−}
405−
github-upload.shnew file+18
@@ -0,0 +1,18 @@
1+#!/bin/bash
2+
3+VERSION=$1
4+FULLNAME=pandoc-$VERSION
5+read -s -p "Token (https://github.com/settings/applications): " TOKEN
6+
7+curl -H "Authorization: token $TOKEN" \
8+ -H "Accept: application/vnd.github.manifold-preview" \
9+ -H "Content-Type: application/x-apple-diskimage" \
10+ --data-binary @$FULLNAME.pkg.zip \
11+ "https://uploads.github.com/repos/jgm/pandoc/releases/$VERSION/assets?name=$FULLNAME.pkg.zip"
12+
13+curl -H "Authorization: token $TOKEN" \
14+ -H "Accept: application/vnd.github.manifold-preview" \
15+ -H "Content-Type: application/x-msi" \
16+ --data-binary @$FULLNAME.msi \
17+ "https://uploads.github.com/repos/jgm/pandoc/releases/$VERSION/assets?name=$FULLNAME.msi"
18+
googlecode-upload.sh+1−1
@@ -2,4 +2,4 @@
22VERSION=$1
33googlecode_upload.py -s "Source tarball" -p pandoc -u fiddlosopher --labels=Featured,Type-Source,OpSys-All dist/pandoc-$VERSION.tar.gz
44googlecode_upload.py -s "Windows installer" -p pandoc -u fiddlosopher --labels=Featured,Type-Installer,OpSys-Windows pandoc-$VERSION.msi
5−googlecode_upload.py -s "Mac OS X installer" -p pandoc -u fiddlosopher --labels=Featured,Type-Installer,OpSys-OSX pandoc-$VERSION.dmg
5+googlecode_upload.py -s "Mac OS X installer" -p pandoc -u fiddlosopher --labels=Featured,Type-Installer,OpSys-OSX pandoc-$VERSION.pkg.zip
make_osx_package.sh+49−25
@@ -1,64 +1,88 @@
1−#!/bin/sh -e
1+#!/bin/bash -e
22
3−DIST=osx_package
3+DIST=`pwd`/osx_package
4+SANDBOX=`pwd`/.cabal-sandbox
45VERSION=$(grep -e '^Version' pandoc.cabal | awk '{print $2}')
56RESOURCES=$DIST/Resources
67ROOT=$DIST/pandoc
7−SCRIPTS=osx-resources
8+DEST=$ROOT/usr/local
9+OSX=osx
10+SCRIPTS=$OSX/osx-resources
811BASE=pandoc-$VERSION
9−ME=jgm
12+ME=$(whoami)
1013CODESIGNID="Developer ID Application: John Macfarlane"
11−PACKAGEMAKER=/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker
14+PACKAGEMAKER=/Applications/PackageMaker.app/Contents/MacOS/PackageMaker
15+EXES="pandoc pandoc-citeproc"
16+
17+read -s -p "sudo password: " PASSWORD
18+echo $PASSWORD | sudo -S echo "Password valid, continuing."
1219
1320echo Removing old files...
1421rm -rf $DIST
1522mkdir -p $RESOURCES
1623
24+cabal sandbox init
25+# echo Updating database
26+# cabal update
27+
1728echo Building pandoc...
18−cabal-dev install-deps
19−cabal-dev install --reinstall --force-reinstalls --flags="embed_data_files" citeproc-hs
20−cabal-dev configure --prefix=/usr/local --datasubdir=$BASE --docdir=/usr/local/doc/$BASE
21−cabal-dev build
22−cabal-dev copy --destdir=$ROOT
23−# remove library files
24−rm -r $ROOT/usr/local/lib
25−chown -R $ME:staff $DIST
29+cabal clean
30+# Use cpphs to avoid problems with clang cpp on ghc 7.8 osx:
31+cabal install cpphs alex happy hsb2hs
32+cabal install --ghc-options="-optl-mmacosx-version-min=10.6" --reinstall --flags="embed_data_files" --ghc-options '-pgmPcpphs -optP--cpp'
33+cabal install --ghc-options="-optl-mmacosx-version-min=10.6" --reinstall --flags="embed_data_files" pandoc-citeproc --ghc-options '-pgmPcpphs -optP--cpp'
2634
27−gzip $ROOT/usr/local/share/man/man?/*.*
35+mkdir -p $DEST/bin
36+mkdir -p $DEST/share/man/man1
37+mkdir -p $DEST/share/man/man5
38+for f in $EXES; do
39+ cp $SANDBOX/bin/$f $DEST/bin/;
40+ cp $SANDBOX/share/man/man1/$f.1 $DEST/share/man/man1/
41+done
42+cp $SANDBOX/share/man/man5/pandoc_markdown.5 $DEST/share/man/man5/
43+
44+chown -R $ME:staff $DIST
45+# gzip $DEST/share/man/man?/*.*
2846# cabal gives man pages the wrong permissions
29−chmod +r $ROOT/usr/local/share/man/man?/*.*
47+chmod +r $DEST/share/man/man?/*.*
3048
3149echo Copying license...
32−dist/build/pandoc/pandoc --data data -t rtf -s COPYING -o $RESOURCES/License.rtf
50+$SANDBOX/bin/pandoc --data data -t rtf -s COPYING -o $RESOURCES/License.rtf
3351
3452echo Signing pandoc executable...
3553
36−codesign --force --sign "$CODESIGNID" $ROOT/usr/local/bin/pandoc
54+codesign --force --sign "$CODESIGNID" $DEST/bin/pandoc
3755# make sure it's valid... returns nonzero exit code if it isn't:
38−spctl --assess --type execute $ROOT/usr/local/bin/pandoc
56+spctl --assess --type execute $DEST/bin/pandoc
3957
4058echo Creating OSX package...
59+# remove old package first
60+echo $PASSWORD | sudo -S rm -rf $BASE.pkg $BASE.dmg
4161
4262sudo $PACKAGEMAKER \
4363 --root $ROOT \
4464 --id net.johnmacfarlane.pandoc \
4565 --resources $RESOURCES \
4666 --version $VERSION \
47− --no-relocate \
4867 --scripts $SCRIPTS \
4968 --out $BASE.pkg
5069
70+ # --no-relocate
71+
5172echo Signing package...
5273
5374sudo codesign --force --sign "$CODESIGNID" $BASE.pkg
5475# make sure it's valid...
5576spctl --assess --type install $BASE.pkg
5677
57−echo Creating disk image...
78+echo Creating zip...
79+zip -9 -r $BASE-osx.zip $BASE.pkg
80+zip -9 -j -r $BASE-osx.zip $OSX/uninstall-pandoc.pl
5881
59−sudo hdiutil create "$BASE.dmg" \
60− -format UDZO -ov \
61− -volname "pandoc $VERSION" \
62− -srcfolder $BASE.pkg
63−sudo hdiutil internet-enable "$BASE.dmg"
82+# echo Creating disk image...
83+# sudo hdiutil create "$BASE.dmg" \
84+# -format UDZO -ov \
85+# -volname "pandoc $VERSION" \
86+# -srcfolder $BASE.pkg
87+# sudo hdiutil internet-enable "$BASE.dmg"
6488
man/make-pandoc-man-pages.hs+1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12-- Create pandoc.1 man and pandoc_markdown.5 man pages from README
23import Text.Pandoc
34import qualified Text.Pandoc.UTF8 as UTF8
osx-resources/InstallationCheck → osx/osx-resources/InstallationCheckrenamed

The content is the same.

osx-resources/InstallationCheck.strings → osx/osx-resources/InstallationCheck.stringsrenamed

The content is the same.

osx/uninstall-pandoc.plnew file+79
@@ -0,0 +1,79 @@
1+#!/usr/bin/perl
2+
3+# Script to remove all files installed by the OSX pandoc installer
4+# and unregister the package. Modified from a script contributed
5+# by Daniel T. Staal.
6+
7+use warnings;
8+use strict;
9+
10+use File::Spec;
11+
12+# The main info: this is the list of files to remove and the pkg_id.
13+my $pkg_id = 'net.johnmacfarlane.pandoc';
14+
15+# Find which, if any, volume Pandoc is installed on.
16+my $volume;
17+
18+# First check /, then other volumes on the box.
19+my $cur_test = `pkgutil --pkgs=$pkg_id`;
20+if ( $cur_test =~ m/$pkg_id/ ) {
21+ $volume = '/';
22+} else {
23+ opendir( my $dh, '/Volumes' ) or die "Can't list Volumes: $!\n";
24+ foreach my $dir ( readdir($dh) ) {
25+ next if $dir =~ m/^\./; # Skip dotfiles.
26+
27+ my $path = File::Spec->rel2abs( $dir, '/Volumes' );
28+ next if !( -d $path ); # Skip anything that isn't a directory.
29+
30+ my $cur_test = `pkgutil --pkgs=$pkg_id --volume '$path'`;
31+ if ( $cur_test =~ m/$pkg_id/ ) {
32+ $volume = $path;
33+ last;
34+ }
35+ }
36+}
37+
38+die "Pandoc not installed.\n" if !( defined($volume) );
39+
40+# Get the list of files to remove.
41+my @pkg_files = `pkgutil --volume '$volume' --only-files --files '$pkg_id'`;
42+@pkg_files = map { chomp; File::Spec->rel2abs($_, $volume) } @pkg_files;
43+
44+# Confirm uninistall with the user.
45+print "The following files will be deleted:\n\n";
46+print join("\n", @pkg_files);
47+print "\n\n";
48+print "Do you want to proceed and uninstall pandoc (Y/N)?";
49+my $input = <STDIN>;
50+
51+if ($input =~ m/^[Yy]/) {
52+
53+ # Actually remove the files.
54+ foreach my $file (@pkg_files) {
55+ if ( -e $file ) {
56+ if ( system( 'sudo', 'rm', $file ) == 0 ) {
57+ warn "Deleted $file\n";
58+ } else {
59+ warn "Unable to delete $file: $?\n";
60+ die "Aborting Uninstall.\n";
61+ }
62+ } else {
63+ warn "File $file does not exist. Skipping.\n";
64+ }
65+ }
66+
67+ # Clean up the install.
68+ if (system('sudo', 'pkgutil', '--forget', $pkg_id, '--volume', $volume) != 0) {
69+ die "Unable to clean up install: $?\n";
70+ }
71+
72+} else {
73+
74+ print "OK, aborting uninstall.\n";
75+ exit;
76+}
77+
78+print "Pandoc has been successfully uninstalled.\n";
79+exit;
pandoc.cabal+104−131
@@ -1,29 +1,29 @@
11Name: pandoc
2−Version: 1.12
2+Version: 1.13
33Cabal-Version: >= 1.10
44Build-Type: Custom
55License: GPL
66License-File: COPYING
7−Copyright: (c) 2006-2013 John MacFarlane
7+Copyright: (c) 2006-2014 John MacFarlane
88Author: John MacFarlane <jgm@berkeley.edu>
99Maintainer: John MacFarlane <jgm@berkeley.edu>
1010Bug-Reports: https://github.com/jgm/pandoc/issues
1111Stability: alpha
1212Homepage: http://johnmacfarlane.net/pandoc
1313Category: Text
14−Tested-With: GHC == 7.4.2, GHC == 7.6.1
14+Tested-With: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.2
1515Synopsis: Conversion between markup formats
1616Description: Pandoc is a Haskell library for converting from one markup
1717 format to another, and a command-line tool that uses
1818 this library. It can read markdown and (subsets of) HTML,
1919 reStructuredText, LaTeX, DocBook, MediaWiki markup, Haddock
20− markup, OPML, and Textile, and it can write markdown,
21− reStructuredText, HTML, LaTeX, ConTeXt, Docbook, OPML,
20+ markup, OPML, Emacs Org-Mode, and Textile, and it can write
21+ markdown, reStructuredText, HTML, LaTeX, ConTeXt, Docbook, OPML,
2222 OpenDocument, ODT, Word docx, RTF, MediaWiki, DokuWiki, Textile,
2323 groff man pages, plain text, Emacs Org-Mode, AsciiDoc,
24− EPUB (v2 and v3), FictionBook2, and several kinds of
25− HTML/javascript slide shows (S5, Slidy, Slideous, DZSlides,
26− reveal.js).
24+ Haddock markup, EPUB (v2 and v3), FictionBook2,
25+ InDesign ICML, and several kinds of HTML/javascript
26+ slide shows (S5, Slidy, Slideous, DZSlides, reveal.js).
2727 .
2828 Pandoc extends standard markdown syntax with footnotes,
2929 embedded LaTeX, definition lists, tables, and other
@@ -45,12 +45,13 @@ Data-Files:
4545 data/templates/default.docbook,
4646 data/templates/default.beamer,
4747 data/templates/default.opendocument,
48+ data/templates/default.icml,
4849 data/templates/default.opml,
49− data/templates/default.latex,
50+ data/templates/default.latex,
5051 data/templates/default.context,
51− data/templates/default.texinfo,
52+ data/templates/default.texinfo,
5253 data/templates/default.man,
53− data/templates/default.markdown,
54+ data/templates/default.markdown,
5455 data/templates/default.rst,
5556 data/templates/default.plain,
5657 data/templates/default.mediawiki,
@@ -60,7 +61,8 @@ Data-Files:
6061 data/templates/default.slideous,
6162 data/templates/default.revealjs,
6263 data/templates/default.dzslides,
63− data/templates/default.asciidoc,
64+ data/templates/default.asciidoc,
65+ data/templates/default.haddock,
6466 data/templates/default.textile,
6567 data/templates/default.org,
6668 data/templates/default.epub,
@@ -74,38 +76,15 @@ Data-Files:
7476 -- data for LaTeXMathML writer
7577 data/LaTeXMathML.js,
7678 data/MathMLinHTML.js,
77− -- data for S5 writer
78− data/s5/default/slides.js,
79− data/s5/default/s5-core.css,
80− data/s5/default/framing.css,
81− data/s5/default/pretty.css,
82− data/s5/default/opera.css,
83− data/s5/default/outline.css,
84− data/s5/default/print.css,
85− data/s5/default/slides.css,
86− data/s5/default/iepngfix.htc,
87− data/s5/default/blank.gif,
88− data/s5/default/bodybg.gif,
89− -- data for slidy writer
90− data/slidy/styles/slidy.css,
91− data/slidy/scripts/slidy.js,
92− data/slidy/graphics/fold.gif,
93− data/slidy/graphics/unfold.gif,
94− data/slidy/graphics/nofold-dim.gif,
95− data/slidy/graphics/unfold-dim.gif,
96− data/slidy/graphics/fold-dim.gif,
97− -- data for slideous writer
98− data/slideous/slideous.css,
99− data/slideous/slideous.js,
10079 -- data for dzslides writer
10180 data/dzslides/template.html,
102− -- data for citeproc
103− data/default.csl,
10481 -- sample lua custom writer
10582 data/sample.lua
10683 -- documentation
107− README, INSTALL, COPYRIGHT, BUGS, CONTRIBUTING.md, changelog
84+ README, COPYRIGHT
10885Extra-Source-Files:
86+ -- documentation
87+ INSTALL, BUGS, CONTRIBUTING.md, changelog
10988 -- code to create pandoc.1 man page
11089 man/man1/pandoc.1.template,
11190 man/man5/pandoc_markdown.5.template,
@@ -118,17 +97,13 @@ Extra-Source-Files:
11897 tests/docbook-reader.native
11998 tests/html-reader.html,
12099 tests/html-reader.native,
121− tests/opml-reader.html,
100+ tests/opml-reader.opml,
122101 tests/opml-reader.native,
123− tests/haddock-reader.html,
102+ tests/haddock-reader.haddock,
124103 tests/haddock-reader.native,
125104 tests/insert,
126105 tests/lalune.jpg,
127106 tests/movie.jpg,
128− tests/biblio.bib,
129− tests/chicago-author-date.csl,
130− tests/ieee.csl,
131− tests/mhra.csl,
132107 tests/latex-reader.latex,
133108 tests/latex-reader.native,
134109 tests/textile-reader.textile,
@@ -136,9 +111,7 @@ Extra-Source-Files:
136111 tests/markdown-reader-more.txt,
137112 tests/markdown-reader-more.native,
138113 tests/markdown-citations.txt,
139− tests/markdown-citations.chicago-author-date.txt,
140− tests/markdown-citations.mhra.txt,
141− tests/markdown-citations.ieee.txt,
114+ tests/markdown-citations.native,
142115 tests/textile-reader.textile,
143116 tests/mediawiki-reader.wiki,
144117 tests/mediawiki-reader.native,
@@ -162,6 +135,7 @@ Extra-Source-Files:
162135 tests/tables.opendocument,
163136 tests/tables.org,
164137 tests/tables.asciidoc,
138+ tests/tables.haddock,
165139 tests/tables.texinfo,
166140 tests/tables.rst,
167141 tests/tables.rtf,
@@ -183,6 +157,7 @@ Extra-Source-Files:
183157 tests/writer.opendocument,
184158 tests/writer.org,
185159 tests/writer.asciidoc,
160+ tests/writer.haddock,
186161 tests/writer.rst,
187162 tests/writer.rtf,
188163 tests/writer.texinfo,
@@ -212,7 +187,25 @@ Extra-Source-Files:
212187 tests/fb2.math.markdown,
213188 tests/fb2.math.fb2,
214189 tests/fb2.test-small.png,
215− tests/fb2.test.jpg
190+ tests/fb2.test.jpg,
191+ tests/docx.block_quotes.docx,
192+ tests/docx.block_quotes_parse_indent.native,
193+ tests/docx.headers.docx,
194+ tests/docx.headers.native,
195+ tests/docx.image.docx,
196+ tests/docx.image_no_embed.native,
197+ tests/docx.inline_formatting.docx,
198+ tests/docx.inline_formatting.native,
199+ tests/docx.links.docx,
200+ tests/docx.links.native,
201+ tests/docx.lists.docx,
202+ tests/docx.lists.native,
203+ tests/docx.notes.docx,
204+ tests/docx.notes.native,
205+ tests/docx.tables.docx,
206+ tests/docx.tables.native,
207+ tests/docx.unicode.docx,
208+ tests/docx.unicode.native
216209Extra-Tmp-Files: man/man1/pandoc.1,
217210 man/man5/pandoc_markdown.5
218211
@@ -224,8 +217,8 @@ Flag embed_data_files
224217 Description: Embed data files in binary for relocatable executable.
225218 Default: False
226219
227−Flag http-conduit
228− Description: Enable downloading of resources over https.
220+Flag https
221+ Description: Enable support for downloading of resources over https.
229222 Default: True
230223
231224Library
@@ -233,60 +226,54 @@ Library
233226 syb >= 0.1 && < 0.5,
234227 containers >= 0.1 && < 0.6,
235228 unordered-containers >= 0.2 && < 0.3,
236− array >= 0.3 && < 0.5,
229+ array >= 0.3 && < 0.6,
237230 parsec >= 3.1 && < 3.2,
238− mtl >= 1.1 && < 2.2,
239− network >= 2 && < 2.5,
231+ mtl >= 1.1 && < 2.3,
232+ network >= 2 && < 2.6,
240233 filepath >= 1.1 && < 1.4,
241− process >= 1 && < 1.2,
234+ process >= 1 && < 1.3,
242235 directory >= 1 && < 1.3,
243236 bytestring >= 0.9 && < 0.11,
244− text >= 0.11 && < 0.12,
245− zip-archive >= 0.1.3.3 && < 0.2,
237+ text >= 0.11 && < 1.2,
238+ zip-archive >= 0.2.3.2 && < 0.3,
246239 old-locale >= 1 && < 1.1,
247240 time >= 1.2 && < 1.5,
248241 HTTP >= 4000.0.5 && < 4000.3,
249− texmath >= 0.6.1.5 && < 0.7,
242+ texmath >= 0.6.6.3 && < 0.7,
250243 xml >= 1.3.12 && < 1.4,
251244 random >= 1 && < 1.1,
252245 extensible-exceptions >= 0.1 && < 0.2,
253− citeproc-hs >= 0.3.7 && < 0.4,
254− pandoc-types >= 1.12 && < 1.13,
255− aeson >= 0.6 && < 0.7,
256− tagsoup >= 0.12.5 && < 0.13,
246+ pandoc-types >= 1.12.3.3 && < 1.13,
247+ aeson >= 0.7 && < 0.8,
248+ tagsoup >= 0.13.1 && < 0.14,
257249 base64-bytestring >= 0.1 && < 1.1,
258250 zlib >= 0.5 && < 0.6,
259− highlighting-kate >= 0.5.4 && < 0.6,
251+ highlighting-kate >= 0.5.8.3 && < 0.6,
260252 data-default >= 0.4 && < 0.6,
261− temporary >= 1.1 && < 1.2,
262− blaze-html >= 0.5 && < 0.7,
263− blaze-markup >= 0.5.1 && < 0.6,
264− attoparsec >= 0.10 && < 0.11,
265− stringable >= 0.1 && < 0.2,
266− yaml >= 0.8.3 && < 0.9,
253+ temporary >= 1.1 && < 1.3,
254+ blaze-html >= 0.5 && < 0.8,
255+ blaze-markup >= 0.5.1 && < 0.7,
256+ yaml >= 0.8.8.2 && < 0.9,
257+ scientific >= 0.2 && < 0.4,
267258 vector >= 0.10 && < 0.11,
268− hslua >= 0.3 && < 0.4
269− if flag(http-conduit)
270− Build-Depends: http-conduit >= 1.9 && < 1.10,
259+ hslua >= 0.3 && < 0.4,
260+ binary >= 0.5 && < 0.8,
261+ SHA >= 1.6 && < 1.7,
262+ haddock-library >= 1.1 && < 1.2
263+ if flag(https)
264+ Build-Depends: http-client >= 0.3.2 && < 0.4,
265+ http-client-tls >= 0.2 && < 0.3,
271266 http-types >= 0.8 && < 0.9
272− cpp-options: -DHTTP_CONDUIT
267+ cpp-options: -DHTTP_CLIENT
273268 if flag(embed_data_files)
274269 cpp-options: -DEMBED_DATA_FILES
275− -- build-tools: hsb2hs
270+ -- Build-Tools: hsb2hs -- not yet recognized by cabal
276271 other-modules: Text.Pandoc.Data
277− if impl(ghc >= 7.0.1)
278− Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
279− else
280− if impl(ghc >= 6.12)
281− Ghc-Options: -Wall -fno-warn-unused-do-bind
282− else
283− Ghc-Options: -Wall
284− if impl(ghc >= 7.0.1)
285− Ghc-Prof-Options: -auto-all -caf-all -rtsopts
286− else
287− Ghc-Prof-Options: -auto-all -caf-all
272+ if os(windows)
273+ Cpp-options: -D_WINDOWS
274+ Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
275+ Ghc-Prof-Options: -auto-all -caf-all -rtsopts
288276 Default-Language: Haskell98
289− Default-Extensions: CPP
290277 Other-Extensions: PatternGuards, OverloadedStrings,
291278 ScopedTypeVariables, GeneralizedNewtypeDeriving,
292279 RelaxedPolyRec, DeriveDataTypeable, TypeSynonymInstances,
@@ -302,22 +289,26 @@ Library
302289 Text.Pandoc.Readers.Markdown,
303290 Text.Pandoc.Readers.MediaWiki,
304291 Text.Pandoc.Readers.RST,
292+ Text.Pandoc.Readers.Org,
305293 Text.Pandoc.Readers.DocBook,
306294 Text.Pandoc.Readers.OPML,
307295 Text.Pandoc.Readers.TeXMath,
308296 Text.Pandoc.Readers.Textile,
309297 Text.Pandoc.Readers.Native,
310298 Text.Pandoc.Readers.Haddock,
299+ Text.Pandoc.Readers.Docx,
311300 Text.Pandoc.Writers.Native,
312301 Text.Pandoc.Writers.Docbook,
313302 Text.Pandoc.Writers.OPML,
314303 Text.Pandoc.Writers.HTML,
304+ Text.Pandoc.Writers.ICML,
315305 Text.Pandoc.Writers.LaTeX,
316306 Text.Pandoc.Writers.ConTeXt,
317307 Text.Pandoc.Writers.OpenDocument,
318308 Text.Pandoc.Writers.Texinfo,
319309 Text.Pandoc.Writers.Man,
320310 Text.Pandoc.Writers.Markdown,
311+ Text.Pandoc.Writers.Haddock,
321312 Text.Pandoc.Writers.RST,
322313 Text.Pandoc.Writers.Org,
323314 Text.Pandoc.Writers.AsciiDoc,
@@ -334,10 +325,11 @@ Library
334325 Text.Pandoc.UTF8,
335326 Text.Pandoc.Templates,
336327 Text.Pandoc.XML,
337− Text.Pandoc.Biblio,
338− Text.Pandoc.SelfContained
339− Other-Modules: Text.Pandoc.Readers.Haddock.Lex,
340− Text.Pandoc.Readers.Haddock.Parse,
328+ Text.Pandoc.SelfContained,
329+ Text.Pandoc.Process
330+ Other-Modules: Text.Pandoc.Readers.Docx.Lists,
331+ Text.Pandoc.Readers.Docx.Reducible,
332+ Text.Pandoc.Readers.Docx.Parse,
341333 Text.Pandoc.Writers.Shared,
342334 Text.Pandoc.Asciify,
343335 Text.Pandoc.MIME,
@@ -346,37 +338,32 @@ Library
346338 Text.Pandoc.ImageSize,
347339 Text.Pandoc.Slides,
348340 Text.Pandoc.Highlighting,
341+ Text.Pandoc.Compat.Monoid,
342+ Text.Pandoc.Compat.TagSoupEntity,
349343 Paths_pandoc
350344
351345 Buildable: True
352346
353347Executable pandoc
354348 Build-Depends: pandoc,
349+ pandoc-types >= 1.12.3.3 && < 1.13,
355350 base >= 4.2 && <5,
356351 directory >= 1 && < 1.3,
357352 filepath >= 1.1 && < 1.4,
358− network >= 2 && < 2.5,
359− text >= 0.11 && < 0.12,
353+ network >= 2 && < 2.6,
354+ text >= 0.11 && < 1.2,
360355 bytestring >= 0.9 && < 0.11,
361356 extensible-exceptions >= 0.1 && < 0.2,
362− highlighting-kate >= 0.5.4 && < 0.6,
363− HTTP >= 4000.0.5 && < 4000.3,
364− citeproc-hs >= 0.3.7 && < 0.4
365− if impl(ghc >= 7.0.1)
366− Ghc-Options: -rtsopts -with-rtsopts=-K16m -Wall -fno-warn-unused-do-bind
367− else
368− if impl(ghc >= 6.12)
369− Ghc-Options: -Wall -fno-warn-unused-do-bind
370− else
371− Ghc-Options: -Wall
372− if impl(ghc >= 7.0.1)
373− Ghc-Prof-Options: -auto-all -caf-all -rtsopts -with-rtsopts=-K16m
374− else
375− Ghc-Prof-Options: -auto-all -caf-all
357+ highlighting-kate >= 0.5.8.3 && < 0.6,
358+ aeson >= 0.7.0.5 && < 0.8,
359+ yaml >= 0.8.8.2 && < 0.9,
360+ containers >= 0.1 && < 0.6,
361+ HTTP >= 4000.0.5 && < 4000.3
362+ Ghc-Options: -rtsopts -with-rtsopts=-K16m -Wall -fno-warn-unused-do-bind
363+ Ghc-Prof-Options: -auto-all -caf-all -rtsopts -with-rtsopts=-K16m
376364 if os(windows)
377365 Cpp-options: -D_WINDOWS
378366 Default-Language: Haskell98
379− Default-Extensions: CPP
380367 Other-Extensions: PatternGuards, OverloadedStrings,
381368 ScopedTypeVariables, GeneralizedNewtypeDeriving,
382369 RelaxedPolyRec, DeriveDataTypeable, TypeSynonymInstances,
@@ -396,7 +383,6 @@ Executable make-pandoc-man-pages
396383 old-time >= 1.0 && < 1.2,
397384 time >= 1.2 && < 1.5
398385 Default-Language: Haskell98
399− Default-Extensions: CPP
400386
401387Test-Suite test-pandoc
402388 Type: exitcode-stdio-1.0
@@ -405,18 +391,18 @@ Test-Suite test-pandoc
405391 Build-Depends: base >= 4.2 && < 5,
406392 syb >= 0.1 && < 0.5,
407393 pandoc,
408− pandoc-types >= 1.12 && < 1.13,
394+ pandoc-types >= 1.12.3.3 && < 1.13,
409395 bytestring >= 0.9 && < 0.11,
410− text >= 0.11 && < 0.12,
396+ text >= 0.11 && < 1.2,
411397 directory >= 1 && < 1.3,
412398 filepath >= 1.1 && < 1.4,
413− process >= 1 && < 1.2,
414− highlighting-kate >= 0.5.4 && < 0.6,
399+ process >= 1 && < 1.3,
400+ highlighting-kate >= 0.5.8.3 && < 0.6,
415401 Diff >= 0.2 && < 0.4,
416402 test-framework >= 0.3 && < 0.9,
417403 test-framework-hunit >= 0.2 && < 0.4,
418404 test-framework-quickcheck2 >= 0.2.9 && < 0.4,
419− QuickCheck >= 2.4 && < 2.7,
405+ QuickCheck >= 2.4 && < 2.8,
420406 HUnit >= 1.2 && < 1.3,
421407 containers >= 0.1 && < 0.6,
422408 ansi-terminal >= 0.5 && < 0.7
@@ -424,27 +410,20 @@ Test-Suite test-pandoc
424410 Tests.Helpers
425411 Tests.Arbitrary
426412 Tests.Shared
413+ Tests.Walk
427414 Tests.Readers.LaTeX
428415 Tests.Readers.Markdown
416+ Tests.Readers.Org
429417 Tests.Readers.RST
418+ Tests.Readers.Docx
430419 Tests.Writers.Native
431420 Tests.Writers.ConTeXt
432421 Tests.Writers.HTML
433422 Tests.Writers.Markdown
423+ Tests.Writers.AsciiDoc
434424 Tests.Writers.LaTeX
435− if impl(ghc >= 7.0.1)
436− Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
437− else
438− if impl(ghc >= 6.12)
439− Ghc-Options: -Wall -fno-warn-unused-do-bind
440− else
441− Ghc-Options: -Wall
442− if impl(ghc >= 7)
443− cpp-options: -D_LIT=lit
444− else
445− cpp-options: -D_LIT=$lit
425+ Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
446426 Default-Language: Haskell98
447− Default-Extensions: CPP
448427
449428benchmark benchmark-pandoc
450429 Type: exitcode-stdio-1.0
@@ -454,11 +433,5 @@ benchmark benchmark-pandoc
454433 base >= 4.2 && < 5,
455434 syb >= 0.1 && < 0.5,
456435 criterion >= 0.5 && < 0.9
457− if impl(ghc >= 7.0.1)
458− Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
459− else
460− if impl(ghc >= 6.12)
461− Ghc-Options: -Wall -fno-warn-unused-do-bind
462− else
463− Ghc-Options: -Wall
436+ Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
464437 Default-Language: Haskell98
pandoc.hs+231−124
@@ -1,6 +1,6 @@
11{-# LANGUAGE CPP #-}
22{-
3−Copyright (C) 2006-2013 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Main
22− Copyright : Copyright (C) 2006-2013 John MacFarlane
22+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley@edu>
@@ -31,12 +31,15 @@ writers.
3131-}
3232module Main where
3333import Text.Pandoc
34−import Text.Pandoc.PDF (tex2pdf)
34+import Text.Pandoc.Builder (setMeta)
35+import Text.Pandoc.PDF (makePDF)
3536import Text.Pandoc.Readers.LaTeX (handleIncludes)
36−import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, safeRead,
37− headerShift, normalize, err, warn )
38−import Text.Pandoc.XML ( toEntities, fromEntities )
37+import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile,
38+ safeRead, headerShift, normalize, err, warn,
39+ openURL )
40+import Text.Pandoc.XML ( toEntities )
3941import Text.Pandoc.SelfContained ( makeSelfContained )
42+import Text.Pandoc.Process (pipeProcess)
4043import Text.Highlighting.Kate ( languages, Style, tango, pygments,
4144 espresso, zenburn, kate, haddock, monochrome )
4245import System.Environment ( getArgs, getProgName )
@@ -44,29 +47,34 @@ import System.Exit ( exitWith, ExitCode (..) )
4447import System.FilePath
4548import System.Console.GetOpt
4649import Data.Char ( toLower )
47−import Data.List ( intercalate, isPrefixOf, sort )
48−import System.Directory ( getAppUserDataDirectory, doesFileExist, findExecutable )
49−import System.IO ( stdout )
50+import Data.List ( intercalate, isPrefixOf, isSuffixOf, sort )
51+import System.Directory ( getAppUserDataDirectory, findExecutable,
52+ doesFileExist )
53+import System.IO ( stdout, stderr )
5054import System.IO.Error ( isDoesNotExistError )
5155import qualified Control.Exception as E
5256import Control.Exception.Extensible ( throwIO )
5357import qualified Text.Pandoc.UTF8 as UTF8
54−import qualified Text.CSL as CSL
5558import Control.Monad (when, unless, liftM)
56−import Network.HTTP (simpleHTTP, mkRequest, getResponseBody, RequestMethod(..))
59+import Data.Foldable (foldrM)
5760import Network.URI (parseURI, isURI, URI(..))
5861import qualified Data.ByteString.Lazy as B
59−import Text.CSL.Reference (Reference(..))
62+import qualified Data.ByteString as BS
63+import Data.Aeson (eitherDecode', encode)
64+import qualified Data.Map as M
65+import Data.Yaml (decode)
66+import qualified Data.Yaml as Yaml
67+import qualified Data.Text as T
6068
6169copyrightMessage :: String
62−copyrightMessage = "\nCopyright (C) 2006-2013 John MacFarlane\n" ++
70+copyrightMessage = "\nCopyright (C) 2006-2014 John MacFarlane\n" ++
6371 "Web: http://johnmacfarlane.net/pandoc\n" ++
6472 "This is free software; see the source for copying conditions. There is no\n" ++
6573 "warranty, not even for merchantability or fitness for a particular purpose."
6674
6775compileInfo :: String
6876compileInfo =
69− "\nCompiled with citeproc-hs " ++ VERSION_citeproc_hs ++ ", texmath " ++
77+ "\nCompiled with texmath " ++
7078 VERSION_texmath ++ ", highlighting-kate " ++ VERSION_highlighting_kate ++
7179 ".\nSyntax highlighting is supported for the following languages:\n " ++
7280 wrapWords 4 78
@@ -86,6 +94,35 @@ wrapWords indent c = wrap' (c - indent) (c - indent)
8694isTextFormat :: String -> Bool
8795isTextFormat s = takeWhile (`notElem` "+-") s `notElem` ["odt","docx","epub","epub3"]
8896
97+externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc
98+externalFilter f args' d = do
99+ mbexe <- if '/' `elem` f -- don't check PATH if filter name it has a path
100+ then return Nothing
101+ else findExecutable f
102+ (f', args'') <- case mbexe of
103+ Just x -> return (x, args')
104+ Nothing -> do
105+ exists <- doesFileExist f
106+ if exists
107+ then return $
108+ case map toLower $ takeExtension f of
109+ ".py" -> ("python", f:args')
110+ ".hs" -> ("runhaskell", f:args')
111+ ".pl" -> ("perl", f:args')
112+ ".rb" -> ("ruby", f:args')
113+ ".php" -> ("php", f:args')
114+ _ -> (f, args')
115+ else err 85 $ "Filter " ++ f ++ " not found"
116+ (exitcode, outbs, errbs) <- E.handle filterException $
117+ pipeProcess Nothing f' args'' $ encode d
118+ when (not $ B.null errbs) $ B.hPutStr stderr errbs
119+ case exitcode of
120+ ExitSuccess -> return $ either error id $ eitherDecode' outbs
121+ ExitFailure _ -> err 83 $ "Error running filter " ++ f
122+ where filterException :: E.SomeException -> IO a
123+ filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++
124+ show e
125+
89126-- | Data structure for command line options.
90127data Opt = Opt
91128 { optTabStop :: Int -- ^ Number of spaces per tab
@@ -98,6 +135,7 @@ data Opt = Opt
98135 , optTransforms :: [Pandoc -> Pandoc] -- ^ Doc transforms to apply
99136 , optTemplate :: Maybe FilePath -- ^ Custom template
100137 , optVariables :: [(String,String)] -- ^ Template variables to set
138+ , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set
101139 , optOutputFile :: String -- ^ Name of output file
102140 , optNumberSections :: Bool -- ^ Number sections in LaTeX
103141 , optNumberOffset :: [Int] -- ^ Starting number for sections
@@ -124,15 +162,12 @@ data Opt = Opt
124162 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
125163 , optWrapText :: Bool -- ^ Wrap text
126164 , optColumns :: Int -- ^ Line length in characters
127− , optPlugins :: [Pandoc -> IO Pandoc] -- ^ Plugins to apply
165+ , optFilters :: [FilePath] -- ^ Filters to apply
128166 , optEmailObfuscation :: ObfuscationMethod
129167 , optIdentifierPrefix :: String
130168 , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
131169 , optDataDir :: Maybe FilePath
132170 , optCiteMethod :: CiteMethod -- ^ Method to output cites
133− , optBibliography :: [String]
134− , optCslFile :: Maybe FilePath
135− , optAbbrevsFile :: Maybe FilePath
136171 , optListings :: Bool -- ^ Use listings package for code blocks
137172 , optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
138173 , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
@@ -140,6 +175,8 @@ data Opt = Opt
140175 , optAscii :: Bool -- ^ Use ascii characters only in html
141176 , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes
142177 , optDefaultImageExtension :: String -- ^ Default image extension
178+ , optTrace :: Bool -- ^ Print debug information
179+ , optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes.
143180 }
144181
145182-- | Defaults for command-line options.
@@ -155,6 +192,7 @@ defaultOpts = Opt
155192 , optTransforms = []
156193 , optTemplate = Nothing
157194 , optVariables = []
195+ , optMetadata = M.empty
158196 , optOutputFile = "-" -- "-" means stdout
159197 , optNumberSections = False
160198 , optNumberOffset = [0,0,0,0,0,0]
@@ -181,15 +219,12 @@ defaultOpts = Opt
181219 , optReferenceLinks = False
182220 , optWrapText = True
183221 , optColumns = 72
184− , optPlugins = []
222+ , optFilters = []
185223 , optEmailObfuscation = JavascriptObfuscation
186224 , optIdentifierPrefix = ""
187225 , optIndentedCodeClasses = []
188226 , optDataDir = Nothing
189227 , optCiteMethod = Citeproc
190− , optBibliography = []
191− , optCslFile = Nothing
192− , optAbbrevsFile = Nothing
193228 , optListings = False
194229 , optLaTeXEngine = "pdflatex"
195230 , optSlideLevel = Nothing
@@ -197,6 +232,8 @@ defaultOpts = Opt
197232 , optAscii = False
198233 , optTeXLigatures = True
199234 , optDefaultImageExtension = ""
235+ , optTrace = False
236+ , optTrackChanges = AcceptChanges
200237 }
201238
202239-- | A list of functions, each transforming the options data structure
@@ -205,13 +242,13 @@ options :: [OptDescr (Opt -> IO Opt)]
205242options =
206243 [ Option "fr" ["from","read"]
207244 (ReqArg
208− (\arg opt -> return opt { optReader = map toLower arg })
245+ (\arg opt -> return opt { optReader = arg })
209246 "FORMAT")
210247 ""
211248
212249 , Option "tw" ["to","write"]
213250 (ReqArg
214− (\arg opt -> return opt { optWriter = map toLower arg })
251+ (\arg opt -> return opt { optWriter = arg })
215252 "FORMAT")
216253 ""
217254
@@ -272,6 +309,12 @@ options =
272309 "STRING")
273310 "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
274311
312+ , Option "F" ["filter"]
313+ (ReqArg
314+ (\arg opt -> return opt { optFilters = arg : optFilters opt })
315+ "PROGRAM")
316+ "" -- "External JSON filter"
317+
275318 , Option "" ["normalize"]
276319 (NoArg
277320 (\opt -> return opt { optTransforms =
@@ -306,6 +349,17 @@ options =
306349 "FILENAME")
307350 "" -- "Use custom template"
308351
352+ , Option "M" ["metadata"]
353+ (ReqArg
354+ (\arg opt -> do
355+ let (key,val) = case break (`elem` ":=") arg of
356+ (k,_:v) -> (k, readMetaValue v)
357+ (k,_) -> (k, MetaBool True)
358+ return opt{ optMetadata = addMetadata key val
359+ $ optMetadata opt })
360+ "KEY[:VALUE]")
361+ ""
362+
309363 , Option "V" ["variable"]
310364 (ReqArg
311365 (\arg opt -> do
@@ -314,7 +368,7 @@ options =
314368 (k,_) -> (k,"true")
315369 return opt{ optVariables = (key,val) : optVariables opt })
316370 "KEY[:VALUE]")
317− "" -- "Use custom template"
371+ ""
318372
319373 , Option "D" ["print-default-template"]
320374 (ReqArg
@@ -327,13 +381,13 @@ options =
327381 "FORMAT")
328382 "" -- "Print default template for FORMAT"
329383
330− , Option "" ["print-sample-lua-writer"]
331− (NoArg
332− (\_ -> do
333− sample <- readDataFileUTF8 Nothing "sample.lua"
334− UTF8.hPutStr stdout sample
335− exitWith ExitSuccess))
336− "" -- "Print sample lua custom writer"
384+ , Option "" ["print-default-data-file"]
385+ (ReqArg
386+ (\arg _ -> do
387+ readDataFile Nothing arg >>= BS.hPutStr stdout
388+ exitWith ExitSuccess)
389+ "FILE")
390+ "" -- "Print default data file"
337391
338392 , Option "" ["no-wrap"]
339393 (NoArg
@@ -424,8 +478,6 @@ options =
424478 , Option "" ["self-contained"]
425479 (NoArg
426480 (\opt -> return opt { optSelfContained = True,
427− optVariables = ("slidy-url","slidy") :
428− optVariables opt,
429481 optStandalone = True }))
430482 "" -- "Make slide shows include all the needed js and css"
431483
@@ -621,7 +673,7 @@ options =
621673 (ReqArg
622674 (\arg opt -> do
623675 let b = takeBaseName arg
624− if (b == "pdflatex" || b == "lualatex" || b == "xelatex")
676+ if b `elem` ["pdflatex", "lualatex", "xelatex"]
625677 then return opt { optLaTeXEngine = arg }
626678 else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.")
627679 "PROGRAM")
@@ -629,20 +681,33 @@ options =
629681
630682 , Option "" ["bibliography"]
631683 (ReqArg
632− (\arg opt -> return opt { optBibliography = (optBibliography opt) ++ [arg] })
633− "FILENAME")
684+ (\arg opt -> return opt{ optMetadata = addMetadata
685+ "bibliography" (readMetaValue arg)
686+ $ optMetadata opt
687+ , optVariables =
688+ ("biblio-files", dropExtension arg) :
689+ optVariables opt
690+ })
691+ "FILE")
634692 ""
635693
636− , Option "" ["csl"]
694+ , Option "" ["csl"]
637695 (ReqArg
638− (\arg opt -> return opt { optCslFile = Just arg })
639− "FILENAME")
696+ (\arg opt ->
697+ return opt{ optMetadata = addMetadata "csl"
698+ (readMetaValue arg)
699+ $ optMetadata opt })
700+ "FILE")
640701 ""
641702
642− , Option "" ["citation-abbreviations"]
703+ , Option "" ["citation-abbreviations"]
643704 (ReqArg
644− (\arg opt -> return opt { optAbbrevsFile = Just arg })
645− "FILENAME")
705+ (\arg opt ->
706+ return opt{ optMetadata = addMetadata
707+ "citation-abbreviations"
708+ (readMetaValue arg)
709+ $ optMetadata opt })
710+ "FILE")
646711 ""
647712
648713 , Option "" ["natbib"]
@@ -710,6 +775,24 @@ options =
710775 (\opt -> return opt { optHTMLMathMethod = GladTeX }))
711776 "" -- "Use gladtex for HTML math"
712777
778+ , Option "" ["trace"]
779+ (NoArg
780+ (\opt -> return opt { optTrace = True }))
781+ "" -- "Turn on diagnostic tracing in readers."
782+
783+ , Option "" ["track-changes"]
784+ (ReqArg
785+ (\arg opt -> do
786+ action <- case arg of
787+ "accept" -> return AcceptChanges
788+ "reject" -> return RejectChanges
789+ "all" -> return AllChanges
790+ _ -> err 6
791+ ("Unknown option for track-changes: " ++ arg)
792+ return opt { optTrackChanges = action })
793+ "accept|reject|all")
794+ "" -- "Accepting or reject MS Word track-changes.""
795+
713796 , Option "" ["dump-args"]
714797 (NoArg
715798 (\opt -> return opt { optDumpArgs = True }))
@@ -741,6 +824,20 @@ options =
741824
742825 ]
743826
827+addMetadata :: String -> MetaValue -> M.Map String MetaValue
828+ -> M.Map String MetaValue
829+addMetadata k v m = case M.lookup k m of
830+ Nothing -> M.insert k v m
831+ Just (MetaList xs) -> M.insert k
832+ (MetaList (xs ++ [v])) m
833+ Just x -> M.insert k (MetaList [v, x]) m
834+
835+readMetaValue :: String -> MetaValue
836+readMetaValue s = case decode (UTF8.fromString s) of
837+ Just (Yaml.String t) -> MetaString $ T.unpack t
838+ Just (Yaml.Bool b) -> MetaBool b
839+ _ -> MetaString s
840+
744841-- Returns usage message
745842usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
746843usageMessage programName = usageInfo
@@ -765,6 +862,7 @@ defaultReaderName fallback (x:xs) =
765862 ".latex" -> "latex"
766863 ".ltx" -> "latex"
767864 ".rst" -> "rst"
865+ ".org" -> "org"
768866 ".lhs" -> "markdown+lhs"
769867 ".db" -> "docbook"
770868 ".opml" -> "opml"
@@ -773,6 +871,7 @@ defaultReaderName fallback (x:xs) =
773871 ".textile" -> "textile"
774872 ".native" -> "native"
775873 ".json" -> "json"
874+ ".docx" -> "docx"
776875 _ -> defaultReaderName fallback xs
777876
778877-- Returns True if extension of first source is .lhs
@@ -848,6 +947,7 @@ main = do
848947 , optWriter = writerName
849948 , optParseRaw = parseRaw
850949 , optVariables = variables
950+ , optMetadata = metadata
851951 , optTableOfContents = toc
852952 , optTransforms = transforms
853953 , optTemplate = templatePath
@@ -877,13 +977,11 @@ main = do
877977 , optReferenceLinks = referenceLinks
878978 , optWrapText = wrap
879979 , optColumns = columns
980+ , optFilters = filters
880981 , optEmailObfuscation = obfuscationMethod
881982 , optIdentifierPrefix = idPrefix
882983 , optIndentedCodeClasses = codeBlockClasses
883984 , optDataDir = mbDataDir
884− , optBibliography = reffiles
885− , optCslFile = mbCsl
886− , optAbbrevsFile = cslabbrevs
887985 , optCiteMethod = citeMethod
888986 , optListings = listings
889987 , optLaTeXEngine = latexEngine
@@ -892,6 +990,8 @@ main = do
892990 , optAscii = ascii
893991 , optTeXLigatures = texLigatures
894992 , optDefaultImageExtension = defaultImageExtension
993+ , optTrace = trace
994+ , optTrackChanges = trackChanges
895995 } = opts
896996
897997 when dumpArgs $
@@ -899,6 +999,15 @@ main = do
899999 mapM_ (\arg -> UTF8.hPutStrLn stdout arg) args
9001000 exitWith ExitSuccess
9011001
1002+ -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
1003+ let filters' = case M.lookup "bibliography" metadata of
1004+ Just _ | optCiteMethod opts /= Natbib &&
1005+ optCiteMethod opts /= Biblatex &&
1006+ all (\f -> takeBaseName f /= "pandoc-citeproc")
1007+ filters -> "pandoc-citeproc" : filters
1008+ _ -> filters
1009+ let plugins = map externalFilter filters'
1010+
9021011 let sources = if ignoreArgs then [] else args
9031012
9041013 datadir <- case mbDataDir of
@@ -909,33 +1018,37 @@ main = do
9091018 Just _ -> return mbDataDir
9101019
9111020 -- assign reader and writer based on options and filenames
912− let readerName' = if null readerName
913− then let fallback = if any isURI sources
914− then "html"
915− else "markdown"
916− in defaultReaderName fallback sources
917− else readerName
918−
919− let writerName' = if null writerName
920− then defaultWriterName outputFile
921− else writerName
1021+ let readerName' = case map toLower readerName of
1022+ [] -> defaultReaderName
1023+ (if any isURI sources
1024+ then "html"
1025+ else "markdown") sources
1026+ "html4" -> "html"
1027+ x -> x
1028+
1029+ let writerName' = case map toLower writerName of
1030+ [] -> defaultWriterName outputFile
1031+ "epub2" -> "epub"
1032+ "html4" -> "html"
1033+ x -> x
9221034
9231035 let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
9241036
9251037 let laTeXOutput = "latex" `isPrefixOf` writerName' ||
9261038 "beamer" `isPrefixOf` writerName'
9271039
928− when pdfOutput $ do
929− -- make sure writer is latex or beamer
930− unless laTeXOutput $
931− err 47 $ "cannot produce pdf output with " ++ writerName' ++ " writer"
932− -- check for latex program
933− mbLatex <- findExecutable latexEngine
934− case mbLatex of
935− Nothing -> err 41 $
936− latexEngine ++ " not found. " ++
937− latexEngine ++ " is needed for pdf output."
938− Just _ -> return ()
1040+ writer <- if ".lua" `isSuffixOf` writerName'
1041+ -- note: use non-lowercased version writerName
1042+ then return $ IOStringWriter $ writeCustom writerName
1043+ else case getWriter writerName' of
1044+ Left e -> err 9 $
1045+ if writerName' == "pdf"
1046+ then e ++ "\nTo create a pdf with pandoc, use " ++
1047+ "the latex or beamer writer and specify\n" ++
1048+ "an output file with .pdf extension " ++
1049+ "(pandoc -t latex -o filename.pdf)."
1050+ else e
1051+ Right w -> return w
9391052
9401053 reader <- case getReader readerName' of
9411054 Right r -> return r
@@ -967,12 +1080,10 @@ main = do
9671080
9681081 variables' <- case mathMethod of
9691082 LaTeXMathML Nothing -> do
970− s <- readDataFileUTF8 datadir
971− ("LaTeXMathML.js")
1083+ s <- readDataFileUTF8 datadir "LaTeXMathML.js"
9721084 return $ ("mathml-script", s) : variables
9731085 MathML Nothing -> do
974− s <- readDataFileUTF8 datadir
975− ("MathMLinHTML.js")
1086+ s <- readDataFileUTF8 datadir "MathMLinHTML.js"
9761087 return $ ("mathml-script", s) : variables
9771088 _ -> return variables
9781089
@@ -984,43 +1095,15 @@ main = do
9841095 $ lines dztempl
9851096 return $ ("dzslides-core", dzcore) : variables'
9861097 else return variables'
987−
988− -- unescape reference ids, which may contain XML entities, so
989− -- that we can do lookups with regular string equality
990− let unescapeRefId ref = ref{ refId = fromEntities (refId ref) }
991−
992− refs <- mapM (\f -> E.catch (CSL.readBiblioFile f)
993− (\e -> let _ = (e :: E.SomeException)
994− in err 23 $ "Error reading bibliography `" ++ f ++
995− "'" ++ "\n" ++ show e))
996− reffiles >>=
997− return . map unescapeRefId . concat
998−
999− mbsty <- if citeMethod == Citeproc && not (null refs)
1000− then do
1001− csl <- CSL.parseCSL =<<
1002− case mbCsl of
1003− Nothing -> readDataFileUTF8 datadir
1004− "default.csl"
1005− Just cslfile -> do
1006− exists <- doesFileExist cslfile
1007− if exists
1008− then UTF8.readFile cslfile
1009− else do
1010− csldir <- getAppUserDataDirectory "csl"
1011− readDataFileUTF8 (Just csldir)
1012− (replaceExtension cslfile "csl")
1013− abbrevs <- maybe (return []) CSL.readJsonAbbrevFile cslabbrevs
1014− return $ Just csl { CSL.styleAbbrevs = abbrevs }
1015− else return Nothing
1016−
1017− let sourceDir = case sources of
1018− [] -> "."
1098+ let sourceURL = case sources of
1099+ [] -> Nothing
10191100 (x:_) -> case parseURI x of
10201101 Just u
10211102 | uriScheme u `elem` ["http:","https:"] ->
1022− show u{ uriPath = "", uriQuery = "", uriFragment = "" }
1023− _ -> takeDirectory x
1103+ Just $ show u{ uriPath = "",
1104+ uriQuery = "",
1105+ uriFragment = "" }
1106+ _ -> Nothing
10241107
10251108 let readerOpts = def{ readerSmart = smart || (texLigatures &&
10261109 (laTeXOutput || "context" `isPrefixOf` writerName'))
@@ -1029,11 +1112,11 @@ main = do
10291112 , readerColumns = columns
10301113 , readerTabStop = tabStop
10311114 , readerOldDashes = oldDashes
1032− , readerReferences = refs
1033− , readerCitationStyle = mbsty
10341115 , readerIndentedCodeClasses = codeBlockClasses
10351116 , readerApplyMacros = not laTeXOutput
10361117 , readerDefaultImageExtension = defaultImageExtension
1118+ , readerTrace = trace
1119+ , readerTrackChanges = trackChanges
10371120 }
10381121
10391122 let writerOptions = def { writerStandalone = standalone',
@@ -1044,7 +1127,6 @@ main = do
10441127 writerHTMLMathMethod = mathMethod,
10451128 writerIncremental = incremental,
10461129 writerCiteMethod = citeMethod,
1047− writerBiblioFiles = reffiles,
10481130 writerIgnoreNotes = False,
10491131 writerNumberSections = numberSections,
10501132 writerNumberOffset = numberFrom,
@@ -1054,7 +1136,7 @@ main = do
10541136 writerColumns = columns,
10551137 writerEmailObfuscation = obfuscationMethod,
10561138 writerIdentifierPrefix = idPrefix,
1057− writerSourceDirectory = sourceDir,
1139+ writerSourceURL = sourceURL,
10581140 writerUserDataDir = datadir,
10591141 writerHtml5 = html5,
10601142 writerHtmlQTags = htmlQTags,
@@ -1084,10 +1166,16 @@ main = do
10841166 readSource "-" = UTF8.getContents
10851167 readSource src = case parseURI src of
10861168 Just u | uriScheme u `elem` ["http:","https:"] ->
1087− readURI u
1169+ readURI src
10881170 _ -> UTF8.readFile src
1089− readURI uri = simpleHTTP (mkRequest GET uri) >>= getResponseBody >>=
1090− return . UTF8.toStringLazy -- treat all as UTF8
1171+ readURI src = do
1172+ res <- openURL src
1173+ case res of
1174+ Left e -> throwIO e
1175+ Right (bs,_) -> return $ UTF8.toString bs
1176+
1177+ let readFiles [] = error "Cannot read archive from stdin"
1178+ readFiles (x:_) = B.readFile x
10911179
10921180 let convertTabs = tabFilter (if preserveTabs then 0 else tabStop)
10931181
@@ -1095,11 +1183,17 @@ main = do
10951183 then handleIncludes
10961184 else return
10971185
1098− doc <- readSources sources >>=
1099− handleIncludes' . convertTabs . intercalate "\n" >>=
1100− reader readerOpts
1186+ doc <- case reader of
1187+ StringReader r->
1188+ readSources sources >>=
1189+ handleIncludes' . convertTabs . intercalate "\n" >>=
1190+ r readerOpts
1191+ ByteStringReader r -> readFiles sources >>= r readerOpts
1192+
11011193
1102− let doc0 = foldr ($) doc transforms
1194+ let doc0 = M.foldWithKey setMeta doc metadata
1195+ let doc1 = foldr ($) doc0 transforms
1196+ doc2 <- foldrM ($) doc1 $ map ($ [writerName']) plugins
11031197
11041198 let writeBinary :: B.ByteString -> IO ()
11051199 writeBinary = B.writeFile (UTF8.encodePath outputFile)
@@ -1108,17 +1202,30 @@ main = do
11081202 writerFn "-" = UTF8.putStr
11091203 writerFn f = UTF8.writeFile f
11101204
1111− case getWriter writerName' of
1112− Left e -> err 9 e
1113− Right (IOStringWriter f) -> f writerOptions doc0 >>= writerFn outputFile
1114− Right (IOByteStringWriter f) -> f writerOptions doc0 >>= writeBinary
1115− Right (PureStringWriter f)
1205+ case writer of
1206+ IOStringWriter f -> f writerOptions doc2 >>= writerFn outputFile
1207+ IOByteStringWriter f -> f writerOptions doc2 >>= writeBinary
1208+ PureStringWriter f
11161209 | pdfOutput -> do
1117− res <- tex2pdf latexEngine $ f writerOptions doc0
1210+ -- make sure writer is latex or beamer
1211+ unless laTeXOutput $
1212+ err 47 $ "cannot produce pdf output with " ++ writerName' ++
1213+ " writer"
1214+
1215+ -- check for latex program
1216+ mbLatex <- findExecutable latexEngine
1217+ when (mbLatex == Nothing) $
1218+ err 41 $ latexEngine ++ " not found. " ++
1219+ latexEngine ++ " is needed for pdf output."
1220+
1221+ res <- makePDF latexEngine f writerOptions doc2
11181222 case res of
11191223 Right pdf -> writeBinary pdf
1120− Left err' -> err 43 $ UTF8.toStringLazy err'
1121− | otherwise -> selfcontain (f writerOptions doc0 ++
1224+ Left err' -> do
1225+ B.hPutStr stderr $ err'
1226+ B.hPut stderr $ B.pack [10]
1227+ err 43 "Error producing PDF from TeX source"
1228+ | otherwise -> selfcontain (f writerOptions doc2 ++
11221229 ['\n' | not standalone'])
11231230 >>= writerFn outputFile . handleEntities
11241231 where htmlFormat = writerName' `elem`
src/Text/Pandoc.hs+86−106
@@ -1,6 +1,6 @@
11{-# LANGUAGE ScopedTypeVariables, FlexibleInstances #-}
22{-
3−Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Text.Pandoc
22− Copyright : Copyright (C) 2006-2010 John MacFarlane
22+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -62,9 +62,12 @@ module Text.Pandoc
6262 , readers
6363 , writers
6464 -- * Readers: converting /to/ Pandoc format
65+ , Reader (..)
66+ , readDocx
6567 , readMarkdown
6668 , readMediaWiki
6769 , readRST
70+ , readOrg
6871 , readLaTeX
6972 , readHtml
7073 , readTextile
@@ -72,9 +75,11 @@ module Text.Pandoc
7275 , readOPML
7376 , readHaddock
7477 , readNative
78+ , readJSON
7579 -- * Writers: converting /from/ Pandoc format
7680 , Writer (..)
7781 , writeNative
82+ , writeJSON
7883 , writeMarkdown
7984 , writePlain
8085 , writeRST
@@ -83,6 +88,7 @@ module Text.Pandoc
8388 , writeTexinfo
8489 , writeHtml
8590 , writeHtmlString
91+ , writeICML
8692 , writeDocbook
8793 , writeOPML
8894 , writeOpenDocument
@@ -97,6 +103,7 @@ module Text.Pandoc
97103 , writeFB2
98104 , writeOrg
99105 , writeAsciiDoc
106+ , writeHaddock
100107 , writeCustom
101108 -- * Rendering templates and default templates
102109 , module Text.Pandoc.Templates
@@ -105,15 +112,16 @@ module Text.Pandoc
105112 -- * Miscellaneous
106113 , getReader
107114 , getWriter
108− , jsonFilter
109115 , ToJsonFilter(..)
110116 ) where
111117
112118import Text.Pandoc.Definition
113119import Text.Pandoc.Generic
120+import Text.Pandoc.JSON
114121import Text.Pandoc.Readers.Markdown
115122import Text.Pandoc.Readers.MediaWiki
116123import Text.Pandoc.Readers.RST
124+import Text.Pandoc.Readers.Org
117125import Text.Pandoc.Readers.DocBook
118126import Text.Pandoc.Readers.OPML
119127import Text.Pandoc.Readers.LaTeX
@@ -121,6 +129,7 @@ import Text.Pandoc.Readers.HTML
121129import Text.Pandoc.Readers.Textile
122130import Text.Pandoc.Readers.Native
123131import Text.Pandoc.Readers.Haddock
132+import Text.Pandoc.Readers.Docx
124133import Text.Pandoc.Writers.Native
125134import Text.Pandoc.Writers.Markdown
126135import Text.Pandoc.Writers.RST
@@ -132,6 +141,7 @@ import Text.Pandoc.Writers.ODT
132141import Text.Pandoc.Writers.Docx
133142import Text.Pandoc.Writers.EPUB
134143import Text.Pandoc.Writers.FB2
144+import Text.Pandoc.Writers.ICML
135145import Text.Pandoc.Writers.Docbook
136146import Text.Pandoc.Writers.OPML
137147import Text.Pandoc.Writers.OpenDocument
@@ -142,17 +152,16 @@ import Text.Pandoc.Writers.DokuWiki
142152import Text.Pandoc.Writers.Textile
143153import Text.Pandoc.Writers.Org
144154import Text.Pandoc.Writers.AsciiDoc
155+import Text.Pandoc.Writers.Haddock
145156import Text.Pandoc.Writers.Custom
146157import Text.Pandoc.Templates
147158import Text.Pandoc.Options
148159import Text.Pandoc.Shared (safeRead, warn)
149−import Data.ByteString.Lazy (ByteString)
160+import Data.Aeson
150161import qualified Data.ByteString.Lazy as BL
151−import Data.List (intercalate, isSuffixOf)
162+import Data.List (intercalate)
152163import Data.Version (showVersion)
153−import Data.Aeson.Generic
154164import Data.Set (Set)
155−import Data.Data
156165import qualified Data.Set as Set
157166import Text.Parsec
158167import Text.Parsec.Error
@@ -190,45 +199,56 @@ markdown o s = do
190199 mapM_ warn warnings
191200 return doc
192201
202+data Reader = StringReader (ReaderOptions -> String -> IO Pandoc)
203+ | ByteStringReader (ReaderOptions -> BL.ByteString -> IO Pandoc)
204+
205+mkStringReader :: (ReaderOptions -> String -> Pandoc) -> Reader
206+mkStringReader r = StringReader (\o s -> return $ r o s)
207+
208+mkBSReader :: (ReaderOptions -> BL.ByteString -> Pandoc) -> Reader
209+mkBSReader r = ByteStringReader (\o s -> return $ r o s)
210+
193211-- | Association list of formats and readers.
194−readers :: [(String, ReaderOptions -> String -> IO Pandoc)]
195−readers = [("native" , \_ s -> return $ readNative s)
196− ,("json" , \_ s -> return $ checkJSON
197− $ decode $ UTF8.fromStringLazy s)
198− ,("markdown" , markdown)
199− ,("markdown_strict" , markdown)
200− ,("markdown_phpextra" , markdown)
201− ,("markdown_github" , markdown)
202− ,("markdown_mmd", markdown)
203− ,("rst" , \o s -> return $ readRST o s)
204− ,("mediawiki" , \o s -> return $ readMediaWiki o s)
205− ,("docbook" , \o s -> return $ readDocBook o s)
206− ,("opml" , \o s -> return $ readOPML o s)
207− ,("textile" , \o s -> return $ readTextile o s) -- TODO : textile+lhs
208− ,("html" , \o s -> return $ readHtml o s)
209− ,("latex" , \o s -> return $ readLaTeX o s)
210− ,("haddock" , \o s -> return $ readHaddock o s)
211− ]
212+readers :: [(String, Reader)]
213+readers = [ ("native" , StringReader $ \_ s -> return $ readNative s)
214+ ,("json" , mkStringReader readJSON )
215+ ,("markdown" , StringReader markdown)
216+ ,("markdown_strict" , StringReader markdown)
217+ ,("markdown_phpextra" , StringReader markdown)
218+ ,("markdown_github" , StringReader markdown)
219+ ,("markdown_mmd", StringReader markdown)
220+ ,("rst" , mkStringReader readRST )
221+ ,("mediawiki" , mkStringReader readMediaWiki)
222+ ,("docbook" , mkStringReader readDocBook)
223+ ,("opml" , mkStringReader readOPML)
224+ ,("org" , mkStringReader readOrg)
225+ ,("textile" , mkStringReader readTextile) -- TODO : textile+lhs
226+ ,("html" , mkStringReader readHtml)
227+ ,("latex" , mkStringReader readLaTeX)
228+ ,("haddock" , mkStringReader readHaddock)
229+ ,("docx" , mkBSReader readDocx)
230+ ]
212231
213232data Writer = PureStringWriter (WriterOptions -> Pandoc -> String)
214233 | IOStringWriter (WriterOptions -> Pandoc -> IO String)
215− | IOByteStringWriter (WriterOptions -> Pandoc -> IO ByteString)
234+ | IOByteStringWriter (WriterOptions -> Pandoc -> IO BL.ByteString)
216235
217236-- | Association list of formats and writers.
218237writers :: [ ( String, Writer ) ]
219238writers = [
220239 ("native" , PureStringWriter writeNative)
221− ,("json" , PureStringWriter $ \_ -> UTF8.toStringLazy . encode)
240+ ,("json" , PureStringWriter writeJSON)
222241 ,("docx" , IOByteStringWriter writeDocx)
223− ,("odt" , IOByteStringWriter writeODT)
224− ,("epub" , IOByteStringWriter $ \o ->
242+ ,("odt" , IOByteStringWriter writeODT)
243+ ,("epub" , IOByteStringWriter $ \o ->
225244 writeEPUB o{ writerEpubVersion = Just EPUB2 })
226− ,("epub3" , IOByteStringWriter $ \o ->
245+ ,("epub3" , IOByteStringWriter $ \o ->
227246 writeEPUB o{ writerEpubVersion = Just EPUB3 })
228247 ,("fb2" , IOStringWriter writeFB2)
229248 ,("html" , PureStringWriter writeHtmlString)
230249 ,("html5" , PureStringWriter $ \o ->
231250 writeHtmlString o{ writerHtml5 = True })
251+ ,("icml" , PureStringWriter writeICML)
232252 ,("s5" , PureStringWriter $ \o ->
233253 writeHtmlString o{ writerSlideVariant = S5Slides
234254 , writerTableOfContents = False })
@@ -264,6 +284,7 @@ writers = [
264284 ,("rtf" , IOStringWriter writeRTFWithEmbeddedImages)
265285 ,("org" , PureStringWriter writeOrg)
266286 ,("asciidoc" , PureStringWriter writeAsciiDoc)
287+ ,("haddock" , PureStringWriter writeHaddock)
267288 ]
268289
269290getDefaultExtensions :: String -> Set Extension
@@ -271,94 +292,53 @@ getDefaultExtensions "markdown_strict" = strictExtensions
271292getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
272293getDefaultExtensions "markdown_mmd" = multimarkdownExtensions
273294getDefaultExtensions "markdown_github" = githubMarkdownExtensions
274−getDefaultExtensions _ = pandocExtensions
295+getDefaultExtensions "markdown" = pandocExtensions
296+getDefaultExtensions "plain" = pandocExtensions
297+getDefaultExtensions "org" = Set.fromList [Ext_citations]
298+getDefaultExtensions "textile" = Set.fromList [Ext_auto_identifiers, Ext_raw_tex]
299+getDefaultExtensions _ = Set.fromList [Ext_auto_identifiers]
275300
276301-- | Retrieve reader based on formatSpec (format+extensions).
277−getReader :: String -> Either String (ReaderOptions -> String -> IO Pandoc)
302+getReader :: String -> Either String Reader
278303getReader s =
279304 case parseFormatSpec s of
280305 Left e -> Left $ intercalate "\n" $ [m | Message m <- errorMessages e]
281− Right (readerName, setExts) ->
306+ Right (readerName, setExts) ->
282307 case lookup readerName readers of
283308 Nothing -> Left $ "Unknown reader: " ++ readerName
284− Just r -> Right $ \o ->
309+ Just (StringReader r) -> Right $ StringReader $ \o ->
310+ r o{ readerExtensions = setExts $
311+ getDefaultExtensions readerName }
312+ Just (ByteStringReader r) -> Right $ ByteStringReader $ \o ->
285313 r o{ readerExtensions = setExts $
286314 getDefaultExtensions readerName }
287315
288316-- | Retrieve writer based on formatSpec (format+extensions).
289317getWriter :: String -> Either String Writer
290−getWriter s =
291− case parseFormatSpec s of
292− Left e -> Left $ intercalate "\n" $ [m | Message m <- errorMessages e]
293− Right (writerName, setExts) ->
294− case lookup writerName writers of
295− Nothing
296− | ".lua" `isSuffixOf` s ->
297− Right $ IOStringWriter $ writeCustom s
298− | otherwise -> Left $ "Unknown writer: " ++ writerName
299− Just (PureStringWriter r) -> Right $ PureStringWriter $
300− \o -> r o{ writerExtensions = setExts $
301− getDefaultExtensions writerName }
302− Just (IOStringWriter r) -> Right $ IOStringWriter $
303− \o -> r o{ writerExtensions = setExts $
304− getDefaultExtensions writerName }
305− Just (IOByteStringWriter r) -> Right $ IOByteStringWriter $
306− \o -> r o{ writerExtensions = setExts $
307− getDefaultExtensions writerName }
308−
309−{-# DEPRECATED jsonFilter "Use toJsonFilter instead" #-}
310−-- | Converts a transformation on the Pandoc AST into a function
311−-- that reads and writes a JSON-encoded string. This is useful
312−-- for writing small scripts.
313−jsonFilter :: (Pandoc -> Pandoc) -> String -> String
314−jsonFilter f = UTF8.toStringLazy . encode . f . checkJSON . decode . UTF8.fromStringLazy
315−
316−-- | 'toJsonFilter' convert a function into a filter that reads pandoc's json output
317−-- from stdin, transforms it by walking the AST and applying the specified
318−-- function, and writes the result as json to stdout. Usage example:
319−--
320−-- > -- capitalize.hs
321−-- > -- compile with: ghc --make capitalize
322−-- > -- run with: pandoc -t json | ./capitalize | pandoc -f json
323−-- >
324−-- > import Text.Pandoc
325−-- > import Data.Char (toUpper)
326−-- >
327−-- > main :: IO ()
328−-- > main = toJsonFilter capitalizeStrings
329−-- >
330−-- > capitalizeStrings :: Inline -> Inline
331−-- > capitalizeStrings (Str s) = Str $ map toUpper s
332−-- > capitalizeStrings x = x
333−--
334−-- The function can be any type @(a -> a)@, @(a -> IO a)@, @(a -> [a])@,
335−-- or @(a -> IO [a])@, where @a@ is an instance of 'Data'.
336−-- So, for example, @a@ can be 'Pandoc', 'Inline', 'Block', ['Inline'],
337−-- ['Block'], 'Meta', 'ListNumberStyle', 'Alignment', 'ListNumberDelim',
338−-- 'QuoteType', etc. See 'Text.Pandoc.Definition'.
339−class ToJsonFilter a where
340− toJsonFilter :: a -> IO ()
341−
342−instance (Data a) => ToJsonFilter (a -> a) where
343− toJsonFilter f = BL.getContents >>=
344− BL.putStr . encode . (bottomUp f :: Pandoc -> Pandoc) . checkJSON . decode
345−
346−instance (Data a) => ToJsonFilter (a -> IO a) where
347− toJsonFilter f = BL.getContents >>=
348− (bottomUpM f :: Pandoc -> IO Pandoc) . checkJSON . decode >>=
349− BL.putStr . encode
318+getWriter s
319+ = case parseFormatSpec s of
320+ Left e -> Left $ intercalate "\n" $ [m | Message m <- errorMessages e]
321+ Right (writerName, setExts) ->
322+ case lookup writerName writers of
323+ Nothing -> Left $ "Unknown writer: " ++ writerName
324+ Just (PureStringWriter r) -> Right $ PureStringWriter $
325+ \o -> r o{ writerExtensions = setExts $
326+ getDefaultExtensions writerName }
327+ Just (IOStringWriter r) -> Right $ IOStringWriter $
328+ \o -> r o{ writerExtensions = setExts $
329+ getDefaultExtensions writerName }
330+ Just (IOByteStringWriter r) -> Right $ IOByteStringWriter $
331+ \o -> r o{ writerExtensions = setExts $
332+ getDefaultExtensions writerName }
350333
351−instance (Data a) => ToJsonFilter (a -> [a]) where
352− toJsonFilter f = BL.getContents >>=
353− BL.putStr . encode . (bottomUp (concatMap f) :: Pandoc -> Pandoc) .
354− checkJSON . decode
334+{-# DEPRECATED toJsonFilter "Use 'toJSONFilter' from 'Text.Pandoc.JSON' instead" #-}
335+-- | Deprecated. Use @toJSONFilter@ from @Text.Pandoc.JSON@ instead.
336+class ToJSONFilter a => ToJsonFilter a
337+ where toJsonFilter :: a -> IO ()
338+ toJsonFilter = toJSONFilter
355339
356−instance (Data a) => ToJsonFilter (a -> IO [a]) where
357− toJsonFilter f = BL.getContents >>=
358− (bottomUpM (fmap concat . mapM f) :: Pandoc -> IO Pandoc)
359− . checkJSON . decode >>=
360− BL.putStr . encode
340+readJSON :: ReaderOptions -> String -> Pandoc
341+readJSON _ = either error id . eitherDecode' . UTF8.fromStringLazy
361342
362−checkJSON :: Maybe a -> a
363−checkJSON Nothing = error "Error parsing JSON"
364−checkJSON (Just r) = r
343+writeJSON :: WriterOptions -> Pandoc -> String
344+writeJSON _ = UTF8.toStringLazy . encode
src/Text/Pandoc/Asciify.hs+2−2
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2013 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2013-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.SelfContained
21− Copyright : Copyright (C) 2013 John MacFarlane
21+ Copyright : Copyright (C) 2013-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
src/Text/Pandoc/Biblio.hsdeleted−187
@@ -1,187 +0,0 @@
1−{-# LANGUAGE PatternGuards #-}
2−{-
3−Copyright (C) 2008 Andrea Rossato <andrea.rossato@ing.unitn.it>
4−
5−This program is free software; you can redistribute it and/or modify
6−it under the terms of the GNU General Public License as published by
7−the Free Software Foundation; either version 2 of the License, or
8−(at your option) any later version.
9−
10−This program is distributed in the hope that it will be useful,
11−but WITHOUT ANY WARRANTY; without even the implied warranty of
12−MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13−GNU General Public License for more details.
14−
15−You should have received a copy of the GNU General Public License
16−along with this program; if not, write to the Free Software
17−Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18−-}
19−
20−{- |
21− Module : Text.Pandoc.Biblio
22− Copyright : Copyright (C) 2008-2010 Andrea Rossato
23− License : GNU GPL, version 2 or above
24−
25− Maintainer : Andrea Rossato <andrea.rossato@unitn.it>
26− Stability : alpha
27− Portability : portable
28−-}
29−
30−module Text.Pandoc.Biblio ( processBiblio ) where
31−
32−import Data.List
33−import Data.Char ( isDigit, isPunctuation )
34−import qualified Data.Map as M
35−import Text.CSL hiding ( Cite(..), Citation(..) )
36−import qualified Text.CSL as CSL ( Cite(..) )
37−import Text.Pandoc.Definition
38−import Text.Pandoc.Generic
39−import Text.Pandoc.Shared (stringify)
40−import Text.Parsec hiding (State)
41−import Control.Monad
42−import Control.Monad.State
43−
44−-- | Process a 'Pandoc' document by adding citations formatted
45−-- according to a CSL style, using 'citeproc' from citeproc-hs.
46−processBiblio :: Maybe Style -> [Reference] -> Pandoc -> Pandoc
47−processBiblio Nothing _ p = p
48−processBiblio _ [] p = p
49−processBiblio (Just style) r p =
50− let p' = evalState (bottomUpM setHash p) 1
51− grps = queryWith getCitation p'
52− result = citeproc procOpts style r (setNearNote style $
53− map (map toCslCite) grps)
54− cits_map = M.fromList $ zip grps (citations result)
55− biblioList = map (renderPandoc' style) (bibliography result)
56− Pandoc m b = bottomUp mvPunct . deNote . bottomUp (processCite style cits_map) $ p'
57− in Pandoc m $ b ++ biblioList
58−
59−-- | Substitute 'Cite' elements with formatted citations.
60−processCite :: Style -> M.Map [Citation] [FormattedOutput] -> Inline -> Inline
61−processCite s cs (Cite t _) =
62− case M.lookup t cs of
63− Just (x:xs)
64− | isTextualCitation t && not (null xs) ->
65− let xs' = renderPandoc s xs
66− in if styleClass s == "note"
67− then Cite t (renderPandoc s [x] ++ [Note [Para xs']])
68− else Cite t (renderPandoc s [x] ++ [Space | not (startWithPunct xs')] ++ xs')
69− | otherwise -> if styleClass s == "note"
70− then Cite t [Note [Para $ renderPandoc s (x:xs)]]
71− else Cite t (renderPandoc s (x:xs))
72− _ -> Strong [Str "???"] -- TODO raise error instead?
73−processCite _ _ x = x
74−
75−isNote :: Inline -> Bool
76−isNote (Note _) = True
77−isNote (Cite _ [Note _]) = True
78−isNote _ = False
79−
80−mvPunct :: [Inline] -> [Inline]
81−mvPunct (Space : Space : xs) = Space : xs
82−mvPunct (Space : x : ys) | isNote x, startWithPunct ys =
83− Str (headInline ys) : x : tailFirstInlineStr ys
84−mvPunct (Space : x : ys) | isNote x = x : ys
85−mvPunct xs = xs
86−
87−sanitize :: [Inline] -> [Inline]
88−sanitize xs | endWithPunct xs = toCapital xs
89− | otherwise = toCapital (xs ++ [Str "."])
90−
91−deNote :: Pandoc -> Pandoc
92−deNote = topDown go
93− where go (Note [Para xs]) = Note $ bottomUp go' [Para $ sanitize xs]
94− go (Note xs) = Note $ bottomUp go' xs
95− go x = x
96− go' (Note [Para xs]:ys) =
97− if startWithPunct ys && endWithPunct xs
98− then initInline xs ++ ys
99− else xs ++ ys
100− go' xs = xs
101−
102−isTextualCitation :: [Citation] -> Bool
103−isTextualCitation (c:_) = citationMode c == AuthorInText
104−isTextualCitation _ = False
105−
106−-- | Retrieve all citations from a 'Pandoc' docuument. To be used with
107−-- 'queryWith'.
108−getCitation :: Inline -> [[Citation]]
109−getCitation i | Cite t _ <- i = [t]
110− | otherwise = []
111−
112−setHash :: Citation -> State Int Citation
113−setHash c = do
114− ident <- get
115− put $ ident + 1
116− return c{ citationHash = ident }
117−
118−toCslCite :: Citation -> CSL.Cite
119−toCslCite c
120− = let (l, s) = locatorWords $ citationSuffix c
121− (la,lo) = parseLocator l
122− s' = case (l,s,citationMode c) of
123− -- treat a bare locator as if it begins with comma
124− -- so @item1 [blah] is like [@item1, blah]
125− ("",(x:_),AuthorInText) | not (isPunct x)
126− -> [Str ",",Space] ++ s
127− _ -> s
128− isPunct (Str (x:_)) = isPunctuation x
129− isPunct _ = False
130− citMode = case citationMode c of
131− AuthorInText -> (True, False)
132− SuppressAuthor -> (False,True )
133− NormalCitation -> (False,False)
134− in emptyCite { CSL.citeId = citationId c
135− , CSL.citePrefix = PandocText $ citationPrefix c
136− , CSL.citeSuffix = PandocText s'
137− , CSL.citeLabel = la
138− , CSL.citeLocator = lo
139− , CSL.citeNoteNumber = show $ citationNoteNum c
140− , CSL.authorInText = fst citMode
141− , CSL.suppressAuthor = snd citMode
142− , CSL.citeHash = citationHash c
143− }
144−
145−locatorWords :: [Inline] -> (String, [Inline])
146−locatorWords inp =
147− case parse pLocatorWords "suffix" $ breakup inp of
148− Right r -> r
149− Left _ -> ("",inp)
150− where breakup [] = []
151− breakup (Str x : xs) = map Str (splitup x) ++ breakup xs
152− breakup (x : xs) = x : breakup xs
153− splitup = groupBy (\x y -> x /= '\160' && y /= '\160')
154−
155−pLocatorWords :: Parsec [Inline] st (String, [Inline])
156−pLocatorWords = do
157− l <- pLocator
158− s <- getInput -- rest is suffix
159− if length l > 0 && last l == ','
160− then return (init l, Str "," : s)
161− else return (l, s)
162−
163−pMatch :: (Inline -> Bool) -> Parsec [Inline] st Inline
164−pMatch condition = try $ do
165− t <- anyToken
166− guard $ condition t
167− return t
168−
169−pSpace :: Parsec [Inline] st Inline
170−pSpace = pMatch (\t -> t == Space || t == Str "\160")
171−
172−pLocator :: Parsec [Inline] st String
173−pLocator = try $ do
174− optional $ pMatch (== Str ",")
175− optional pSpace
176− f <- many1 (notFollowedBy pSpace >> anyToken)
177− gs <- many1 pWordWithDigits
178− return $ stringify f ++ (' ' : unwords gs)
179−
180−pWordWithDigits :: Parsec [Inline] st String
181−pWordWithDigits = try $ do
182− pSpace
183− r <- many1 (notFollowedBy pSpace >> anyToken)
184− let s = stringify r
185− guard $ any isDigit s
186− return s
187−
src/Text/Pandoc/Compat/Monoid.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE CPP #-}
2+module Text.Pandoc.Compat.Monoid ( Monoid(..)
3+ , (<>)
4+ ) where
5+
6+#if MIN_VERSION_base(4,5,0)
7+import Data.Monoid ((<>), Monoid(..))
8+#else
9+import Data.Monoid (mappend, Monoid(..))
10+#endif
11+
12+#if MIN_VERSION_base(4,5,0)
13+#else
14+infixr 6 <>
15+
16+-- | An infix synonym for 'mappend'.
17+(<>) :: Monoid m => m -> m -> m
18+(<>) = mappend
19+{-# INLINE (<>) #-}
20+#endif
src/Text/Pandoc/Compat/TagSoupEntity.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE CPP #-}
2+module Text.Pandoc.Compat.TagSoupEntity (lookupEntity
3+ ) where
4+
5+import qualified Text.HTML.TagSoup.Entity as TE
6+
7+lookupEntity :: String -> Maybe Char
8+#if MIN_VERSION_tagsoup(0,13,0)
9+lookupEntity = str2chr . TE.lookupEntity
10+ where str2chr :: Maybe String -> Maybe Char
11+ str2chr (Just [c]) = Just c
12+ str2chr _ = Nothing
13+#else
14+lookupEntity = TE.lookupEntity
15+#endif
src/Text/Pandoc/Highlighting.hs+8−3
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2008 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2008-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.Highlighting
21− Copyright : Copyright (C) 2008 John MacFarlane
21+ Copyright : Copyright (C) 2008-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -74,7 +74,12 @@ highlight formatter (_, classes, keyvals) rawCode =
7474 ["number","numberLines", "number-lines"]) classes }
7575 lcclasses = map (map toLower) classes
7676 in case find (`elem` lcLanguages) lcclasses of
77− Nothing -> Nothing
77+ Nothing
78+ | numberLines fmtOpts -> Just
79+ $ formatter fmtOpts{ codeClasses = [],
80+ containerClasses = classes }
81+ $ map (\ln -> [(NormalTok, ln)]) $ lines rawCode
82+ | otherwise -> Nothing
7883 Just language -> Just
7984 $ formatter fmtOpts{ codeClasses = [language],
8085 containerClasses = classes }
src/Text/Pandoc/ImageSize.hs+258−9
@@ -1,6 +1,6 @@
11{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
22{-
3− Copyright (C) 2011 John MacFarlane <jgm@berkeley.edu>
3+ Copyright (C) 2011-2014 John MacFarlane <jgm@berkeley.edu>
44
55 This program is free software; you can redistribute it and/or modify
66 it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
1919
2020{- |
2121Module : Text.Pandoc.ImageSize
22−Copyright : Copyright (C) 2011 John MacFarlane
22+Copyright : Copyright (C) 2011-2014 John MacFarlane
2323License : GNU GPL, version 2 or above
2424
2525Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -32,13 +32,19 @@ module Text.Pandoc.ImageSize ( ImageType(..), imageType, imageSize,
3232 sizeInPixels, sizeInPoints ) where
3333import Data.ByteString (ByteString, unpack)
3434import qualified Data.ByteString.Char8 as B
35+import qualified Data.ByteString.Lazy as BL
36+import Control.Applicative
3537import Control.Monad
3638import Data.Bits
39+import Data.Binary
40+import Data.Binary.Get
41+import Text.Pandoc.Shared (safeRead)
42+import qualified Data.Map as M
3743
3844-- quick and dirty functions to get image sizes
3945-- algorithms borrowed from wwwis.pl
4046
41−data ImageType = Png | Gif | Jpeg | Pdf deriving Show
47+data ImageType = Png | Gif | Jpeg | Pdf | Eps deriving Show
4248
4349data ImageSize = ImageSize{
4450 pxX :: Integer
@@ -52,8 +58,12 @@ imageType :: ByteString -> Maybe ImageType
5258imageType img = case B.take 4 img of
5359 "\x89\x50\x4e\x47" -> return Png
5460 "\x47\x49\x46\x38" -> return Gif
55− "\xff\xd8\xff\xe0" -> return Jpeg
61+ "\xff\xd8\xff\xe0" -> return Jpeg -- JFIF
62+ "\xff\xd8\xff\xe1" -> return Jpeg -- Exif
5663 "%PDF" -> return Pdf
64+ "%!PS"
65+ | (B.take 4 $ B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
66+ -> return Eps
5767 _ -> fail "Unknown image type"
5868
5969imageSize :: ByteString -> Maybe ImageSize
@@ -63,14 +73,35 @@ imageSize img = do
6373 Png -> pngSize img
6474 Gif -> gifSize img
6575 Jpeg -> jpegSize img
76+ Eps -> epsSize img
6677 Pdf -> Nothing -- TODO
6778
79+defaultSize :: (Integer, Integer)
80+defaultSize = (72, 72)
81+
6882sizeInPixels :: ImageSize -> (Integer, Integer)
6983sizeInPixels s = (pxX s, pxY s)
7084
7185sizeInPoints :: ImageSize -> (Integer, Integer)
7286sizeInPoints s = (pxX s * 72 `div` dpiX s, pxY s * 72 `div` dpiY s)
7387
88+epsSize :: ByteString -> Maybe ImageSize
89+epsSize img = do
90+ let ls = takeWhile ("%" `B.isPrefixOf`) $ B.lines img
91+ let ls' = dropWhile (not . ("%%BoundingBox:" `B.isPrefixOf`)) ls
92+ case ls' of
93+ [] -> mzero
94+ (x:_) -> case B.words x of
95+ (_:_:_:ux:uy:[]) -> do
96+ ux' <- safeRead $ B.unpack ux
97+ uy' <- safeRead $ B.unpack uy
98+ return ImageSize{
99+ pxX = ux'
100+ , pxY = uy'
101+ , dpiX = 72
102+ , dpiY = 72 }
103+ _ -> mzero
104+
74105pngSize :: ByteString -> Maybe ImageSize
75106pngSize img = do
76107 let (h, rest) = B.splitAt 8 img
@@ -117,8 +148,14 @@ gifSize img = do
117148jpegSize :: ByteString -> Maybe ImageSize
118149jpegSize img = do
119150 let (hdr, rest) = B.splitAt 4 img
120− guard $ hdr == "\xff\xd8\xff\xe0"
121151 guard $ B.length rest >= 14
152+ case hdr of
153+ "\xff\xd8\xff\xe0" -> jfifSize rest
154+ "\xff\xd8\xff\xe1" -> exifSize $ B.takeWhile (/= '\xff') rest
155+ _ -> mzero
156+
157+jfifSize :: ByteString -> Maybe ImageSize
158+jfifSize rest = do
122159 let [dpiDensity,dpix1,dpix2,dpiy1,dpiy2] = map fromIntegral
123160 $ unpack $ B.take 5 $ B.drop 9 $ rest
124161 let factor = case dpiDensity of
@@ -127,11 +164,11 @@ jpegSize img = do
127164 _ -> const 72
128165 let dpix = factor (shift dpix1 8 + dpix2)
129166 let dpiy = factor (shift dpiy1 8 + dpiy2)
130− (w,h) <- findJpegSize rest
167+ (w,h) <- findJfifSize rest
131168 return $ ImageSize { pxX = w, pxY = h, dpiX = dpix, dpiY = dpiy }
132169
133−findJpegSize :: ByteString -> Maybe (Integer,Integer)
134−findJpegSize bs = do
170+findJfifSize :: ByteString -> Maybe (Integer,Integer)
171+findJfifSize bs = do
135172 let bs' = B.dropWhile (=='\xff') $ B.dropWhile (/='\xff') bs
136173 case B.uncons bs' of
137174 Just (c,bs'') | c >= '\xc0' && c <= '\xc3' -> do
@@ -143,8 +180,220 @@ findJpegSize bs = do
143180 [c1,c2] -> do
144181 let len = shift c1 8 + c2
145182 -- skip variables
146− findJpegSize $ B.drop len bs''
183+ findJfifSize $ B.drop len bs''
147184 _ -> fail "JPEG parse error"
148185 Nothing -> fail "Did not find length record"
149186
187+exifSize :: ByteString -> Maybe ImageSize
188+exifSize bs = runGet (Just <$> exifHeader bl) bl
189+ where bl = BL.fromChunks [bs]
190+-- NOTE: It would be nicer to do
191+-- runGet ((Just <$> exifHeader) <|> return Nothing)
192+-- which would prevent pandoc from raising an error when an exif header can't
193+-- be parsed. But we only get an Alternative instance for Get in binary 0.6,
194+-- and binary 0.5 ships with ghc 7.6.
195+
196+exifHeader :: BL.ByteString -> Get ImageSize
197+exifHeader hdr = do
198+ _app1DataSize <- getWord16be
199+ exifHdr <- getWord32be
200+ unless (exifHdr == 0x45786966) $ fail "Did not find exif header"
201+ zeros <- getWord16be
202+ unless (zeros == 0) $ fail "Expected zeros after exif header"
203+ -- beginning of tiff header -- we read whole thing to use
204+ -- in getting data from offsets:
205+ let tiffHeader = BL.drop 8 hdr
206+ byteAlign <- getWord16be
207+ let bigEndian = byteAlign == 0x4d4d
208+ let (getWord16, getWord32, getWord64) =
209+ if bigEndian
210+ then (getWord16be, getWord32be, getWord64be)
211+ else (getWord16le, getWord32le, getWord64le)
212+ let getRational = do
213+ num <- getWord32
214+ den <- getWord32
215+ return $ fromIntegral num / fromIntegral den
216+ tagmark <- getWord16
217+ unless (tagmark == 0x002a) $ fail "Failed alignment sanity check"
218+ ifdOffset <- getWord32
219+ skip (fromIntegral ifdOffset - 8) -- skip to IDF
220+ numentries <- getWord16
221+ let ifdEntry = do
222+ tag <- getWord16 >>= \t ->
223+ maybe (return UnknownTagType) return
224+ (M.lookup t tagTypeTable)
225+ dataFormat <- getWord16
226+ numComponents <- getWord32
227+ (fmt, bytesPerComponent) <-
228+ case dataFormat of
229+ 1 -> return (UnsignedByte . runGet getWord8, 1)
230+ 2 -> return (AsciiString, 1)
231+ 3 -> return (UnsignedShort . runGet getWord16, 2)
232+ 4 -> return (UnsignedLong . runGet getWord32, 4)
233+ 5 -> return (UnsignedRational . runGet getRational, 8)
234+ 6 -> return (SignedByte . runGet getWord8, 1)
235+ 7 -> return (Undefined . runGet getWord8, 1)
236+ 8 -> return (SignedShort . runGet getWord16, 2)
237+ 9 -> return (SignedLong . runGet getWord32, 4)
238+ 10 -> return (SignedRational . runGet getRational, 8)
239+ 11 -> return (SingleFloat . runGet getWord32 {- TODO -}, 4)
240+ 12 -> return (DoubleFloat . runGet getWord64 {- TODO -}, 8)
241+ _ -> fail $ "Unknown data format " ++ show dataFormat
242+ let totalBytes = fromIntegral $ numComponents * bytesPerComponent
243+ payload <- if totalBytes <= 4 -- data is right here
244+ then fmt <$>
245+ (getLazyByteString (fromIntegral totalBytes) <*
246+ skip (4 - totalBytes))
247+ else do -- get data from offset
248+ offs <- getWord32
249+ return $ fmt $ BL.take (fromIntegral totalBytes) $
250+ BL.drop (fromIntegral offs) tiffHeader
251+ return (tag, payload)
252+ entries <- sequence $ replicate (fromIntegral numentries) ifdEntry
253+ subentries <- case lookup ExifOffset entries of
254+ Just (UnsignedLong offset) -> do
255+ pos <- bytesRead
256+ skip (fromIntegral offset - (fromIntegral pos - 8))
257+ numsubentries <- getWord16
258+ sequence $
259+ replicate (fromIntegral numsubentries) ifdEntry
260+ _ -> return []
261+ let allentries = entries ++ subentries
262+ (width, height) <- case (lookup ExifImageWidth allentries,
263+ lookup ExifImageHeight allentries) of
264+ (Just (UnsignedLong w), Just (UnsignedLong h)) ->
265+ return (fromIntegral w, fromIntegral h)
266+ _ -> return defaultSize
267+ -- we return a default width and height when
268+ -- the exif header doesn't contain these
269+ let resfactor = case lookup ResolutionUnit allentries of
270+ Just (UnsignedShort 1) -> (100 / 254)
271+ _ -> 1
272+ let xres = maybe 72 (\(UnsignedRational x) -> floor $ x * resfactor)
273+ $ lookup XResolution allentries
274+ let yres = maybe 72 (\(UnsignedRational x) -> floor $ x * resfactor)
275+ $ lookup YResolution allentries
276+ return $ ImageSize{
277+ pxX = width
278+ , pxY = height
279+ , dpiX = xres
280+ , dpiY = yres }
281+
282+data DataFormat = UnsignedByte Word8
283+ | AsciiString BL.ByteString
284+ | UnsignedShort Word16
285+ | UnsignedLong Word32
286+ | UnsignedRational Rational
287+ | SignedByte Word8
288+ | Undefined Word8
289+ | SignedShort Word16
290+ | SignedLong Word32
291+ | SignedRational Rational
292+ | SingleFloat Word32
293+ | DoubleFloat Word64
294+ deriving (Show)
295+
296+data TagType = ImageDescription
297+ | Make
298+ | Model
299+ | Orientation
300+ | XResolution
301+ | YResolution
302+ | ResolutionUnit
303+ | Software
304+ | DateTime
305+ | WhitePoint
306+ | PrimaryChromaticities
307+ | YCbCrCoefficients
308+ | YCbCrPositioning
309+ | ReferenceBlackWhite
310+ | Copyright
311+ | ExifOffset
312+ | ExposureTime
313+ | FNumber
314+ | ExposureProgram
315+ | ISOSpeedRatings
316+ | ExifVersion
317+ | DateTimeOriginal
318+ | DateTimeDigitized
319+ | ComponentConfiguration
320+ | CompressedBitsPerPixel
321+ | ShutterSpeedValue
322+ | ApertureValue
323+ | BrightnessValue
324+ | ExposureBiasValue
325+ | MaxApertureValue
326+ | SubjectDistance
327+ | MeteringMode
328+ | LightSource
329+ | Flash
330+ | FocalLength
331+ | MakerNote
332+ | UserComment
333+ | FlashPixVersion
334+ | ColorSpace
335+ | ExifImageWidth
336+ | ExifImageHeight
337+ | RelatedSoundFile
338+ | ExifInteroperabilityOffset
339+ | FocalPlaneXResolution
340+ | FocalPlaneYResolution
341+ | FocalPlaneResolutionUnit
342+ | SensingMethod
343+ | FileSource
344+ | SceneType
345+ | UnknownTagType
346+ deriving (Show, Eq, Ord)
150347
348+tagTypeTable :: M.Map Word16 TagType
349+tagTypeTable = M.fromList
350+ [ (0x010e, ImageDescription)
351+ , (0x010f, Make)
352+ , (0x0110, Model)
353+ , (0x0112, Orientation)
354+ , (0x011a, XResolution)
355+ , (0x011b, YResolution)
356+ , (0x0128, ResolutionUnit)
357+ , (0x0131, Software)
358+ , (0x0132, DateTime)
359+ , (0x013e, WhitePoint)
360+ , (0x013f, PrimaryChromaticities)
361+ , (0x0211, YCbCrCoefficients)
362+ , (0x0213, YCbCrPositioning)
363+ , (0x0214, ReferenceBlackWhite)
364+ , (0x8298, Copyright)
365+ , (0x8769, ExifOffset)
366+ , (0x829a, ExposureTime)
367+ , (0x829d, FNumber)
368+ , (0x8822, ExposureProgram)
369+ , (0x8827, ISOSpeedRatings)
370+ , (0x9000, ExifVersion)
371+ , (0x9003, DateTimeOriginal)
372+ , (0x9004, DateTimeDigitized)
373+ , (0x9101, ComponentConfiguration)
374+ , (0x9102, CompressedBitsPerPixel)
375+ , (0x9201, ShutterSpeedValue)
376+ , (0x9202, ApertureValue)
377+ , (0x9203, BrightnessValue)
378+ , (0x9204, ExposureBiasValue)
379+ , (0x9205, MaxApertureValue)
380+ , (0x9206, SubjectDistance)
381+ , (0x9207, MeteringMode)
382+ , (0x9208, LightSource)
383+ , (0x9209, Flash)
384+ , (0x920a, FocalLength)
385+ , (0x927c, MakerNote)
386+ , (0x9286, UserComment)
387+ , (0xa000, FlashPixVersion)
388+ , (0xa001, ColorSpace)
389+ , (0xa002, ExifImageWidth)
390+ , (0xa003, ExifImageHeight)
391+ , (0xa004, RelatedSoundFile)
392+ , (0xa005, ExifInteroperabilityOffset)
393+ , (0xa20e, FocalPlaneXResolution)
394+ , (0xa20f, FocalPlaneYResolution)
395+ , (0xa210, FocalPlaneResolutionUnit)
396+ , (0xa217, SensingMethod)
397+ , (0xa300, FileSource)
398+ , (0xa301, SceneType)
399+ ]
src/Text/Pandoc/MIME.hs+16−4
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2011 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2011-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.MIME
21− Copyright : Copyright (C) 2011 John MacFarlane
21+ Copyright : Copyright (C) 2011-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2727
2828Mime type lookup for ODT writer.
2929-}
30−module Text.Pandoc.MIME ( getMimeType )
30+module Text.Pandoc.MIME ( getMimeType, extensionFromMimeType )
3131where
3232import System.FilePath
3333import Data.Char ( toLower )
@@ -37,7 +37,15 @@ import qualified Data.Map as M
3737getMimeType :: FilePath -> Maybe String
3838getMimeType "layout-cache" = Just "application/binary" -- in ODT
3939getMimeType f = M.lookup (map toLower $ drop 1 $ takeExtension f) mimeTypes
40− where mimeTypes = M.fromList -- List borrowed from happstack-server.
40+ where mimeTypes = M.fromList mimeTypesList
41+
42+extensionFromMimeType :: String -> Maybe String
43+extensionFromMimeType mimetype = M.lookup (takeWhile (/=';') mimetype) reverseMimeTypes
44+ -- note: we just look up the basic mime type, dropping the content-encoding etc.
45+ where reverseMimeTypes = M.fromList $ map (\(k,v) -> (v,k)) mimeTypesList
46+
47+mimeTypesList :: [(String, String)]
48+mimeTypesList = -- List borrowed from happstack-server.
4149 [("gz","application/x-gzip")
4250 ,("cabal","application/x-cabal")
4351 ,("%","application/x-trash")
@@ -139,6 +147,7 @@ getMimeType f = M.lookup (map toLower $ drop 1 $ takeExtension f) mimeTypes
139147 ,("dxr","application/x-director")
140148 ,("emb","chemical/x-embl-dl-nucleotide")
141149 ,("embl","chemical/x-embl-dl-nucleotide")
150+ ,("emf","image/x-emf")
142151 ,("eml","message/rfc822")
143152 ,("ent","chemical/x-ncbi-asn1-ascii")
144153 ,("eot","application/vnd.ms-fontobject")
@@ -212,6 +221,7 @@ getMimeType f = M.lookup (map toLower $ drop 1 $ takeExtension f) mimeTypes
212221 ,("jnlp","application/x-java-jnlp-file")
213222 ,("jpe","image/jpeg")
214223 ,("jpeg","image/jpeg")
224+ ,("jfif","image/jpeg")
215225 ,("jpg","image/jpeg")
216226 ,("js","application/x-javascript")
217227 ,("kar","audio/midi")
@@ -236,6 +246,7 @@ getMimeType f = M.lookup (map toLower $ drop 1 $ takeExtension f) mimeTypes
236246 ,("lzx","application/x-lzx")
237247 ,("m3u","audio/mpegurl")
238248 ,("m4a","audio/mpeg")
249+ ,("m4v","video/x-m4v")
239250 ,("maker","application/x-maker")
240251 ,("man","application/x-troff-man")
241252 ,("mcif","chemical/x-mmcif")
@@ -456,6 +467,7 @@ getMimeType f = M.lookup (map toLower $ drop 1 $ takeExtension f) mimeTypes
456467 ,("wm","video/x-ms-wm")
457468 ,("wma","audio/x-ms-wma")
458469 ,("wmd","application/x-ms-wmd")
470+ ,("wmf","image/x-wmf")
459471 ,("wml","text/vnd.wap.wml")
460472 ,("wmlc","application/vnd.wap.wmlc")
461473 ,("wmls","text/vnd.wap.wmlscript")
src/Text/Pandoc/Options.hs+18−11
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2012 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.Options
21− Copyright : Copyright (C) 2012 John MacFarlane
21+ Copyright : Copyright (C) 2012-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -41,6 +41,7 @@ module Text.Pandoc.Options ( Extension(..)
4141 , HTMLSlideVariant (..)
4242 , EPUBVersion (..)
4343 , WriterOptions (..)
44+ , TrackChanges (..)
4445 , def
4546 , isEnabled
4647 ) where
@@ -48,7 +49,6 @@ import Data.Set (Set)
4849import qualified Data.Set as Set
4950import Data.Default
5051import Text.Pandoc.Highlighting (Style, pygments)
51−import qualified Text.CSL as CSL
5252
5353-- | Individually selectable syntax extensions.
5454data Extension =
@@ -81,6 +81,7 @@ data Extension =
8181 | Ext_link_attributes -- ^ MMD style reference link attributes
8282 | Ext_autolink_bare_uris -- ^ Make all absolute URIs into links
8383 | Ext_fancy_lists -- ^ Enable fancy list numbers and delimiters
84+ | Ext_lists_without_preceding_blankline -- ^ Allow lists without preceding blank
8485 | Ext_startnum -- ^ Make start number of ordered list significant
8586 | Ext_definition_lists -- ^ Definition lists as in pandoc, mmd, php
8687 | Ext_example_lists -- ^ Markdown-style numbered examples
@@ -92,6 +93,7 @@ data Extension =
9293 | Ext_superscript -- ^ Superscript using ^this^ syntax
9394 | Ext_subscript -- ^ Subscript using ~this~ syntax
9495 | Ext_hard_line_breaks -- ^ All newlines become hard line breaks
96+ | Ext_ignore_line_breaks -- ^ Newlines in paragraphs are ignored
9597 | Ext_literate_haskell -- ^ Enable literate Haskell conventions
9698 | Ext_abbreviations -- ^ PHP markdown extra abbreviation definitions
9799 | Ext_auto_identifiers -- ^ Automatic identifiers for headers
@@ -169,6 +171,7 @@ githubMarkdownExtensions = Set.fromList
169171 , Ext_intraword_underscores
170172 , Ext_strikeout
171173 , Ext_hard_line_breaks
174+ , Ext_lists_without_preceding_blankline
172175 ]
173176
174177multimarkdownExtensions :: Set Extension
@@ -204,12 +207,12 @@ data ReaderOptions = ReaderOptions{
204207 , readerOldDashes :: Bool -- ^ Use pandoc <= 1.8.2.1 behavior
205208 -- in parsing dashes; -- is em-dash;
206209 -- - before numerial is en-dash
207− , readerReferences :: [CSL.Reference] -- ^ Bibliographic references
208− , readerCitationStyle :: Maybe CSL.Style -- ^ Citation style
209210 , readerApplyMacros :: Bool -- ^ Apply macros to TeX math
210211 , readerIndentedCodeClasses :: [String] -- ^ Default classes for
211212 -- indented code blocks
212213 , readerDefaultImageExtension :: String -- ^ Default extension for images
214+ , readerTrace :: Bool -- ^ Print debugging info
215+ , readerTrackChanges :: TrackChanges
213216} deriving (Show, Read)
214217
215218instance Default ReaderOptions
@@ -222,11 +225,11 @@ instance Default ReaderOptions
222225 , readerColumns = 80
223226 , readerTabStop = 4
224227 , readerOldDashes = False
225− , readerReferences = []
226− , readerCitationStyle = Nothing
227228 , readerApplyMacros = True
228229 , readerIndentedCodeClasses = []
229230 , readerDefaultImageExtension = ""
231+ , readerTrace = False
232+ , readerTrackChanges = AcceptChanges
230233 }
231234
232235--
@@ -264,6 +267,12 @@ data HTMLSlideVariant = S5Slides
264267 | NoSlides
265268 deriving (Show, Read, Eq)
266269
270+-- | Options for accepting or rejecting MS Word track-changes.
271+data TrackChanges = AcceptChanges
272+ | RejectChanges
273+ | AllChanges
274+ deriving (Show, Read, Eq)
275+
267276-- | Options for writers
268277data WriterOptions = WriterOptions
269278 { writerStandalone :: Bool -- ^ Include header and footer
@@ -285,10 +294,9 @@ data WriterOptions = WriterOptions
285294 , writerEmailObfuscation :: ObfuscationMethod -- ^ How to obfuscate emails
286295 , writerIdentifierPrefix :: String -- ^ Prefix for section & note ids in HTML
287296 -- and for footnote marks in markdown
288− , writerSourceDirectory :: FilePath -- ^ Directory path of 1st source file
297+ , writerSourceURL :: Maybe String -- ^ Absolute URL + directory of 1st source file
289298 , writerUserDataDir :: Maybe FilePath -- ^ Path of user data directory
290299 , writerCiteMethod :: CiteMethod -- ^ How to print cites
291− , writerBiblioFiles :: [FilePath] -- ^ Biblio files to use for citations
292300 , writerHtml5 :: Bool -- ^ Produce HTML5
293301 , writerHtmlQTags :: Bool -- ^ Use @<q>@ tags for quotes in HTML
294302 , writerBeamer :: Bool -- ^ Produce beamer LaTeX slide show
@@ -328,10 +336,9 @@ instance Default WriterOptions where
328336 , writerColumns = 72
329337 , writerEmailObfuscation = JavascriptObfuscation
330338 , writerIdentifierPrefix = ""
331− , writerSourceDirectory = "."
339+ , writerSourceURL = Nothing
332340 , writerUserDataDir = Nothing
333341 , writerCiteMethod = Citeproc
334− , writerBiblioFiles = []
335342 , writerHtml5 = False
336343 , writerHtmlQTags = False
337344 , writerBeamer = False
src/Text/Pandoc/PDF.hs+88−47
@@ -1,6 +1,6 @@
11{-# LANGUAGE OverloadedStrings, CPP #-}
22{-
3−Copyright (C) 2012 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Text.Pandoc.PDF
22− Copyright : Copyright (C) 2012 John MacFarlane
22+ Copyright : Copyright (C) 2012-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -28,22 +28,32 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2828
2929Conversion of LaTeX documents to PDF.
3030-}
31−module Text.Pandoc.PDF ( tex2pdf ) where
31+module Text.Pandoc.PDF ( makePDF ) where
3232
3333import System.IO.Temp
3434import Data.ByteString.Lazy (ByteString)
3535import qualified Data.ByteString.Lazy as B
3636import qualified Data.ByteString.Lazy.Char8 as BC
37+import qualified Data.ByteString as BS
3738import System.Exit (ExitCode (..))
3839import System.FilePath
3940import System.Directory
40−import System.Process
41−import Control.Exception (evaluate)
42−import System.IO (hClose)
43−import Control.Concurrent (putMVar, takeMVar, newEmptyMVar, forkIO)
44−import Text.Pandoc.UTF8 as UTF8
41+import Data.Digest.Pure.SHA (showDigest, sha1)
42+import System.Environment
4543import Control.Monad (unless)
4644import Data.List (isInfixOf)
45+import Data.Maybe (fromMaybe)
46+import qualified Text.Pandoc.UTF8 as UTF8
47+import Text.Pandoc.Definition
48+import Text.Pandoc.Walk (walkM)
49+import Text.Pandoc.Shared (fetchItem, warn)
50+import Text.Pandoc.Options (WriterOptions(..))
51+import Text.Pandoc.MIME (extensionFromMimeType)
52+import Text.Pandoc.Process (pipeProcess)
53+import qualified Data.ByteString.Lazy as BL
54+#ifdef _WINDOWS
55+import Data.List (intercalate)
56+#endif
4757
4858withTempDir :: String -> (FilePath -> IO a) -> IO a
4959withTempDir =
@@ -53,12 +63,50 @@ withTempDir =
5363 withSystemTempDirectory
5464#endif
5565
56−tex2pdf :: String -- ^ tex program (pdflatex, lualatex, xelatex)
57− -> String -- ^ latex source
66+#ifdef _WINDOWS
67+changePathSeparators :: FilePath -> FilePath
68+changePathSeparators = intercalate "/" . splitDirectories
69+#endif
70+
71+makePDF :: String -- ^ pdf creator (pdflatex, lualatex, xelatex)
72+ -> (WriterOptions -> Pandoc -> String) -- ^ writer
73+ -> WriterOptions -- ^ options
74+ -> Pandoc -- ^ document
5875 -> IO (Either ByteString ByteString)
59−tex2pdf program source = withTempDir "tex2pdf." $ \tmpdir ->
76+makePDF program writer opts doc = withTempDir "tex2pdf." $ \tmpdir -> do
77+ doc' <- handleImages (writerSourceURL opts) tmpdir doc
78+ let source = writer opts doc'
6079 tex2pdf' tmpdir program source
6180
81+handleImages :: Maybe String -- ^ source base URL
82+ -> FilePath -- ^ temp dir to store images
83+ -> Pandoc -- ^ document
84+ -> IO Pandoc
85+handleImages baseURL tmpdir = walkM (handleImage' baseURL tmpdir)
86+
87+handleImage' :: Maybe String
88+ -> FilePath
89+ -> Inline
90+ -> IO Inline
91+handleImage' baseURL tmpdir (Image ils (src,tit)) = do
92+ exists <- doesFileExist src
93+ if exists
94+ then return $ Image ils (src,tit)
95+ else do
96+ res <- fetchItem baseURL src
97+ case res of
98+ Right (contents, Just mime) -> do
99+ let ext = fromMaybe (takeExtension src) $
100+ extensionFromMimeType mime
101+ let basename = showDigest $ sha1 $ BL.fromChunks [contents]
102+ let fname = tmpdir </> basename <.> ext
103+ BS.writeFile fname contents
104+ return $ Image ils (fname,tit)
105+ _ -> do
106+ warn $ "Could not find image `" ++ src ++ "', skipping..."
107+ return $ Image ils (src,tit)
108+handleImage' _ _ x = return x
109+
62110tex2pdf' :: FilePath -- ^ temp directory for output
63111 -> String -- ^ tex program
64112 -> String -- ^ tex source
@@ -68,11 +116,16 @@ tex2pdf' tmpDir program source = do
68116 then 3 -- to get page numbers
69117 else 2 -- 1 run won't give you PDF bookmarks
70118 (exit, log', mbPdf) <- runTeXProgram program numruns tmpDir source
71− let msg = "Error producing PDF from TeX source."
72119 case (exit, mbPdf) of
73− (ExitFailure _, _) -> return $ Left $
74− msg <> "\n" <> extractMsg log'
75− (ExitSuccess, Nothing) -> return $ Left msg
120+ (ExitFailure _, _) -> do
121+ let logmsg = extractMsg log'
122+ let extramsg =
123+ case logmsg of
124+ x | "! Package inputenc Error" `BC.isPrefixOf` x ->
125+ "\nTry running pandoc with --latex-engine=xelatex."
126+ _ -> ""
127+ return $ Left $ logmsg <> extramsg
128+ (ExitSuccess, Nothing) -> return $ Left ""
76129 (ExitSuccess, Just pdf) -> return $ Right pdf
77130
78131(<>) :: ByteString -> ByteString -> ByteString
@@ -100,45 +153,33 @@ runTeXProgram program runsLeft tmpDir source = do
100153 let file = tmpDir </> "input.tex"
101154 exists <- doesFileExist file
102155 unless exists $ UTF8.writeFile file source
156+#ifdef _WINDOWS
157+ -- note: we want / even on Windows, for TexLive
158+ let tmpDir' = changePathSeparators tmpDir
159+ let file' = changePathSeparators file
160+#else
161+ let tmpDir' = tmpDir
162+ let file' = file
163+#endif
103164 let programArgs = ["-halt-on-error", "-interaction", "nonstopmode",
104− "-output-directory", tmpDir, file]
105− (exit, out, err) <- readCommand program programArgs
165+ "-output-directory", tmpDir', file']
166+ env' <- getEnvironment
167+ let sep = searchPathSeparator:[]
168+ let texinputs = maybe (tmpDir' ++ sep) ((tmpDir' ++ sep) ++)
169+ $ lookup "TEXINPUTS" env'
170+ let env'' = ("TEXINPUTS", texinputs) :
171+ [(k,v) | (k,v) <- env', k /= "TEXINPUTS"]
172+ (exit, out, err) <- pipeProcess (Just env'') program programArgs BL.empty
106173 if runsLeft > 1
107174 then runTeXProgram program (runsLeft - 1) tmpDir source
108175 else do
109176 let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
110177 pdfExists <- doesFileExist pdfFile
111178 pdf <- if pdfExists
112− then Just `fmap` B.readFile pdfFile
179+ -- We read PDF as a strict bytestring to make sure that the
180+ -- temp directory is removed on Windows.
181+ -- See https://github.com/jgm/pandoc/issues/1192.
182+ then (Just . B.fromChunks . (:[])) `fmap` BS.readFile pdfFile
113183 else return Nothing
114184 return (exit, out <> err, pdf)
115185
116−-- utility functions
117−
118−-- Run a command and return exitcode, contents of stdout, and
119−-- contents of stderr. (Based on
120−-- 'readProcessWithExitCode' from 'System.Process'.)
121−readCommand :: FilePath -- ^ command to run
122− -> [String] -- ^ any arguments
123− -> IO (ExitCode,ByteString,ByteString) -- ^ exit, stdout, stderr
124−readCommand cmd args = do
125− (Just inh, Just outh, Just errh, pid) <-
126− createProcess (proc cmd args){ std_in = CreatePipe,
127− std_out = CreatePipe,
128− std_err = CreatePipe }
129− outMVar <- newEmptyMVar
130− -- fork off a thread to start consuming stdout
131− out <- B.hGetContents outh
132− _ <- forkIO $ evaluate (B.length out) >> putMVar outMVar ()
133− -- fork off a thread to start consuming stderr
134− err <- B.hGetContents errh
135− _ <- forkIO $ evaluate (B.length err) >> putMVar outMVar ()
136− -- now write and flush any input
137− hClose inh -- done with stdin
138− -- wait on the output
139− takeMVar outMVar
140− takeMVar outMVar
141− hClose outh
142− -- wait on the process
143− ex <- waitForProcess pid
144− return (ex, out, err)
src/Text/Pandoc/Parsing.hs+187−51
@@ -1,6 +1,7 @@
1−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1+{-# LANGUAGE GeneralizedNewtypeDeriving, TypeSynonymInstances,
2+ FlexibleInstances#-}
23{-
3−Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
4+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
45
56This program is free software; you can redistribute it and/or modify
67it 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
1920
2021{- |
2122 Module : Text.Pandoc.Parsing
22− Copyright : Copyright (C) 2006-2010 John MacFarlane
23+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2324 License : GNU GPL, version 2 or above
2425
2526 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -47,11 +48,12 @@ module Text.Pandoc.Parsing ( (>>~),
4748 romanNumeral,
4849 emailAddress,
4950 uri,
51+ mathInline,
52+ mathDisplay,
5053 withHorizDisplacement,
5154 withRaw,
5255 escaped,
5356 characterReference,
54− updateLastStrPos,
5557 anyOrderedListMarker,
5658 orderedListMarker,
5759 charRef,
@@ -61,10 +63,16 @@ module Text.Pandoc.Parsing ( (>>~),
6163 gridTableWith,
6264 readWith,
6365 testStringWith,
64− getOption,
6566 guardEnabled,
6667 guardDisabled,
68+ updateLastStrPos,
69+ notAfterString,
6770 ParserState (..),
71+ HasReaderOptions (..),
72+ HasHeaderMap (..),
73+ HasIdentifierList (..),
74+ HasMacros (..),
75+ HasLastStrPosition (..),
6876 defaultParserState,
6977 HeaderType (..),
7078 ParserContext (..),
@@ -75,6 +83,7 @@ module Text.Pandoc.Parsing ( (>>~),
7583 SubstTable,
7684 Key (..),
7785 toKey,
86+ registerHeader,
7887 smartPunctuation,
7988 withQuoteContext,
8089 singleQuoteStart,
@@ -85,6 +94,7 @@ module Text.Pandoc.Parsing ( (>>~),
8594 apostrophe,
8695 dash,
8796 nested,
97+ citeKey,
8898 macro,
8999 applyMacros',
90100 Parser,
@@ -151,6 +161,7 @@ where
151161import Text.Pandoc.Definition
152162import Text.Pandoc.Options
153163import Text.Pandoc.Builder (Blocks, Inlines, rawBlock, HasMeta(..))
164+import qualified Text.Pandoc.Builder as B
154165import Text.Pandoc.XML (fromEntities)
155166import qualified Text.Pandoc.UTF8 as UTF8 (putStrLn)
156167import Text.Parsec
@@ -161,16 +172,18 @@ import Data.List ( intercalate, transpose )
161172import Text.Pandoc.Shared
162173import qualified Data.Map as M
163174import Text.TeXMath.Macros (applyMacros, Macro, parseMacroDefinitions)
164−import Text.HTML.TagSoup.Entity ( lookupEntity )
175+import Text.Pandoc.Compat.TagSoupEntity ( lookupEntity )
176+import Text.Pandoc.Asciify (toAsciiChar)
165177import Data.Default
166178import qualified Data.Set as Set
167179import Control.Monad.Reader
168−import Control.Applicative ((*>), (<*), (<$), liftA2)
180+import Control.Applicative ((*>), (<*), (<$), liftA2, Applicative)
169181import Data.Monoid
182+import Data.Maybe (catMaybes)
170183
171184type Parser t s = Parsec t s
172185
173−newtype F a = F { unF :: Reader ParserState a } deriving (Monad, Functor)
186+newtype F a = F { unF :: Reader ParserState a } deriving (Monad, Applicative, Functor)
174187
175188runF :: F a -> ParserState -> a
176189runF = runReader . unF
@@ -261,7 +274,7 @@ spaceChar = satisfy $ \c -> c == ' ' || c == '\t'
261274
262275-- | Parses a nonspace, nonnewline character.
263276nonspaceChar :: Parser [Char] st Char
264−nonspaceChar = satisfy $ \x -> x /= '\t' && x /= '\n' && x /= ' ' && x /= '\r'
277+nonspaceChar = satisfy $ flip notElem ['\t', '\n', ' ', '\r']
265278
266279-- | Skips zero or more spaces or tabs.
267280skipSpaces :: Parser [Char] st ()
@@ -421,7 +434,6 @@ uri :: Parser [Char] st (String, String)
421434uri = try $ do
422435 scheme <- uriScheme
423436 char ':'
424− -- /^[\/\w\u0080-\uffff]+|%[A-Fa-f0-9]+|&#?\w+;|(?:[,]+|[\S])[%&~\w\u0080-\uffff]/
425437 -- We allow punctuation except at the end, since
426438 -- we don't want the trailing '.' in 'http://google.com.' We want to allow
427439 -- http://en.wikipedia.org/wiki/State_of_emergency_(disambiguation)
@@ -448,6 +460,41 @@ uri = try $ do
448460 let uri' = scheme ++ ":" ++ fromEntities str'
449461 return (uri', escapeURI uri')
450462
463+mathInlineWith :: String -> String -> Parser [Char] st String
464+mathInlineWith op cl = try $ do
465+ string op
466+ notFollowedBy space
467+ words' <- many1Till (count 1 (noneOf " \t\n\\")
468+ <|> (char '\\' >> anyChar >>= \c -> return ['\\',c])
469+ <|> do (blankline <* notFollowedBy' blankline) <|>
470+ (oneOf " \t" <* skipMany (oneOf " \t"))
471+ notFollowedBy (char '$')
472+ return " "
473+ ) (try $ string cl)
474+ notFollowedBy digit -- to prevent capture of $5
475+ return $ concat words'
476+
477+mathDisplayWith :: String -> String -> Parser [Char] st String
478+mathDisplayWith op cl = try $ do
479+ string op
480+ many1Till (noneOf "\n" <|> (newline >>~ notFollowedBy' blankline)) (try $ string cl)
481+
482+mathDisplay :: Parser [Char] ParserState String
483+mathDisplay =
484+ (guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
485+ <|> (guardEnabled Ext_tex_math_single_backslash >>
486+ mathDisplayWith "\\[" "\\]")
487+ <|> (guardEnabled Ext_tex_math_double_backslash >>
488+ mathDisplayWith "\\\\[" "\\\\]")
489+
490+mathInline :: Parser [Char] ParserState String
491+mathInline =
492+ (guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
493+ <|> (guardEnabled Ext_tex_math_single_backslash >>
494+ mathInlineWith "\\(" "\\)")
495+ <|> (guardEnabled Ext_tex_math_double_backslash >>
496+ mathInlineWith "\\\\(" "\\\\)")
497+
451498-- | Applies a parser, returns tuple of its results and its horizontal
452499-- displacement (the difference between the source column at the end
453500-- and the source column at the beginning). Vertical displacement
@@ -462,7 +509,7 @@ withHorizDisplacement parser = do
462509
463510-- | Applies a parser and returns the raw string that was parsed,
464511-- along with the value produced by the parser.
465−withRaw :: Parser [Char] st a -> Parser [Char] st (a, [Char])
512+withRaw :: Monad m => ParsecT [Char] st m a -> ParsecT [Char] st m (a, [Char])
466513withRaw parser = do
467514 pos1 <- getPosition
468515 inp <- getInput
@@ -802,6 +849,7 @@ data ParserState = ParserState
802849 stateNotes :: NoteTable, -- ^ List of notes (raw bodies)
803850 stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
804851 stateMeta :: Meta, -- ^ Document metadata
852+ stateMeta' :: F Meta, -- ^ Document metadata
805853 stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
806854 stateHeaders :: M.Map Inlines String, -- ^ List of headers and ids (used for implicit ref links)
807855 stateIdentifiers :: [String], -- ^ List of header identifiers used
@@ -810,6 +858,11 @@ data ParserState = ParserState
810858 stateHasChapters :: Bool, -- ^ True if \chapter encountered
811859 stateMacros :: [Macro], -- ^ List of macros defined so far
812860 stateRstDefaultRole :: String, -- ^ Current rST default interpreted text role
861+ stateRstCustomRoles :: M.Map String (String, Maybe String, Attr -> (String, Attr)), -- ^ Current rST custom text roles
862+ -- Triple represents: 1) Base role, 2) Optional format (only for :raw:
863+ -- roles), 3) Source language annotation for code (could be used to
864+ -- annotate role classes too).
865+ stateCaption :: Maybe Inlines, -- ^ Caption in current environment
813866 stateWarnings :: [String] -- ^ Warnings generated by the parser
814867 }
815868
@@ -822,6 +875,48 @@ instance HasMeta ParserState where
822875 deleteMeta field st =
823876 st{ stateMeta = deleteMeta field $ stateMeta st }
824877
878+class HasReaderOptions st where
879+ extractReaderOptions :: st -> ReaderOptions
880+ getOption :: (ReaderOptions -> b) -> Parser s st b
881+ -- default
882+ getOption f = (f . extractReaderOptions) `fmap` getState
883+
884+instance HasReaderOptions ParserState where
885+ extractReaderOptions = stateOptions
886+
887+class HasHeaderMap st where
888+ extractHeaderMap :: st -> M.Map Inlines String
889+ updateHeaderMap :: (M.Map Inlines String -> M.Map Inlines String) ->
890+ st -> st
891+
892+instance HasHeaderMap ParserState where
893+ extractHeaderMap = stateHeaders
894+ updateHeaderMap f st = st{ stateHeaders = f $ stateHeaders st }
895+
896+class HasIdentifierList st where
897+ extractIdentifierList :: st -> [String]
898+ updateIdentifierList :: ([String] -> [String]) -> st -> st
899+
900+instance HasIdentifierList ParserState where
901+ extractIdentifierList = stateIdentifiers
902+ updateIdentifierList f st = st{ stateIdentifiers = f $ stateIdentifiers st }
903+
904+class HasMacros st where
905+ extractMacros :: st -> [Macro]
906+ updateMacros :: ([Macro] -> [Macro]) -> st -> st
907+
908+instance HasMacros ParserState where
909+ extractMacros = stateMacros
910+ updateMacros f st = st{ stateMacros = f $ stateMacros st }
911+
912+class HasLastStrPosition st where
913+ setLastStrPos :: SourcePos -> st -> st
914+ getLastStrPos :: st -> Maybe SourcePos
915+
916+instance HasLastStrPosition ParserState where
917+ setLastStrPos pos st = st{ stateLastStrPos = Just pos }
918+ getLastStrPos st = stateLastStrPos st
919+
825920defaultParserState :: ParserState
826921defaultParserState =
827922 ParserState { stateOptions = def,
@@ -835,6 +930,7 @@ defaultParserState =
835930 stateNotes = [],
836931 stateNotes' = [],
837932 stateMeta = nullMeta,
933+ stateMeta' = return nullMeta,
838934 stateHeaderTable = [],
839935 stateHeaders = M.empty,
840936 stateIdentifiers = [],
@@ -843,19 +939,29 @@ defaultParserState =
843939 stateHasChapters = False,
844940 stateMacros = [],
845941 stateRstDefaultRole = "title-reference",
942+ stateRstCustomRoles = M.empty,
943+ stateCaption = Nothing,
846944 stateWarnings = []}
847945
848−getOption :: (ReaderOptions -> a) -> Parser s ParserState a
849−getOption f = (f . stateOptions) `fmap` getState
850−
851946-- | Succeed only if the extension is enabled.
852−guardEnabled :: Extension -> Parser s ParserState ()
947+guardEnabled :: HasReaderOptions st => Extension -> Parser s st ()
853948guardEnabled ext = getOption readerExtensions >>= guard . Set.member ext
854949
855950-- | Succeed only if the extension is disabled.
856−guardDisabled :: Extension -> Parser s ParserState ()
951+guardDisabled :: HasReaderOptions st => Extension -> Parser s st ()
857952guardDisabled ext = getOption readerExtensions >>= guard . not . Set.member ext
858953
954+-- | Update the position on which the last string ended.
955+updateLastStrPos :: HasLastStrPosition st => Parser s st ()
956+updateLastStrPos = getPosition >>= updateState . setLastStrPos
957+
958+-- | Whether we are right after the end of a string.
959+notAfterString :: HasLastStrPosition st => Parser s st Bool
960+notAfterString = do
961+ pos <- getPosition
962+ st <- getState
963+ return $ getLastStrPos st /= Just pos
964+
859965data HeaderType
860966 = SingleHeader Char -- ^ Single line of characters underneath
861967 | DoubleHeader Char -- ^ Lines of characters above and below
@@ -885,21 +991,47 @@ type KeyTable = M.Map Key Target
885991
886992type SubstTable = M.Map Key Inlines
887993
994+-- | Add header to the list of headers in state, together
995+-- with its associated identifier. If the identifier is null
996+-- and the auto_identifers extension is set, generate a new
997+-- unique identifier, and update the list of identifiers
998+-- in state.
999+registerHeader :: (HasReaderOptions st, HasHeaderMap st, HasIdentifierList st)
1000+ => Attr -> Inlines -> Parser s st Attr
1001+registerHeader (ident,classes,kvs) header' = do
1002+ ids <- extractIdentifierList `fmap` getState
1003+ exts <- getOption readerExtensions
1004+ let insert' = M.insertWith (\_new old -> old)
1005+ if null ident && Ext_auto_identifiers `Set.member` exts
1006+ then do
1007+ let id' = uniqueIdent (B.toList header') ids
1008+ let id'' = if Ext_ascii_identifiers `Set.member` exts
1009+ then catMaybes $ map toAsciiChar id'
1010+ else id'
1011+ updateState $ updateIdentifierList $
1012+ if id' == id'' then (id' :) else ([id', id''] ++)
1013+ updateState $ updateHeaderMap $ insert' header' id'
1014+ return (id'',classes,kvs)
1015+ else do
1016+ unless (null ident) $
1017+ updateState $ updateHeaderMap $ insert' header' ident
1018+ return (ident,classes,kvs)
1019+
8881020-- | Fail unless we're in "smart typography" mode.
889−failUnlessSmart :: Parser [tok] ParserState ()
1021+failUnlessSmart :: HasReaderOptions st => Parser s st ()
8901022failUnlessSmart = getOption readerSmart >>= guard
8911023
892−smartPunctuation :: Parser [Char] ParserState Inline
893− -> Parser [Char] ParserState Inline
1024+smartPunctuation :: Parser [Char] ParserState Inlines
1025+ -> Parser [Char] ParserState Inlines
8941026smartPunctuation inlineParser = do
8951027 failUnlessSmart
8961028 choice [ quoted inlineParser, apostrophe, dash, ellipses ]
8971029
898−apostrophe :: Parser [Char] ParserState Inline
899−apostrophe = (char '\'' <|> char '\8217') >> return (Str "\x2019")
1030+apostrophe :: Parser [Char] ParserState Inlines
1031+apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\x2019")
9001032
901−quoted :: Parser [Char] ParserState Inline
902− -> Parser [Char] ParserState Inline
1033+quoted :: Parser [Char] ParserState Inlines
1034+ -> Parser [Char] ParserState Inlines
9031035quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser
9041036
9051037withQuoteContext :: QuoteContext
@@ -914,20 +1046,19 @@ withQuoteContext context parser = do
9141046 setState newState { stateQuoteContext = oldQuoteContext }
9151047 return result
9161048
917−singleQuoted :: Parser [Char] ParserState Inline
918− -> Parser [Char] ParserState Inline
1049+singleQuoted :: Parser [Char] ParserState Inlines
1050+ -> Parser [Char] ParserState Inlines
9191051singleQuoted inlineParser = try $ do
9201052 singleQuoteStart
9211053 withQuoteContext InSingleQuote $ many1Till inlineParser singleQuoteEnd >>=
922− return . Quoted SingleQuote . normalizeSpaces
1054+ return . B.singleQuoted . mconcat
9231055
924−doubleQuoted :: Parser [Char] ParserState Inline
925− -> Parser [Char] ParserState Inline
1056+doubleQuoted :: Parser [Char] ParserState Inlines
1057+ -> Parser [Char] ParserState Inlines
9261058doubleQuoted inlineParser = try $ do
9271059 doubleQuoteStart
928− withQuoteContext InDoubleQuote $ do
929− contents <- manyTill inlineParser doubleQuoteEnd
930− return . Quoted DoubleQuote . normalizeSpaces $ contents
1060+ withQuoteContext InDoubleQuote $ manyTill inlineParser doubleQuoteEnd >>=
1061+ return . B.doubleQuoted . mconcat
9311062
9321063failIfInQuoteContext :: QuoteContext -> Parser [tok] ParserState ()
9331064failIfInQuoteContext context = do
@@ -942,17 +1073,11 @@ charOrRef cs =
9421073 guard (c `elem` cs)
9431074 return c)
9441075
945−updateLastStrPos :: Parser [Char] ParserState ()
946−updateLastStrPos = getPosition >>= \p ->
947− updateState $ \s -> s{ stateLastStrPos = Just p }
948−
9491076singleQuoteStart :: Parser [Char] ParserState ()
9501077singleQuoteStart = do
9511078 failIfInQuoteContext InSingleQuote
952− pos <- getPosition
953− st <- getState
9541079 -- single quote start can't be right after str
955− guard $ stateLastStrPos st /= Just pos
1080+ guard =<< notAfterString
9561081 () <$ charOrRef "'\8216\145"
9571082
9581083singleQuoteEnd :: Parser [Char] st ()
@@ -964,24 +1089,24 @@ doubleQuoteStart :: Parser [Char] ParserState ()
9641089doubleQuoteStart = do
9651090 failIfInQuoteContext InDoubleQuote
9661091 try $ do charOrRef "\"\8220\147"
967− notFollowedBy (satisfy (\c -> c == ' ' || c == '\t' || c == '\n'))
1092+ notFollowedBy . satisfy $ flip elem [' ', '\t', '\n']
9681093
9691094doubleQuoteEnd :: Parser [Char] st ()
9701095doubleQuoteEnd = do
9711096 charOrRef "\"\8221\148"
9721097 return ()
9731098
974−ellipses :: Parser [Char] st Inline
1099+ellipses :: Parser [Char] st Inlines
9751100ellipses = do
9761101 try (charOrRef "\8230\133") <|> try (string "..." >> return '…')
977− return (Str "\8230")
1102+ return (B.str "\8230")
9781103
979−dash :: Parser [Char] ParserState Inline
1104+dash :: Parser [Char] ParserState Inlines
9801105dash = do
9811106 oldDashes <- getOption readerOldDashes
9821107 if oldDashes
9831108 then emDashOld <|> enDashOld
984− else Str `fmap` (hyphenDash <|> emDash <|> enDash)
1109+ else B.str `fmap` (hyphenDash <|> emDash <|> enDash)
9851110
9861111-- Two hyphens = en-dash, three = em-dash
9871112hyphenDash :: Parser [Char] st String
@@ -999,16 +1124,16 @@ enDash = do
9991124 try (charOrRef "\8212\151")
10001125 return "\8211"
10011126
1002−enDashOld :: Parser [Char] st Inline
1127+enDashOld :: Parser [Char] st Inlines
10031128enDashOld = do
10041129 try (charOrRef "\8211\150") <|>
10051130 try (char '-' >> lookAhead (satisfy isDigit) >> return '–')
1006− return (Str "\8211")
1131+ return (B.str "\8211")
10071132
1008−emDashOld :: Parser [Char] st Inline
1133+emDashOld :: Parser [Char] st Inlines
10091134emDashOld = do
10101135 try (charOrRef "\8212\151") <|> (try $ string "--" >> optional (char '-') >> return '-')
1011− return (Str "\8212")
1136+ return (B.str "\8212")
10121137
10131138-- This is used to prevent exponential blowups for things like:
10141139-- a**a*a**a*a**a*a**a*a**a*a**a*a**
@@ -1022,12 +1147,24 @@ nested p = do
10221147 updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
10231148 return res
10241149
1150+citeKey :: HasLastStrPosition st => Parser [Char] st (Bool, String)
1151+citeKey = try $ do
1152+ guard =<< notAfterString
1153+ suppress_author <- option False (char '-' *> return True)
1154+ char '@'
1155+ firstChar <- letter <|> char '_'
1156+ let regchar = satisfy (\c -> isAlphaNum c || c == '_')
1157+ let internal p = try $ p <* lookAhead regchar
1158+ rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/")
1159+ let key = firstChar:rest
1160+ return (suppress_author, key)
1161+
10251162--
10261163-- Macros
10271164--
10281165
10291166-- | Parse a \newcommand or \renewcommand macro definition.
1030−macro :: Parser [Char] ParserState Blocks
1167+macro :: (HasMacros st, HasReaderOptions st) => Parser [Char] st Blocks
10311168macro = do
10321169 apply <- getOption readerApplyMacros
10331170 inp <- getInput
@@ -1037,7 +1174,7 @@ macro = do
10371174 if apply
10381175 then do
10391176 updateState $ \st ->
1040− st { stateMacros = ms ++ stateMacros st }
1177+ updateMacros (ms ++) st
10411178 return mempty
10421179 else return $ rawBlock "latex" def'
10431180
@@ -1046,7 +1183,6 @@ applyMacros' :: String -> Parser [Char] ParserState String
10461183applyMacros' target = do
10471184 apply <- getOption readerApplyMacros
10481185 if apply
1049− then do macros <- liftM stateMacros getState
1186+ then do macros <- extractMacros `fmap` getState
10501187 return $ applyMacros macros target
10511188 else return target
1052−
src/Text/Pandoc/Pretty.hs+14−6
@@ -1,6 +1,6 @@
1−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1+{-# LANGUAGE GeneralizedNewtypeDeriving, CPP #-}
22{-
3−Copyright (C) 2010 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2010-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111(-1)307 USA
1919
2020{- |
2121 Module : Text.Pandoc.Pretty
22− Copyright : Copyright (C) 2010 John MacFarlane
22+ Copyright : Copyright (C) 2010-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -60,6 +60,7 @@ module Text.Pandoc.Pretty (
6060 , hsep
6161 , vcat
6262 , vsep
63+ , nestle
6364 , chomp
6465 , inside
6566 , braces
@@ -72,7 +73,7 @@ module Text.Pandoc.Pretty (
7273 )
7374
7475where
75−import Data.Sequence (Seq, fromList, (<|), singleton, mapWithIndex)
76+import Data.Sequence (Seq, fromList, (<|), singleton, mapWithIndex, viewl, ViewL(..))
7677import Data.Foldable (toList)
7778import Data.List (intercalate)
7879import Data.Monoid
@@ -80,8 +81,7 @@ import Data.String
8081import Control.Monad.State
8182import Data.Char (isSpace)
8283
83−data Monoid a =>
84− RenderState a = RenderState{
84+data RenderState a = RenderState{
8585 output :: [a] -- ^ In reverse order
8686 , prefix :: String
8787 , usePrefix :: Bool
@@ -186,6 +186,14 @@ vcat = foldr ($$) empty
186186vsep :: [Doc] -> Doc
187187vsep = foldr ($+$) empty
188188
189+-- | Removes leading blank lines from a 'Doc'.
190+nestle :: Doc -> Doc
191+nestle (Doc d) = Doc $ go d
192+ where go x = case viewl x of
193+ (BlankLine :< rest) -> go rest
194+ (NewLine :< rest) -> go rest
195+ _ -> x
196+
189197-- | Chomps trailing blank space off of a 'Doc'.
190198chomp :: Doc -> Doc
191199chomp d = Doc (fromList dl')
src/Text/Pandoc/Process.hsnew file+104
@@ -0,0 +1,104 @@
1+{-
2+Copyright (C) 2013-2014 John MacFarlane <jgm@berkeley.edu>
3+
4+This program is free software; you can redistribute it and/or modify
5+it under the terms of the GNU General Public License as published by
6+the Free Software Foundation; either version 2 of the License, or
7+(at your option) any later version.
8+
9+This program is distributed in the hope that it will be useful,
10+but WITHOUT ANY WARRANTY; without even the implied warranty of
11+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+GNU General Public License for more details.
13+
14+You should have received a copy of the GNU General Public License
15+along with this program; if not, write to the Free Software
16+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+-}
18+
19+{- |
20+ Module : Text.Pandoc.Process
21+ Copyright : Copyright (C) 2013-2014 John MacFarlane
22+ License : GNU GPL, version 2 or above
23+
24+ Maintainer : John MacFarlane <jgm@berkeley.edu>
25+ Stability : alpha
26+ Portability : portable
27+
28+ByteString variant of 'readProcessWithExitCode'.
29+-}
30+module Text.Pandoc.Process (pipeProcess)
31+where
32+import System.Process
33+import System.Exit (ExitCode (..))
34+import Control.Exception
35+import System.IO (hClose, hFlush)
36+import Control.Concurrent (putMVar, takeMVar, newEmptyMVar, forkIO)
37+import Control.Monad (unless)
38+import qualified Data.ByteString.Lazy as BL
39+
40+{- |
41+Version of 'System.Process.readProcessWithExitCode' that uses lazy bytestrings
42+instead of strings and allows setting environment variables.
43+
44+@readProcessWithExitCode@ creates an external process, reads its
45+standard output and standard error strictly, waits until the process
46+terminates, and then returns the 'ExitCode' of the process,
47+the standard output, and the standard error.
48+
49+If an asynchronous exception is thrown to the thread executing
50+@readProcessWithExitCode@, the forked process will be terminated and
51+@readProcessWithExitCode@ will wait (block) until the process has been
52+terminated.
53+-}
54+
55+pipeProcess
56+ :: Maybe [(String, String)] -- ^ environment variables
57+ -> FilePath -- ^ Filename of the executable (see 'proc' for details)
58+ -> [String] -- ^ any arguments
59+ -> BL.ByteString -- ^ standard input
60+ -> IO (ExitCode,BL.ByteString,BL.ByteString) -- ^ exitcode, stdout, stderr
61+pipeProcess mbenv cmd args input =
62+ mask $ \restore -> do
63+ (Just inh, Just outh, Just errh, pid) <- createProcess (proc cmd args)
64+ { env = mbenv,
65+ std_in = CreatePipe,
66+ std_out = CreatePipe,
67+ std_err = CreatePipe }
68+ flip onException
69+ (do hClose inh; hClose outh; hClose errh;
70+ terminateProcess pid; waitForProcess pid) $ restore $ do
71+ -- fork off a thread to start consuming stdout
72+ out <- BL.hGetContents outh
73+ waitOut <- forkWait $ evaluate $ BL.length out
74+
75+ -- fork off a thread to start consuming stderr
76+ err <- BL.hGetContents errh
77+ waitErr <- forkWait $ evaluate $ BL.length err
78+
79+ -- now write and flush any input
80+ let writeInput = do
81+ unless (BL.null input) $ do
82+ BL.hPutStr inh input
83+ hFlush inh
84+ hClose inh
85+
86+ writeInput
87+
88+ -- wait on the output
89+ waitOut
90+ waitErr
91+
92+ hClose outh
93+ hClose errh
94+
95+ -- wait on the process
96+ ex <- waitForProcess pid
97+
98+ return (ex, out, err)
99+
100+forkWait :: IO a -> IO (IO a)
101+forkWait a = do
102+ res <- newEmptyMVar
103+ _ <- mask $ \restore -> forkIO $ try (restore a) >>= putMVar res
104+ return (takeMVar res >>= either (\ex -> throwIO (ex :: SomeException)) return)
src/Text/Pandoc/Readers/DocBook.hs+90−50
@@ -1,16 +1,18 @@
11module Text.Pandoc.Readers.DocBook ( readDocBook ) where
2−import Data.Char (toUpper, isDigit)
2+import Data.Char (toUpper)
3+import Text.Pandoc.Shared (safeRead)
34import Text.Pandoc.Options
45import Text.Pandoc.Definition
56import Text.Pandoc.Builder
67import Text.XML.Light
7−import Text.HTML.TagSoup.Entity (lookupEntity)
8+import Text.Pandoc.Compat.TagSoupEntity (lookupEntity)
89import Data.Generics
910import Data.Monoid
1011import Data.Char (isSpace)
1112import Control.Monad.State
1213import Control.Applicative ((<$>))
1314import Data.List (intersperse)
15+import Data.Maybe (fromMaybe)
1416
1517{-
1618
@@ -43,7 +45,7 @@ List of all DocBook tags, with [x] indicating implemented,
4345[ ] audioobject - A wrapper for audio data and its associated meta-information
4446[x] author - The name of an individual author
4547[ ] authorblurb - A short description or note about an author
46−[ ] authorgroup - Wrapper for author information when a document has
48+[x] authorgroup - Wrapper for author information when a document has
4749 multiple authors or collabarators
4850[x] authorinitials - The initials or other short identifier for an author
4951[o] beginpage - The location of a page break in a print version of the document
@@ -339,7 +341,7 @@ List of all DocBook tags, with [x] indicating implemented,
339341[x] refsectioninfo - Meta-information for a refsection
340342[ ] refsynopsisdiv - A syntactic synopsis of the subject of the reference page
341343[ ] refsynopsisdivinfo - Meta-information for a RefSynopsisDiv
342−[ ] releaseinfo - Information about a particular release of a document
344+[x] releaseinfo - Information about a particular release of a document
343345[ ] remark - A remark (or comment) intended for presentation in a draft
344346 manuscript
345347[ ] replaceable - Content that may or must be replaced by the user
@@ -490,34 +492,40 @@ List of all DocBook tags, with [x] indicating implemented,
490492 anything else
491493[ ] xref - A cross reference to another part of the document
492494[ ] year - The year of publication of a document
493−
495+[x] ?asciidoc-br? - line break from asciidoc docbook output
494496-}
495497
496498type DB = State DBState
497499
498500data DBState = DBState{ dbSectionLevel :: Int
499501 , dbQuoteType :: QuoteType
500− , dbDocTitle :: Inlines
501− , dbDocAuthors :: [Inlines]
502− , dbDocDate :: Inlines
502+ , dbMeta :: Meta
503+ , dbAcceptsMeta :: Bool
503504 , dbBook :: Bool
504505 , dbFigureTitle :: Inlines
505506 } deriving Show
506507
507508readDocBook :: ReaderOptions -> String -> Pandoc
508−readDocBook _ inp = setTitle (dbDocTitle st')
509− $ setAuthors (dbDocAuthors st')
510− $ setDate (dbDocDate st')
511− $ doc $ mconcat bs
512− where (bs, st') = runState (mapM parseBlock $ normalizeTree $ parseXML inp)
509+readDocBook _ inp = Pandoc (dbMeta st') (toList $ mconcat bs)
510+ where (bs, st') = runState (mapM parseBlock $ normalizeTree $ parseXML inp')
513511 DBState{ dbSectionLevel = 0
514512 , dbQuoteType = DoubleQuote
515− , dbDocTitle = mempty
516− , dbDocAuthors = []
517− , dbDocDate = mempty
513+ , dbMeta = mempty
514+ , dbAcceptsMeta = False
518515 , dbBook = False
519516 , dbFigureTitle = mempty
520517 }
518+ inp' = handleInstructions inp
519+
520+-- We treat <?asciidoc-br?> specially (issue #1236), converting it
521+-- to <br/>, since xml-light doesn't parse the instruction correctly.
522+-- Other xml instructions are simply removed from the input stream.
523+handleInstructions :: String -> String
524+handleInstructions ('<':'?':'a':'s':'c':'i':'i':'d':'o':'c':'-':'b':'r':'?':'>':xs) = '<':'b':'r':'/':'>': handleInstructions xs
525+handleInstructions xs = case break (=='<') xs of
526+ (ys, []) -> ys
527+ ([], '<':zs) -> '<' : handleInstructions zs
528+ (ys, zs) -> ys ++ handleInstructions zs
521529
522530getFigure :: Element -> DB Blocks
523531getFigure e = do
@@ -558,6 +566,30 @@ attrValue attr elt =
558566named :: String -> Element -> Bool
559567named s e = qName (elName e) == s
560568
569+--
570+
571+acceptingMetadata :: DB a -> DB a
572+acceptingMetadata p = do
573+ modify (\s -> s { dbAcceptsMeta = True } )
574+ res <- p
575+ modify (\s -> s { dbAcceptsMeta = False })
576+ return res
577+
578+checkInMeta :: Monoid a => DB () -> DB a
579+checkInMeta p = do
580+ accepts <- dbAcceptsMeta <$> get
581+ when accepts p
582+ return mempty
583+
584+
585+
586+addMeta :: ToMetaValue a => String -> a -> DB ()
587+addMeta field val = modify (setMeta field val)
588+
589+instance HasMeta DBState where
590+ setMeta field v s = s {dbMeta = setMeta field v (dbMeta s)}
591+ deleteMeta field s = s {dbMeta = deleteMeta field (dbMeta s)}
592+
561593isBlockElement :: Content -> Bool
562594isBlockElement (Elem e) = qName (elName e) `elem` blocktags
563595 where blocktags = ["toc","index","para","formalpara","simpara",
@@ -604,6 +636,7 @@ getImage e = do
604636getBlocks :: Element -> DB Blocks
605637getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
606638
639+
607640parseBlock :: Content -> DB Blocks
608641parseBlock (Text (CData CDataRaw _ _)) = return mempty -- DOCTYPE
609642parseBlock (Text (CData _ s _)) = if all isSpace s
@@ -617,10 +650,10 @@ parseBlock (Elem e) =
617650 "para" -> parseMixed para (elContent e)
618651 "formalpara" -> do
619652 tit <- case filterChild (named "title") e of
620− Just t -> (<> str "." <> linebreak) <$> emph
621− <$> getInlines t
653+ Just t -> (para . strong . (<> str ".")) <$>
654+ getInlines t
622655 Nothing -> return mempty
623− addToStart tit <$> parseMixed para (elContent e)
656+ (tit <>) <$> parseMixed para (elContent e)
624657 "simpara" -> parseMixed para (elContent e)
625658 "ackno" -> parseMixed para (elContent e)
626659 "epigraph" -> parseBlockquote
@@ -628,7 +661,11 @@ parseBlock (Elem e) =
628661 "attribution" -> return mempty
629662 "titleabbrev" -> return mempty
630663 "authorinitials" -> return mempty
631− "title" -> return mempty -- handled by getTitle or sect or figure
664+ "title" -> checkInMeta getTitle
665+ "author" -> checkInMeta getAuthor
666+ "authorgroup" -> checkInMeta getAuthorGroup
667+ "releaseinfo" -> checkInMeta (getInlines e >>= addMeta "release")
668+ "date" -> checkInMeta getDate
632669 "bibliography" -> sect 0
633670 "bibliodiv" -> sect 1
634671 "biblioentry" -> parseMixed para (elContent e)
@@ -682,18 +719,17 @@ parseBlock (Elem e) =
682719 "lowerroman" -> LowerRoman
683720 "upperroman" -> UpperRoman
684721 _ -> Decimal
685− let start = case attrValue "override" <$>
686− filterElement (named "listitem") e of
687− Just x@(_:_) | all isDigit x -> read x
688− _ -> 1
722+ let start = fromMaybe 1 $
723+ (attrValue "override" <$> filterElement (named "listitem") e)
724+ >>= safeRead
689725 orderedListWith (start,listStyle,DefaultDelim)
690726 <$> listitems
691727 "variablelist" -> definitionList <$> deflistitems
692728 "figure" -> getFigure e
693729 "mediaobject" -> para <$> getImage e
694730 "caption" -> return mempty
695− "info" -> getTitle >> getAuthors >> getDate >> return mempty
696− "articleinfo" -> getTitle >> getAuthors >> getDate >> return mempty
731+ "info" -> metaBlock
732+ "articleinfo" -> metaBlock
697733 "sectioninfo" -> return mempty -- keywords & other metadata
698734 "refsectioninfo" -> return mempty -- keywords & other metadata
699735 "refsect1info" -> return mempty -- keywords & other metadata
@@ -707,10 +743,10 @@ parseBlock (Elem e) =
707743 "chapterinfo" -> return mempty -- keywords & other metadata
708744 "glossaryinfo" -> return mempty -- keywords & other metadata
709745 "appendixinfo" -> return mempty -- keywords & other metadata
710− "bookinfo" -> getTitle >> getAuthors >> getDate >> return mempty
746+ "bookinfo" -> metaBlock
711747 "article" -> modify (\st -> st{ dbBook = False }) >>
712− getTitle >> getBlocks e
713− "book" -> modify (\st -> st{ dbBook = True }) >> getTitle >> getBlocks e
748+ getBlocks e
749+ "book" -> modify (\st -> st{ dbBook = True }) >> getBlocks e
714750 "table" -> parseTable
715751 "informaltable" -> parseTable
716752 "literallayout" -> codeBlockWithLang
@@ -756,30 +792,25 @@ parseBlock (Elem e) =
756792 terms' <- mapM getInlines terms
757793 items' <- mapM getBlocks items
758794 return (mconcat $ intersperse (str "; ") terms', items')
759− getTitle = case filterChild (named "title") e of
760− Just t -> do
761− tit <- getInlines t
762− subtit <- case filterChild (named "subtitle") e of
763− Just s -> (text ": " <>) <$>
764− getInlines s
765− Nothing -> return mempty
766− modify $ \st -> st{dbDocTitle = tit <> subtit}
767− Nothing -> return ()
768− getAuthors = do
769− auths <- mapM getInlines
770− $ filterChildren (named "author") e
771− modify $ \st -> st{dbDocAuthors = auths}
772− getDate = case filterChild (named "date") e of
773− Just t -> do
774− dat <- getInlines t
775− modify $ \st -> st{dbDocDate = dat}
776− Nothing -> return ()
795+ getTitle = do
796+ tit <- getInlines e
797+ subtit <- case filterChild (named "subtitle") e of
798+ Just s -> (text ": " <>) <$>
799+ getInlines s
800+ Nothing -> return mempty
801+ addMeta "title" (tit <> subtit)
802+
803+ getAuthor = (:[]) <$> getInlines e >>= addMeta "author"
804+ getAuthorGroup = do
805+ let terms = filterChildren (named "author") e
806+ mapM getInlines terms >>= addMeta "author"
807+ getDate = getInlines e >>= addMeta "date"
777808 parseTable = do
778809 let isCaption x = named "title" x || named "caption" x
779810 caption <- case filterChild isCaption e of
780811 Just t -> getInlines t
781812 Nothing -> return mempty
782− let e' = maybe e id $ filterChild (named "tgroup") e
813+ let e' = fromMaybe e $ filterChild (named "tgroup") e
783814 let isColspec x = named "colspec" x || named "col" x
784815 let colspecs = case filterChild (named "colgroup") e' of
785816 Just c -> filterChildren isColspec c
@@ -801,11 +832,14 @@ parseBlock (Elem e) =
801832 Just "center" -> AlignCenter
802833 _ -> AlignDefault
803834 let toWidth c = case findAttr (unqual "colwidth") c of
804− Just w -> read $ filter (\x ->
835+ Just w -> fromMaybe 0
836+ $ safeRead $ '0': filter (\x ->
805837 (x >= '0' && x <= '9')
806838 || x == '.') w
807839 Nothing -> 0 :: Double
808− let numrows = maximum $ map length bodyrows
840+ let numrows = case bodyrows of
841+ [] -> 0
842+ xs -> maximum $ map length xs
809843 let aligns = case colspecs of
810844 [] -> replicate numrows AlignDefault
811845 cs -> map toAlignment cs
@@ -832,6 +866,7 @@ parseBlock (Elem e) =
832866 b <- getBlocks e
833867 modify $ \st -> st{ dbSectionLevel = n - 1 }
834868 return $ header n' headerText <> b
869+ metaBlock = acceptingMetadata (getBlocks e) >> return mempty
835870
836871getInlines :: Element -> DB Inlines
837872getInlines e' = (trimInlines . mconcat) <$> (mapM parseInline $ elContent e')
@@ -895,6 +930,11 @@ parseInline (Elem e) =
895930 _ -> emph <$> innerInlines
896931 "footnote" -> (note . mconcat) <$> (mapM parseBlock $ elContent e)
897932 "title" -> return mempty
933+ "affiliation" -> return mempty
934+ -- Note: this isn't a real docbook tag; it's what we convert
935+ -- <?asciidor-br?> to in handleInstructions, above. A kludge to
936+ -- work around xml-light's inability to parse an instruction.
937+ "br" -> return linebreak
898938 _ -> innerInlines
899939 where innerInlines = (trimInlines . mconcat) <$>
900940 (mapM parseInline $ elContent e)
src/Text/Pandoc/Readers/Docx.hsnew file+489
@@ -0,0 +1,489 @@
1+{-# LANGUAGE PatternGuards #-}
2+
3+{-
4+Copyright (C) 2014 Jesse Rosenthal <jrosenthal@jhu.edu>
5+
6+This program is free software; you can redistribute it and/or modify
7+it under the terms of the GNU General Public License as published by
8+the Free Software Foundation; either version 2 of the License, or
9+(at your option) any later version.
10+
11+This program is distributed in the hope that it will be useful,
12+but WITHOUT ANY WARRANTY; without even the implied warranty of
13+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+GNU General Public License for more details.
15+
16+You should have received a copy of the GNU General Public License
17+along with this program; if not, write to the Free Software
18+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19+-}
20+
21+{- |
22+ Module : Text.Pandoc.Readers.Docx
23+ Copyright : Copyright (C) 2014 Jesse Rosenthal
24+ License : GNU GPL, version 2 or above
25+
26+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
27+ Stability : alpha
28+ Portability : portable
29+
30+Conversion of Docx type (defined in Text.Pandoc.Readers.Docx.Parse)
31+to 'Pandoc' document. -}
32+
33+{-
34+Current state of implementation of Docx entities ([x] means
35+implemented, [-] means partially implemented):
36+
37+* Blocks
38+
39+ - [X] Para
40+ - [X] CodeBlock (styled with `SourceCode`)
41+ - [X] BlockQuote (styled with `Quote`, `BlockQuote`, or, optionally,
42+ indented)
43+ - [X] OrderedList
44+ - [X] BulletList
45+ - [X] DefinitionList (styled with adjacent `DefinitionTerm` and `Definition`)
46+ - [X] Header (styled with `Heading#`)
47+ - [ ] HorizontalRule
48+ - [-] Table (column widths and alignments not yet implemented)
49+
50+* Inlines
51+
52+ - [X] Str
53+ - [X] Emph (From italics. `underline` currently read as span. In
54+ future, it might optionally be emph as well)
55+ - [X] Strong
56+ - [X] Strikeout
57+ - [X] Superscript
58+ - [X] Subscript
59+ - [X] SmallCaps
60+ - [ ] Quoted
61+ - [ ] Cite
62+ - [X] Code (styled with `VerbatimChar`)
63+ - [X] Space
64+ - [X] LineBreak (these are invisible in Word: entered with Shift-Return)
65+ - [ ] Math
66+ - [X] Link (links to an arbitrary bookmark create a span with the target as
67+ id and "anchor" class)
68+ - [-] Image (Links to path in archive. Future option for
69+ data-encoded URI likely.)
70+ - [X] Note (Footnotes and Endnotes are silently combined.)
71+-}
72+
73+module Text.Pandoc.Readers.Docx
74+ ( readDocx
75+ ) where
76+
77+import Codec.Archive.Zip
78+import Text.Pandoc.Definition
79+import Text.Pandoc.Options
80+import Text.Pandoc.Builder (text, toList)
81+import Text.Pandoc.MIME (getMimeType)
82+import Text.Pandoc.UTF8 (toString)
83+import Text.Pandoc.Walk
84+import Text.Pandoc.Readers.Docx.Parse
85+import Text.Pandoc.Readers.Docx.Lists
86+import Text.Pandoc.Readers.Docx.Reducible
87+import Text.Pandoc.Shared
88+import Data.Maybe (mapMaybe)
89+import Data.List (delete, isPrefixOf, (\\))
90+import qualified Data.ByteString as BS
91+import qualified Data.ByteString.Lazy as B
92+import Data.ByteString.Base64 (encode)
93+import System.FilePath (combine)
94+import qualified Data.Map as M
95+import Control.Monad.Reader
96+import Control.Monad.State
97+
98+readDocx :: ReaderOptions
99+ -> B.ByteString
100+ -> Pandoc
101+readDocx opts bytes =
102+ case archiveToDocx (toArchive bytes) of
103+ Just docx -> Pandoc nullMeta (docxToBlocks opts docx)
104+ Nothing -> error $ "couldn't parse docx file"
105+
106+data DState = DState { docxAnchorMap :: M.Map String String }
107+
108+data DEnv = DEnv { docxOptions :: ReaderOptions
109+ , docxDocument :: Docx}
110+
111+type DocxContext = ReaderT DEnv (State DState)
112+
113+evalDocxContext :: DocxContext a -> DEnv -> DState -> a
114+evalDocxContext ctx env st = evalState (runReaderT ctx env) st
115+
116+concatMapM :: (Monad m) => (a -> m [b]) -> [a] -> m [b]
117+concatMapM f xs = liftM concat (mapM f xs)
118+
119+-- This is empty, but we put it in for future-proofing.
120+spansToKeep :: [String]
121+spansToKeep = []
122+
123+divsToKeep :: [String]
124+divsToKeep = ["list-item", "Definition", "DefinitionTerm"]
125+
126+runStyleToContainers :: RunStyle -> [Container Inline]
127+runStyleToContainers rPr =
128+ let spanClassToContainers :: String -> [Container Inline]
129+ spanClassToContainers s | s `elem` codeSpans =
130+ [Container $ (\ils -> Code ("", [], []) (concatMap ilToCode ils))]
131+ spanClassToContainers s | s `elem` spansToKeep =
132+ [Container $ Span ("", [s], [])]
133+ spanClassToContainers _ = []
134+
135+ classContainers = case rStyle rPr of
136+ Nothing -> []
137+ Just s -> spanClassToContainers s
138+
139+ formatters = map Container $ mapMaybe id
140+ [ if isBold rPr then (Just Strong) else Nothing
141+ , if isItalic rPr then (Just Emph) else Nothing
142+ , if isSmallCaps rPr then (Just SmallCaps) else Nothing
143+ , if isStrike rPr then (Just Strikeout) else Nothing
144+ , if isSuperScript rPr then (Just Superscript) else Nothing
145+ , if isSubScript rPr then (Just Subscript) else Nothing
146+ , underline rPr >>= (\f -> Just $ Span ("", [], [("underline", f)]))
147+ ]
148+ in
149+ classContainers ++ formatters
150+
151+
152+divAttrToContainers :: [String] -> [(String, String)] -> [Container Block]
153+divAttrToContainers (c:cs) _ | Just n <- isHeaderClass c =
154+ [Container $ \_ ->
155+ Header n ("", delete ("Heading" ++ show n) cs, []) []]
156+divAttrToContainers (c:cs) kvs | c `elem` divsToKeep =
157+ (Container $ Div ("", [c], [])) : (divAttrToContainers cs kvs)
158+divAttrToContainers (c:cs) kvs | c `elem` codeDivs =
159+ -- This is a bit of a cludge. We make the codeblock from the raw
160+ -- parparts in bodyPartToBlocks. But we need something to match against.
161+ (Container $ \_ -> CodeBlock ("", [], []) "") : (divAttrToContainers cs kvs)
162+divAttrToContainers (c:cs) kvs | c `elem` listParagraphDivs =
163+ let kvs' = filter (\(k,_) -> k /= "indent") kvs
164+ in
165+ (Container $ Div ("", [c], [])) : (divAttrToContainers cs kvs')
166+divAttrToContainers (c:cs) kvs | c `elem` blockQuoteDivs =
167+ (Container BlockQuote) : (divAttrToContainers (cs \\ blockQuoteDivs) kvs)
168+divAttrToContainers (_:cs) kvs = divAttrToContainers cs kvs
169+divAttrToContainers [] kvs | Just numString <- lookup "indent" kvs =
170+ let kvs' = filter (\(k,_) -> k /= "indent") kvs
171+ in
172+ case numString of
173+ "0" -> divAttrToContainers [] kvs'
174+ ('-' : _) -> divAttrToContainers [] kvs'
175+ _ -> (Container BlockQuote) : divAttrToContainers [] kvs'
176+divAttrToContainers _ _ = []
177+
178+
179+parStyleToContainers :: ParagraphStyle -> [Container Block]
180+parStyleToContainers pPr =
181+ let classes = pStyle pPr
182+ kvs = case indent pPr of
183+ Just n -> [("indent", show n)]
184+ Nothing -> []
185+ in
186+ divAttrToContainers classes kvs
187+
188+
189+strToInlines :: String -> [Inline]
190+strToInlines = toList . text
191+
192+codeSpans :: [String]
193+codeSpans = ["VerbatimChar"]
194+
195+blockQuoteDivs :: [String]
196+blockQuoteDivs = ["Quote", "BlockQuote"]
197+
198+codeDivs :: [String]
199+codeDivs = ["SourceCode"]
200+
201+runElemToInlines :: RunElem -> [Inline]
202+runElemToInlines (TextRun s) = strToInlines s
203+runElemToInlines (LnBrk) = [LineBreak]
204+runElemToInlines (Tab) = [Space]
205+
206+runElemToString :: RunElem -> String
207+runElemToString (TextRun s) = s
208+runElemToString (LnBrk) = ['\n']
209+runElemToString (Tab) = ['\t']
210+
211+runElemsToString :: [RunElem] -> String
212+runElemsToString = concatMap runElemToString
213+
214+runToString :: Run -> String
215+runToString (Run _ runElems) = runElemsToString runElems
216+runToString _ = ""
217+
218+parPartToString :: ParPart -> String
219+parPartToString (PlainRun run) = runToString run
220+parPartToString (InternalHyperLink _ runs) = concatMap runToString runs
221+parPartToString (ExternalHyperLink _ runs) = concatMap runToString runs
222+parPartToString _ = ""
223+
224+
225+inlineCodeContainer :: Container Inline -> Bool
226+inlineCodeContainer (Container f) = case f [] of
227+ Code _ "" -> True
228+ _ -> False
229+inlineCodeContainer _ = False
230+
231+
232+runToInlines :: Run -> DocxContext [Inline]
233+runToInlines (Run rs runElems)
234+ | any inlineCodeContainer (runStyleToContainers rs) =
235+ return $
236+ rebuild (runStyleToContainers rs) $ [Str $ runElemsToString runElems]
237+ | otherwise =
238+ return $
239+ rebuild (runStyleToContainers rs) (concatMap runElemToInlines runElems)
240+runToInlines (Footnote fnId) = do
241+ (Docx _ notes _ _ _ ) <- asks docxDocument
242+ case (getFootNote fnId notes) of
243+ Just bodyParts -> do
244+ blks <- concatMapM bodyPartToBlocks bodyParts
245+ return $ [Note blks]
246+ Nothing -> return [Note []]
247+runToInlines (Endnote fnId) = do
248+ (Docx _ notes _ _ _ ) <- asks docxDocument
249+ case (getEndNote fnId notes) of
250+ Just bodyParts -> do
251+ blks <- concatMapM bodyPartToBlocks bodyParts
252+ return $ [Note blks]
253+ Nothing -> return [Note []]
254+
255+parPartToInlines :: ParPart -> DocxContext [Inline]
256+parPartToInlines (PlainRun r) = runToInlines r
257+parPartToInlines (Insertion _ author date runs) = do
258+ opts <- asks docxOptions
259+ case readerTrackChanges opts of
260+ AcceptChanges -> concatMapM runToInlines runs >>= return
261+ RejectChanges -> return []
262+ AllChanges -> do
263+ ils <- (concatMapM runToInlines runs)
264+ return [Span
265+ ("", ["insertion"], [("author", author), ("date", date)])
266+ ils]
267+parPartToInlines (Deletion _ author date runs) = do
268+ opts <- asks docxOptions
269+ case readerTrackChanges opts of
270+ AcceptChanges -> return []
271+ RejectChanges -> concatMapM runToInlines runs >>= return
272+ AllChanges -> do
273+ ils <- concatMapM runToInlines runs
274+ return [Span
275+ ("", ["deletion"], [("author", author), ("date", date)])
276+ ils]
277+parPartToInlines (BookMark _ anchor) | anchor `elem` dummyAnchors = return []
278+parPartToInlines (BookMark _ anchor) =
279+ -- We record these, so we can make sure not to overwrite
280+ -- user-defined anchor links with header auto ids.
281+ do
282+ -- Get the anchor map.
283+ anchorMap <- gets docxAnchorMap
284+ -- Check to see if the id is already in there. Rewrite if
285+ -- necessary. This will have the possible effect of rewriting
286+ -- user-defined anchor links. However, since these are not defined
287+ -- in pandoc, it seems like a necessary evil to avoid an extra
288+ -- pass.
289+ let newAnchor = case anchor `elem` (M.elems anchorMap) of
290+ True -> uniqueIdent [Str anchor] (M.elems anchorMap)
291+ False -> anchor
292+ put DState{ docxAnchorMap = M.insert anchor newAnchor anchorMap}
293+ return [Span (anchor, ["anchor"], []) []]
294+parPartToInlines (Drawing relid) = do
295+ (Docx _ _ _ rels _) <- asks docxDocument
296+ return $ case lookupRelationship relid rels of
297+ Just target -> [Image [] (combine "word" target, "")]
298+ Nothing -> [Image [] ("", "")]
299+parPartToInlines (InternalHyperLink anchor runs) = do
300+ ils <- concatMapM runToInlines runs
301+ return [Link ils ('#' : anchor, "")]
302+parPartToInlines (ExternalHyperLink relid runs) = do
303+ (Docx _ _ _ rels _) <- asks docxDocument
304+ rs <- concatMapM runToInlines runs
305+ return $ case lookupRelationship relid rels of
306+ Just target ->
307+ [Link rs (target, "")]
308+ Nothing ->
309+ [Link rs ("", "")]
310+
311+isAnchorSpan :: Inline -> Bool
312+isAnchorSpan (Span (ident, classes, kvs) ils) =
313+ (not . null) ident &&
314+ classes == ["anchor"] &&
315+ null kvs &&
316+ null ils
317+isAnchorSpan _ = False
318+
319+dummyAnchors :: [String]
320+dummyAnchors = ["_GoBack"]
321+
322+makeHeaderAnchor :: Block -> DocxContext Block
323+-- If there is an anchor already there (an anchor span in the header,
324+-- to be exact), we rename and associate the new id with the old one.
325+makeHeaderAnchor (Header n (_, classes, kvs) ils)
326+ | (x : xs) <- filter isAnchorSpan ils
327+ , (Span (ident, _, _) _) <- x
328+ , notElem ident dummyAnchors =
329+ do
330+ hdrIDMap <- gets docxAnchorMap
331+ let newIdent = uniqueIdent ils (M.elems hdrIDMap)
332+ put DState{docxAnchorMap = M.insert ident newIdent hdrIDMap}
333+ return $ Header n (newIdent, classes, kvs) (ils \\ (x:xs))
334+-- Otherwise we just give it a name, and register that name (associate
335+-- it with itself.)
336+makeHeaderAnchor (Header n (_, classes, kvs) ils) =
337+ do
338+ hdrIDMap <- gets docxAnchorMap
339+ let newIdent = uniqueIdent ils (M.elems hdrIDMap)
340+ put DState{docxAnchorMap = M.insert newIdent newIdent hdrIDMap}
341+ return $ Header n (newIdent, classes, kvs) ils
342+makeHeaderAnchor blk = return blk
343+
344+
345+parPartsToInlines :: [ParPart] -> DocxContext [Inline]
346+parPartsToInlines parparts = do
347+ ils <- concatMapM parPartToInlines parparts >>=
348+ -- TODO: Option for self-containted images
349+ (if False then (walkM makeImagesSelfContained) else return)
350+ return $ reduceList $ ils
351+
352+cellToBlocks :: Cell -> DocxContext [Block]
353+cellToBlocks (Cell bps) = concatMapM bodyPartToBlocks bps
354+
355+rowToBlocksList :: Row -> DocxContext [[Block]]
356+rowToBlocksList (Row cells) = mapM cellToBlocks cells
357+
358+isBlockCodeContainer :: Container Block -> Bool
359+isBlockCodeContainer (Container f) | CodeBlock _ _ <- f [] = True
360+isBlockCodeContainer _ = False
361+
362+isHeaderContainer :: Container Block -> Bool
363+isHeaderContainer (Container f) | Header _ _ _ <- f [] = True
364+isHeaderContainer _ = False
365+
366+bodyPartToBlocks :: BodyPart -> DocxContext [Block]
367+bodyPartToBlocks (Paragraph pPr parparts)
368+ | any isBlockCodeContainer (parStyleToContainers pPr) =
369+ let
370+ otherConts = filter (not . isBlockCodeContainer) (parStyleToContainers pPr)
371+ in
372+ return $
373+ rebuild
374+ otherConts
375+ [CodeBlock ("", [], []) (concatMap parPartToString parparts)]
376+bodyPartToBlocks (Paragraph pPr parparts)
377+ | any isHeaderContainer (parStyleToContainers pPr) = do
378+ ils <- parPartsToInlines parparts >>= (return . normalizeSpaces)
379+ let (Container hdrFun) = head $ filter isHeaderContainer (parStyleToContainers pPr)
380+ Header n attr _ = hdrFun []
381+ hdr <- makeHeaderAnchor $ Header n attr ils
382+ return [hdr]
383+bodyPartToBlocks (Paragraph pPr parparts) = do
384+ ils <- parPartsToInlines parparts >>= (return . normalizeSpaces)
385+ case ils of
386+ [] -> return []
387+ _ -> do
388+ return $
389+ rebuild
390+ (parStyleToContainers pPr)
391+ [Para ils]
392+bodyPartToBlocks (ListItem pPr numId lvl parparts) = do
393+ (Docx _ _ numbering _ _) <- asks docxDocument
394+ let
395+ kvs = case lookupLevel numId lvl numbering of
396+ Just (_, fmt, txt, Just start) -> [ ("level", lvl)
397+ , ("num-id", numId)
398+ , ("format", fmt)
399+ , ("text", txt)
400+ , ("start", (show start))
401+ ]
402+
403+ Just (_, fmt, txt, Nothing) -> [ ("level", lvl)
404+ , ("num-id", numId)
405+ , ("format", fmt)
406+ , ("text", txt)
407+ ]
408+ Nothing -> []
409+ blks <- bodyPartToBlocks (Paragraph pPr parparts)
410+ return $ [Div ("", ["list-item"], kvs) blks]
411+bodyPartToBlocks (Tbl _ _ _ []) =
412+ return [Para []]
413+bodyPartToBlocks (Tbl cap _ look (r:rs)) = do
414+ let caption = strToInlines cap
415+ (hdr, rows) = case firstRowFormatting look of
416+ True -> (Just r, rs)
417+ False -> (Nothing, r:rs)
418+ hdrCells <- case hdr of
419+ Just r' -> rowToBlocksList r'
420+ Nothing -> return []
421+
422+ cells <- mapM rowToBlocksList rows
423+
424+ let size = case null hdrCells of
425+ True -> length $ head cells
426+ False -> length $ hdrCells
427+ --
428+ -- The two following variables (horizontal column alignment and
429+ -- relative column widths) go to the default at the
430+ -- moment. Width information is in the TblGrid field of the Tbl,
431+ -- so should be possible. Alignment might be more difficult,
432+ -- since there doesn't seem to be a column entity in docx.
433+ alignments = replicate size AlignDefault
434+ widths = replicate size 0 :: [Double]
435+
436+ return [Table caption alignments widths hdrCells cells]
437+
438+-- replace targets with generated anchors.
439+rewriteLink :: Inline -> DocxContext Inline
440+rewriteLink l@(Link ils ('#':target, title)) = do
441+ anchorMap <- gets docxAnchorMap
442+ return $ case M.lookup target anchorMap of
443+ Just newTarget -> (Link ils ('#':newTarget, title))
444+ Nothing -> l
445+rewriteLink il = return il
446+
447+makeImagesSelfContained :: Inline -> DocxContext Inline
448+makeImagesSelfContained i@(Image alt (uri, title)) = do
449+ (Docx _ _ _ _ media) <- asks docxDocument
450+ return $ case lookup uri media of
451+ Just bs ->
452+ case getMimeType uri of
453+ Just mime ->
454+ let data_uri = "data:" ++ mime ++ ";base64," ++
455+ toString (encode $ BS.concat $ B.toChunks bs)
456+ in
457+ Image alt (data_uri, title)
458+ Nothing -> i
459+ Nothing -> i
460+makeImagesSelfContained inline = return inline
461+
462+bodyToBlocks :: Body -> DocxContext [Block]
463+bodyToBlocks (Body bps) = do
464+ blks <- concatMapM bodyPartToBlocks bps >>=
465+ walkM rewriteLink
466+ return $
467+ blocksToDefinitions $
468+ blocksToBullets $ blks
469+
470+docxToBlocks :: ReaderOptions -> Docx -> [Block]
471+docxToBlocks opts d@(Docx (Document _ body) _ _ _ _) =
472+ let dState = DState { docxAnchorMap = M.empty }
473+ dEnv = DEnv { docxOptions = opts
474+ , docxDocument = d}
475+ in
476+ evalDocxContext (bodyToBlocks body) dEnv dState
477+
478+ilToCode :: Inline -> String
479+ilToCode (Str s) = s
480+ilToCode Space = " "
481+ilToCode _ = ""
482+
483+isHeaderClass :: String -> Maybe Int
484+isHeaderClass s | "Heading" `isPrefixOf` s =
485+ case reads (drop (length "Heading") s) :: [(Int, String)] of
486+ [] -> Nothing
487+ ((n, "") : []) -> Just n
488+ _ -> Nothing
489+isHeaderClass _ = Nothing
src/Text/Pandoc/Readers/Docx/Lists.hsnew file+227
@@ -0,0 +1,227 @@
1+{-
2+Copyright (C) 2014 Jesse Rosenthal <jrosenthal@jhu.edu>
3+
4+This program is free software; you can redistribute it and/or modify
5+it under the terms of the GNU General Public License as published by
6+the Free Software Foundation; either version 2 of the License, or
7+(at your option) any later version.
8+
9+This program is distributed in the hope that it will be useful,
10+but WITHOUT ANY WARRANTY; without even the implied warranty of
11+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+GNU General Public License for more details.
13+
14+You should have received a copy of the GNU General Public License
15+along with this program; if not, write to the Free Software
16+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+-}
18+
19+{- |
20+ Module : Text.Pandoc.Readers.Docx.Lists
21+ Copyright : Copyright (C) 2014 Jesse Rosenthal
22+ License : GNU GPL, version 2 or above
23+
24+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
25+ Stability : alpha
26+ Portability : portable
27+
28+Functions for converting flat docx paragraphs into nested lists.
29+-}
30+
31+module Text.Pandoc.Readers.Docx.Lists ( blocksToBullets
32+ , blocksToDefinitions
33+ , listParagraphDivs
34+ ) where
35+
36+import Text.Pandoc.JSON
37+import Text.Pandoc.Generic (bottomUp)
38+import Text.Pandoc.Shared (trim)
39+import Control.Monad
40+import Data.List
41+import Data.Maybe
42+
43+isListItem :: Block -> Bool
44+isListItem (Div (_, classes, _) _) | "list-item" `elem` classes = True
45+isListItem _ = False
46+
47+getLevel :: Block -> Maybe Integer
48+getLevel (Div (_, _, kvs) _) = liftM read $ lookup "level" kvs
49+getLevel _ = Nothing
50+
51+getLevelN :: Block -> Integer
52+getLevelN b = case getLevel b of
53+ Just n -> n
54+ Nothing -> -1
55+
56+getNumId :: Block -> Maybe Integer
57+getNumId (Div (_, _, kvs) _) = liftM read $ lookup "num-id" kvs
58+getNumId _ = Nothing
59+
60+getNumIdN :: Block -> Integer
61+getNumIdN b = case getNumId b of
62+ Just n -> n
63+ Nothing -> -1
64+
65+getText :: Block -> Maybe String
66+getText (Div (_, _, kvs) _) = lookup "text" kvs
67+getText _ = Nothing
68+
69+data ListType = Itemized | Enumerated ListAttributes
70+
71+listStyleMap :: [(String, ListNumberStyle)]
72+listStyleMap = [("upperLetter", UpperAlpha),
73+ ("lowerLetter", LowerAlpha),
74+ ("upperRoman", UpperRoman),
75+ ("lowerRoman", LowerRoman),
76+ ("decimal", Decimal)]
77+
78+listDelimMap :: [(String, ListNumberDelim)]
79+listDelimMap = [("%1)", OneParen),
80+ ("(%1)", TwoParens),
81+ ("%1.", Period)]
82+
83+getListType :: Block -> Maybe ListType
84+getListType b@(Div (_, _, kvs) _) | isListItem b =
85+ let
86+ start = lookup "start" kvs
87+ frmt = lookup "format" kvs
88+ txt = lookup "text" kvs
89+ in
90+ case frmt of
91+ Just "bullet" -> Just Itemized
92+ Just f ->
93+ case txt of
94+ Just t -> Just $ Enumerated (
95+ read (fromMaybe "1" start) :: Int,
96+ fromMaybe DefaultStyle (lookup f listStyleMap),
97+ fromMaybe DefaultDelim (lookup t listDelimMap))
98+ Nothing -> Nothing
99+ _ -> Nothing
100+getListType _ = Nothing
101+
102+listParagraphDivs :: [String]
103+listParagraphDivs = ["ListParagraph"]
104+
105+-- This is a first stab at going through and attaching meaning to list
106+-- paragraphs, without an item marker, following a list item. We
107+-- assume that these are paragraphs in the same item.
108+
109+handleListParagraphs :: [Block] -> [Block]
110+handleListParagraphs [] = []
111+handleListParagraphs (
112+ (Div attr1@(_, classes1, _) blks1) :
113+ (Div (ident2, classes2, kvs2) blks2) :
114+ blks
115+ ) | "list-item" `elem` classes1 &&
116+ not ("list-item" `elem` classes2) &&
117+ (not . null) (listParagraphDivs `intersect` classes2) =
118+ -- We don't want to keep this indent.
119+ let newDiv2 =
120+ (Div (ident2, classes2, filter (\kv -> fst kv /= "indent") kvs2) blks2)
121+ in
122+ handleListParagraphs ((Div attr1 (blks1 ++ [newDiv2])) : blks)
123+handleListParagraphs (blk:blks) = blk : (handleListParagraphs blks)
124+
125+separateBlocks' :: Block -> [[Block]] -> [[Block]]
126+separateBlocks' blk ([] : []) = [[blk]]
127+separateBlocks' b@(BulletList _) acc = (init acc) ++ [(last acc) ++ [b]]
128+separateBlocks' b@(OrderedList _ _) acc = (init acc) ++ [(last acc) ++ [b]]
129+-- The following is for the invisible bullet lists. This is how
130+-- pandoc-generated ooxml does multiparagraph item lists.
131+separateBlocks' b acc | liftM trim (getText b) == Just "" =
132+ (init acc) ++ [(last acc) ++ [b]]
133+separateBlocks' b acc = acc ++ [[b]]
134+
135+separateBlocks :: [Block] -> [[Block]]
136+separateBlocks blks = foldr separateBlocks' [[]] (reverse blks)
137+
138+flatToBullets' :: Integer -> [Block] -> [Block]
139+flatToBullets' _ [] = []
140+flatToBullets' num xs@(b : elems)
141+ | getLevelN b == num = b : (flatToBullets' num elems)
142+ | otherwise =
143+ let bNumId = getNumIdN b
144+ bLevel = getLevelN b
145+ (children, remaining) =
146+ span
147+ (\b' ->
148+ ((getLevelN b') > bLevel ||
149+ ((getLevelN b') == bLevel && (getNumIdN b') == bNumId)))
150+ xs
151+ in
152+ case getListType b of
153+ Just (Enumerated attr) ->
154+ (OrderedList attr (separateBlocks $ flatToBullets' bLevel children)) :
155+ (flatToBullets' num remaining)
156+ _ ->
157+ (BulletList (separateBlocks $ flatToBullets' bLevel children)) :
158+ (flatToBullets' num remaining)
159+
160+flatToBullets :: [Block] -> [Block]
161+flatToBullets elems = flatToBullets' (-1) elems
162+
163+blocksToBullets :: [Block] -> [Block]
164+blocksToBullets blks =
165+ bottomUp removeListDivs $
166+ flatToBullets $ (handleListParagraphs blks)
167+
168+plainParaInlines :: Block -> [Inline]
169+plainParaInlines (Plain ils) = ils
170+plainParaInlines (Para ils) = ils
171+plainParaInlines _ = []
172+
173+blocksToDefinitions' :: [([Inline], [[Block]])] -> [Block] -> [Block] -> [Block]
174+blocksToDefinitions' [] acc [] = reverse acc
175+blocksToDefinitions' defAcc acc [] =
176+ reverse $ (DefinitionList (reverse defAcc)) : acc
177+blocksToDefinitions' defAcc acc
178+ ((Div (_, classes1, _) blks1) : (Div (ident2, classes2, kvs2) blks2) : blks)
179+ | "DefinitionTerm" `elem` classes1 && "Definition" `elem` classes2 =
180+ let remainingAttr2 = (ident2, delete "Definition" classes2, kvs2)
181+ pair = case remainingAttr2 == ("", [], []) of
182+ True -> (concatMap plainParaInlines blks1, [blks2])
183+ False -> (concatMap plainParaInlines blks1, [[Div remainingAttr2 blks2]])
184+ in
185+ blocksToDefinitions' (pair : defAcc) acc blks
186+blocksToDefinitions' defAcc acc
187+ ((Div (ident2, classes2, kvs2) blks2) : blks)
188+ | (not . null) defAcc && "Definition" `elem` classes2 =
189+ let remainingAttr2 = (ident2, delete "Definition" classes2, kvs2)
190+ defItems2 = case remainingAttr2 == ("", [], []) of
191+ True -> blks2
192+ False -> [Div remainingAttr2 blks2]
193+ ((defTerm, defItems):defs) = defAcc
194+ defAcc' = case null defItems of
195+ True -> (defTerm, [defItems2]) : defs
196+ False -> (defTerm, init defItems ++ [last defItems ++ defItems2]) : defs
197+ in
198+ blocksToDefinitions' defAcc' acc blks
199+blocksToDefinitions' [] acc (b:blks) =
200+ blocksToDefinitions' [] (b:acc) blks
201+blocksToDefinitions' defAcc acc (b:blks) =
202+ blocksToDefinitions' [] (b : (DefinitionList (reverse defAcc)) : acc) blks
203+
204+removeListDivs' :: Block -> [Block]
205+removeListDivs' (Div (ident, classes, kvs) blks)
206+ | "list-item" `elem` classes =
207+ case delete "list-item" classes of
208+ [] -> blks
209+ classes' -> [Div (ident, classes', kvs) $ blks]
210+removeListDivs' (Div (ident, classes, kvs) blks)
211+ | not $ null $ listParagraphDivs `intersect` classes =
212+ case classes \\ listParagraphDivs of
213+ [] -> blks
214+ classes' -> [Div (ident, classes', kvs) blks]
215+removeListDivs' blk = [blk]
216+
217+removeListDivs :: [Block] -> [Block]
218+removeListDivs = concatMap removeListDivs'
219+
220+
221+
222+blocksToDefinitions :: [Block] -> [Block]
223+blocksToDefinitions = blocksToDefinitions' [] []
224+
225+
226+
227+
src/Text/Pandoc/Readers/Docx/Parse.hsnew file+596
@@ -0,0 +1,596 @@
1+{-
2+Copyright (C) 2014 Jesse Rosenthal <jrosenthal@jhu.edu>
3+
4+This program is free software; you can redistribute it and/or modify
5+it under the terms of the GNU General Public License as published by
6+the Free Software Foundation; either version 2 of the License, or
7+(at your option) any later version.
8+
9+This program is distributed in the hope that it will be useful,
10+but WITHOUT ANY WARRANTY; without even the implied warranty of
11+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+GNU General Public License for more details.
13+
14+You should have received a copy of the GNU General Public License
15+along with this program; if not, write to the Free Software
16+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+-}
18+
19+{- |
20+ Module : Text.Pandoc.Readers.Docx.Parse
21+ Copyright : Copyright (C) 2014 Jesse Rosenthal
22+ License : GNU GPL, version 2 or above
23+
24+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
25+ Stability : alpha
26+ Portability : portable
27+
28+Conversion of docx archive into Docx haskell type
29+-}
30+
31+
32+module Text.Pandoc.Readers.Docx.Parse ( Docx(..)
33+ , Document(..)
34+ , Body(..)
35+ , BodyPart(..)
36+ , TblLook(..)
37+ , ParPart(..)
38+ , Run(..)
39+ , RunElem(..)
40+ , Notes
41+ , Numbering
42+ , Relationship
43+ , Media
44+ , RunStyle(..)
45+ , ParagraphStyle(..)
46+ , Row(..)
47+ , Cell(..)
48+ , getFootNote
49+ , getEndNote
50+ , lookupLevel
51+ , lookupRelationship
52+ , archiveToDocx
53+ ) where
54+import Codec.Archive.Zip
55+import Text.XML.Light
56+import Data.Maybe
57+import Data.List
58+import System.FilePath
59+import Data.Bits ((.|.))
60+import qualified Data.ByteString.Lazy as B
61+import qualified Text.Pandoc.UTF8 as UTF8
62+
63+attrToNSPair :: Attr -> Maybe (String, String)
64+attrToNSPair (Attr (QName s _ (Just "xmlns")) val) = Just (s, val)
65+attrToNSPair _ = Nothing
66+
67+
68+type NameSpaces = [(String, String)]
69+
70+data Docx = Docx Document Notes Numbering [Relationship] Media
71+ deriving Show
72+
73+archiveToDocx :: Archive -> Maybe Docx
74+archiveToDocx archive = do
75+ let notes = archiveToNotes archive
76+ rels = archiveToRelationships archive
77+ media = archiveToMedia archive
78+ doc <- archiveToDocument archive
79+ numbering <- archiveToNumbering archive
80+ return $ Docx doc notes numbering rels media
81+
82+data Document = Document NameSpaces Body
83+ deriving Show
84+
85+archiveToDocument :: Archive -> Maybe Document
86+archiveToDocument zf = do
87+ entry <- findEntryByPath "word/document.xml" zf
88+ docElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
89+ let namespaces = mapMaybe attrToNSPair (elAttribs docElem)
90+ bodyElem <- findChild (QName "body" (lookup "w" namespaces) Nothing) docElem
91+ body <- elemToBody namespaces bodyElem
92+ return $ Document namespaces body
93+
94+type Media = [(FilePath, B.ByteString)]
95+
96+filePathIsMedia :: FilePath -> Bool
97+filePathIsMedia fp =
98+ let (dir, _) = splitFileName fp
99+ in
100+ (dir == "word/media/")
101+
102+getMediaPair :: Archive -> FilePath -> Maybe (FilePath, B.ByteString)
103+getMediaPair zf fp =
104+ case findEntryByPath fp zf of
105+ Just e -> Just (fp, fromEntry e)
106+ Nothing -> Nothing
107+
108+archiveToMedia :: Archive -> Media
109+archiveToMedia zf =
110+ mapMaybe (getMediaPair zf) (filter filePathIsMedia (filesInArchive zf))
111+
112+data Numbering = Numbering NameSpaces [Numb] [AbstractNumb]
113+ deriving Show
114+
115+data Numb = Numb String String -- right now, only a key to an abstract num
116+ deriving Show
117+
118+data AbstractNumb = AbstractNumb String [Level]
119+ deriving Show
120+
121+-- (ilvl, format, string, start)
122+type Level = (String, String, String, Maybe Integer)
123+
124+lookupLevel :: String -> String -> Numbering -> Maybe Level
125+lookupLevel numId ilvl (Numbering _ numbs absNumbs) = do
126+ absNumId <- lookup numId $ map (\(Numb nid absnumid) -> (nid, absnumid)) numbs
127+ lvls <- lookup absNumId $ map (\(AbstractNumb aid ls) -> (aid, ls)) absNumbs
128+ lvl <- lookup ilvl $ map (\l@(i, _, _, _) -> (i, l)) lvls
129+ return lvl
130+
131+numElemToNum :: NameSpaces -> Element -> Maybe Numb
132+numElemToNum ns element |
133+ qName (elName element) == "num" &&
134+ qURI (elName element) == (lookup "w" ns) = do
135+ numId <- findAttr (QName "numId" (lookup "w" ns) (Just "w")) element
136+ absNumId <- findChild (QName "abstractNumId" (lookup "w" ns) (Just "w")) element
137+ >>= findAttr (QName "val" (lookup "w" ns) (Just "w"))
138+ return $ Numb numId absNumId
139+numElemToNum _ _ = Nothing
140+
141+absNumElemToAbsNum :: NameSpaces -> Element -> Maybe AbstractNumb
142+absNumElemToAbsNum ns element |
143+ qName (elName element) == "abstractNum" &&
144+ qURI (elName element) == (lookup "w" ns) = do
145+ absNumId <- findAttr
146+ (QName "abstractNumId" (lookup "w" ns) (Just "w"))
147+ element
148+ let levelElems = findChildren
149+ (QName "lvl" (lookup "w" ns) (Just "w"))
150+ element
151+ levels = mapMaybe (levelElemToLevel ns) levelElems
152+ return $ AbstractNumb absNumId levels
153+absNumElemToAbsNum _ _ = Nothing
154+
155+levelElemToLevel :: NameSpaces -> Element -> Maybe Level
156+levelElemToLevel ns element |
157+ qName (elName element) == "lvl" &&
158+ qURI (elName element) == (lookup "w" ns) = do
159+ ilvl <- findAttr (QName "ilvl" (lookup "w" ns) (Just "w")) element
160+ fmt <- findChild (QName "numFmt" (lookup "w" ns) (Just "w")) element
161+ >>= findAttr (QName "val" (lookup "w" ns) (Just "w"))
162+ txt <- findChild (QName "lvlText" (lookup "w" ns) (Just "w")) element
163+ >>= findAttr (QName "val" (lookup "w" ns) (Just "w"))
164+ let start = findChild (QName "start" (lookup "w" ns) (Just "w")) element
165+ >>= findAttr (QName "val" (lookup "w" ns) (Just "w"))
166+ >>= (\s -> listToMaybe (map fst (reads s :: [(Integer, String)])))
167+ return (ilvl, fmt, txt, start)
168+levelElemToLevel _ _ = Nothing
169+
170+archiveToNumbering :: Archive -> Maybe Numbering
171+archiveToNumbering zf =
172+ case findEntryByPath "word/numbering.xml" zf of
173+ Nothing -> Just $ Numbering [] [] []
174+ Just entry -> do
175+ numberingElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
176+ let namespaces = mapMaybe attrToNSPair (elAttribs numberingElem)
177+ numElems = findChildren
178+ (QName "num" (lookup "w" namespaces) (Just "w"))
179+ numberingElem
180+ absNumElems = findChildren
181+ (QName "abstractNum" (lookup "w" namespaces) (Just "w"))
182+ numberingElem
183+ nums = mapMaybe (numElemToNum namespaces) numElems
184+ absNums = mapMaybe (absNumElemToAbsNum namespaces) absNumElems
185+ return $ Numbering namespaces nums absNums
186+
187+data Notes = Notes NameSpaces (Maybe [(String, [BodyPart])]) (Maybe [(String, [BodyPart])])
188+ deriving Show
189+
190+noteElemToNote :: NameSpaces -> Element -> Maybe (String, [BodyPart])
191+noteElemToNote ns element
192+ | qName (elName element) `elem` ["endnote", "footnote"] &&
193+ qURI (elName element) == (lookup "w" ns) =
194+ do
195+ noteId <- findAttr (QName "id" (lookup "w" ns) (Just "w")) element
196+ let bps = mapMaybe (elemToBodyPart ns)
197+ $ elChildren element
198+ return $ (noteId, bps)
199+noteElemToNote _ _ = Nothing
200+
201+getFootNote :: String -> Notes -> Maybe [BodyPart]
202+getFootNote s (Notes _ fns _) = fns >>= (lookup s)
203+
204+getEndNote :: String -> Notes -> Maybe [BodyPart]
205+getEndNote s (Notes _ _ ens) = ens >>= (lookup s)
206+
207+elemToNotes :: NameSpaces -> String -> Element -> Maybe [(String, [BodyPart])]
208+elemToNotes ns notetype element
209+ | qName (elName element) == (notetype ++ "s") &&
210+ qURI (elName element) == (lookup "w" ns) =
211+ Just $ mapMaybe (noteElemToNote ns)
212+ $ findChildren (QName notetype (lookup "w" ns) (Just "w")) element
213+elemToNotes _ _ _ = Nothing
214+
215+archiveToNotes :: Archive -> Notes
216+archiveToNotes zf =
217+ let fnElem = findEntryByPath "word/footnotes.xml" zf
218+ >>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
219+ enElem = findEntryByPath "word/endnotes.xml" zf
220+ >>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
221+ fn_namespaces = case fnElem of
222+ Just e -> mapMaybe attrToNSPair (elAttribs e)
223+ Nothing -> []
224+ en_namespaces = case enElem of
225+ Just e -> mapMaybe attrToNSPair (elAttribs e)
226+ Nothing -> []
227+ ns = unionBy (\x y -> fst x == fst y) fn_namespaces en_namespaces
228+ fn = fnElem >>= (elemToNotes ns "footnote")
229+ en = enElem >>= (elemToNotes ns "endnote")
230+ in
231+ Notes ns fn en
232+
233+
234+data Relationship = Relationship (RelId, Target)
235+ deriving Show
236+
237+lookupRelationship :: RelId -> [Relationship] -> Maybe Target
238+lookupRelationship relid rels =
239+ lookup relid (map (\(Relationship pair) -> pair) rels)
240+
241+filePathIsRel :: FilePath -> Bool
242+filePathIsRel fp =
243+ let (dir, name) = splitFileName fp
244+ in
245+ (dir == "word/_rels/") && ((takeExtension name) == ".rels")
246+
247+relElemToRelationship :: Element -> Maybe Relationship
248+relElemToRelationship element | qName (elName element) == "Relationship" =
249+ do
250+ relId <- findAttr (QName "Id" Nothing Nothing) element
251+ target <- findAttr (QName "Target" Nothing Nothing) element
252+ return $ Relationship (relId, target)
253+relElemToRelationship _ = Nothing
254+
255+
256+archiveToRelationships :: Archive -> [Relationship]
257+archiveToRelationships archive =
258+ let relPaths = filter filePathIsRel (filesInArchive archive)
259+ entries = mapMaybe (\f -> findEntryByPath f archive) relPaths
260+ relElems = mapMaybe (parseXMLDoc . UTF8.toStringLazy . fromEntry) entries
261+ rels = mapMaybe relElemToRelationship $ concatMap elChildren relElems
262+ in
263+ rels
264+
265+data Body = Body [BodyPart]
266+ deriving Show
267+
268+elemToBody :: NameSpaces -> Element -> Maybe Body
269+elemToBody ns element | qName (elName element) == "body" && qURI (elName element) == (lookup "w" ns) =
270+ Just $ Body
271+ $ mapMaybe (elemToBodyPart ns) $ elChildren element
272+elemToBody _ _ = Nothing
273+
274+elemToNumInfo :: NameSpaces -> Element -> Maybe (String, String)
275+elemToNumInfo ns element
276+ | qName (elName element) == "p" &&
277+ qURI (elName element) == (lookup "w" ns) =
278+ do
279+ pPr <- findChild (QName "pPr" (lookup "w" ns) (Just "w")) element
280+ numPr <- findChild (QName "numPr" (lookup "w" ns) (Just "w")) pPr
281+ lvl <- findChild (QName "ilvl" (lookup "w" ns) (Just "w")) numPr >>=
282+ findAttr (QName "val" (lookup "w" ns) (Just "w"))
283+ numId <- findChild (QName "numId" (lookup "w" ns) (Just "w")) numPr >>=
284+ findAttr (QName "val" (lookup "w" ns) (Just "w"))
285+ return (numId, lvl)
286+elemToNumInfo _ _ = Nothing
287+
288+elemToBodyPart :: NameSpaces -> Element -> Maybe BodyPart
289+elemToBodyPart ns element
290+ | qName (elName element) == "p" &&
291+ qURI (elName element) == (lookup "w" ns) =
292+ let parstyle = elemToParagraphStyle ns element
293+ parparts = mapMaybe (elemToParPart ns)
294+ $ elChildren element
295+ in
296+ case elemToNumInfo ns element of
297+ Just (numId, lvl) -> Just $ ListItem parstyle numId lvl parparts
298+ Nothing -> Just $ Paragraph parstyle parparts
299+ | qName (elName element) == "tbl" &&
300+ qURI (elName element) == (lookup "w" ns) =
301+ let
302+ caption = findChild (QName "tblPr" (lookup "w" ns) (Just "w")) element
303+ >>= findChild (QName "tblCaption" (lookup "w" ns) (Just "w"))
304+ >>= findAttr (QName "val" (lookup "w" ns) (Just "w"))
305+ grid = case
306+ findChild (QName "tblGrid" (lookup "w" ns) (Just "w")) element
307+ of
308+ Just g -> elemToTblGrid ns g
309+ Nothing -> []
310+ tblLook = findChild (QName "tblPr" (lookup "w" ns) (Just "w")) element
311+ >>= findChild (QName "tblLook" (lookup "w" ns) (Just "w"))
312+ >>= elemToTblLook ns
313+ in
314+ Just $ Tbl
315+ (fromMaybe "" caption)
316+ grid
317+ (fromMaybe defaultTblLook tblLook)
318+ (mapMaybe (elemToRow ns) (elChildren element))
319+ | otherwise = Nothing
320+
321+elemToTblLook :: NameSpaces -> Element -> Maybe TblLook
322+elemToTblLook ns element
323+ | qName (elName element) == "tblLook" &&
324+ qURI (elName element) == (lookup "w" ns) =
325+ let firstRow = findAttr (QName "firstRow" (lookup "w" ns) (Just "w")) element
326+ val = findAttr (QName "val" (lookup "w" ns) (Just "w")) element
327+ firstRowFmt =
328+ case firstRow of
329+ Just "1" -> True
330+ Just _ -> False
331+ Nothing -> case val of
332+ Just bitMask -> testBitMask bitMask 0x020
333+ Nothing -> False
334+ in
335+ Just $ TblLook{firstRowFormatting = firstRowFmt}
336+elemToTblLook _ _ = Nothing
337+
338+testBitMask :: String -> Int -> Bool
339+testBitMask bitMaskS n =
340+ case (reads ("0x" ++ bitMaskS) :: [(Int, String)]) of
341+ [] -> False
342+ ((n', _) : _) -> ((n' .|. n) /= 0)
343+
344+data ParagraphStyle = ParagraphStyle { pStyle :: [String]
345+ , indent :: Maybe Integer
346+ }
347+ deriving Show
348+
349+defaultParagraphStyle :: ParagraphStyle
350+defaultParagraphStyle = ParagraphStyle { pStyle = []
351+ , indent = Nothing
352+ }
353+
354+elemToParagraphStyle :: NameSpaces -> Element -> ParagraphStyle
355+elemToParagraphStyle ns element =
356+ case findChild (QName "pPr" (lookup "w" ns) (Just "w")) element of
357+ Just pPr ->
358+ ParagraphStyle
359+ {pStyle =
360+ mapMaybe
361+ (findAttr (QName "val" (lookup "w" ns) (Just "w")))
362+ (findChildren (QName "pStyle" (lookup "w" ns) (Just "w")) pPr)
363+ , indent =
364+ findChild (QName "ind" (lookup "w" ns) (Just "w")) pPr >>=
365+ findAttr (QName "left" (lookup "w" ns) (Just "w")) >>=
366+ stringToInteger
367+ }
368+ Nothing -> defaultParagraphStyle
369+
370+
371+data BodyPart = Paragraph ParagraphStyle [ParPart]
372+ | ListItem ParagraphStyle String String [ParPart]
373+ | Tbl String TblGrid TblLook [Row]
374+
375+ deriving Show
376+
377+type TblGrid = [Integer]
378+
379+data TblLook = TblLook {firstRowFormatting::Bool}
380+ deriving Show
381+
382+defaultTblLook :: TblLook
383+defaultTblLook = TblLook{firstRowFormatting = False}
384+
385+stringToInteger :: String -> Maybe Integer
386+stringToInteger s = listToMaybe $ map fst (reads s :: [(Integer, String)])
387+
388+elemToTblGrid :: NameSpaces -> Element -> TblGrid
389+elemToTblGrid ns element
390+ | qName (elName element) == "tblGrid" &&
391+ qURI (elName element) == (lookup "w" ns) =
392+ let
393+ cols = findChildren (QName "gridCol" (lookup "w" ns) (Just "w")) element
394+ in
395+ mapMaybe (\e ->
396+ findAttr (QName "val" (lookup "w" ns) (Just ("w"))) e
397+ >>= stringToInteger
398+ )
399+ cols
400+elemToTblGrid _ _ = []
401+
402+data Row = Row [Cell]
403+ deriving Show
404+
405+
406+elemToRow :: NameSpaces -> Element -> Maybe Row
407+elemToRow ns element
408+ | qName (elName element) == "tr" &&
409+ qURI (elName element) == (lookup "w" ns) =
410+ let
411+ cells = findChildren (QName "tc" (lookup "w" ns) (Just "w")) element
412+ in
413+ Just $ Row (mapMaybe (elemToCell ns) cells)
414+elemToRow _ _ = Nothing
415+
416+data Cell = Cell [BodyPart]
417+ deriving Show
418+
419+elemToCell :: NameSpaces -> Element -> Maybe Cell
420+elemToCell ns element
421+ | qName (elName element) == "tc" &&
422+ qURI (elName element) == (lookup "w" ns) =
423+ Just $ Cell (mapMaybe (elemToBodyPart ns) (elChildren element))
424+elemToCell _ _ = Nothing
425+
426+data ParPart = PlainRun Run
427+ | Insertion ChangeId Author ChangeDate [Run]
428+ | Deletion ChangeId Author ChangeDate [Run]
429+ | BookMark BookMarkId Anchor
430+ | InternalHyperLink Anchor [Run]
431+ | ExternalHyperLink RelId [Run]
432+ | Drawing String
433+ deriving Show
434+
435+data Run = Run RunStyle [RunElem]
436+ | Footnote String
437+ | Endnote String
438+ deriving Show
439+
440+data RunElem = TextRun String | LnBrk | Tab
441+ deriving Show
442+
443+data RunStyle = RunStyle { isBold :: Bool
444+ , isItalic :: Bool
445+ , isSmallCaps :: Bool
446+ , isStrike :: Bool
447+ , isSuperScript :: Bool
448+ , isSubScript :: Bool
449+ , underline :: Maybe String
450+ , rStyle :: Maybe String }
451+ deriving Show
452+
453+defaultRunStyle :: RunStyle
454+defaultRunStyle = RunStyle { isBold = False
455+ , isItalic = False
456+ , isSmallCaps = False
457+ , isStrike = False
458+ , isSuperScript = False
459+ , isSubScript = False
460+ , underline = Nothing
461+ , rStyle = Nothing
462+ }
463+
464+elemToRunStyle :: NameSpaces -> Element -> RunStyle
465+elemToRunStyle ns element =
466+ case findChild (QName "rPr" (lookup "w" ns) (Just "w")) element of
467+ Just rPr ->
468+ RunStyle
469+ {
470+ isBold = isJust $ findChild (QName "b" (lookup "w" ns) (Just "w")) rPr
471+ , isItalic = isJust $ findChild (QName "i" (lookup "w" ns) (Just "w")) rPr
472+ , isSmallCaps = isJust $ findChild (QName "smallCaps" (lookup "w" ns) (Just "w")) rPr
473+ , isStrike = isJust $ findChild (QName "strike" (lookup "w" ns) (Just "w")) rPr
474+ , isSuperScript =
475+ (Just "superscript" ==
476+ (findChild (QName "vertAlign" (lookup "w" ns) (Just "w")) rPr >>=
477+ findAttr (QName "val" (lookup "w" ns) (Just "w"))))
478+ , isSubScript =
479+ (Just "subscript" ==
480+ (findChild (QName "vertAlign" (lookup "w" ns) (Just "w")) rPr >>=
481+ findAttr (QName "val" (lookup "w" ns) (Just "w"))))
482+ , underline =
483+ findChild (QName "u" (lookup "w" ns) (Just "w")) rPr >>=
484+ findAttr (QName "val" (lookup "w" ns) (Just "w"))
485+ , rStyle =
486+ findChild (QName "rStyle" (lookup "w" ns) (Just "w")) rPr >>=
487+ findAttr (QName "val" (lookup "w" ns) (Just "w"))
488+ }
489+ Nothing -> defaultRunStyle
490+
491+elemToRun :: NameSpaces -> Element -> Maybe Run
492+elemToRun ns element
493+ | qName (elName element) == "r" &&
494+ qURI (elName element) == (lookup "w" ns) =
495+ case
496+ findChild (QName "footnoteReference" (lookup "w" ns) (Just "w")) element >>=
497+ findAttr (QName "id" (lookup "w" ns) (Just "w"))
498+ of
499+ Just s -> Just $ Footnote s
500+ Nothing ->
501+ case
502+ findChild (QName "endnoteReference" (lookup "w" ns) (Just "w")) element >>=
503+ findAttr (QName "id" (lookup "w" ns) (Just "w"))
504+ of
505+ Just s -> Just $ Endnote s
506+ Nothing -> Just $
507+ Run (elemToRunStyle ns element)
508+ (elemToRunElems ns element)
509+elemToRun _ _ = Nothing
510+
511+elemToRunElem :: NameSpaces -> Element -> Maybe RunElem
512+elemToRunElem ns element
513+ | (qName (elName element) == "t" || qName (elName element) == "delText") &&
514+ qURI (elName element) == (lookup "w" ns) =
515+ Just $ TextRun (strContent element)
516+ | qName (elName element) == "br" &&
517+ qURI (elName element) == (lookup "w" ns) =
518+ Just $ LnBrk
519+ | qName (elName element) == "tab" &&
520+ qURI (elName element) == (lookup "w" ns) =
521+ Just $ Tab
522+ | otherwise = Nothing
523+
524+
525+elemToRunElems :: NameSpaces -> Element -> [RunElem]
526+elemToRunElems ns element
527+ | qName (elName element) == "r" &&
528+ qURI (elName element) == (lookup "w" ns) =
529+ mapMaybe (elemToRunElem ns) (elChildren element)
530+ | otherwise = []
531+
532+elemToDrawing :: NameSpaces -> Element -> Maybe ParPart
533+elemToDrawing ns element
534+ | qName (elName element) == "drawing" &&
535+ qURI (elName element) == (lookup "w" ns) =
536+ let a_ns = "http://schemas.openxmlformats.org/drawingml/2006/main"
537+ in
538+ findElement (QName "blip" (Just a_ns) (Just "a")) element
539+ >>= findAttr (QName "embed" (lookup "r" ns) (Just "r"))
540+ >>= (\s -> Just $ Drawing s)
541+elemToDrawing _ _ = Nothing
542+
543+
544+elemToParPart :: NameSpaces -> Element -> Maybe ParPart
545+elemToParPart ns element
546+ | qName (elName element) == "r" &&
547+ qURI (elName element) == (lookup "w" ns) =
548+ case findChild (QName "drawing" (lookup "w" ns) (Just "w")) element of
549+ Just drawingElem -> elemToDrawing ns drawingElem
550+ Nothing -> do
551+ r <- elemToRun ns element
552+ return $ PlainRun r
553+elemToParPart ns element
554+ | qName (elName element) == "ins" &&
555+ qURI (elName element) == (lookup "w" ns) = do
556+ cId <- findAttr (QName "id" (lookup "w" ns) (Just "w")) element
557+ cAuthor <- findAttr (QName "author" (lookup "w" ns) (Just "w")) element
558+ cDate <- findAttr (QName "date" (lookup "w" ns) (Just "w")) element
559+ let runs = mapMaybe (elemToRun ns) (elChildren element)
560+ return $ Insertion cId cAuthor cDate runs
561+elemToParPart ns element
562+ | qName (elName element) == "del" &&
563+ qURI (elName element) == (lookup "w" ns) = do
564+ cId <- findAttr (QName "id" (lookup "w" ns) (Just "w")) element
565+ cAuthor <- findAttr (QName "author" (lookup "w" ns) (Just "w")) element
566+ cDate <- findAttr (QName "date" (lookup "w" ns) (Just "w")) element
567+ let runs = mapMaybe (elemToRun ns) (elChildren element)
568+ return $ Deletion cId cAuthor cDate runs
569+elemToParPart ns element
570+ | qName (elName element) == "bookmarkStart" &&
571+ qURI (elName element) == (lookup "w" ns) = do
572+ bmId <- findAttr (QName "id" (lookup "w" ns) (Just "w")) element
573+ bmName <- findAttr (QName "name" (lookup "w" ns) (Just "w")) element
574+ return $ BookMark bmId bmName
575+elemToParPart ns element
576+ | qName (elName element) == "hyperlink" &&
577+ qURI (elName element) == (lookup "w" ns) =
578+ let runs = mapMaybe (elemToRun ns)
579+ $ findChildren (QName "r" (lookup "w" ns) (Just "w")) element
580+ in
581+ case findAttr (QName "anchor" (lookup "w" ns) (Just "w")) element of
582+ Just anchor ->
583+ Just $ InternalHyperLink anchor runs
584+ Nothing ->
585+ case findAttr (QName "id" (lookup "r" ns) (Just "r")) element of
586+ Just relId -> Just $ ExternalHyperLink relId runs
587+ Nothing -> Nothing
588+elemToParPart _ _ = Nothing
589+
590+type Target = String
591+type Anchor = String
592+type BookMarkId = String
593+type RelId = String
594+type ChangeId = String
595+type Author = String
596+type ChangeDate = String
src/Text/Pandoc/Readers/Docx/Reducible.hsnew file+181
@@ -0,0 +1,181 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+{-
4+Copyright (C) 2014 Jesse Rosenthal <jrosenthal@jhu.edu>
5+
6+This program is free software; you can redistribute it and/or modify
7+it under the terms of the GNU General Public License as published by
8+the Free Software Foundation; either version 2 of the License, or
9+(at your option) any later version.
10+
11+This program is distributed in the hope that it will be useful,
12+but WITHOUT ANY WARRANTY; without even the implied warranty of
13+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+GNU General Public License for more details.
15+
16+You should have received a copy of the GNU General Public License
17+along with this program; if not, write to the Free Software
18+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19+-}
20+
21+{- |
22+ Module : Text.Pandoc.Readers.Docx.Reducible
23+ Copyright : Copyright (C) 2014 Jesse Rosenthal
24+ License : GNU GPL, version 2 or above
25+
26+ Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
27+ Stability : alpha
28+ Portability : portable
29+
30+Typeclass for combining adjacent blocks and inlines correctly.
31+-}
32+
33+
34+module Text.Pandoc.Readers.Docx.Reducible ((<++>),
35+ (<+++>),
36+ Reducible,
37+ Container(..),
38+ container,
39+ innards,
40+ reduceList,
41+ reduceListB,
42+ rebuild)
43+ where
44+
45+import Text.Pandoc.Builder
46+import Data.List ((\\), intersect)
47+
48+data Container a = Container ([a] -> a) | NullContainer
49+
50+instance (Eq a) => Eq (Container a) where
51+ (Container x) == (Container y) = ((x []) == (y []))
52+ NullContainer == NullContainer = True
53+ _ == _ = False
54+
55+instance (Show a) => Show (Container a) where
56+ show (Container x) = "Container {" ++
57+ (reverse $ drop 3 $ reverse $ show $ x []) ++
58+ "}"
59+ show (NullContainer) = "NullContainer"
60+
61+class Reducible a where
62+ (<++>) :: a -> a -> [a]
63+ container :: a -> Container a
64+ innards :: a -> [a]
65+ isSpace :: a -> Bool
66+
67+(<+++>) :: (Reducible a) => Many a -> Many a -> Many a
68+mr <+++> ms = fromList $ reduceList $ toList mr ++ toList ms
69+
70+reduceListB :: (Reducible a) => Many a -> Many a
71+reduceListB = fromList . reduceList . toList
72+
73+reduceList' :: (Reducible a) => [a] -> [a] -> [a]
74+reduceList' acc [] = acc
75+reduceList' [] (x:xs) = reduceList' [x] xs
76+reduceList' as (x:xs) = reduceList' (init as ++ (last as <++> x) ) xs
77+
78+reduceList :: (Reducible a) => [a] -> [a]
79+reduceList = reduceList' []
80+
81+combineReducibles :: (Reducible a, Eq a) => a -> a -> [a]
82+combineReducibles r s =
83+ let (conts, rs) = topLevelContainers r
84+ (conts', ss) = topLevelContainers s
85+ shared = conts `intersect` conts'
86+ remaining = conts \\ shared
87+ remaining' = conts' \\ shared
88+ in
89+ case null shared of
90+ True -> case (not . null) rs && isSpace (last rs) of
91+ True -> rebuild conts (init rs) ++ [last rs, s]
92+ False -> [r,s]
93+ False -> rebuild
94+ shared $
95+ reduceList $
96+ (rebuild remaining rs) ++ (rebuild remaining' ss)
97+
98+instance Reducible Inline where
99+ s1@(Span (id1, classes1, kvs1) ils1) <++> s2@(Span (id2, classes2, kvs2) ils2) =
100+ let classes' = classes1 `intersect` classes2
101+ kvs' = kvs1 `intersect` kvs2
102+ classes1' = classes1 \\ classes'
103+ kvs1' = kvs1 \\ kvs'
104+ classes2' = classes2 \\ classes'
105+ kvs2' = kvs2 \\ kvs'
106+ in
107+ case null classes' && null kvs' of
108+ True -> [s1,s2]
109+ False -> let attr' = ("", classes', kvs')
110+ attr1' = (id1, classes1', kvs1')
111+ attr2' = (id2, classes2', kvs2')
112+ s1' = case null classes1' && null kvs1' of
113+ True -> ils1
114+ False -> [Span attr1' ils1]
115+ s2' = case null classes2' && null kvs2' of
116+ True -> ils2
117+ False -> [Span attr2' ils2]
118+ in
119+ [Span attr' $ reduceList $ s1' ++ s2']
120+
121+ (Str x) <++> (Str y) = [Str (x++y)]
122+ il <++> il' = combineReducibles il il'
123+
124+ container (Emph _) = Container Emph
125+ container (Strong _) = Container Strong
126+ container (Strikeout _) = Container Strikeout
127+ container (Subscript _) = Container Subscript
128+ container (Superscript _) = Container Superscript
129+ container (Quoted qt _) = Container $ Quoted qt
130+ container (Cite cs _) = Container $ Cite cs
131+ container (Span attr _) = Container $ Span attr
132+ container _ = NullContainer
133+
134+ innards (Emph ils) = ils
135+ innards (Strong ils) = ils
136+ innards (Strikeout ils) = ils
137+ innards (Subscript ils) = ils
138+ innards (Superscript ils) = ils
139+ innards (Quoted _ ils) = ils
140+ innards (Cite _ ils) = ils
141+ innards (Span _ ils) = ils
142+ innards _ = []
143+
144+ isSpace Space = True
145+ isSpace _ = False
146+
147+instance Reducible Block where
148+ (Div (ident, classes, kvs) blks) <++> blk | "list-item" `elem` classes =
149+ [Div (ident, classes, kvs) (reduceList blks), blk]
150+
151+ blk <++> blk' = combineReducibles blk blk'
152+
153+ container (BlockQuote _) = Container BlockQuote
154+ container (Div attr _) = Container $ Div attr
155+ container _ = NullContainer
156+
157+ innards (BlockQuote bs) = bs
158+ innards (Div _ bs) = bs
159+ innards _ = []
160+
161+ isSpace _ = False
162+
163+
164+topLevelContainers' :: (Reducible a) => [a] -> ([Container a], [a])
165+topLevelContainers' (r : []) = case container r of
166+ NullContainer -> ([], [r])
167+ _ ->
168+ let (conts, inns) = topLevelContainers' (innards r)
169+ in
170+ ((container r) : conts, inns)
171+topLevelContainers' rs = ([], rs)
172+
173+topLevelContainers :: (Reducible a) => a -> ([Container a], [a])
174+topLevelContainers il = topLevelContainers' [il]
175+
176+rebuild :: [Container a] -> [a] -> [a]
177+rebuild [] xs = xs
178+rebuild ((Container f) : cs) xs = rebuild cs $ [f xs]
179+rebuild (NullContainer : cs) xs = rebuild cs $ xs
180+
181+
src/Text/Pandoc/Readers/HTML.hs+214−129
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.Readers.HTML
21− Copyright : Copyright (C) 2006-2010 John MacFarlane
21+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -40,6 +40,7 @@ import Text.HTML.TagSoup
4040import Text.HTML.TagSoup.Match
4141import Text.Pandoc.Definition
4242import qualified Text.Pandoc.Builder as B
43+import Text.Pandoc.Builder (Blocks, Inlines, trimInlines)
4344import Text.Pandoc.Shared
4445import Text.Pandoc.Options
4546import Text.Pandoc.Parsing
@@ -47,7 +48,10 @@ import Data.Maybe ( fromMaybe, isJust )
4748import Data.List ( intercalate )
4849import Data.Char ( isDigit )
4950import Control.Monad ( liftM, guard, when, mzero )
50−import Control.Applicative ( (<$>), (<$) )
51+import Control.Applicative ( (<$>), (<$), (<*) )
52+import Data.Monoid
53+import Text.Printf (printf)
54+import Debug.Trace (trace)
5155
5256isSpace :: Char -> Bool
5357isSpace ' ' = True
@@ -66,39 +70,56 @@ readHtml opts inp =
6670 where tags = canonicalizeTags $
6771 parseTagsOptions parseOptions{ optTagPosition = True } inp
6872 parseDoc = do
69− blocks <- (fixPlains False . concat) <$> manyTill block eof
73+ blocks <- (fixPlains False) . mconcat <$> manyTill block eof
7074 meta <- stateMeta <$> getState
71− return $ Pandoc meta blocks
75+ return $ Pandoc meta (B.toList blocks)
7276
7377type TagParser = Parser [Tag String] ParserState
7478
75−pBody :: TagParser [Block]
79+pBody :: TagParser Blocks
7680pBody = pInTags "body" block
7781
78−pHead :: TagParser [Block]
79−pHead = pInTags "head" $ pTitle <|> ([] <$ pAnyTag)
80− where pTitle = pInTags "title" inline >>= setTitle . normalizeSpaces
81− setTitle t = [] <$ (updateState $ B.setMeta "title" (B.fromList t))
82−
83−block :: TagParser [Block]
84−block = choice
82+pHead :: TagParser Blocks
83+pHead = pInTags "head" $ pTitle <|> pMetaTag <|> (mempty <$ pAnyTag)
84+ where pTitle = pInTags "title" inline >>= setTitle . trimInlines
85+ setTitle t = mempty <$ (updateState $ B.setMeta "title" t)
86+ pMetaTag = do
87+ mt <- pSatisfy (~== TagOpen "meta" [])
88+ let name = fromAttrib "name" mt
89+ if null name
90+ then return mempty
91+ else do
92+ let content = fromAttrib "content" mt
93+ updateState $ B.setMeta name (B.text content)
94+ return mempty
95+
96+block :: TagParser Blocks
97+block = do
98+ tr <- getOption readerTrace
99+ pos <- getPosition
100+ res <- choice
85101 [ pPara
86102 , pHeader
87103 , pBlockQuote
88104 , pCodeBlock
89105 , pList
90106 , pHrule
91− , pSimpleTable
107+ , pTable
92108 , pHead
93109 , pBody
94110 , pPlain
111+ , pDiv
95112 , pRawHtmlBlock
96113 ]
114+ when tr $ trace (printf "line %d: %s" (sourceLine pos)
115+ (take 60 $ show $ B.toList res)) (return ())
116+ return res
97117
98−pList :: TagParser [Block]
118+
119+pList :: TagParser Blocks
99120pList = pBulletList <|> pOrderedList <|> pDefinitionList
100121
101−pBulletList :: TagParser [Block]
122+pBulletList :: TagParser Blocks
102123pBulletList = try $ do
103124 pSatisfy (~== TagOpen "ul" [])
104125 let nonItem = pSatisfy (\t ->
@@ -108,9 +129,9 @@ pBulletList = try $ do
108129 -- treat it as a list item, though it's not valid xhtml...
109130 skipMany nonItem
110131 items <- manyTill (pInTags "li" block >>~ skipMany nonItem) (pCloses "ul")
111− return [BulletList $ map (fixPlains True) items]
132+ return $ B.bulletList $ map (fixPlains True) items
112133
113−pOrderedList :: TagParser [Block]
134+pOrderedList :: TagParser Blocks
114135pOrderedList = try $ do
115136 TagOpen _ attribs <- pSatisfy (~== TagOpen "ol" [])
116137 let (start, style) = (sta', sty')
@@ -136,27 +157,27 @@ pOrderedList = try $ do
136157 -- treat it as a list item, though it's not valid xhtml...
137158 skipMany nonItem
138159 items <- manyTill (pInTags "li" block >>~ skipMany nonItem) (pCloses "ol")
139− return [OrderedList (start, style, DefaultDelim) $ map (fixPlains True) items]
160+ return $ B.orderedListWith (start, style, DefaultDelim) $ map (fixPlains True) items
140161
141−pDefinitionList :: TagParser [Block]
162+pDefinitionList :: TagParser Blocks
142163pDefinitionList = try $ do
143164 pSatisfy (~== TagOpen "dl" [])
144165 items <- manyTill pDefListItem (pCloses "dl")
145− return [DefinitionList items]
166+ return $ B.definitionList items
146167
147−pDefListItem :: TagParser ([Inline],[[Block]])
168+pDefListItem :: TagParser (Inlines, [Blocks])
148169pDefListItem = try $ do
149170 let nonItem = pSatisfy (\t -> not (t ~== TagOpen "dt" []) &&
150171 not (t ~== TagOpen "dd" []) && not (t ~== TagClose "dl"))
151172 terms <- many1 (try $ skipMany nonItem >> pInTags "dt" inline)
152173 defs <- many1 (try $ skipMany nonItem >> pInTags "dd" block)
153174 skipMany nonItem
154− let term = intercalate [LineBreak] terms
175+ let term = foldl1 (\x y -> x <> B.linebreak <> y) terms
155176 return (term, map (fixPlains True) defs)
156177
157−fixPlains :: Bool -> [Block] -> [Block]
158−fixPlains inList bs = if any isParaish bs
159− then map plainToPara bs
178+fixPlains :: Bool -> Blocks -> Blocks
179+fixPlains inList bs = if any isParaish bs'
180+ then B.fromList $ map plainToPara bs'
160181 else bs
161182 where isParaish (Para _) = True
162183 isParaish (CodeBlock _ _) = True
@@ -168,6 +189,7 @@ fixPlains inList bs = if any isParaish bs
168189 isParaish _ = False
169190 plainToPara (Plain xs) = Para xs
170191 plainToPara x = x
192+ bs' = B.toList bs
171193
172194pRawTag :: TagParser String
173195pRawTag = do
@@ -177,13 +199,20 @@ pRawTag = do
177199 then return []
178200 else return $ renderTags' [tag]
179201
180−pRawHtmlBlock :: TagParser [Block]
202+pDiv :: TagParser Blocks
203+pDiv = try $ do
204+ getOption readerParseRaw >>= guard
205+ TagOpen _ attr <- lookAhead $ pSatisfy $ tagOpen (=="div") (const True)
206+ contents <- pInTags "div" block
207+ return $ B.divWith (mkAttr attr) contents
208+
209+pRawHtmlBlock :: TagParser Blocks
181210pRawHtmlBlock = do
182211 raw <- pHtmlBlock "script" <|> pHtmlBlock "style" <|> pRawTag
183212 parseRaw <- getOption readerParseRaw
184213 if parseRaw && not (null raw)
185− then return [RawBlock "html" raw]
186− else return []
214+ then return $ B.rawBlock "html" raw
215+ else return mempty
187216
188217pHtmlBlock :: String -> TagParser String
189218pHtmlBlock t = try $ do
@@ -191,70 +220,96 @@ pHtmlBlock t = try $ do
191220 contents <- manyTill pAnyTag (pSatisfy (~== TagClose t))
192221 return $ renderTags' $ [open] ++ contents ++ [TagClose t]
193222
194−pHeader :: TagParser [Block]
223+pHeader :: TagParser Blocks
195224pHeader = try $ do
196225 TagOpen tagtype attr <- pSatisfy $
197226 tagOpen (`elem` ["h1","h2","h3","h4","h5","h6"])
198227 (const True)
199228 let bodyTitle = TagOpen tagtype attr ~== TagOpen "h1" [("class","title")]
200229 let level = read (drop 1 tagtype)
201− contents <- liftM concat $ manyTill inline (pCloses tagtype <|> eof)
202− let ident = maybe "" id $ lookup "id" attr
230+ contents <- trimInlines . mconcat <$> manyTill inline (pCloses tagtype <|> eof)
231+ let ident = fromMaybe "" $ lookup "id" attr
203232 let classes = maybe [] words $ lookup "class" attr
204233 let keyvals = [(k,v) | (k,v) <- attr, k /= "class", k /= "id"]
205234 return $ if bodyTitle
206− then [] -- skip a representation of the title in the body
207− else [Header level (ident, classes, keyvals) $
208− normalizeSpaces contents]
235+ then mempty -- skip a representation of the title in the body
236+ else B.headerWith (ident, classes, keyvals) level contents
209237
210−pHrule :: TagParser [Block]
238+pHrule :: TagParser Blocks
211239pHrule = do
212240 pSelfClosing (=="hr") (const True)
213− return [HorizontalRule]
241+ return B.horizontalRule
214242
215−pSimpleTable :: TagParser [Block]
216−pSimpleTable = try $ do
243+pTable :: TagParser Blocks
244+pTable = try $ do
217245 TagOpen _ _ <- pSatisfy (~== TagOpen "table" [])
218246 skipMany pBlank
219− caption <- option [] $ pInTags "caption" inline >>~ skipMany pBlank
220− skipMany $ (pInTags "col" block >> skipMany pBlank) <|>
221− (pInTags "colgroup" block >> skipMany pBlank)
247+ caption <- option mempty $ pInTags "caption" inline >>~ skipMany pBlank
248+ -- TODO actually read these and take width information from them
249+ widths' <- pColgroup <|> many pCol
222250 head' <- option [] $ pOptInTag "thead" $ pInTags "tr" (pCell "th")
223251 skipMany pBlank
224252 rows <- pOptInTag "tbody"
225253 $ many1 $ try $ skipMany pBlank >> pInTags "tr" (pCell "td")
226254 skipMany pBlank
227255 TagClose _ <- pSatisfy (~== TagClose "table")
228− let cols = maximum $ map length rows
229− let aligns = replicate cols AlignLeft
230− let widths = replicate cols 0
231− return [Table caption aligns widths head' rows]
256+ let isSinglePlain x = case B.toList x of
257+ [Plain _] -> True
258+ _ -> False
259+ let isSimple = all isSinglePlain $ concat (head':rows)
260+ let cols = length $ if null head' then head rows else head'
261+ -- fail if there are colspans or rowspans
262+ guard $ all (\r -> length r == cols) rows
263+ let aligns = replicate cols AlignDefault
264+ let widths = if null widths'
265+ then if isSimple
266+ then replicate cols 0
267+ else replicate cols (1.0 / fromIntegral cols)
268+ else widths'
269+ return $ B.table caption (zip aligns widths) head' rows
270+
271+pCol :: TagParser Double
272+pCol = try $ do
273+ TagOpen _ attribs <- pSatisfy (~== TagOpen "col" [])
274+ skipMany pBlank
275+ optional $ pSatisfy (~== TagClose "col")
276+ skipMany pBlank
277+ return $ case lookup "width" attribs of
278+ Just x | not (null x) && last x == '%' ->
279+ fromMaybe 0.0 $ safeRead ('0':'.':init x)
280+ _ -> 0.0
281+
282+pColgroup :: TagParser [Double]
283+pColgroup = try $ do
284+ pSatisfy (~== TagOpen "colgroup" [])
285+ skipMany pBlank
286+ manyTill pCol (pCloses "colgroup" <|> eof) <* skipMany pBlank
232287
233−pCell :: String -> TagParser [TableCell]
288+pCell :: String -> TagParser [Blocks]
234289pCell celltype = try $ do
235290 skipMany pBlank
236− res <- pInTags celltype pPlain
291+ res <- pInTags celltype block
237292 skipMany pBlank
238293 return [res]
239294
240−pBlockQuote :: TagParser [Block]
295+pBlockQuote :: TagParser Blocks
241296pBlockQuote = do
242297 contents <- pInTags "blockquote" block
243− return [BlockQuote $ fixPlains False contents]
298+ return $ B.blockQuote $ fixPlains False contents
244299
245−pPlain :: TagParser [Block]
300+pPlain :: TagParser Blocks
246301pPlain = do
247− contents <- liftM (normalizeSpaces . concat) $ many1 inline
248− if null contents
249− then return []
250− else return [Plain contents]
302+ contents <- trimInlines . mconcat <$> many1 inline
303+ if B.isNull contents
304+ then return mempty
305+ else return $ B.plain contents
251306
252−pPara :: TagParser [Block]
307+pPara :: TagParser Blocks
253308pPara = do
254− contents <- pInTags "p" inline
255− return [Para $ normalizeSpaces contents]
309+ contents <- trimInlines <$> pInTags "p" inline
310+ return $ B.para contents
256311
257−pCodeBlock :: TagParser [Block]
312+pCodeBlock :: TagParser Blocks
258313pCodeBlock = try $ do
259314 TagOpen _ attr <- pSatisfy (~== TagOpen "pre" [])
260315 contents <- manyTill pAnyTag (pCloses "pre" <|> eof)
@@ -267,13 +322,9 @@ pCodeBlock = try $ do
267322 let result = case reverse result' of
268323 '\n':_ -> init result'
269324 _ -> result'
270− let attribsId = fromMaybe "" $ lookup "id" attr
271− let attribsClasses = words $ fromMaybe "" $ lookup "class" attr
272− let attribsKV = filter (\(k,_) -> k /= "class" && k /= "id") attr
273− let attribs = (attribsId, attribsClasses, attribsKV)
274− return [CodeBlock attribs result]
325+ return $ B.codeBlockWith (mkAttr attr) result
275326
276−inline :: TagParser [Inline]
327+inline :: TagParser Inlines
277328inline = choice
278329 [ pTagText
279330 , pQ
@@ -286,6 +337,7 @@ inline = choice
286337 , pLink
287338 , pImage
288339 , pCode
340+ , pSpan
289341 , pRawHtmlInline
290342 ]
291343
@@ -312,7 +364,7 @@ pSelfClosing f g = do
312364 optional $ pSatisfy (tagClose f)
313365 return open
314366
315−pQ :: TagParser [Inline]
367+pQ :: TagParser Inlines
316368pQ = do
317369 quoteContext <- stateQuoteContext `fmap` getState
318370 let quoteType = case quoteContext of
@@ -321,79 +373,84 @@ pQ = do
321373 let innerQuoteContext = if quoteType == SingleQuote
322374 then InSingleQuote
323375 else InDoubleQuote
324− withQuoteContext innerQuoteContext $ pInlinesInTags "q" (Quoted quoteType)
376+ let constructor = case quoteType of
377+ SingleQuote -> B.singleQuoted
378+ DoubleQuote -> B.doubleQuoted
379+ withQuoteContext innerQuoteContext $
380+ pInlinesInTags "q" constructor
325381
326−pEmph :: TagParser [Inline]
327−pEmph = pInlinesInTags "em" Emph <|> pInlinesInTags "i" Emph
382+pEmph :: TagParser Inlines
383+pEmph = pInlinesInTags "em" B.emph <|> pInlinesInTags "i" B.emph
328384
329−pStrong :: TagParser [Inline]
330−pStrong = pInlinesInTags "strong" Strong <|> pInlinesInTags "b" Strong
385+pStrong :: TagParser Inlines
386+pStrong = pInlinesInTags "strong" B.strong <|> pInlinesInTags "b" B.strong
331387
332−pSuperscript :: TagParser [Inline]
333−pSuperscript = pInlinesInTags "sup" Superscript
388+pSuperscript :: TagParser Inlines
389+pSuperscript = pInlinesInTags "sup" B.superscript
334390
335−pSubscript :: TagParser [Inline]
336−pSubscript = pInlinesInTags "sub" Subscript
391+pSubscript :: TagParser Inlines
392+pSubscript = pInlinesInTags "sub" B.subscript
337393
338−pStrikeout :: TagParser [Inline]
394+pStrikeout :: TagParser Inlines
339395pStrikeout = do
340− pInlinesInTags "s" Strikeout <|>
341− pInlinesInTags "strike" Strikeout <|>
342− pInlinesInTags "del" Strikeout <|>
396+ pInlinesInTags "s" B.strikeout <|>
397+ pInlinesInTags "strike" B.strikeout <|>
398+ pInlinesInTags "del" B.strikeout <|>
343399 try (do pSatisfy (~== TagOpen "span" [("class","strikeout")])
344− contents <- liftM concat $ manyTill inline (pCloses "span")
345− return [Strikeout contents])
400+ contents <- mconcat <$> manyTill inline (pCloses "span")
401+ return $ B.strikeout contents)
346402
347−pLineBreak :: TagParser [Inline]
403+pLineBreak :: TagParser Inlines
348404pLineBreak = do
349405 pSelfClosing (=="br") (const True)
350− return [LineBreak]
406+ return B.linebreak
351407
352−pLink :: TagParser [Inline]
408+pLink :: TagParser Inlines
353409pLink = try $ do
354410 tag <- pSatisfy (tagOpenLit "a" (isJust . lookup "href"))
355411 let url = fromAttrib "href" tag
356412 let title = fromAttrib "title" tag
357− lab <- liftM concat $ manyTill inline (pCloses "a")
358− return [Link (normalizeSpaces lab) (escapeURI url, title)]
413+ lab <- trimInlines . mconcat <$> manyTill inline (pCloses "a")
414+ return $ B.link (escapeURI url) title lab
359415
360−pImage :: TagParser [Inline]
416+pImage :: TagParser Inlines
361417pImage = do
362418 tag <- pSelfClosing (=="img") (isJust . lookup "src")
363419 let url = fromAttrib "src" tag
364420 let title = fromAttrib "title" tag
365421 let alt = fromAttrib "alt" tag
366− return [Image (B.toList $ B.text alt) (escapeURI url, title)]
422+ return $ B.image (escapeURI url) title (B.text alt)
367423
368−pCode :: TagParser [Inline]
424+pCode :: TagParser Inlines
369425pCode = try $ do
370426 (TagOpen open attr) <- pSatisfy $ tagOpen (`elem` ["code","tt"]) (const True)
371427 result <- manyTill pAnyTag (pCloses open)
372− let ident = fromMaybe "" $ lookup "id" attr
373− let classes = words $ fromMaybe [] $ lookup "class" attr
374− let rest = filter (\(x,_) -> x /= "id" && x /= "class") attr
375− return [Code (ident,classes,rest)
376− $ intercalate " " $ lines $ innerText result]
428+ return $ B.codeWith (mkAttr attr) $ intercalate " " $ lines $ innerText result
377429
378−pRawHtmlInline :: TagParser [Inline]
430+pSpan :: TagParser Inlines
431+pSpan = try $ do
432+ getOption readerParseRaw >>= guard
433+ TagOpen _ attr <- lookAhead $ pSatisfy $ tagOpen (=="span") (const True)
434+ contents <- pInTags "span" inline
435+ return $ B.spanWith (mkAttr attr) contents
436+
437+pRawHtmlInline :: TagParser Inlines
379438pRawHtmlInline = do
380439 result <- pSatisfy (tagComment (const True)) <|> pSatisfy isInlineTag
381440 parseRaw <- getOption readerParseRaw
382441 if parseRaw
383− then return [RawInline "html" $ renderTags' [result]]
384− else return []
442+ then return $ B.rawInline "html" $ renderTags' [result]
443+ else return mempty
385444
386−pInlinesInTags :: String -> ([Inline] -> Inline)
387− -> TagParser [Inline]
388−pInlinesInTags tagtype f = do
389− contents <- pInTags tagtype inline
390− return [f $ normalizeSpaces contents]
445+pInlinesInTags :: String -> (Inlines -> Inlines)
446+ -> TagParser Inlines
447+pInlinesInTags tagtype f = extractSpaces f <$> pInTags tagtype inline
391448
392−pInTags :: String -> TagParser [a]
393− -> TagParser [a]
449+pInTags :: (Monoid a) => String -> TagParser a
450+ -> TagParser a
394451pInTags tagtype parser = try $ do
395452 pSatisfy (~== TagOpen tagtype [])
396− liftM concat $ manyTill parser (pCloses tagtype <|> eof)
453+ mconcat <$> manyTill parser (pCloses tagtype <|> eof)
397454
398455pOptInTag :: String -> TagParser a
399456 -> TagParser a
@@ -409,56 +466,65 @@ pCloses :: String -> TagParser ()
409466pCloses tagtype = try $ do
410467 t <- lookAhead $ pSatisfy $ \tag -> isTagClose tag || isTagOpen tag
411468 case t of
412− (TagClose t') | t' == tagtype -> pAnyTag >> return ()
469+ (TagClose t') | t' == tagtype -> pAnyTag >> return ()
413470 (TagOpen t' _) | t' `closes` tagtype -> return ()
414471 (TagClose "ul") | tagtype == "li" -> return ()
415472 (TagClose "ol") | tagtype == "li" -> return ()
416473 (TagClose "dl") | tagtype == "li" -> return ()
474+ (TagClose "table") | tagtype == "td" -> return ()
475+ (TagClose "table") | tagtype == "tr" -> return ()
417476 _ -> mzero
418477
419−pTagText :: TagParser [Inline]
478+pTagText :: TagParser Inlines
420479pTagText = try $ do
421480 (TagText str) <- pSatisfy isTagText
422481 st <- getState
423482 case runParser (many pTagContents) st "text" str of
424483 Left _ -> fail $ "Could not parse `" ++ str ++ "'"
425− Right result -> return result
484+ Right result -> return $ mconcat result
426485
427486pBlank :: TagParser ()
428487pBlank = try $ do
429488 (TagText str) <- pSatisfy isTagText
430489 guard $ all isSpace str
431490
432−pTagContents :: Parser [Char] ParserState Inline
491+pTagContents :: Parser [Char] ParserState Inlines
433492pTagContents =
434− pStr <|> pSpace <|> smartPunctuation pTagContents <|> pSymbol <|> pBad
435−
436−pStr :: Parser [Char] ParserState Inline
493+ B.displayMath <$> mathDisplay
494+ <|> B.math <$> mathInline
495+ <|> pStr
496+ <|> pSpace
497+ <|> smartPunctuation pTagContents
498+ <|> pSymbol
499+ <|> pBad
500+
501+pStr :: Parser [Char] ParserState Inlines
437502pStr = do
438503 result <- many1 $ satisfy $ \c ->
439504 not (isSpace c) && not (isSpecial c) && not (isBad c)
440505 pos <- getPosition
441506 updateState $ \s -> s{ stateLastStrPos = Just pos }
442− return $ Str result
507+ return $ B.str result
443508
444509isSpecial :: Char -> Bool
445510isSpecial '"' = True
446511isSpecial '\'' = True
447512isSpecial '.' = True
448513isSpecial '-' = True
514+isSpecial '$' = True
449515isSpecial '\8216' = True
450516isSpecial '\8217' = True
451517isSpecial '\8220' = True
452518isSpecial '\8221' = True
453519isSpecial _ = False
454520
455−pSymbol :: Parser [Char] ParserState Inline
456−pSymbol = satisfy isSpecial >>= return . Str . (:[])
521+pSymbol :: Parser [Char] ParserState Inlines
522+pSymbol = satisfy isSpecial >>= return . B.str . (:[])
457523
458524isBad :: Char -> Bool
459525isBad c = c >= '\128' && c <= '\159' -- not allowed in HTML
460526
461−pBad :: Parser [Char] ParserState Inline
527+pBad :: Parser [Char] ParserState Inlines
462528pBad = do
463529 c <- satisfy isBad
464530 let c' = case c of
@@ -490,10 +556,10 @@ pBad = do
490556 '\158' -> '\382'
491557 '\159' -> '\376'
492558 _ -> '?'
493− return $ Str [c']
559+ return $ B.str [c']
494560
495−pSpace :: Parser [Char] ParserState Inline
496−pSpace = many1 (satisfy isSpace) >> return Space
561+pSpace :: Parser [Char] ParserState Inlines
562+pSpace = many1 (satisfy isSpace) >> return B.space
497563
498564--
499565-- Constants
@@ -521,7 +587,7 @@ blockHtmlTags = ["address", "article", "aside", "blockquote", "body", "button",
521587 "noframes", "noscript", "object", "ol", "output", "p", "pre", "progress",
522588 "section", "table", "tbody", "textarea", "thead", "tfoot", "ul", "dd",
523589 "dt", "frameset", "li", "tbody", "td", "tfoot",
524− "th", "thead", "tr", "script", "style", "video"]
590+ "th", "thead", "tr", "script", "style", "svg", "video"]
525591
526592-- We want to allow raw docbook in markdown documents, so we
527593-- include docbook block tags here too.
@@ -543,15 +609,19 @@ blockTags :: [String]
543609blockTags = blockHtmlTags ++ blockDocBookTags
544610
545611isInlineTag :: Tag String -> Bool
546−isInlineTag t = tagOpen (`notElem` blockTags) (const True) t ||
547− tagClose (`notElem` blockTags) t ||
612+isInlineTag t = tagOpen isInlineTagName (const True) t ||
613+ tagClose isInlineTagName t ||
548614 tagComment (const True) t
615+ where isInlineTagName x = x `notElem` blockTags
549616
550617isBlockTag :: Tag String -> Bool
551−isBlockTag t = tagOpen (`elem` blocktags) (const True) t ||
552− tagClose (`elem` blocktags) t ||
618+isBlockTag t = tagOpen isBlockTagName (const True) t ||
619+ tagClose isBlockTagName t ||
553620 tagComment (const True) t
554− where blocktags = blockTags ++ eitherBlockOrInline
621+ where isBlockTagName ('?':_) = True
622+ isBlockTagName ('!':_) = True
623+ isBlockTagName x = x `elem` blockTags
624+ || x `elem` eitherBlockOrInline
555625
556626isTextTag :: Tag String -> Bool
557627isTextTag = tagText (const True)
@@ -560,7 +630,7 @@ isCommentTag :: Tag String -> Bool
560630isCommentTag = tagComment (const True)
561631
562632-- taken from HXT and extended
563−
633+-- See http://www.w3.org/TR/html5/syntax.html sec 8.1.2.4 optional tags
564634closes :: String -> String -> Bool
565635_ `closes` "body" = False
566636_ `closes` "html" = False
@@ -568,11 +638,18 @@ _ `closes` "html" = False
568638"li" `closes` "li" = True
569639"th" `closes` t | t `elem` ["th","td"] = True
570640"tr" `closes` t | t `elem` ["th","td","tr"] = True
641+"dd" `closes` t | t `elem` ["dt", "dd"] = True
571642"dt" `closes` t | t `elem` ["dt","dd"] = True
572−"hr" `closes` "p" = True
573−"p" `closes` "p" = True
643+"rt" `closes` t | t `elem` ["rb", "rt", "rtc"] = True
644+"optgroup" `closes` "optgroup" = True
645+"optgroup" `closes` "option" = True
646+"option" `closes` "option" = True
647+-- http://www.w3.org/TR/html-markup/p.html
648+x `closes` "p" | x `elem` ["address", "article", "aside", "blockquote",
649+ "dir", "div", "dl", "fieldset", "footer", "form", "h1", "h2", "h3", "h4",
650+ "h5", "h6", "header", "hr", "menu", "nav", "ol", "p", "pre", "section",
651+ "table", "ul"] = True
574652"meta" `closes` "meta" = True
575−"colgroup" `closes` "colgroup" = True
576653"form" `closes` "form" = True
577654"label" `closes` "label" = True
578655"map" `closes` "map" = True
@@ -620,3 +697,11 @@ htmlTag f = try $ do
620697 _ -> do
621698 rendered <- manyTill anyChar (char '>')
622699 return (next, rendered ++ ">")
700+
701+mkAttr :: [(String, String)] -> Attr
702+mkAttr attr = (attribsId, attribsClasses, attribsKV)
703+ where attribsId = fromMaybe "" $ lookup "id" attr
704+ attribsClasses = words $ fromMaybe "" $ lookup "class" attr
705+ attribsKV = filter (\(k,_) -> k /= "class" && k /= "id") attr
706+
707+
src/Text/Pandoc/Readers/Haddock.hs+118−21
@@ -3,7 +3,8 @@
33 Copyright : Copyright (C) 2013 David Lazar
44 License : GNU GPL, version 2 or above
55
6− Maintainer : David Lazar <lazar6@illinois.edu>
6+ Maintainer : David Lazar <lazar6@illinois.edu>,
7+ John MacFarlane <jgm@berkeley.edu>
78 Stability : alpha
89
910Conversion of Haddock markup to 'Pandoc' document.
@@ -12,30 +13,126 @@ module Text.Pandoc.Readers.Haddock
1213 ( readHaddock
1314 ) where
1415
15−import Text.Pandoc.Builder
16+import Text.Pandoc.Builder (Blocks, Inlines)
17+import qualified Text.Pandoc.Builder as B
18+import Text.Pandoc.Shared (trim, splitBy)
19+import Data.Monoid
20+import Data.List (intersperse, stripPrefix)
21+import Data.Maybe (fromMaybe)
22+import Text.Pandoc.Definition
1623import Text.Pandoc.Options
17−import Text.Pandoc.Readers.Haddock.Lex
18−import Text.Pandoc.Readers.Haddock.Parse
24+import Documentation.Haddock.Parser
25+import Documentation.Haddock.Types
26+import Debug.Trace (trace)
1927
2028-- | Parse Haddock markup and return a 'Pandoc' document.
2129readHaddock :: ReaderOptions -- ^ Reader options
2230 -> String -- ^ String to parse
2331 -> Pandoc
24−readHaddock _ s = Pandoc nullMeta blocks
32+readHaddock opts = B.doc . docHToBlocks . trace' . parseParas
33+ where trace' x = if readerTrace opts
34+ then trace (show x) x
35+ else x
36+
37+docHToBlocks :: DocH String Identifier -> Blocks
38+docHToBlocks d' =
39+ case d' of
40+ DocEmpty -> mempty
41+ DocAppend (DocParagraph (DocHeader h)) (DocParagraph (DocAName ident)) ->
42+ B.headerWith (ident,[],[]) (headerLevel h)
43+ (docHToInlines False $ headerTitle h)
44+ DocAppend d1 d2 -> mappend (docHToBlocks d1) (docHToBlocks d2)
45+ DocString _ -> inlineFallback
46+ DocParagraph (DocAName h) -> B.plain $ docHToInlines False $ DocAName h
47+ DocParagraph x -> B.para $ docHToInlines False x
48+ DocIdentifier _ -> inlineFallback
49+ DocIdentifierUnchecked _ -> inlineFallback
50+ DocModule s -> B.plain $ docHToInlines False $ DocModule s
51+ DocWarning _ -> mempty -- TODO
52+ DocEmphasis _ -> inlineFallback
53+ DocMonospaced _ -> inlineFallback
54+ DocBold _ -> inlineFallback
55+ DocHeader h -> B.header (headerLevel h)
56+ (docHToInlines False $ headerTitle h)
57+ DocUnorderedList items -> B.bulletList (map docHToBlocks items)
58+ DocOrderedList items -> B.orderedList (map docHToBlocks items)
59+ DocDefList items -> B.definitionList (map (\(d,t) ->
60+ (docHToInlines False d,
61+ [consolidatePlains $ docHToBlocks t])) items)
62+ DocCodeBlock (DocString s) -> B.codeBlockWith ("",[],[]) s
63+ DocCodeBlock d -> B.para $ docHToInlines True d
64+ DocHyperlink _ -> inlineFallback
65+ DocPic _ -> inlineFallback
66+ DocAName _ -> inlineFallback
67+ DocProperty s -> B.codeBlockWith ("",["property","haskell"],[]) (trim s)
68+ DocExamples es -> mconcat $ map (\e ->
69+ makeExample ">>>" (exampleExpression e) (exampleResult e)) es
70+
71+ where inlineFallback = B.plain $ docHToInlines False d'
72+ consolidatePlains = B.fromList . consolidatePlains' . B.toList
73+ consolidatePlains' zs@(Plain _ : _) =
74+ let (xs, ys) = span isPlain zs in
75+ Para (concatMap extractContents xs) : consolidatePlains' ys
76+ consolidatePlains' (x : xs) = x : consolidatePlains' xs
77+ consolidatePlains' [] = []
78+ isPlain (Plain _) = True
79+ isPlain _ = False
80+ extractContents (Plain xs) = xs
81+ extractContents _ = []
82+
83+docHToInlines :: Bool -> DocH String Identifier -> Inlines
84+docHToInlines isCode d' =
85+ case d' of
86+ DocEmpty -> mempty
87+ DocAppend d1 d2 -> mappend (docHToInlines isCode d1)
88+ (docHToInlines isCode d2)
89+ DocString s
90+ | isCode -> mconcat $ intersperse B.linebreak
91+ $ map B.code $ splitBy (=='\n') s
92+ | otherwise -> B.text s
93+ DocParagraph _ -> mempty
94+ DocIdentifier (_,s,_) -> B.codeWith ("",["haskell","identifier"],[]) s
95+ DocIdentifierUnchecked s -> B.codeWith ("",["haskell","identifier"],[]) s
96+ DocModule s -> B.codeWith ("",["haskell","module"],[]) s
97+ DocWarning _ -> mempty -- TODO
98+ DocEmphasis d -> B.emph (docHToInlines isCode d)
99+ DocMonospaced (DocString s) -> B.code s
100+ DocMonospaced d -> docHToInlines True d
101+ DocBold d -> B.strong (docHToInlines isCode d)
102+ DocHeader _ -> mempty
103+ DocUnorderedList _ -> mempty
104+ DocOrderedList _ -> mempty
105+ DocDefList _ -> mempty
106+ DocCodeBlock _ -> mempty
107+ DocHyperlink h -> B.link (hyperlinkUrl h) (hyperlinkUrl h)
108+ (maybe (B.text $ hyperlinkUrl h) B.text $ hyperlinkLabel h)
109+ DocPic p -> B.image (pictureUri p) (fromMaybe (pictureUri p) $ pictureTitle p)
110+ (maybe mempty B.text $ pictureTitle p)
111+ DocAName s -> B.spanWith (s,["anchor"],[]) mempty
112+ DocProperty _ -> mempty
113+ DocExamples _ -> mempty
114+
115+-- | Create an 'Example', stripping superfluous characters as appropriate
116+makeExample :: String -> String -> [String] -> Blocks
117+makeExample prompt expression result =
118+ B.para $ B.codeWith ("",["prompt"],[]) prompt
119+ <> B.space
120+ <> B.codeWith ([], ["haskell","expr"], []) (trim expression)
121+ <> B.linebreak
122+ <> (mconcat $ intersperse B.linebreak $ map coder result')
25123 where
26− blocks = case parseParas (tokenise s (0,0)) of
27− Left [] -> error "parse failure"
28− Left (tok:_) -> error $ "parse failure " ++ pos (tokenPos tok)
29− where pos (l, c) = "(line " ++ show l ++ ", column " ++ show c ++ ")"
30− Right x -> mergeLists (toList x)
31−
32−-- similar to 'docAppend' in Haddock.Doc
33−mergeLists :: [Block] -> [Block]
34−mergeLists (BulletList xs : BulletList ys : blocks)
35− = mergeLists (BulletList (xs ++ ys) : blocks)
36−mergeLists (OrderedList _ xs : OrderedList a ys : blocks)
37− = mergeLists (OrderedList a (xs ++ ys) : blocks)
38−mergeLists (DefinitionList xs : DefinitionList ys : blocks)
39− = mergeLists (DefinitionList (xs ++ ys) : blocks)
40−mergeLists (x : blocks) = x : mergeLists blocks
41−mergeLists [] = []
124+ -- 1. drop trailing whitespace from the prompt, remember the prefix
125+ prefix = takeWhile (`elem` " \t") prompt
126+
127+ -- 2. drop, if possible, the exact same sequence of whitespace
128+ -- characters from each result line
129+ --
130+ -- 3. interpret lines that only contain the string "<BLANKLINE>" as an
131+ -- empty line
132+ result' = map (substituteBlankLine . tryStripPrefix prefix) result
133+ where
134+ tryStripPrefix xs ys = fromMaybe ys $ stripPrefix xs ys
135+
136+ substituteBlankLine "<BLANKLINE>" = ""
137+ substituteBlankLine line = line
138+ coder = B.codeWith ([], ["result"], [])
src/Text/Pandoc/Readers/Haddock/Lex.xdeleted−171
@@ -1,171 +0,0 @@
1−--
2−-- Haddock - A Haskell Documentation Tool
3−--
4−-- (c) Simon Marlow 2002
5−--
6−-- This file was modified and integrated into GHC by David Waern 2006.
7−-- Then moved back into Haddock by Isaac Dupree in 2009 :-)
8−-- Then copied into Pandoc by David Lazar in 2013 :-D
9−
10−{
11−{-# LANGUAGE BangPatterns #-} -- Generated by Alex
12−{-# OPTIONS -Wwarn -w #-}
13−-- The above warning supression flag is a temporary kludge.
14−-- While working on this module you are encouraged to remove it and fix
15−-- any warnings in the module. See
16−-- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
17−-- for details
18−
19−module Text.Pandoc.Readers.Haddock.Lex (
20− Token(..),
21− LToken,
22− tokenise,
23− tokenPos
24− ) where
25−
26−import Data.Char
27−import Numeric (readHex)
28−}
29−
30−%wrapper "posn"
31−
32−$ws = $white # \n
33−$digit = [0-9]
34−$hexdigit = [0-9a-fA-F]
35−$special = [\"\@]
36−$alphanum = [A-Za-z0-9]
37−$ident = [$alphanum \'\_\.\!\#\$\%\&\*\+\/\<\=\>\?\@\\\\\^\|\-\~\:]
38−
39−:-
40−
41−-- beginning of a paragraph
42−<0,para> {
43− $ws* \n ;
44− $ws* \> { begin birdtrack }
45− $ws* prop \> .* \n { strtoken TokProperty `andBegin` property}
46− $ws* \>\>\> { strtoken TokExamplePrompt `andBegin` exampleexpr }
47− $ws* [\*\-] { token TokBullet `andBegin` string }
48− $ws* \[ { token TokDefStart `andBegin` def }
49− $ws* \( $digit+ \) { token TokNumber `andBegin` string }
50− $ws* $digit+ \. { token TokNumber `andBegin` string }
51− $ws* { begin string }
52−}
53−
54−-- beginning of a line
55−<line> {
56− $ws* \> { begin birdtrack }
57− $ws* \>\>\> { strtoken TokExamplePrompt `andBegin` exampleexpr }
58−
59− $ws* \n { token TokPara `andBegin` para }
60− -- ^ Here, we really want to be able to say
61− -- $ws* (\n | <eof>) { token TokPara `andBegin` para}
62− -- because otherwise a trailing line of whitespace will result in
63− -- a spurious TokString at the end of a docstring. We don't have <eof>,
64− -- though (NOW I realise what it was for :-). To get around this, we always
65− -- append \n to the end of a docstring.
66−
67− () { begin string }
68−}
69−
70−<birdtrack> .* \n? { strtokenNL TokBirdTrack `andBegin` line }
71−
72−<property> () { token TokPara `andBegin` para }
73−
74−<example> {
75− $ws* \n { token TokPara `andBegin` para }
76− $ws* \>\>\> { strtoken TokExamplePrompt `andBegin` exampleexpr }
77− () { begin exampleresult }
78−}
79−
80−<exampleexpr> .* \n { strtokenNL TokExampleExpression `andBegin` example }
81−
82−<exampleresult> .* \n { strtokenNL TokExampleResult `andBegin` example }
83−
84−<string,def> {
85− $special { strtoken $ \s -> TokSpecial (head s) }
86− \<\< [^\>]* \>\> { strtoken $ \s -> TokPic (init $ init $ tail $ tail s) }
87− \< [^\>]* \> { strtoken $ \s -> TokURL (init (tail s)) }
88− \# [^\#]* \# { strtoken $ \s -> TokAName (init (tail s)) }
89− \/ [^\/]* \/ { strtoken $ \s -> TokEmphasis (init (tail s)) }
90− [\'\`] $ident+ [\'\`] { strtoken $ \s -> TokIdent (init (tail s)) }
91− \\ . { strtoken (TokString . tail) }
92− "&#" $digit+ \; { strtoken $ \s -> TokString [chr (read (init (drop 2 s)))] }
93− "&#" [xX] $hexdigit+ \;
94− { strtoken $ \s -> case readHex (init (drop 3 s)) of [(n,_)] -> TokString [chr n] }
95− -- allow special characters through if they don't fit one of the previous
96− -- patterns.
97− [\/\'\`\<\#\&\\] { strtoken TokString }
98− [^ $special \/ \< \# \n \'\` \& \\ \]]* \n { strtokenNL TokString `andBegin` line }
99− [^ $special \/ \< \# \n \'\` \& \\ \]]+ { strtoken TokString }
100−}
101−
102−<def> {
103− \] { token TokDefEnd `andBegin` string }
104−}
105−
106−-- ']' doesn't have any special meaning outside of the [...] at the beginning
107−-- of a definition paragraph.
108−<string> {
109− \] { strtoken TokString }
110−}
111−
112−{
113−-- | A located token
114−type LToken = (Token, AlexPosn)
115−
116−data Token
117− = TokPara
118− | TokNumber
119− | TokBullet
120− | TokDefStart
121− | TokDefEnd
122− | TokSpecial Char
123− | TokIdent String
124− | TokString String
125− | TokURL String
126− | TokPic String
127− | TokEmphasis String
128− | TokAName String
129− | TokBirdTrack String
130− | TokProperty String
131− | TokExamplePrompt String
132− | TokExampleExpression String
133− | TokExampleResult String
134− deriving Show
135−
136−tokenPos :: LToken -> (Int, Int)
137−tokenPos t = let AlexPn _ line col = snd t in (line, col)
138−
139−type StartCode = Int
140−type Action = AlexPosn -> String -> StartCode -> (StartCode -> [LToken]) -> [LToken]
141−
142−tokenise :: String -> (Int, Int) -> [LToken]
143−tokenise str (line, col) = go (posn,'\n',[],eofHack str) para
144− where posn = AlexPn 0 line col
145− go inp@(pos,_,_,str) sc =
146− case alexScan inp sc of
147− AlexEOF -> []
148− AlexError _ -> []
149− AlexSkip inp' len -> go inp' sc
150− AlexToken inp' len act -> act pos (take len str) sc (\sc -> go inp' sc)
151−
152−-- NB. we add a final \n to the string, (see comment in the beginning of line
153−-- production above).
154−eofHack str = str++"\n"
155−
156−andBegin :: Action -> StartCode -> Action
157−andBegin act new_sc = \pos str _ cont -> act pos str new_sc cont
158−
159−token :: Token -> Action
160−token t = \pos _ sc cont -> (t, pos) : cont sc
161−
162−strtoken, strtokenNL :: (String -> Token) -> Action
163−strtoken t = \pos str sc cont -> (t str, pos) : cont sc
164−strtokenNL t = \pos str sc cont -> (t (filter (/= '\r') str), pos) : cont sc
165−-- ^ We only want LF line endings in our internal doc string format, so we
166−-- filter out all CRs.
167−
168−begin :: StartCode -> Action
169−begin sc = \_ _ _ cont -> cont sc
170−
171−}
src/Text/Pandoc/Readers/Haddock/Parse.ydeleted−178
@@ -1,178 +0,0 @@
1−-- This code was copied from the 'haddock' package, modified, and integrated
2−-- into Pandoc by David Lazar.
3−{
4−{-# LANGUAGE BangPatterns #-} -- required for versions of Happy before 1.18.6
5−-- The above warning supression flag is a temporary kludge.
6−-- While working on this module you are encouraged to remove it and fix
7−-- any warnings in the module. See
8−-- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
9−-- for details
10−
11−module Text.Pandoc.Readers.Haddock.Parse (parseString, parseParas) where
12−
13−import Text.Pandoc.Readers.Haddock.Lex
14−import Text.Pandoc.Builder
15−import Text.Pandoc.Shared (trim, trimr)
16−import Data.Generics (everywhere, mkT)
17−import Data.Char (isSpace)
18−import Data.Maybe (fromMaybe)
19−import Data.List (stripPrefix, intersperse)
20−import Data.Monoid (mempty, mconcat)
21−}
22−
23−%expect 0
24−
25−%tokentype { LToken }
26−
27−%token
28− '/' { (TokSpecial '/',_) }
29− '@' { (TokSpecial '@',_) }
30− '[' { (TokDefStart,_) }
31− ']' { (TokDefEnd,_) }
32− DQUO { (TokSpecial '\"',_) }
33− URL { (TokURL $$,_) }
34− PIC { (TokPic $$,_) }
35− ANAME { (TokAName $$,_) }
36− '/../' { (TokEmphasis $$,_) }
37− '-' { (TokBullet,_) }
38− '(n)' { (TokNumber,_) }
39− '>..' { (TokBirdTrack $$,_) }
40− PROP { (TokProperty $$,_) }
41− PROMPT { (TokExamplePrompt $$,_) }
42− RESULT { (TokExampleResult $$,_) }
43− EXP { (TokExampleExpression $$,_) }
44− IDENT { (TokIdent $$,_) }
45− PARA { (TokPara,_) }
46− STRING { (TokString $$,_) }
47−
48−%monad { Either [LToken] }
49−
50−%name parseParas doc
51−%name parseString seq
52−
53−%%
54−
55−doc :: { Blocks }
56− : apara PARA doc { $1 <> $3 }
57− | PARA doc { $2 }
58− | apara { $1 }
59− | {- empty -} { mempty }
60−
61−apara :: { Blocks }
62− : ulpara { bulletList [$1] }
63− | olpara { orderedList [$1] }
64− | defpara { definitionList [$1] }
65− | para { $1 }
66−
67−ulpara :: { Blocks }
68− : '-' para { $2 }
69−
70−olpara :: { Blocks }
71− : '(n)' para { $2 }
72−
73−defpara :: { (Inlines, [Blocks]) }
74− : '[' seq ']' seq { (trimInlines $2, [plain $ trimInlines $4]) }
75−
76−para :: { Blocks }
77− : seq { para' $1 }
78− | codepara { codeBlockWith ([], ["haskell"], []) $1 }
79− | property { $1 }
80− | examples { $1 }
81−
82−codepara :: { String }
83− : '>..' codepara { $1 ++ $2 }
84− | '>..' { $1 }
85−
86−property :: { Blocks }
87− : PROP { makeProperty $1 }
88−
89−examples :: { Blocks }
90− : example examples { $1 <> $2 }
91− | example { $1 }
92−
93−example :: { Blocks }
94− : PROMPT EXP result { makeExample $1 $2 (lines $3) }
95− | PROMPT EXP { makeExample $1 $2 [] }
96−
97−result :: { String }
98− : RESULT result { $1 ++ $2 }
99− | RESULT { $1 }
100−
101−seq :: { Inlines }
102− : elem seq { $1 <> $2 }
103− | elem { $1 }
104−
105−elem :: { Inlines }
106− : elem1 { $1 }
107− | '@' seq1 '@' { monospace $2 }
108−
109−seq1 :: { Inlines }
110− : PARA seq1 { linebreak <> $2 }
111− | elem1 seq1 { $1 <> $2 }
112− | elem1 { $1 }
113−
114−elem1 :: { Inlines }
115− : STRING { text $1 }
116− | '/../' { emph (str $1) }
117− | URL { makeHyperlink $1 }
118− | PIC { image $1 $1 mempty }
119− | ANAME { mempty } -- TODO
120− | IDENT { codeWith ([], ["haskell"], []) $1 }
121− | DQUO strings DQUO { codeWith ([], ["haskell"], []) $2 }
122−
123−strings :: { String }
124− : STRING { $1 }
125− | STRING strings { $1 ++ $2 }
126−
127−{
128−happyError :: [LToken] -> Either [LToken] a
129−happyError toks = Left toks
130−
131−para' :: Inlines -> Blocks
132−para' = para . trimInlines
133−
134−monospace :: Inlines -> Inlines
135−monospace = everywhere (mkT go)
136− where
137− go (Str s) = Code nullAttr s
138− go x = x
139−
140−-- | Create a `Hyperlink` from given string.
141−--
142−-- A hyperlink consists of a URL and an optional label. The label is separated
143−-- from the url by one or more whitespace characters.
144−makeHyperlink :: String -> Inlines
145−makeHyperlink input = case break isSpace $ trim input of
146− (url, "") -> link url url (str url)
147− (url, lb) -> link url url (trimInlines $ text lb)
148−
149−makeProperty :: String -> Blocks
150−makeProperty s = case trim s of
151− 'p':'r':'o':'p':'>':xs ->
152− codeBlockWith ([], ["property"], []) (dropWhile isSpace xs)
153− xs ->
154− error $ "makeProperty: invalid input " ++ show xs
155−
156−-- | Create an 'Example', stripping superfluous characters as appropriate
157−makeExample :: String -> String -> [String] -> Blocks
158−makeExample prompt expression result =
159− para $ codeWith ([], ["haskell","expr"], []) (trim expression)
160− <> linebreak
161− <> (mconcat $ intersperse linebreak $ map coder result')
162− where
163− -- 1. drop trailing whitespace from the prompt, remember the prefix
164− prefix = takeWhile isSpace prompt
165−
166− -- 2. drop, if possible, the exact same sequence of whitespace
167− -- characters from each result line
168− --
169− -- 3. interpret lines that only contain the string "<BLANKLINE>" as an
170− -- empty line
171− result' = map (substituteBlankLine . tryStripPrefix prefix) result
172− where
173− tryStripPrefix xs ys = fromMaybe ys $ stripPrefix xs ys
174−
175− substituteBlankLine "<BLANKLINE>" = ""
176− substituteBlankLine line = line
177− coder = codeWith ([], ["result"], [])
178−}
src/Text/Pandoc/Readers/LaTeX.hs+455−264
@@ -1,6 +1,6 @@
1−{-# LANGUAGE ScopedTypeVariables #-}
1+{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}
22{-
3−Copyright (C) 2006-2012 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Text.Pandoc.Readers.LaTeX
22− Copyright : Copyright (C) 2006-2012 John MacFarlane
22+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,22 +31,26 @@ Conversion of LaTeX to 'Pandoc' document.
3131module Text.Pandoc.Readers.LaTeX ( readLaTeX,
3232 rawLaTeXInline,
3333 rawLaTeXBlock,
34+ inlineCommand,
3435 handleIncludes
3536 ) where
3637
3738import Text.Pandoc.Definition
38−import Text.Pandoc.Generic
39+import Text.Pandoc.Walk
3940import Text.Pandoc.Shared
4041import Text.Pandoc.Options
41−import Text.Pandoc.Biblio (processBiblio)
42−import Text.Pandoc.Parsing hiding ((<|>), many, optional, space)
42+import Text.Pandoc.Parsing hiding ((<|>), many, optional, space,
43+ mathDisplay, mathInline)
44+import Text.Parsec.Prim (ParsecT, runParserT)
4345import qualified Text.Pandoc.UTF8 as UTF8
4446import Data.Char ( chr, ord )
47+import Control.Monad.Trans (lift)
4548import Control.Monad
4649import Text.Pandoc.Builder
47−import Data.Char (isLetter, isPunctuation, isSpace)
50+import Data.Char (isLetter, isAlphaNum)
4851import Control.Applicative
4952import Data.Monoid
53+import Data.Maybe (fromMaybe)
5054import System.Environment (getEnv)
5155import System.FilePath (replaceExtension, (</>))
5256import Data.List (intercalate, intersperse)
@@ -67,9 +71,7 @@ parseLaTeX = do
6771 eof
6872 st <- getState
6973 let meta = stateMeta st
70− refs <- getOption readerReferences
71− mbsty <- getOption readerCitationStyle
72− let (Pandoc _ bs') = processBiblio mbsty refs $ doc bs
74+ let (Pandoc _ bs') = doc bs
7375 return $ Pandoc meta bs'
7476
7577type LP = Parser [Char] ParserState
@@ -124,7 +126,7 @@ comment :: LP ()
124126comment = do
125127 char '%'
126128 skipMany (satisfy (/='\n'))
127− newline
129+ optional newline
128130 return ()
129131
130132bgroup :: LP ()
@@ -165,28 +167,40 @@ mathChars = concat <$>
165167 <|> (\c -> ['\\',c]) <$> (try $ char '\\' *> anyChar)
166168 )
167169
170+quoted' :: (Inlines -> Inlines) -> LP String -> LP () -> LP Inlines
171+quoted' f starter ender = do
172+ startchs <- starter
173+ try ((f . mconcat) <$> manyTill inline ender) <|> lit startchs
174+
168175double_quote :: LP Inlines
169−double_quote = (doubleQuoted . mconcat) <$>
170− (try $ string "``" *> manyTill inline (try $ string "''"))
176+double_quote =
177+ ( quoted' doubleQuoted (try $ string "``") (void $ try $ string "''")
178+ <|> quoted' doubleQuoted (string "“") (void $ char '”')
179+ -- the following is used by babel for localized quotes:
180+ <|> quoted' doubleQuoted (try $ string "\"`") (void $ try $ string "\"'")
181+ <|> quoted' doubleQuoted (string "\"") (void $ char '"')
182+ )
171183
172184single_quote :: LP Inlines
173−single_quote = (singleQuoted . mconcat) <$>
174− (try $ char '`' *> manyTill inline (try $ char '\'' >> notFollowedBy letter))
185+single_quote =
186+ ( quoted' singleQuoted (string "`") (try $ char '\'' >> notFollowedBy letter)
187+ <|> quoted' singleQuoted (string "‘") (try $ char '’' >> notFollowedBy letter)
188+ )
175189
176190inline :: LP Inlines
177191inline = (mempty <$ comment)
178192 <|> (space <$ sp)
179193 <|> inlineText
180194 <|> inlineCommand
181− <|> grouped inline
195+ <|> inlineGroup
182196 <|> (char '-' *> option (str "-")
183197 ((char '-') *> option (str "–") (str "—" <$ char '-')))
184198 <|> double_quote
185199 <|> single_quote
186− <|> (str "“" <$ try (string "``")) -- nb. {``} won't be caught by double_quote
187200 <|> (str "”" <$ try (string "''"))
188− <|> (str "‘" <$ char '`') -- nb. {`} won't be caught by single_quote
201+ <|> (str "”" <$ char '”')
189202 <|> (str "’" <$ char '\'')
203+ <|> (str "’" <$ char '’')
190204 <|> (str "\160" <$ char '~')
191205 <|> (mathDisplay $ string "$$" *> mathChars <* string "$$")
192206 <|> (mathInline $ char '$' *> mathChars <* char '$')
@@ -201,6 +215,15 @@ inline = (mempty <$ comment)
201215inlines :: LP Inlines
202216inlines = mconcat <$> many (notFollowedBy (char '}') *> inline)
203217
218+inlineGroup :: LP Inlines
219+inlineGroup = do
220+ ils <- grouped inline
221+ if isNull ils
222+ then return mempty
223+ else return $ spanWith nullAttr ils
224+ -- we need the span so we can detitlecase bibtex entries;
225+ -- we need to know when something is {C}apitalized
226+
204227block :: LP Blocks
205228block = (mempty <$ comment)
206229 <|> (mempty <$ ((spaceChar <|> newline) *> spaces))
@@ -282,6 +305,13 @@ blockCommands = M.fromList $
282305 , ("item", skipopts *> loose_item)
283306 , ("documentclass", skipopts *> braced *> preamble)
284307 , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
308+ , ("caption", skipopts *> tok >>= setCaption)
309+ , ("PandocStartInclude", startInclude)
310+ , ("PandocEndInclude", endInclude)
311+ , ("bibliography", mempty <$ (skipopts *> braced >>=
312+ addMeta "bibliography" . splitBibs))
313+ , ("addbibresource", mempty <$ (skipopts *> braced >>=
314+ addMeta "bibliography" . splitBibs))
285315 ] ++ map ignoreBlocks
286316 -- these commands will be ignored unless --parse-raw is specified,
287317 -- in which case they will appear as raw latex blocks
@@ -289,7 +319,7 @@ blockCommands = M.fromList $
289319 -- newcommand, etc. should be parsed by macro, but we need this
290320 -- here so these aren't parsed as inline commands to ignore
291321 , "special", "pdfannot", "pdfstringdef"
292− , "bibliography", "bibliographystyle"
322+ , "bibliographystyle"
293323 , "maketitle", "makeindex", "makeglossary"
294324 , "addcontentsline", "addtocontents", "addtocounter"
295325 -- \ignore{} is used conventionally in literate haskell for definitions
@@ -301,7 +331,19 @@ blockCommands = M.fromList $
301331 ]
302332
303333addMeta :: ToMetaValue a => String -> a -> LP ()
304−addMeta field val = updateState $ setMeta field val
334+addMeta field val = updateState $ \st ->
335+ st{ stateMeta = addMetaField field val $ stateMeta st }
336+
337+splitBibs :: String -> [Inlines]
338+splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
339+
340+setCaption :: Inlines -> LP Blocks
341+setCaption ils = do
342+ updateState $ \st -> st{ stateCaption = Just ils }
343+ return mempty
344+
345+resetCaption :: LP ()
346+resetCaption = updateState $ \st -> st{ stateCaption = Nothing }
305347
306348authors :: LP ()
307349authors = try $ do
@@ -312,15 +354,17 @@ authors = try $ do
312354 -- skip e.g. \vspace{10pt}
313355 auths <- sepBy oneAuthor (controlSeq "and")
314356 char '}'
315− addMeta "authors" (map trimInlines auths)
357+ addMeta "author" (map trimInlines auths)
316358
317359section :: Attr -> Int -> LP Blocks
318−section attr lvl = do
360+section (ident, classes, kvs) lvl = do
319361 hasChapters <- stateHasChapters `fmap` getState
320362 let lvl' = if hasChapters then lvl + 1 else lvl
321363 skipopts
322364 contents <- grouped inline
323− return $ headerWith attr lvl' contents
365+ lab <- option ident $ try (spaces >> controlSeq "label" >> spaces >> braced)
366+ attr' <- registerHeader (lab, classes, kvs) contents
367+ return $ headerWith attr' lvl' contents
324368
325369inlineCommand :: LP Inlines
326370inlineCommand = try $ do
@@ -353,17 +397,18 @@ isBlockCommand s = maybe False (const True) $ M.lookup s blockCommands
353397
354398inlineCommands :: M.Map String (LP Inlines)
355399inlineCommands = M.fromList $
356− [ ("emph", emph <$> tok)
357− , ("textit", emph <$> tok)
358− , ("textsl", emph <$> tok)
359− , ("textsc", smallcaps <$> tok)
360− , ("sout", strikeout <$> tok)
361− , ("textsuperscript", superscript <$> tok)
362− , ("textsubscript", subscript <$> tok)
400+ [ ("emph", extractSpaces emph <$> tok)
401+ , ("textit", extractSpaces emph <$> tok)
402+ , ("textsl", extractSpaces emph <$> tok)
403+ , ("textsc", extractSpaces smallcaps <$> tok)
404+ , ("sout", extractSpaces strikeout <$> tok)
405+ , ("textsuperscript", extractSpaces superscript <$> tok)
406+ , ("textsubscript", extractSpaces subscript <$> tok)
363407 , ("textbackslash", lit "\\")
364408 , ("backslash", lit "\\")
365409 , ("slash", lit "/")
366− , ("textbf", strong <$> tok)
410+ , ("textbf", extractSpaces strong <$> tok)
411+ , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
367412 , ("ldots", lit "…")
368413 , ("dots", lit "…")
369414 , ("mdots", lit "…")
@@ -383,15 +428,15 @@ inlineCommands = M.fromList $
383428 , ("{", lit "{")
384429 , ("}", lit "}")
385430 -- old TeX commands
386− , ("em", emph <$> inlines)
387− , ("it", emph <$> inlines)
388− , ("sl", emph <$> inlines)
389− , ("bf", strong <$> inlines)
431+ , ("em", extractSpaces emph <$> inlines)
432+ , ("it", extractSpaces emph <$> inlines)
433+ , ("sl", extractSpaces emph <$> inlines)
434+ , ("bf", extractSpaces strong <$> inlines)
390435 , ("rm", inlines)
391− , ("itshape", emph <$> inlines)
392− , ("slshape", emph <$> inlines)
393− , ("scshape", smallcaps <$> inlines)
394− , ("bfseries", strong <$> inlines)
436+ , ("itshape", extractSpaces emph <$> inlines)
437+ , ("slshape", extractSpaces emph <$> inlines)
438+ , ("scshape", extractSpaces smallcaps <$> inlines)
439+ , ("bfseries", extractSpaces strong <$> inlines)
395440 , ("/", pure mempty) -- italic correction
396441 , ("aa", lit "å")
397442 , ("AA", lit "Å")
@@ -402,6 +447,8 @@ inlineCommands = M.fromList $
402447 , ("l", lit "ł")
403448 , ("ae", lit "æ")
404449 , ("AE", lit "Æ")
450+ , ("oe", lit "œ")
451+ , ("OE", lit "Œ")
405452 , ("pounds", lit "£")
406453 , ("euro", lit "€")
407454 , ("copyright", lit "©")
@@ -415,6 +462,8 @@ inlineCommands = M.fromList $
415462 , (".", option (str ".") $ try $ tok >>= accent dot)
416463 , ("=", option (str "=") $ try $ tok >>= accent macron)
417464 , ("c", option (str "c") $ try $ tok >>= accent cedilla)
465+ , ("v", option (str "v") $ try $ tok >>= accent hacek)
466+ , ("u", option (str "u") $ try $ tok >>= accent breve)
418467 , ("i", lit "i")
419468 , ("\\", linebreak <$ (optional (bracketed inline) *> optional sp))
420469 , (",", pure mempty)
@@ -430,6 +479,7 @@ inlineCommands = M.fromList $
430479 , ("footnote", (note . mconcat) <$> (char '{' *> manyTill block (char '}')))
431480 , ("verb", doverb)
432481 , ("lstinline", doverb)
482+ , ("Verb", doverb)
433483 , ("texttt", (code . stringify . toList) <$> tok)
434484 , ("url", (unescapeURL <$> braced) >>= \url ->
435485 pure (link url "" (str url)))
@@ -488,25 +538,21 @@ inlineCommands = M.fromList $
488538 , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
489539 complexNatbibCitation AuthorInText)
490540 <|> citation "citeauthor" AuthorInText False)
541+ , ("nocite", mempty <$ (citation "nocite" NormalCitation False >>=
542+ addMeta "nocite"))
491543 ] ++ map ignoreInlines
492544 -- these commands will be ignored unless --parse-raw is specified,
493545 -- in which case they will appear as raw latex blocks:
494− [ "noindent", "index", "nocite" ]
546+ [ "noindent", "index" ]
495547
496548mkImage :: String -> LP Inlines
497549mkImage src = do
498− -- try for a caption
499− (alt, tit) <- option (str "image", "") $ try $ do
500− spaces
501− controlSeq "caption"
502− optional (char '*')
503− ils <- grouped inline
504− return (ils, "fig:")
550+ let alt = str "image"
505551 case takeExtension src of
506552 "" -> do
507553 defaultExt <- getOption readerDefaultImageExtension
508− return $ image (addExtension src defaultExt) tit alt
509− _ -> return $ image src tit alt
554+ return $ image (addExtension src defaultExt) "" alt
555+ _ -> return $ image src "" alt
510556
511557inNote :: Inlines -> Inlines
512558inNote ils =
@@ -514,9 +560,7 @@ inNote ils =
514560
515561unescapeURL :: String -> String
516562unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
517− where isEscapable '%' = True
518− isEscapable '#' = True
519− isEscapable _ = False
563+ where isEscapable c = c `elem` "#$%&~_^\\{}"
520564unescapeURL (x:xs) = x:unescapeURL xs
521565unescapeURL [] = ""
522566
@@ -539,137 +583,196 @@ doLHSverb = codeWith ("",["haskell"],[]) <$> manyTill (satisfy (/='\n')) (char '
539583lit :: String -> LP Inlines
540584lit = pure . str
541585
542−accent :: (Char -> Char) -> Inlines -> LP Inlines
586+accent :: (Char -> String) -> Inlines -> LP Inlines
543587accent f ils =
544588 case toList ils of
545− (Str (x:xs) : ys) -> return $ fromList $ (Str (f x : xs) : ys)
589+ (Str (x:xs) : ys) -> return $ fromList $ (Str (f x ++ xs) : ys)
546590 [] -> mzero
547591 _ -> return ils
548592
549−grave :: Char -> Char
550−grave 'A' = 'À'
551−grave 'E' = 'È'
552−grave 'I' = 'Ì'
553−grave 'O' = 'Ò'
554−grave 'U' = 'Ù'
555−grave 'a' = 'à'
556−grave 'e' = 'è'
557−grave 'i' = 'ì'
558−grave 'o' = 'ò'
559−grave 'u' = 'ù'
560−grave c = c
561−
562−acute :: Char -> Char
563−acute 'A' = 'Á'
564−acute 'E' = 'É'
565−acute 'I' = 'Í'
566−acute 'O' = 'Ó'
567−acute 'U' = 'Ú'
568−acute 'Y' = 'Ý'
569−acute 'a' = 'á'
570−acute 'e' = 'é'
571−acute 'i' = 'í'
572−acute 'o' = 'ó'
573−acute 'u' = 'ú'
574−acute 'y' = 'ý'
575−acute 'C' = 'Ć'
576−acute 'c' = 'ć'
577−acute 'L' = 'Ĺ'
578−acute 'l' = 'ĺ'
579−acute 'N' = 'Ń'
580−acute 'n' = 'ń'
581−acute 'R' = 'Ŕ'
582−acute 'r' = 'ŕ'
583−acute 'S' = 'Ś'
584−acute 's' = 'ś'
585−acute 'Z' = 'Ź'
586−acute 'z' = 'ź'
587−acute c = c
588−
589−circ :: Char -> Char
590−circ 'A' = 'Â'
591−circ 'E' = 'Ê'
592−circ 'I' = 'Î'
593−circ 'O' = 'Ô'
594−circ 'U' = 'Û'
595−circ 'a' = 'â'
596−circ 'e' = 'ê'
597−circ 'i' = 'î'
598−circ 'o' = 'ô'
599−circ 'u' = 'û'
600−circ 'C' = 'Ĉ'
601−circ 'c' = 'ĉ'
602−circ 'G' = 'Ĝ'
603−circ 'g' = 'ĝ'
604−circ 'H' = 'Ĥ'
605−circ 'h' = 'ĥ'
606−circ 'J' = 'Ĵ'
607−circ 'j' = 'ĵ'
608−circ 'S' = 'Ŝ'
609−circ 's' = 'ŝ'
610−circ 'W' = 'Ŵ'
611−circ 'w' = 'ŵ'
612−circ 'Y' = 'Ŷ'
613−circ 'y' = 'ŷ'
614−circ c = c
615−
616−tilde :: Char -> Char
617−tilde 'A' = 'Ã'
618−tilde 'a' = 'ã'
619−tilde 'O' = 'Õ'
620−tilde 'o' = 'õ'
621−tilde 'I' = 'Ĩ'
622−tilde 'i' = 'ĩ'
623−tilde 'U' = 'Ũ'
624−tilde 'u' = 'ũ'
625−tilde 'N' = 'Ñ'
626−tilde 'n' = 'ñ'
627−tilde c = c
628−
629−umlaut :: Char -> Char
630−umlaut 'A' = 'Ä'
631−umlaut 'E' = 'Ë'
632−umlaut 'I' = 'Ï'
633−umlaut 'O' = 'Ö'
634−umlaut 'U' = 'Ü'
635−umlaut 'a' = 'ä'
636−umlaut 'e' = 'ë'
637−umlaut 'i' = 'ï'
638−umlaut 'o' = 'ö'
639−umlaut 'u' = 'ü'
640−umlaut c = c
641−
642−dot :: Char -> Char
643−dot 'C' = 'Ċ'
644−dot 'c' = 'ċ'
645−dot 'E' = 'Ė'
646−dot 'e' = 'ė'
647−dot 'G' = 'Ġ'
648−dot 'g' = 'ġ'
649−dot 'I' = 'İ'
650−dot 'Z' = 'Ż'
651−dot 'z' = 'ż'
652−dot c = c
653−
654−macron :: Char -> Char
655−macron 'A' = 'Ā'
656−macron 'E' = 'Ē'
657−macron 'I' = 'Ī'
658−macron 'O' = 'Ō'
659−macron 'U' = 'Ū'
660−macron 'a' = 'ā'
661−macron 'e' = 'ē'
662−macron 'i' = 'ī'
663−macron 'o' = 'ō'
664−macron 'u' = 'ū'
665−macron c = c
666−
667−cedilla :: Char -> Char
668−cedilla 'c' = 'ç'
669−cedilla 'C' = 'Ç'
670−cedilla 's' = 'ş'
671−cedilla 'S' = 'Ş'
672−cedilla c = c
593+grave :: Char -> String
594+grave 'A' = "À"
595+grave 'E' = "È"
596+grave 'I' = "Ì"
597+grave 'O' = "Ò"
598+grave 'U' = "Ù"
599+grave 'a' = "à"
600+grave 'e' = "è"
601+grave 'i' = "ì"
602+grave 'o' = "ò"
603+grave 'u' = "ù"
604+grave c = [c]
605+
606+acute :: Char -> String
607+acute 'A' = "Á"
608+acute 'E' = "É"
609+acute 'I' = "Í"
610+acute 'O' = "Ó"
611+acute 'U' = "Ú"
612+acute 'Y' = "Ý"
613+acute 'a' = "á"
614+acute 'e' = "é"
615+acute 'i' = "í"
616+acute 'o' = "ó"
617+acute 'u' = "ú"
618+acute 'y' = "ý"
619+acute 'C' = "Ć"
620+acute 'c' = "ć"
621+acute 'L' = "Ĺ"
622+acute 'l' = "ĺ"
623+acute 'N' = "Ń"
624+acute 'n' = "ń"
625+acute 'R' = "Ŕ"
626+acute 'r' = "ŕ"
627+acute 'S' = "Ś"
628+acute 's' = "ś"
629+acute 'Z' = "Ź"
630+acute 'z' = "ź"
631+acute c = [c]
632+
633+circ :: Char -> String
634+circ 'A' = "Â"
635+circ 'E' = "Ê"
636+circ 'I' = "Î"
637+circ 'O' = "Ô"
638+circ 'U' = "Û"
639+circ 'a' = "â"
640+circ 'e' = "ê"
641+circ 'i' = "î"
642+circ 'o' = "ô"
643+circ 'u' = "û"
644+circ 'C' = "Ĉ"
645+circ 'c' = "ĉ"
646+circ 'G' = "Ĝ"
647+circ 'g' = "ĝ"
648+circ 'H' = "Ĥ"
649+circ 'h' = "ĥ"
650+circ 'J' = "Ĵ"
651+circ 'j' = "ĵ"
652+circ 'S' = "Ŝ"
653+circ 's' = "ŝ"
654+circ 'W' = "Ŵ"
655+circ 'w' = "ŵ"
656+circ 'Y' = "Ŷ"
657+circ 'y' = "ŷ"
658+circ c = [c]
659+
660+tilde :: Char -> String
661+tilde 'A' = "Ã"
662+tilde 'a' = "ã"
663+tilde 'O' = "Õ"
664+tilde 'o' = "õ"
665+tilde 'I' = "Ĩ"
666+tilde 'i' = "ĩ"
667+tilde 'U' = "Ũ"
668+tilde 'u' = "ũ"
669+tilde 'N' = "Ñ"
670+tilde 'n' = "ñ"
671+tilde c = [c]
672+
673+umlaut :: Char -> String
674+umlaut 'A' = "Ä"
675+umlaut 'E' = "Ë"
676+umlaut 'I' = "Ï"
677+umlaut 'O' = "Ö"
678+umlaut 'U' = "Ü"
679+umlaut 'a' = "ä"
680+umlaut 'e' = "ë"
681+umlaut 'i' = "ï"
682+umlaut 'o' = "ö"
683+umlaut 'u' = "ü"
684+umlaut c = [c]
685+
686+dot :: Char -> String
687+dot 'C' = "Ċ"
688+dot 'c' = "ċ"
689+dot 'E' = "Ė"
690+dot 'e' = "ė"
691+dot 'G' = "Ġ"
692+dot 'g' = "ġ"
693+dot 'I' = "İ"
694+dot 'Z' = "Ż"
695+dot 'z' = "ż"
696+dot c = [c]
697+
698+macron :: Char -> String
699+macron 'A' = "Ā"
700+macron 'E' = "Ē"
701+macron 'I' = "Ī"
702+macron 'O' = "Ō"
703+macron 'U' = "Ū"
704+macron 'a' = "ā"
705+macron 'e' = "ē"
706+macron 'i' = "ī"
707+macron 'o' = "ō"
708+macron 'u' = "ū"
709+macron c = [c]
710+
711+cedilla :: Char -> String
712+cedilla 'c' = "ç"
713+cedilla 'C' = "Ç"
714+cedilla 's' = "ş"
715+cedilla 'S' = "Ş"
716+cedilla 't' = "ţ"
717+cedilla 'T' = "Ţ"
718+cedilla 'e' = "ȩ"
719+cedilla 'E' = "Ȩ"
720+cedilla 'h' = "ḩ"
721+cedilla 'H' = "Ḩ"
722+cedilla 'o' = "o̧"
723+cedilla 'O' = "O̧"
724+cedilla c = [c]
725+
726+hacek :: Char -> String
727+hacek 'A' = "Ǎ"
728+hacek 'a' = "ǎ"
729+hacek 'C' = "Č"
730+hacek 'c' = "č"
731+hacek 'D' = "Ď"
732+hacek 'd' = "ď"
733+hacek 'E' = "Ě"
734+hacek 'e' = "ě"
735+hacek 'G' = "Ǧ"
736+hacek 'g' = "ǧ"
737+hacek 'H' = "Ȟ"
738+hacek 'h' = "ȟ"
739+hacek 'I' = "Ǐ"
740+hacek 'i' = "ǐ"
741+hacek 'j' = "ǰ"
742+hacek 'K' = "Ǩ"
743+hacek 'k' = "ǩ"
744+hacek 'L' = "Ľ"
745+hacek 'l' = "ľ"
746+hacek 'N' = "Ň"
747+hacek 'n' = "ň"
748+hacek 'O' = "Ǒ"
749+hacek 'o' = "ǒ"
750+hacek 'R' = "Ř"
751+hacek 'r' = "ř"
752+hacek 'S' = "Š"
753+hacek 's' = "š"
754+hacek 'T' = "Ť"
755+hacek 't' = "ť"
756+hacek 'U' = "Ǔ"
757+hacek 'u' = "ǔ"
758+hacek 'Z' = "Ž"
759+hacek 'z' = "ž"
760+hacek c = [c]
761+
762+breve :: Char -> String
763+breve 'A' = "Ă"
764+breve 'a' = "ă"
765+breve 'E' = "Ĕ"
766+breve 'e' = "ĕ"
767+breve 'G' = "Ğ"
768+breve 'g' = "ğ"
769+breve 'I' = "Ĭ"
770+breve 'i' = "ĭ"
771+breve 'O' = "Ŏ"
772+breve 'o' = "ŏ"
773+breve 'U' = "Ŭ"
774+breve 'u' = "ŭ"
775+breve c = [c]
673776
674777tok :: LP Inlines
675778tok = try $ grouped inline <|> inlineCommand <|> str <$> (count 1 $ inlineChar)
@@ -684,7 +787,7 @@ inlineText :: LP Inlines
684787inlineText = str <$> many1 inlineChar
685788
686789inlineChar :: LP Char
687−inlineChar = noneOf "\\$%^_&~#{}^'`-[] \t\n"
790+inlineChar = noneOf "\\$%^_&~#{}^'`\"‘’“”-[] \t\n"
688791
689792environment :: LP Blocks
690793environment = do
@@ -703,31 +806,107 @@ rawEnv name = do
703806 (withRaw (env name blocks) >>= applyMacros' . snd)
704807 else env name blocks
705808
809+----
810+
811+type IncludeParser = ParsecT [Char] [String] IO String
812+
706813-- | Replace "include" commands with file contents.
707814handleIncludes :: String -> IO String
708−handleIncludes = handleIncludes' []
709−
710−-- parents parameter prevents infinite include loops
711−handleIncludes' :: [FilePath] -> String -> IO String
712−handleIncludes' _ [] = return []
713−handleIncludes' parents ('\\':'%':xs) =
714− ("\\%"++) `fmap` handleIncludes' parents xs
715−handleIncludes' parents ('%':xs) = handleIncludes' parents
716− $ drop 1 $ dropWhile (/='\n') xs
717−handleIncludes' parents ('\\':xs) =
718− case runParser include defaultParserState "input" ('\\':xs) of
719− Right (fs, rest) -> do yss <- mapM (\f -> if f `elem` parents
720− then "" <$ warn ("Include file loop in '"
721− ++ f ++ "'.")
722− else readTeXFile f >>=
723− handleIncludes' (f:parents)) fs
724− rest' <- handleIncludes' parents rest
725− return $ intercalate "\n" yss ++ rest'
726− _ -> case runParser (verbCmd <|> verbatimEnv) defaultParserState
727− "input" ('\\':xs) of
728− Right (r, rest) -> (r ++) `fmap` handleIncludes' parents rest
729− _ -> ('\\':) `fmap` handleIncludes' parents xs
730−handleIncludes' parents (x:xs) = (x:) `fmap` handleIncludes' parents xs
815+handleIncludes s = do
816+ res <- runParserT includeParser' [] "input" s
817+ case res of
818+ Right s' -> return s'
819+ Left e -> error $ show e
820+
821+includeParser' :: IncludeParser
822+includeParser' =
823+ concat <$> many (comment' <|> escaped' <|> blob' <|> include'
824+ <|> startMarker' <|> endMarker'
825+ <|> verbCmd' <|> verbatimEnv' <|> backslash')
826+
827+comment' :: IncludeParser
828+comment' = do
829+ char '%'
830+ xs <- manyTill anyChar newline
831+ return ('%':xs ++ "\n")
832+
833+escaped' :: IncludeParser
834+escaped' = try $ string "\\%" <|> string "\\\\"
835+
836+verbCmd' :: IncludeParser
837+verbCmd' = fmap snd <$>
838+ withRaw $ try $ do
839+ string "\\verb"
840+ c <- anyChar
841+ manyTill anyChar (char c)
842+
843+verbatimEnv' :: IncludeParser
844+verbatimEnv' = fmap snd <$>
845+ withRaw $ try $ do
846+ string "\\begin"
847+ name <- braced'
848+ guard $ name `elem` ["verbatim", "Verbatim", "lstlisting",
849+ "minted", "alltt"]
850+ manyTill anyChar (try $ string $ "\\end{" ++ name ++ "}")
851+
852+blob' :: IncludeParser
853+blob' = try $ many1 (noneOf "\\%")
854+
855+backslash' :: IncludeParser
856+backslash' = string "\\"
857+
858+braced' :: IncludeParser
859+braced' = try $ char '{' *> manyTill (satisfy (/='}')) (char '}')
860+
861+include' :: IncludeParser
862+include' = do
863+ fs' <- try $ do
864+ char '\\'
865+ name <- try (string "include")
866+ <|> try (string "input")
867+ <|> string "usepackage"
868+ -- skip options
869+ skipMany $ try $ char '[' *> (manyTill anyChar (char ']'))
870+ fs <- (map trim . splitBy (==',')) <$> braced'
871+ return $ if name == "usepackage"
872+ then map (flip replaceExtension ".sty") fs
873+ else map (flip replaceExtension ".tex") fs
874+ pos <- getPosition
875+ containers <- getState
876+ let fn = case containers of
877+ (f':_) -> f'
878+ [] -> "input"
879+ -- now process each include file in order...
880+ rest <- getInput
881+ results' <- forM fs' (\f -> do
882+ when (f `elem` containers) $
883+ fail "Include file loop!"
884+ contents <- lift $ readTeXFile f
885+ return $ "\\PandocStartInclude{" ++ f ++ "}" ++
886+ contents ++ "\\PandocEndInclude{" ++
887+ fn ++ "}{" ++ show (sourceLine pos) ++ "}{"
888+ ++ show (sourceColumn pos) ++ "}")
889+ setInput $ concat results' ++ rest
890+ return ""
891+
892+startMarker' :: IncludeParser
893+startMarker' = try $ do
894+ string "\\PandocStartInclude"
895+ fn <- braced'
896+ updateState (fn:)
897+ setPosition $ newPos fn 1 1
898+ return $ "\\PandocStartInclude{" ++ fn ++ "}"
899+
900+endMarker' :: IncludeParser
901+endMarker' = try $ do
902+ string "\\PandocEndInclude"
903+ fn <- braced'
904+ ln <- braced'
905+ co <- braced'
906+ updateState tail
907+ setPosition $ newPos fn (fromMaybe 1 $ safeRead ln) (fromMaybe 1 $ safeRead co)
908+ return $ "\\PandocEndInclude{" ++ fn ++ "}{" ++ ln ++ "}{" ++
909+ co ++ "}"
731910
732911readTeXFile :: FilePath -> IO String
733912readTeXFile f = do
@@ -742,27 +921,7 @@ readFileFromDirs (d:ds) f =
742921 E.catch (UTF8.readFile $ d </> f) $ \(_ :: E.SomeException) ->
743922 readFileFromDirs ds f
744923
745−include :: LP ([FilePath], String)
746−include = do
747− name <- controlSeq "include"
748− <|> controlSeq "input"
749− <|> controlSeq "usepackage"
750− skipopts
751− fs <- (splitBy (==',')) <$> braced
752− rest <- getInput
753− let fs' = if name == "usepackage"
754− then map (flip replaceExtension ".sty") fs
755− else map (flip replaceExtension ".tex") fs
756− return (fs', rest)
757−
758−verbCmd :: LP (String, String)
759−verbCmd = do
760− (_,r) <- withRaw $ do
761− controlSeq "verb"
762− c <- anyChar
763− manyTill anyChar (char c)
764− rest <- getInput
765− return (r, rest)
924+----
766925
767926keyval :: LP (String, String)
768927keyval = try $ do
@@ -778,24 +937,12 @@ keyvals :: LP [(String, String)]
778937keyvals = try $ char '[' *> manyTill keyval (char ']')
779938
780939alltt :: String -> LP Blocks
781−alltt t = bottomUp strToCode <$> parseFromString blocks
940+alltt t = walk strToCode <$> parseFromString blocks
782941 (substitute " " "\\ " $ substitute "%" "\\%" $
783942 concat $ intersperse "\\\\\n" $ lines t)
784943 where strToCode (Str s) = Code nullAttr s
785944 strToCode x = x
786945
787−verbatimEnv :: LP (String, String)
788−verbatimEnv = do
789− (_,r) <- withRaw $ do
790− controlSeq "begin"
791− name <- braced
792− guard $ name == "verbatim" || name == "Verbatim" ||
793− name == "lstlisting" || name == "minted" ||
794− name == "alltt"
795− verbEnv name
796− rest <- getInput
797− return (r,rest)
798−
799946rawLaTeXBlock :: Parser [Char] ParserState String
800947rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
801948
@@ -804,12 +951,33 @@ rawLaTeXInline = do
804951 raw <- (snd <$> withRaw inlineCommand) <|> (snd <$> withRaw blockCommand)
805952 RawInline "latex" <$> applyMacros' raw
806953
954+addImageCaption :: Blocks -> LP Blocks
955+addImageCaption = walkM go
956+ where go (Image alt (src,tit)) = do
957+ mbcapt <- stateCaption <$> getState
958+ case mbcapt of
959+ Just ils -> return (Image (toList ils) (src, "fig:"))
960+ Nothing -> return (Image alt (src,tit))
961+ go x = return x
962+
963+addTableCaption :: Blocks -> LP Blocks
964+addTableCaption = walkM go
965+ where go (Table c als ws hs rs) = do
966+ mbcapt <- stateCaption <$> getState
967+ case mbcapt of
968+ Just ils -> return (Table (toList ils) als ws hs rs)
969+ Nothing -> return (Table c als ws hs rs)
970+ go x = return x
971+
807972environments :: M.Map String (LP Blocks)
808973environments = M.fromList
809974 [ ("document", env "document" blocks <* skipMany anyChar)
810975 , ("letter", env "letter" letter_contents)
811− , ("figure", env "figure" $ skipopts *> blocks)
976+ , ("figure", env "figure" $
977+ resetCaption *> skipopts *> blocks >>= addImageCaption)
812978 , ("center", env "center" blocks)
979+ , ("table", env "table" $
980+ resetCaption *> skipopts *> blocks >>= addTableCaption)
813981 , ("tabular", env "tabular" simpTable)
814982 , ("quote", blockQuote <$> env "quote" blocks)
815983 , ("quotation", blockQuote <$> env "quotation" blocks)
@@ -838,7 +1006,7 @@ environments = M.fromList
8381006 lookup "numbers" options == Just "left" ]
8391007 ++ maybe [] (:[]) (lookup "language" options
8401008 >>= fromListingsLanguage)
841− let attr = ("",classes,kvs)
1009+ let attr = (fromMaybe "" (lookup "label" options),classes,kvs)
8421010 codeBlockWith attr <$> (verbEnv "lstlisting"))
8431011 , ("minted", do options <- option [] keyvals
8441012 lang <- grouped (many1 $ satisfy (/='}'))
@@ -966,15 +1134,15 @@ paragraph = do
9661134
9671135preamble :: LP Blocks
9681136preamble = mempty <$> manyTill preambleBlock beginDoc
969− where beginDoc = lookAhead $ controlSeq "begin" *> string "{document}"
970− preambleBlock = (mempty <$ comment)
971− <|> (mempty <$ sp)
972− <|> (mempty <$ blanklines)
973− <|> (mempty <$ macro)
974− <|> blockCommand
975− <|> (mempty <$ anyControlSeq)
976− <|> (mempty <$ braced)
977− <|> (mempty <$ anyChar)
1137+ where beginDoc = lookAhead $ try $ controlSeq "begin" *> string "{document}"
1138+ preambleBlock = (void comment)
1139+ <|> (void sp)
1140+ <|> (void blanklines)
1141+ <|> (void macro)
1142+ <|> (void blockCommand)
1143+ <|> (void anyControlSeq)
1144+ <|> (void braced)
1145+ <|> (void anyChar)
9781146
9791147-------
9801148
@@ -986,12 +1154,8 @@ addPrefix _ _ = []
9861154
9871155addSuffix :: [Inline] -> [Citation] -> [Citation]
9881156addSuffix s ks@(_:_) =
989− let k = last ks
990− s' = case s of
991− (Str (c:_):_)
992− | not (isPunctuation c || isSpace c) -> Str "," : Space : s
993− _ -> s
994− in init ks ++ [k {citationSuffix = citationSuffix k ++ s'}]
1157+ let k = last ks
1158+ in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
9951159addSuffix _ _ = []
9961160
9971161simpleCiteArgs :: LP [Citation]
@@ -999,6 +1163,7 @@ simpleCiteArgs = try $ do
9991163 first <- optionMaybe $ toList <$> opt
10001164 second <- optionMaybe $ toList <$> opt
10011165 char '{'
1166+ optional sp
10021167 keys <- manyTill citationLabel (char '}')
10031168 let (pre, suf) = case (first , second ) of
10041169 (Just s , Nothing) -> (mempty, s )
@@ -1014,18 +1179,24 @@ simpleCiteArgs = try $ do
10141179 return $ addPrefix pre $ addSuffix suf $ map conv keys
10151180
10161181citationLabel :: LP String
1017−citationLabel = trim <$>
1018− (many1 (satisfy $ \c -> c /=',' && c /='}') <* optional (char ',') <* optional sp)
1182+citationLabel = optional sp *>
1183+ (many1 (satisfy isBibtexKeyChar)
1184+ <* optional sp
1185+ <* optional (char ',')
1186+ <* optional sp)
1187+ where isBibtexKeyChar c = isAlphaNum c || c `elem` ".:;?!`'()/*@_+=-[]*"
10191188
10201189cites :: CitationMode -> Bool -> LP [Citation]
10211190cites mode multi = try $ do
10221191 cits <- if multi
10231192 then many1 simpleCiteArgs
10241193 else count 1 simpleCiteArgs
1025− let (c:cs) = concat cits
1194+ let cs = concat cits
10261195 return $ case mode of
1027− AuthorInText -> c {citationMode = mode} : cs
1028− _ -> map (\a -> a {citationMode = mode}) (c:cs)
1196+ AuthorInText -> case cs of
1197+ (c:rest) -> c {citationMode = mode} : rest
1198+ [] -> []
1199+ _ -> map (\a -> a {citationMode = mode}) cs
10291200
10301201citation :: String -> CitationMode -> Bool -> LP Inlines
10311202citation name mode multi = do
@@ -1057,12 +1228,14 @@ complexNatbibCitation mode = try $ do
10571228parseAligns :: LP [Alignment]
10581229parseAligns = try $ do
10591230 char '{'
1060− optional $ char '|'
1231+ let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ try (string "@{}")
1232+ maybeBar
10611233 let cAlign = AlignCenter <$ char 'c'
10621234 let lAlign = AlignLeft <$ char 'l'
10631235 let rAlign = AlignRight <$ char 'r'
1064− let alignChar = optional sp *> (cAlign <|> lAlign <|> rAlign)
1065− aligns' <- sepEndBy alignChar (optional $ char '|')
1236+ let parAlign = AlignLeft <$ (char 'p' >> braced)
1237+ let alignChar = cAlign <|> lAlign <|> rAlign <|> parAlign
1238+ aligns' <- sepEndBy alignChar maybeBar
10661239 spaces
10671240 char '}'
10681241 spaces
@@ -1082,10 +1255,14 @@ parseTableRow :: Int -- ^ number of columns
10821255parseTableRow cols = try $ do
10831256 let tableCellInline = notFollowedBy (amp <|> lbreak) >> inline
10841257 let tableCell = (plain . trimInlines . mconcat) <$> many tableCellInline
1085− cells' <- sepBy tableCell amp
1086− guard $ length cells' == cols
1258+ cells' <- sepBy1 tableCell amp
1259+ let numcells = length cells'
1260+ guard $ numcells <= cols && numcells >= 1
1261+ guard $ cells' /= [mempty]
1262+ -- note: a & b in a three-column table leaves an empty 3rd cell:
1263+ let cells'' = cells' ++ replicate (cols - numcells) mempty
10871264 spaces
1088− return cells'
1265+ return cells''
10891266
10901267simpTable :: LP Blocks
10911268simpTable = try $ do
@@ -1096,9 +1273,23 @@ simpTable = try $ do
10961273 header' <- option [] $ try (parseTableRow cols <* lbreak <* hline)
10971274 rows <- sepEndBy (parseTableRow cols) (lbreak <* optional hline)
10981275 spaces
1276+ skipMany (comment *> spaces)
10991277 let header'' = if null header'
11001278 then replicate cols mempty
11011279 else header'
11021280 lookAhead $ controlSeq "end" -- make sure we're at end
11031281 return $ table mempty (zip aligns (repeat 0)) header'' rows
11041282
1283+startInclude :: LP Blocks
1284+startInclude = do
1285+ fn <- braced
1286+ setPosition $ newPos fn 1 1
1287+ return mempty
1288+
1289+endInclude :: LP Blocks
1290+endInclude = do
1291+ fn <- braced
1292+ ln <- braced
1293+ co <- braced
1294+ setPosition $ newPos fn (fromMaybe 1 $ safeRead ln) (fromMaybe 1 $ safeRead co)
1295+ return mempty
src/Text/Pandoc/Readers/Markdown.hs+264−236
@@ -1,6 +1,6 @@
11{-# LANGUAGE RelaxedPolyRec #-} -- needed for inlinesBetween on GHC < 7
22{-
3−Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Text.Pandoc.Readers.Markdown
22− Copyright : Copyright (C) 2006-2013 John MacFarlane
22+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -33,6 +33,7 @@ module Text.Pandoc.Readers.Markdown ( readMarkdown,
3333
3434import Data.List ( transpose, sortBy, findIndex, intersperse, intercalate )
3535import qualified Data.Map as M
36+import Data.Scientific (coefficient, base10Exponent)
3637import Data.Ord ( comparing )
3738import Data.Char ( isAlphaNum, toLower )
3839import Data.Maybe
@@ -49,13 +50,10 @@ import Text.Pandoc.Builder (Inlines, Blocks, trimInlines, (<>))
4950import Text.Pandoc.Options
5051import Text.Pandoc.Shared
5152import Text.Pandoc.XML (fromEntities)
52−import Text.Pandoc.Asciify (toAsciiChar)
5353import Text.Pandoc.Parsing hiding (tableWith)
5454import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXBlock )
5555import Text.Pandoc.Readers.HTML ( htmlTag, htmlInBalanced, isInlineTag, isBlockTag,
5656 isTextTag, isCommentTag )
57−import Text.Pandoc.Biblio (processBiblio)
58−import qualified Text.CSL as CSL
5957import Data.Monoid (mconcat, mempty)
6058import Control.Applicative ((<$>), (<*), (*>), (<$))
6159import Control.Monad
@@ -63,6 +61,8 @@ import System.FilePath (takeExtension, addExtension)
6361import Text.HTML.TagSoup
6462import Text.HTML.TagSoup.Match (tagOpen)
6563import qualified Data.Set as Set
64+import Text.Printf (printf)
65+import Debug.Trace (trace)
6666
6767type MarkdownParser = Parser [Char] ParserState
6868
@@ -203,13 +203,10 @@ dateLine = try $ do
203203 skipSpaces
204204 trimInlinesF . mconcat <$> manyTill inline newline
205205
206−titleBlock :: MarkdownParser (F (Pandoc -> Pandoc))
207−titleBlock = pandocTitleBlock
208− <|> yamlTitleBlock
209− <|> mmdTitleBlock
210− <|> return (return id)
206+titleBlock :: MarkdownParser ()
207+titleBlock = pandocTitleBlock <|> mmdTitleBlock
211208
212−pandocTitleBlock :: MarkdownParser (F (Pandoc -> Pandoc))
209+pandocTitleBlock :: MarkdownParser ()
213210pandocTitleBlock = try $ do
214211 guardEnabled Ext_pandoc_title_block
215212 lookAhead (char '%')
@@ -217,49 +214,61 @@ pandocTitleBlock = try $ do
217214 author <- option (return []) authorsLine
218215 date <- option mempty dateLine
219216 optional blanklines
220− return $ do
221− title' <- title
222− author' <- author
223− date' <- date
224− return $ B.setMeta "title" title'
225− . B.setMeta "author" author'
226− . B.setMeta "date" date'
227−
228−yamlTitleBlock :: MarkdownParser (F (Pandoc -> Pandoc))
229−yamlTitleBlock = try $ do
217+ let meta' = do title' <- title
218+ author' <- author
219+ date' <- date
220+ return $
221+ (if B.isNull title' then id else B.setMeta "title" title')
222+ . (if null author' then id else B.setMeta "author" author')
223+ . (if B.isNull date' then id else B.setMeta "date" date')
224+ $ nullMeta
225+ updateState $ \st -> st{ stateMeta' = stateMeta' st <> meta' }
226+
227+yamlMetaBlock :: MarkdownParser (F Blocks)
228+yamlMetaBlock = try $ do
230229 guardEnabled Ext_yaml_metadata_block
231230 pos <- getPosition
232231 string "---"
233232 blankline
234− rawYaml <- unlines <$> manyTill anyLine stopLine
233+ notFollowedBy blankline -- if --- is followed by a blank it's an HRULE
234+ rawYamlLines <- manyTill anyLine stopLine
235+ -- by including --- and ..., we allow yaml blocks with just comments:
236+ let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."]))
235237 optional blanklines
236238 opts <- stateOptions <$> getState
237− case Yaml.decodeEither' $ UTF8.fromString rawYaml of
238− Right (Yaml.Object hashmap) -> return $ return $
239− H.foldrWithKey (\k v f ->
240− if ignorable k
241− then f
242− else B.setMeta (T.unpack k) (yamlToMeta opts v) . f)
243− id hashmap
244− Right _ -> do
245− addWarning (Just pos) "YAML header is not an object"
246− return $ return id
247− Left err' -> do
248− case err' of
249− InvalidYaml (Just YamlParseException{
250− yamlProblem = problem
251− , yamlContext = _ctxt
252− , yamlProblemMark = Yaml.YamlMark {
253− yamlLine = yline
254− , yamlColumn = ycol
255− }}) ->
256− addWarning (Just $ setSourceLine
257− (setSourceColumn pos (sourceColumn pos + ycol))
258− (sourceLine pos + 1 + yline))
259− $ "Could not parse YAML header: " ++ problem
260− _ -> addWarning (Just pos)
261− $ "Could not parse YAML header: " ++ show err'
262− return $ return id
239+ meta' <- case Yaml.decodeEither' $ UTF8.fromString rawYaml of
240+ Right (Yaml.Object hashmap) -> return $ return $
241+ H.foldrWithKey (\k v m ->
242+ if ignorable k
243+ then m
244+ else B.setMeta (T.unpack k)
245+ (yamlToMeta opts v) m)
246+ nullMeta hashmap
247+ Right Yaml.Null -> return $ return nullMeta
248+ Right _ -> do
249+ addWarning (Just pos) "YAML header is not an object"
250+ return $ return nullMeta
251+ Left err' -> do
252+ case err' of
253+ InvalidYaml (Just YamlParseException{
254+ yamlProblem = problem
255+ , yamlContext = _ctxt
256+ , yamlProblemMark = Yaml.YamlMark {
257+ yamlLine = yline
258+ , yamlColumn = ycol
259+ }}) ->
260+ addWarning (Just $ setSourceLine
261+ (setSourceColumn pos
262+ (sourceColumn pos + ycol))
263+ (sourceLine pos + 1 + yline))
264+ $ "Could not parse YAML header: " ++
265+ problem
266+ _ -> addWarning (Just pos)
267+ $ "Could not parse YAML header: " ++
268+ show err'
269+ return $ return nullMeta
270+ updateState $ \st -> st{ stateMeta' = stateMeta' st <> meta' }
271+ return mempty
263272
264273-- ignore fields ending with _
265274ignorable :: Text -> Bool
@@ -277,8 +286,12 @@ toMetaValue opts x =
277286
278287yamlToMeta :: ReaderOptions -> Yaml.Value -> MetaValue
279288yamlToMeta opts (Yaml.String t) = toMetaValue opts t
280−yamlToMeta _ (Yaml.Number n) = MetaString $ show n
281−yamlToMeta _ (Yaml.Bool b) = MetaString $ map toLower $ show b
289+yamlToMeta _ (Yaml.Number n)
290+ -- avoid decimal points for numbers that don't need them:
291+ | base10Exponent n >= 0 = MetaString $ show
292+ $ coefficient n * (10 ^ base10Exponent n)
293+ | otherwise = MetaString $ show n
294+yamlToMeta _ (Yaml.Bool b) = MetaBool b
282295yamlToMeta opts (Yaml.Array xs) = B.toMetaValue $ map (yamlToMeta opts)
283296 $ V.toList xs
284297yamlToMeta opts (Yaml.Object o) = MetaMap $ H.foldrWithKey (\k v m ->
@@ -292,13 +305,13 @@ yamlToMeta _ _ = MetaString ""
292305stopLine :: MarkdownParser ()
293306stopLine = try $ (string "---" <|> string "...") >> blankline >> return ()
294307
295−mmdTitleBlock :: MarkdownParser (F (Pandoc -> Pandoc))
308+mmdTitleBlock :: MarkdownParser ()
296309mmdTitleBlock = try $ do
297310 guardEnabled Ext_mmd_title_block
298311 kvPairs <- many1 kvPair
299312 blanklines
300− return $ return $ \(Pandoc m bs) ->
301− Pandoc (foldl (\m' (k,v) -> addMetaField k v m') m kvPairs) bs
313+ updateState $ \st -> st{ stateMeta' = stateMeta' st <>
314+ return (Meta $ M.fromList kvPairs) }
302315
303316kvPair :: MarkdownParser (String, MetaValue)
304317kvPair = try $ do
@@ -315,15 +328,12 @@ parseMarkdown = do
315328 updateState $ \state -> state { stateOptions =
316329 let oldOpts = stateOptions state in
317330 oldOpts{ readerParseRaw = True } }
318− titleTrans <- option (return id) titleBlock
331+ optional titleBlock
319332 blocks <- parseBlocks
320333 st <- getState
321− mbsty <- getOption readerCitationStyle
322− refs <- getOption readerReferences
323− return $ processBiblio mbsty refs
324− $ runF titleTrans st
325− $ B.doc
326− $ runF blocks st
334+ let meta = runF (stateMeta' st) st
335+ let Pandoc _ bs = B.doc $ runF blocks st
336+ return $ Pandoc meta bs
327337
328338addWarning :: Maybe SourcePos -> String -> MarkdownParser ()
329339addWarning mbpos msg =
@@ -339,10 +349,8 @@ referenceKey = try $ do
339349 char ':'
340350 skipSpaces >> optional newline >> skipSpaces >> notFollowedBy (char '[')
341351 let sourceURL = liftM unwords $ many $ try $ do
342− notFollowedBy' referenceTitle
343− skipMany spaceChar
344− optional $ newline >> notFollowedBy blankline
345352 skipMany spaceChar
353+ notFollowedBy' referenceTitle
346354 notFollowedBy' (() <$ reference)
347355 many1 $ notFollowedBy space >> litChar
348356 let betweenAngles = try $ char '<' >>
@@ -351,7 +359,7 @@ referenceKey = try $ do
351359 tit <- option "" referenceTitle
352360 -- currently we just ignore MMD-style link/image attributes
353361 _kvs <- option [] $ guardEnabled Ext_link_attributes
354− >> many (spnl >> keyValAttr)
362+ >> many (try $ spnl >> keyValAttr)
355363 blanklines
356364 let target = (escapeURI $ trimr src, tit)
357365 st <- getState
@@ -437,19 +445,26 @@ parseBlocks :: MarkdownParser (F Blocks)
437445parseBlocks = mconcat <$> manyTill block eof
438446
439447block :: MarkdownParser (F Blocks)
440−block = choice [ mempty <$ blanklines
448+block = do
449+ tr <- getOption readerTrace
450+ pos <- getPosition
451+ res <- choice [ mempty <$ blanklines
441452 , codeBlockFenced
453+ , yamlMetaBlock
442454 , guardEnabled Ext_latex_macros *> (macro >>= return . return)
455+ -- note: bulletList needs to be before header because of
456+ -- the possibility of empty list items: -
457+ , bulletList
443458 , header
444459 , lhsCodeBlock
445460 , rawTeXBlock
461+ , divHtml
446462 , htmlBlock
447463 , table
448464 , lineBlock
449465 , codeBlockIndented
450466 , blockQuote
451467 , hrule
452− , bulletList
453468 , orderedList
454469 , definitionList
455470 , noteBlock
@@ -458,6 +473,11 @@ block = choice [ mempty <$ blanklines
458473 , para
459474 , plain
460475 ] <?> "block"
476+ when tr $ do
477+ st <- getState
478+ trace (printf "line %d: %s" (sourceLine pos)
479+ (take 60 $ show $ B.toList $ runF res st)) (return ())
480+ return res
461481
462482--
463483-- header blocks
@@ -466,39 +486,15 @@ block = choice [ mempty <$ blanklines
466486header :: MarkdownParser (F Blocks)
467487header = setextHeader <|> atxHeader <?> "header"
468488
469−-- returns unique identifier
470−addToHeaderList :: Attr -> F Inlines -> MarkdownParser Attr
471−addToHeaderList (ident,classes,kvs) text = do
472− let header' = runF text defaultParserState
473− exts <- getOption readerExtensions
474− let insert' = M.insertWith (\_new old -> old)
475− if null ident && Ext_auto_identifiers `Set.member` exts
476− then do
477− ids <- stateIdentifiers `fmap` getState
478− let id' = uniqueIdent (B.toList header') ids
479− let id'' = if Ext_ascii_identifiers `Set.member` exts
480− then catMaybes $ map toAsciiChar id'
481− else id'
482− updateState $ \st -> st{
483− stateIdentifiers = if id' == id''
484− then id' : ids
485− else id' : id'' : ids,
486− stateHeaders = insert' header' id' $ stateHeaders st }
487− return (id'',classes,kvs)
488− else do
489− unless (null ident) $
490− updateState $ \st -> st{
491− stateHeaders = insert' header' ident $ stateHeaders st }
492− return (ident,classes,kvs)
493−
494489atxHeader :: MarkdownParser (F Blocks)
495490atxHeader = try $ do
496491 level <- many1 (char '#') >>= return . length
497− notFollowedBy (char '.' <|> char ')') -- this would be a list
492+ notFollowedBy $ guardEnabled Ext_fancy_lists >>
493+ (char '.' <|> char ')') -- this would be a list
498494 skipSpaces
499495 text <- trimInlinesF . mconcat <$> many (notFollowedBy atxClosing >> inline)
500496 attr <- atxClosing
501− attr' <- addToHeaderList attr text
497+ attr' <- registerHeader attr (runF text defaultParserState)
502498 return $ B.headerWith attr' level <$> text
503499
504500atxClosing :: MarkdownParser Attr
@@ -537,7 +533,7 @@ setextHeader = try $ do
537533 many (char underlineChar)
538534 blanklines
539535 let level = (fromMaybe 0 $ findIndex (== underlineChar) setextHChars) + 1
540− attr' <- addToHeaderList attr text
536+ attr' <- registerHeader attr (runF text defaultParserState)
541537 return $ B.headerWith attr' level <$> text
542538
543539--
@@ -622,12 +618,19 @@ codeBlockFenced = try $ do
622618 skipMany spaceChar
623619 attr <- option ([],[],[]) $
624620 try (guardEnabled Ext_fenced_code_attributes >> attributes)
625− <|> ((\x -> ("",[x],[])) <$> identifier)
621+ <|> ((\x -> ("",[toLanguageId x],[])) <$> many1 nonspaceChar)
626622 blankline
627623 contents <- manyTill anyLine (blockDelimiter (== c) (Just size))
628624 blanklines
629625 return $ return $ B.codeBlockWith attr $ intercalate "\n" contents
630626
627+-- correctly handle github language identifiers
628+toLanguageId :: String -> String
629+toLanguageId = map toLower . go
630+ where go "c++" = "cpp"
631+ go "objective-c" = "objectivec"
632+ go x = x
633+
631634codeBlockIndented :: MarkdownParser (F Blocks)
632635codeBlockIndented = do
633636 contents <- many1 (indentedLine <|>
@@ -718,7 +721,7 @@ bulletListStart = try $ do
718721 skipNonindentSpaces
719722 notFollowedBy' (() <$ hrule) -- because hrules start out just like lists
720723 satisfy isBulletListMarker
721− spaceChar
724+ spaceChar <|> lookAhead newline
722725 skipSpaces
723726
724727anyOrderedListStart :: MarkdownParser (Int, ListNumberStyle, ListNumberDelim)
@@ -746,11 +749,16 @@ listStart = bulletListStart <|> (anyOrderedListStart >> return ())
746749-- parse a line of a list item (start = parser for beginning of list item)
747750listLine :: MarkdownParser String
748751listLine = try $ do
749− notFollowedBy blankline
750752 notFollowedBy' (do indentSpaces
751− many (spaceChar)
753+ many spaceChar
752754 listStart)
753− chunks <- manyTill (liftM snd (htmlTag isCommentTag) <|> count 1 anyChar) newline
755+ notFollowedBy' $ htmlTag (~== TagClose "div")
756+ optional (() <$ indentSpaces)
757+ chunks <- manyTill
758+ ( many1 (satisfy $ \c -> c /= '\n' && c /= '<')
759+ <|> liftM snd (htmlTag isCommentTag)
760+ <|> count 1 anyChar
761+ ) newline
754762 return $ concat chunks
755763
756764-- parse raw text for one list item, excluding start marker and continuations
@@ -759,7 +767,7 @@ rawListItem :: MarkdownParser a
759767rawListItem start = try $ do
760768 start
761769 first <- listLine
762− rest <- many (notFollowedBy listStart >> listLine)
770+ rest <- many (notFollowedBy listStart >> notFollowedBy blankline >> listLine)
763771 blanks <- many blankline
764772 return $ unlines (first:rest) ++ blanks
765773
@@ -777,6 +785,7 @@ listContinuationLine :: MarkdownParser String
777785listContinuationLine = try $ do
778786 notFollowedBy blankline
779787 notFollowedBy' listStart
788+ notFollowedBy' $ htmlTag (~== TagClose "div")
780789 optional indentSpaces
781790 result <- anyLine
782791 return $ result ++ "\n"
@@ -801,8 +810,8 @@ listItem start = try $ do
801810orderedList :: MarkdownParser (F Blocks)
802811orderedList = try $ do
803812 (start, style, delim) <- lookAhead anyOrderedListStart
804− unless ((style == DefaultStyle || style == Decimal || style == Example) &&
805− (delim == DefaultDelim || delim == Period)) $
813+ unless (style `elem` [DefaultStyle, Decimal, Example] &&
814+ delim `elem` [DefaultDelim, Period]) $
806815 guardEnabled Ext_fancy_lists
807816 when (style == Example) $ guardEnabled Ext_example_lists
808817 items <- fmap sequence $ many1 $ listItem
@@ -863,22 +872,6 @@ definitionList = do
863872 items <- fmap sequence $ many1 definitionListItem
864873 return $ B.definitionList <$> fmap compactify'DL items
865874
866−compactify'DL :: [(Inlines, [Blocks])] -> [(Inlines, [Blocks])]
867−compactify'DL items =
868− let defs = concatMap snd items
869− defBlocks = reverse $ concatMap B.toList defs
870− isPara (Para _) = True
871− isPara _ = False
872− in case defBlocks of
873− (Para x:_) -> if not $ any isPara (drop 1 defBlocks)
874− then let (t,ds) = last items
875− lastDef = B.toList $ last ds
876− ds' = init ds ++
877− [B.fromList $ init lastDef ++ [Plain x]]
878− in init items ++ [(t, ds')]
879− else items
880− _ -> items
881−
882875--
883876-- paragraph block
884877--
@@ -891,8 +884,11 @@ para = try $ do
891884 $ try $ do
892885 newline
893886 (blanklines >> return mempty)
894− <|> (guardDisabled Ext_blank_before_blockquote >> lookAhead blockQuote)
895− <|> (guardDisabled Ext_blank_before_header >> lookAhead header)
887+ <|> (guardDisabled Ext_blank_before_blockquote >> () <$ lookAhead blockQuote)
888+ <|> (guardEnabled Ext_backtick_code_blocks >> () <$ lookAhead codeBlockFenced)
889+ <|> (guardDisabled Ext_blank_before_header >> () <$ lookAhead header)
890+ <|> (guardEnabled Ext_lists_without_preceding_blankline >>
891+ () <$ lookAhead listStart)
896892 return $ do
897893 result' <- result
898894 case B.toList result' of
@@ -911,7 +907,9 @@ plain = fmap B.plain . trimInlinesF . mconcat <$> many1 inline
911907--
912908
913909htmlElement :: MarkdownParser String
914−htmlElement = strictHtmlBlock <|> liftM snd (htmlTag isBlockTag)
910+htmlElement = rawVerbatimBlock
911+ <|> strictHtmlBlock
912+ <|> liftM snd (htmlTag isBlockTag)
915913
916914htmlBlock :: MarkdownParser (F Blocks)
917915htmlBlock = do
@@ -932,8 +930,8 @@ strictHtmlBlock = htmlInBalanced (not . isInlineTag)
932930
933931rawVerbatimBlock :: MarkdownParser String
934932rawVerbatimBlock = try $ do
935− (TagOpen tag _, open) <- htmlTag (tagOpen (\t ->
936− t == "pre" || t == "style" || t == "script")
933+ (TagOpen tag _, open) <- htmlTag (tagOpen (flip elem
934+ ["pre", "style", "script"])
937935 (const True))
938936 contents <- manyTill anyChar (htmlTag (~== TagClose tag))
939937 return $ open ++ contents ++ renderTags [TagClose tag]
@@ -941,8 +939,10 @@ rawVerbatimBlock = try $ do
941939rawTeXBlock :: MarkdownParser (F Blocks)
942940rawTeXBlock = do
943941 guardEnabled Ext_raw_tex
944− result <- (B.rawBlock "latex" <$> rawLaTeXBlock)
945− <|> (B.rawBlock "context" <$> rawConTeXtEnvironment)
942+ result <- (B.rawBlock "latex" . concat <$>
943+ rawLaTeXBlock `sepEndBy1` blankline)
944+ <|> (B.rawBlock "context" . concat <$>
945+ rawConTeXtEnvironment `sepEndBy1` blankline)
946946 spaces
947947 return $ return result
948948
@@ -951,6 +951,8 @@ rawHtmlBlocks = do
951951 htmlBlocks <- many1 $ try $ do
952952 s <- rawVerbatimBlock <|> try (
953953 do (t,raw) <- htmlTag isBlockTag
954+ guard $ t ~/= TagOpen "div" [] &&
955+ t ~/= TagClose "div"
954956 exts <- getOption readerExtensions
955957 -- if open tag, need markdown="1" if
956958 -- markdown_attributes extension is set
@@ -1117,13 +1119,11 @@ multilineTable headless =
11171119multilineTableHeader :: Bool -- ^ Headerless table
11181120 -> MarkdownParser (F [Blocks], [Alignment], [Int])
11191121multilineTableHeader headless = try $ do
1120− if headless
1121− then return '\n'
1122− else tableSep >>~ notFollowedBy blankline
1122+ unless headless $
1123+ tableSep >> notFollowedBy blankline
11231124 rawContent <- if headless
11241125 then return $ repeat ""
1125− else many1
1126− (notFollowedBy tableSep >> many1Till anyChar newline)
1126+ else many1 $ notFollowedBy tableSep >> anyLine
11271127 initSp <- nonindentSpaces
11281128 dashes <- many1 (dashedLine '-')
11291129 newline
@@ -1133,12 +1133,12 @@ multilineTableHeader headless = try $ do
11331133 then liftM (map (:[]) . tail .
11341134 splitStringByIndices (init indices)) $ lookAhead anyLine
11351135 else return $ transpose $ map
1136− (\ln -> tail $ splitStringByIndices (init indices) ln)
1136+ (tail . splitStringByIndices (init indices))
11371137 rawContent
11381138 let aligns = zipWith alignType rawHeadsList lengths
11391139 let rawHeads = if headless
11401140 then replicate (length dashes) ""
1141− else map unwords rawHeadsList
1141+ else map (unlines . map trim) rawHeadsList
11421142 heads <- fmap sequence $
11431143 mapM (parseFromString (mconcat <$> many plain)) $
11441144 map trim rawHeads
@@ -1195,7 +1195,7 @@ gridTableHeader headless = try $ do
11951195 -- RST does not have a notion of alignments
11961196 let rawHeads = if headless
11971197 then replicate (length dashes) ""
1198− else map unwords $ transpose
1198+ else map (unlines . map trim) $ transpose
11991199 $ map (gridTableSplitLine indices) rawContent
12001200 heads <- fmap sequence $ mapM (parseFromString parseBlocks . trim) rawHeads
12011201 return (heads, aligns, indices)
@@ -1227,11 +1227,20 @@ removeOneLeadingSpace xs =
12271227gridTableFooter :: MarkdownParser [Char]
12281228gridTableFooter = blanklines
12291229
1230+pipeBreak :: MarkdownParser [Alignment]
1231+pipeBreak = try $ do
1232+ nonindentSpaces
1233+ openPipe <- (True <$ char '|') <|> return False
1234+ first <- pipeTableHeaderPart
1235+ rest <- many $ sepPipe *> pipeTableHeaderPart
1236+ -- surrounding pipes needed for a one-column table:
1237+ guard $ not (null rest && not openPipe)
1238+ optional (char '|')
1239+ blankline
1240+ return (first:rest)
1241+
12301242pipeTable :: MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
12311243pipeTable = try $ do
1232− let pipeBreak = nonindentSpaces *> optional (char '|') *>
1233− pipeTableHeaderPart `sepBy1` sepPipe <*
1234− optional (char '|') <* blankline
12351244 (heads,aligns) <- try ( pipeBreak >>= \als ->
12361245 return (return $ replicate (length als) mempty, als))
12371246 <|> ( pipeTableRow >>= \row -> pipeBreak >>= \als ->
@@ -1250,12 +1259,13 @@ sepPipe = try $ do
12501259pipeTableRow :: MarkdownParser (F [Blocks])
12511260pipeTableRow = do
12521261 nonindentSpaces
1253− optional (char '|')
1262+ openPipe <- (True <$ char '|') <|> return False
12541263 let cell = mconcat <$>
12551264 many (notFollowedBy (blankline <|> char '|') >> inline)
12561265 first <- cell
1257− sepPipe
1258− rest <- cell `sepBy1` sepPipe
1266+ rest <- many $ sepPipe *> cell
1267+ -- surrounding pipes needed for a one-column table:
1268+ guard $ not (null rest && not openPipe)
12591269 optional (char '|')
12601270 blankline
12611271 let cells = sequence (first:rest)
@@ -1340,19 +1350,18 @@ inline = choice [ whitespace
13401350 , str
13411351 , endline
13421352 , code
1343− , fours
1344− , strong
1345− , emph
1353+ , strongOrEmph
13461354 , note
13471355 , cite
13481356 , link
13491357 , image
13501358 , math
13511359 , strikeout
1352− , superscript
13531360 , subscript
1361+ , superscript
13541362 , inlineNote -- after superscript because of ^[link](/foo)^
13551363 , autoLink
1364+ , spanHtml
13561365 , rawHtmlInline
13571366 , escapedChar
13581367 , rawLaTeXInline'
@@ -1382,7 +1391,7 @@ ltSign :: MarkdownParser (F Inlines)
13821391ltSign = do
13831392 guardDisabled Ext_raw_html
13841393 <|> guardDisabled Ext_markdown_in_html_blocks
1385− <|> (notFollowedBy' rawHtmlBlocks >> return ())
1394+ <|> (notFollowedBy' (htmlTag isBlockTag) >> return ())
13861395 char '<'
13871396 return $ return $ B.str "<"
13881397
@@ -1422,47 +1431,57 @@ math :: MarkdownParser (F Inlines)
14221431math = (return . B.displayMath <$> (mathDisplay >>= applyMacros'))
14231432 <|> (return . B.math <$> (mathInline >>= applyMacros'))
14241433
1425−mathDisplay :: MarkdownParser String
1426−mathDisplay =
1427− (guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
1428− <|> (guardEnabled Ext_tex_math_single_backslash >>
1429− mathDisplayWith "\\[" "\\]")
1430− <|> (guardEnabled Ext_tex_math_double_backslash >>
1431− mathDisplayWith "\\\\[" "\\\\]")
1432−
1433−mathDisplayWith :: String -> String -> MarkdownParser String
1434−mathDisplayWith op cl = try $ do
1435− string op
1436− many1Till (noneOf "\n" <|> (newline >>~ notFollowedBy' blankline)) (try $ string cl)
1437−
1438−mathInline :: MarkdownParser String
1439−mathInline =
1440− (guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
1441− <|> (guardEnabled Ext_tex_math_single_backslash >>
1442− mathInlineWith "\\(" "\\)")
1443− <|> (guardEnabled Ext_tex_math_double_backslash >>
1444− mathInlineWith "\\\\(" "\\\\)")
1445−
1446−mathInlineWith :: String -> String -> MarkdownParser String
1447−mathInlineWith op cl = try $ do
1448− string op
1449− notFollowedBy space
1450− words' <- many1Till (count 1 (noneOf "\n\\")
1451− <|> (char '\\' >> anyChar >>= \c -> return ['\\',c])
1452− <|> count 1 newline <* notFollowedBy' blankline
1453− *> return " ")
1454− (try $ string cl)
1455− notFollowedBy digit -- to prevent capture of $5
1456− return $ concat words'
1457−
1458−-- to avoid performance problems, treat 4 or more _ or * or ~ or ^ in a row
1459−-- as a literal rather than attempting to parse for emph/strong/strikeout/super/sub
1460−fours :: Parser [Char] st (F Inlines)
1461−fours = try $ do
1462− x <- char '*' <|> char '_' <|> char '~' <|> char '^'
1463− count 2 $ satisfy (==x)
1464− rest <- many1 (satisfy (==x))
1465− return $ return $ B.str (x:x:x:rest)
1434+-- Parses material enclosed in *s, **s, _s, or __s.
1435+-- Designed to avoid backtracking.
1436+enclosure :: Char
1437+ -> MarkdownParser (F Inlines)
1438+enclosure c = do
1439+ cs <- many1 (char c)
1440+ (return (B.str cs) <>) <$> whitespace
1441+ <|> case length cs of
1442+ 3 -> three c
1443+ 2 -> two c mempty
1444+ 1 -> one c mempty
1445+ _ -> return (return $ B.str cs)
1446+
1447+-- Parse inlines til you hit one c or a sequence of two cs.
1448+-- If one c, emit emph and then parse two.
1449+-- If two cs, emit strong and then parse one.
1450+-- Otherwise, emit ccc then the results.
1451+three :: Char -> MarkdownParser (F Inlines)
1452+three c = do
1453+ contents <- mconcat <$> many (notFollowedBy (char c) >> inline)
1454+ (try (string [c,c,c]) >> return ((B.strong . B.emph) <$> contents))
1455+ <|> (try (string [c,c]) >> one c (B.strong <$> contents))
1456+ <|> (char c >> two c (B.emph <$> contents))
1457+ <|> return (return (B.str [c,c,c]) <> contents)
1458+
1459+-- Parse inlines til you hit two c's, and emit strong.
1460+-- If you never do hit two cs, emit ** plus inlines parsed.
1461+two :: Char -> F Inlines -> MarkdownParser (F Inlines)
1462+two c prefix' = do
1463+ let ender = try $ string [c,c]
1464+ contents <- mconcat <$> many (try $ notFollowedBy ender >> inline)
1465+ (ender >> return (B.strong <$> (prefix' <> contents)))
1466+ <|> return (return (B.str [c,c]) <> (prefix' <> contents))
1467+
1468+-- Parse inlines til you hit a c, and emit emph.
1469+-- If you never hit a c, emit * plus inlines parsed.
1470+one :: Char -> F Inlines -> MarkdownParser (F Inlines)
1471+one c prefix' = do
1472+ contents <- mconcat <$> many ( (notFollowedBy (char c) >> inline)
1473+ <|> try (string [c,c] >>
1474+ notFollowedBy (char c) >>
1475+ two c mempty) )
1476+ (char c >> return (B.emph <$> (prefix' <> contents)))
1477+ <|> return (return (B.str [c]) <> (prefix' <> contents))
1478+
1479+strongOrEmph :: MarkdownParser (F Inlines)
1480+strongOrEmph = enclosure '*' <|> (checkIntraword >> enclosure '_')
1481+ where checkIntraword = do
1482+ exts <- getOption readerExtensions
1483+ when (Ext_intraword_underscores `Set.member` exts) $ do
1484+ guard =<< notAfterString
14661485
14671486-- | Parses a list of inlines between start and end delimiters.
14681487inlinesBetween :: (Show b)
@@ -1474,28 +1493,6 @@ inlinesBetween start end =
14741493 where inner = innerSpace <|> (notFollowedBy' (() <$ whitespace) >> inline)
14751494 innerSpace = try $ whitespace >>~ notFollowedBy' end
14761495
1477−emph :: MarkdownParser (F Inlines)
1478−emph = fmap B.emph <$> nested
1479− (inlinesBetween starStart starEnd <|> inlinesBetween ulStart ulEnd)
1480− where starStart = char '*' >> lookAhead nonspaceChar
1481− starEnd = notFollowedBy' (() <$ strong) >> char '*'
1482− ulStart = checkIntraword >> char '_' >> lookAhead nonspaceChar
1483− ulEnd = notFollowedBy' (() <$ strong) >> char '_'
1484− checkIntraword = do
1485− exts <- getOption readerExtensions
1486− when (Ext_intraword_underscores `Set.member` exts) $ do
1487− pos <- getPosition
1488− lastStrPos <- stateLastStrPos <$> getState
1489− guard $ lastStrPos /= Just pos
1490−
1491−strong :: MarkdownParser (F Inlines)
1492−strong = fmap B.strong <$> nested
1493− (inlinesBetween starStart starEnd <|> inlinesBetween ulStart ulEnd)
1494− where starStart = string "**" >> lookAhead nonspaceChar
1495− starEnd = try $ string "**"
1496− ulStart = string "__" >> lookAhead nonspaceChar
1497− ulEnd = try $ string "__"
1498−
14991496strikeout :: MarkdownParser (F Inlines)
15001497strikeout = fmap B.strikeout <$>
15011498 (guardEnabled Ext_strikeout >> inlinesBetween strikeStart strikeEnd)
@@ -1526,8 +1523,7 @@ nonEndline = satisfy (/='\n')
15261523str :: MarkdownParser (F Inlines)
15271524str = do
15281525 result <- many1 alphaNum
1529− pos <- getPosition
1530− updateState $ \s -> s{ stateLastStrPos = Just pos }
1526+ updateLastStrPos
15311527 let spacesToNbr = map (\c -> if c == ' ' then '\160' else c)
15321528 isSmart <- getOption readerSmart
15331529 if isSmart
@@ -1558,14 +1554,17 @@ endline :: MarkdownParser (F Inlines)
15581554endline = try $ do
15591555 newline
15601556 notFollowedBy blankline
1561− guardEnabled Ext_blank_before_blockquote <|> notFollowedBy emailBlockQuoteStart
1562− guardEnabled Ext_blank_before_header <|> notFollowedBy (char '#') -- atx header
15631557 -- parse potential list-starts differently if in a list:
15641558 st <- getState
1565− when (stateParserContext st == ListItemState) $ do
1566− notFollowedBy' bulletListStart
1567− notFollowedBy' anyOrderedListStart
1568− (guardEnabled Ext_hard_line_breaks >> return (return B.linebreak))
1559+ when (stateParserContext st == ListItemState) $ notFollowedBy listStart
1560+ guardDisabled Ext_lists_without_preceding_blankline <|> notFollowedBy listStart
1561+ guardEnabled Ext_blank_before_blockquote <|> notFollowedBy emailBlockQuoteStart
1562+ guardEnabled Ext_blank_before_header <|> notFollowedBy (char '#') -- atx header
1563+ guardDisabled Ext_backtick_code_blocks <|>
1564+ notFollowedBy (() <$ (lookAhead (char '`') >> codeBlockFenced))
1565+ (eof >> return mempty)
1566+ <|> (guardEnabled Ext_hard_line_breaks >> return (return B.linebreak))
1567+ <|> (guardEnabled Ext_ignore_line_breaks >> return mempty)
15691568 <|> (return $ return B.space)
15701569
15711570--
@@ -1660,6 +1659,7 @@ bareURL :: MarkdownParser (F Inlines)
16601659bareURL = try $ do
16611660 guardEnabled Ext_autolink_bare_uris
16621661 (orig, src) <- uri <|> emailAddress
1662+ notFollowedBy $ try $ spaces >> htmlTag (~== TagClose "a")
16631663 return $ return $ B.link src "" (B.str orig)
16641664
16651665autoLink :: MarkdownParser (F Inlines)
@@ -1730,6 +1730,38 @@ inBrackets parser = do
17301730 char ']'
17311731 return $ "[" ++ contents ++ "]"
17321732
1733+spanHtml :: MarkdownParser (F Inlines)
1734+spanHtml = try $ do
1735+ guardEnabled Ext_markdown_in_html_blocks
1736+ (TagOpen _ attrs, _) <- htmlTag (~== TagOpen "span" [])
1737+ contents <- mconcat <$> manyTill inline (htmlTag (~== TagClose "span"))
1738+ let ident = fromMaybe "" $ lookup "id" attrs
1739+ let classes = maybe [] words $ lookup "class" attrs
1740+ let keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
1741+ case lookup "style" keyvals of
1742+ Just s | null ident && null classes &&
1743+ map toLower (filter (`notElem` " \t;") s) ==
1744+ "font-variant:small-caps"
1745+ -> return $ B.smallcaps <$> contents
1746+ _ -> return $ B.spanWith (ident, classes, keyvals) <$> contents
1747+
1748+divHtml :: MarkdownParser (F Blocks)
1749+divHtml = try $ do
1750+ guardEnabled Ext_markdown_in_html_blocks
1751+ (TagOpen _ attrs, rawtag) <- htmlTag (~== TagOpen "div" [])
1752+ bls <- option "" (blankline >> option "" blanklines)
1753+ contents <- mconcat <$>
1754+ many (notFollowedBy' (htmlTag (~== TagClose "div")) >> block)
1755+ closed <- option False (True <$ htmlTag (~== TagClose "div"))
1756+ if closed
1757+ then do
1758+ let ident = fromMaybe "" $ lookup "id" attrs
1759+ let classes = maybe [] words $ lookup "class" attrs
1760+ let keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
1761+ return $ B.divWith (ident, classes, keyvals) <$> contents
1762+ else -- avoid backtracing
1763+ return $ return (B.rawBlock "html" (rawtag <> bls)) <> contents
1764+
17331765rawHtmlInline :: MarkdownParser (F Inlines)
17341766rawHtmlInline = do
17351767 guardEnabled Ext_raw_html
@@ -1745,11 +1777,12 @@ rawHtmlInline = do
17451777cite :: MarkdownParser (F Inlines)
17461778cite = do
17471779 guardEnabled Ext_citations
1748− getOption readerReferences >>= guard . not . null
1749− citations <- textualCite <|> normalCite
1750− return $ flip B.cite mempty <$> citations
1780+ citations <- textualCite
1781+ <|> do (cs, raw) <- withRaw normalCite
1782+ return $ (flip B.cite (B.text raw)) <$> cs
1783+ return citations
17511784
1752−textualCite :: MarkdownParser (F [Citation])
1785+textualCite :: MarkdownParser (F Inlines)
17531786textualCite = try $ do
17541787 (_, key) <- citeKey
17551788 let first = Citation{ citationId = key
@@ -1759,10 +1792,18 @@ textualCite = try $ do
17591792 , citationNoteNum = 0
17601793 , citationHash = 0
17611794 }
1762− mbrest <- option Nothing $ try $ spnl >> Just <$> normalCite
1795+ mbrest <- option Nothing $ try $ spnl >> Just <$> withRaw normalCite
17631796 case mbrest of
1764− Just rest -> return $ (first:) <$> rest
1765− Nothing -> option (return [first]) $ bareloc first
1797+ Just (rest, raw) ->
1798+ return $ (flip B.cite (B.text $ '@':key ++ " " ++ raw) . (first:))
1799+ <$> rest
1800+ Nothing ->
1801+ (do (cs, raw) <- withRaw $ bareloc first
1802+ return $ (flip B.cite (B.text $ '@':key ++ " " ++ raw)) <$> cs)
1803+ <|> return (do st <- askF
1804+ return $ case M.lookup key (stateExamples st) of
1805+ Just n -> B.str (show n)
1806+ _ -> B.cite [first] $ B.str $ '@':key)
17661807
17671808bareloc :: Citation -> MarkdownParser (F [Citation])
17681809bareloc c = try $ do
@@ -1786,18 +1827,6 @@ normalCite = try $ do
17861827 char ']'
17871828 return citations
17881829
1789−citeKey :: MarkdownParser (Bool, String)
1790−citeKey = try $ do
1791− suppress_author <- option False (char '-' >> return True)
1792− char '@'
1793− first <- letter
1794− let internal p = try $ p >>~ lookAhead (letter <|> digit)
1795− rest <- many $ letter <|> digit <|> internal (oneOf ":.#$%&-_+?<>~/")
1796− let key = first:rest
1797− citations' <- map CSL.refId <$> getOption readerReferences
1798− guard $ key `elem` citations'
1799− return (suppress_author, key)
1800−
18011830suffix :: MarkdownParser (F Inlines)
18021831suffix = try $ do
18031832 hasSpace <- option False (notFollowedBy nonspaceChar >> return True)
@@ -1836,7 +1865,7 @@ smart :: MarkdownParser (F Inlines)
18361865smart = do
18371866 getOption readerSmart >>= guard
18381867 doubleQuoted <|> singleQuoted <|>
1839− choice (map (return . B.singleton <$>) [apostrophe, dash, ellipses])
1868+ choice (map (return <$>) [apostrophe, dash, ellipses])
18401869
18411870singleQuoted :: MarkdownParser (F Inlines)
18421871singleQuoted = try $ do
@@ -1855,4 +1884,3 @@ doubleQuoted = try $ do
18551884 (withQuoteContext InDoubleQuote $ doubleQuoteEnd >> return
18561885 (fmap B.doubleQuoted . trimInlinesF $ contents))
18571886 <|> (return $ return (B.str "\8220") <> contents)
1858−
src/Text/Pandoc/Readers/MediaWiki.hs+79−28
@@ -1,6 +1,7 @@
1−{-# LANGUAGE RelaxedPolyRec #-} -- needed for inlinesBetween on GHC < 7
1+{-# LANGUAGE RelaxedPolyRec, FlexibleInstances, TypeSynonymInstances #-}
2+-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
23{-
3− Copyright (C) 2012 John MacFarlane <jgm@berkeley.edu>
4+ Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
45
56This program is free software; you can redistribute it and/or modify
67it 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
1920
2021{- |
2122 Module : Text.Pandoc.Readers.MediaWiki
22− Copyright : Copyright (C) 2012 John MacFarlane
23+ Copyright : Copyright (C) 2012-2014 John MacFarlane
2324 License : GNU GPL, version 2 or above
2425
2526 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -42,8 +43,8 @@ import Text.Pandoc.Options
4243import Text.Pandoc.Readers.HTML ( htmlTag, isBlockTag, isCommentTag )
4344import Text.Pandoc.XML ( fromEntities )
4445import Text.Pandoc.Parsing hiding ( nested )
45−import Text.Pandoc.Generic ( bottomUp )
46−import Text.Pandoc.Shared ( stripTrailingNewlines, safeRead )
46+import Text.Pandoc.Walk ( walk )
47+import Text.Pandoc.Shared ( stripTrailingNewlines, safeRead, stringify, trim )
4748import Data.Monoid (mconcat, mempty)
4849import Control.Applicative ((<$>), (<*), (*>), (<$))
4950import Control.Monad
@@ -51,7 +52,11 @@ import Data.List (intersperse, intercalate, isPrefixOf )
5152import Text.HTML.TagSoup
5253import Data.Sequence (viewl, ViewL(..), (<|))
5354import qualified Data.Foldable as F
55+import qualified Data.Map as M
5456import Data.Char (isDigit, isSpace)
57+import Data.Maybe (fromMaybe)
58+import Text.Printf (printf)
59+import Debug.Trace (trace)
5560
5661-- | Read mediawiki from an input string and return a Pandoc document.
5762readMediaWiki :: ReaderOptions -- ^ Reader options
@@ -62,6 +67,8 @@ readMediaWiki opts s =
6267 , mwMaxNestingLevel = 4
6368 , mwNextLinkNumber = 1
6469 , mwCategoryLinks = []
70+ , mwHeaderMap = M.empty
71+ , mwIdentifierList = []
6572 }
6673 "source" (s ++ "\n") of
6774 Left err' -> error $ "\nError:\n" ++ show err'
@@ -71,10 +78,23 @@ data MWState = MWState { mwOptions :: ReaderOptions
7178 , mwMaxNestingLevel :: Int
7279 , mwNextLinkNumber :: Int
7380 , mwCategoryLinks :: [Inlines]
81+ , mwHeaderMap :: M.Map Inlines String
82+ , mwIdentifierList :: [String]
7483 }
7584
7685type MWParser = Parser [Char] MWState
7786
87+instance HasReaderOptions MWState where
88+ extractReaderOptions = mwOptions
89+
90+instance HasHeaderMap MWState where
91+ extractHeaderMap = mwHeaderMap
92+ updateHeaderMap f st = st{ mwHeaderMap = f $ mwHeaderMap st }
93+
94+instance HasIdentifierList MWState where
95+ extractIdentifierList = mwIdentifierList
96+ updateIdentifierList f st = st{ mwIdentifierList = f $ mwIdentifierList st }
97+
7898--
7999-- auxiliary functions
80100--
@@ -91,7 +111,7 @@ nested p = do
91111 return res
92112
93113specialChars :: [Char]
94−specialChars = "'[]<=&*{}|\""
114+specialChars = "'[]<=&*{}|\":\\"
95115
96116spaceChars :: [Char]
97117spaceChars = " \n\t"
@@ -131,9 +151,16 @@ inlinesInTags tag = try $ do
131151blocksInTags :: String -> MWParser Blocks
132152blocksInTags tag = try $ do
133153 (_,raw) <- htmlTag (~== TagOpen tag [])
154+ let closer = if tag == "li"
155+ then htmlTag (~== TagClose "li")
156+ <|> lookAhead (
157+ htmlTag (~== TagOpen "li" [])
158+ <|> htmlTag (~== TagClose "ol")
159+ <|> htmlTag (~== TagClose "ul"))
160+ else htmlTag (~== TagClose tag)
134161 if '/' `elem` raw -- self-closing tag
135162 then return mempty
136− else mconcat <$> manyTill block (htmlTag (~== TagClose tag))
163+ else mconcat <$> manyTill block closer
137164
138165charsInTags :: String -> MWParser [Char]
139166charsInTags tag = try $ do
@@ -162,7 +189,10 @@ parseMediaWiki = do
162189--
163190
164191block :: MWParser Blocks
165−block = mempty <$ skipMany1 blankline
192+block = do
193+ tr <- getOption readerTrace
194+ pos <- getPosition
195+ res <- mempty <$ skipMany1 blankline
166196 <|> table
167197 <|> header
168198 <|> hrule
@@ -174,6 +204,10 @@ block = mempty <$ skipMany1 blankline
174204 <|> blockTag
175205 <|> (B.rawBlock "mediawiki" <$> template)
176206 <|> para
207+ when tr $
208+ trace (printf "line %d: %s" (sourceLine pos)
209+ (take 60 $ show $ B.toList res)) (return ())
210+ return res
177211
178212para :: MWParser Blocks
179213para = do
@@ -187,7 +221,7 @@ table = do
187221 tableStart
188222 styles <- option [] parseAttrs <* blankline
189223 let tableWidth = case lookup "width" styles of
190− Just w -> maybe 1.0 id $ parseWidth w
224+ Just w -> fromMaybe 1.0 $ parseWidth w
191225 Nothing -> 1.0
192226 caption <- option mempty tableCaption
193227 optional rowsep
@@ -202,6 +236,7 @@ table = do
202236 let widths' = map (\w -> if w == 0 then defaultwidth else w) widths
203237 let cellspecs = zip (map fst cellspecs') widths'
204238 rows' <- many $ try $ rowsep *> (map snd <$> tableRow)
239+ optional blanklines
205240 tableEnd
206241 let cols = length hdr
207242 let (headers,rows) = if hasheader
@@ -250,7 +285,7 @@ tableCaption = try $ do
250285 (trimInlines . mconcat) <$> many (notFollowedBy (cellsep <|> rowsep) *> inline)
251286
252287tableRow :: MWParser [((Alignment, Double), Blocks)]
253−tableRow = try $ many tableCell
288+tableRow = try $ skipMany htmlComment *> many tableCell
254289
255290tableCell :: MWParser ((Alignment, Double), Blocks)
256291tableCell = try $ do
@@ -268,7 +303,7 @@ tableCell = try $ do
268303 Just "center" -> AlignCenter
269304 _ -> AlignDefault
270305 let width = case lookup "width" attrs of
271− Just xs -> maybe 0.0 id $ parseWidth xs
306+ Just xs -> fromMaybe 0.0 $ parseWidth xs
272307 Nothing -> 0.0
273308 return ((align, width), bs)
274309
@@ -282,6 +317,7 @@ template :: MWParser String
282317template = try $ do
283318 string "{{"
284319 notFollowedBy (char '{')
320+ lookAhead $ letter <|> digit <|> char ':'
285321 let chunk = template <|> variable <|> many1 (noneOf "{}") <|> count 1 anyChar
286322 contents <- manyTill chunk (try $ string "}}")
287323 return $ "{{" ++ concat contents ++ "}}"
@@ -342,7 +378,7 @@ preformatted = try $ do
342378 spacesStr _ = False
343379 if F.all spacesStr contents
344380 then return mempty
345− else return $ B.para $ bottomUp strToCode contents
381+ else return $ B.para $ walk strToCode contents
346382
347383header :: MWParser Blocks
348384header = try $ do
@@ -351,7 +387,8 @@ header = try $ do
351387 let lev = length eqs
352388 guard $ lev <= 6
353389 contents <- trimInlines . mconcat <$> manyTill inline (count lev $ char '=')
354− return $ B.header lev contents
390+ attr <- registerHeader nullAttr contents
391+ return $ B.headerWith attr lev contents
355392
356393bulletList :: MWParser Blocks
357394bulletList = B.bulletList <$>
@@ -362,15 +399,13 @@ bulletList = B.bulletList <$>
362399orderedList :: MWParser Blocks
363400orderedList =
364401 (B.orderedList <$> many1 (listItem '#'))
365− <|> (B.orderedList <$> (htmlTag (~== TagOpen "ul" []) *> spaces *>
366− many (listItem '#' <|> li) <*
367− optional (htmlTag (~== TagClose "ul"))))
368− <|> do (tag,_) <- htmlTag (~== TagOpen "ol" [])
369− spaces
370− items <- many (listItem '#' <|> li)
371− optional (htmlTag (~== TagClose "ol"))
372− let start = maybe 1 id $ safeRead $ fromAttrib "start" tag
373− return $ B.orderedListWith (start, DefaultStyle, DefaultDelim) items
402+ <|> try
403+ (do (tag,_) <- htmlTag (~== TagOpen "ol" [])
404+ spaces
405+ items <- many (listItem '#' <|> li)
406+ optional (htmlTag (~== TagClose "ol"))
407+ let start = fromMaybe 1 $ safeRead $ fromAttrib "start" tag
408+ return $ B.orderedListWith (start, DefaultStyle, DefaultDelim) items)
374409
375410definitionList :: MWParser Blocks
376411definitionList = B.definitionList <$> many1 defListItem
@@ -380,8 +415,9 @@ defListItem = try $ do
380415 terms <- mconcat . intersperse B.linebreak <$> many defListTerm
381416 -- we allow dd with no dt, or dt with no dd
382417 defs <- if B.isNull terms
383− then many1 $ listItem ':'
384− else many $ listItem ':'
418+ then notFollowedBy (try $ string ":<math>") *>
419+ many1 (listItem ':')
420+ else many (listItem ':')
385421 return (terms, defs)
386422
387423defListTerm :: MWParser Inlines
@@ -413,7 +449,8 @@ listItem c = try $ do
413449 skipMany spaceChar
414450 first <- concat <$> manyTill listChunk newline
415451 rest <- many
416− (try $ string extras *> (concat <$> manyTill listChunk newline))
452+ (try $ string extras *> lookAhead listStartChar *>
453+ (concat <$> manyTill listChunk newline))
417454 contents <- parseFromString (many1 $ listItem' c)
418455 (unlines (first : rest))
419456 case c of
@@ -462,6 +499,7 @@ inline = whitespace
462499 <|> image
463500 <|> internalLink
464501 <|> externalLink
502+ <|> math
465503 <|> inlineTag
466504 <|> B.singleton <$> charRef
467505 <|> inlineHtml
@@ -472,6 +510,16 @@ inline = whitespace
472510str :: MWParser Inlines
473511str = B.str <$> many1 (noneOf $ specialChars ++ spaceChars)
474512
513+math :: MWParser Inlines
514+math = (B.displayMath . trim <$> try (char ':' >> charsInTags "math"))
515+ <|> (B.math . trim <$> charsInTags "math")
516+ <|> (B.displayMath . trim <$> try (dmStart *> manyTill anyChar dmEnd))
517+ <|> (B.math . trim <$> try (mStart *> manyTill (satisfy (/='\n')) mEnd))
518+ where dmStart = string "\\["
519+ dmEnd = try (string "\\]")
520+ mStart = string "\\("
521+ mEnd = try (string "\\)")
522+
475523variable :: MWParser String
476524variable = try $ do
477525 string "{{{"
@@ -495,7 +543,6 @@ inlineTag = do
495543 TagOpen "del" _ -> B.strikeout <$> inlinesInTags "del"
496544 TagOpen "sub" _ -> B.subscript <$> inlinesInTags "sub"
497545 TagOpen "sup" _ -> B.superscript <$> inlinesInTags "sup"
498− TagOpen "math" _ -> B.math <$> charsInTags "math"
499546 TagOpen "code" _ -> B.code <$> charsInTags "code"
500547 TagOpen "tt" _ -> B.code <$> charsInTags "tt"
501548 TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> charsInTags "hask"
@@ -520,15 +567,19 @@ endline = () <$ try (newline <*
520567 notFollowedBy' header <*
521568 notFollowedBy anyListStart)
522569
570+imageIdentifiers :: [MWParser ()]
571+imageIdentifiers = [sym (identifier ++ ":") | identifier <- identifiers]
572+ where identifiers = ["File", "Image", "Archivo", "Datei", "Fichier"]
573+
523574image :: MWParser Inlines
524575image = try $ do
525576 sym "[["
526− sym "File:"
577+ choice imageIdentifiers
527578 fname <- many1 (noneOf "|]")
528579 _ <- many (try $ char '|' *> imageOption)
529580 caption <- (B.str fname <$ sym "]]")
530581 <|> try (char '|' *> (mconcat <$> manyTill inline (sym "]]")))
531− return $ B.image fname "image" caption
582+ return $ B.image fname ("fig:" ++ stringify caption) caption
532583
533584imageOption :: MWParser String
534585imageOption =
src/Text/Pandoc/Readers/Native.hs+2−2
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2011 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2011-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.Readers.Native
21− Copyright : Copyright (C) 2011 John MacFarlane
21+ Copyright : Copyright (C) 2011-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
src/Text/Pandoc/Readers/OPML.hs+1−1
@@ -6,7 +6,7 @@ import Text.Pandoc.Builder
66import Text.Pandoc.Readers.HTML (readHtml)
77import Text.Pandoc.Readers.Markdown (readMarkdown)
88import Text.XML.Light
9−import Text.HTML.TagSoup.Entity (lookupEntity)
9+import Text.Pandoc.Compat.TagSoupEntity (lookupEntity)
1010import Data.Generics
1111import Data.Monoid
1212import Control.Monad.State
src/Text/Pandoc/Readers/Org.hsnew file+1379
@@ -0,0 +1,1379 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-
4+Copyright (C) 2014 Albert Krewinkel <tarleb@moltkeplatz.de>
5+
6+This program is free software; you can redistribute it and/or modify
7+it under the terms of the GNU General Public License as published by
8+the Free Software Foundation; either version 2 of the License, or
9+(at your option) any later version.
10+
11+This program is distributed in the hope that it will be useful,
12+but WITHOUT ANY WARRANTY; without even the implied warranty of
13+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+GNU General Public License for more details.
15+
16+You should have received a copy of the GNU General Public License
17+along with this program; if not, write to the Free Software
18+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19+-}
20+
21+{- |
22+ Module : Text.Pandoc.Readers.Org
23+ Copyright : Copyright (C) 2014 Albert Krewinkel
24+ License : GNU GPL, version 2 or above
25+
26+ Maintainer : Albert Krewinkel <tarleb@moltkeplatz.de>
27+
28+Conversion of org-mode formatted plain text to 'Pandoc' document.
29+-}
30+module Text.Pandoc.Readers.Org ( readOrg ) where
31+
32+import qualified Text.Pandoc.Builder as B
33+import Text.Pandoc.Builder ( Inlines, Blocks, HasMeta(..), (<>)
34+ , trimInlines )
35+import Text.Pandoc.Definition
36+import Text.Pandoc.Options
37+import qualified Text.Pandoc.Parsing as P
38+import Text.Pandoc.Parsing hiding ( F, unF, askF, asksF, runF
39+ , newline, orderedListMarker
40+ , parseFromString
41+ )
42+import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
43+import Text.Pandoc.Shared (compactify', compactify'DL)
44+import Text.TeXMath (texMathToPandoc, DisplayType(..))
45+
46+import Control.Applicative ( Applicative, pure
47+ , (<$>), (<$), (<*>), (<*), (*>), (<**>) )
48+import Control.Arrow (first)
49+import Control.Monad (foldM, guard, liftM, liftM2, mplus, mzero, when)
50+import Control.Monad.Reader (Reader, runReader, ask, asks)
51+import Data.Char (isAlphaNum, toLower)
52+import Data.Default
53+import Data.List (intersperse, isPrefixOf, isSuffixOf)
54+import qualified Data.Map as M
55+import Data.Maybe (fromMaybe, isJust)
56+import Data.Monoid (Monoid, mconcat, mempty, mappend)
57+import Network.HTTP (urlEncode)
58+
59+-- | Parse org-mode string and return a Pandoc document.
60+readOrg :: ReaderOptions -- ^ Reader options
61+ -> String -- ^ String to parse (assuming @'\n'@ line endings)
62+ -> Pandoc
63+readOrg opts s = readWith parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
64+
65+type OrgParser = Parser [Char] OrgParserState
66+
67+parseOrg :: OrgParser Pandoc
68+parseOrg = do
69+ blocks' <- parseBlocks
70+ st <- getState
71+ let meta = runF (orgStateMeta' st) st
72+ return $ Pandoc meta $ filter (/= Null) (B.toList $ runF blocks' st)
73+
74+--
75+-- Parser State for Org
76+--
77+
78+type OrgNoteRecord = (String, F Blocks)
79+type OrgNoteTable = [OrgNoteRecord]
80+
81+type OrgBlockAttributes = M.Map String String
82+
83+type OrgLinkFormatters = M.Map String (String -> String)
84+
85+-- | Org-mode parser state
86+data OrgParserState = OrgParserState
87+ { orgStateOptions :: ReaderOptions
88+ , orgStateAnchorIds :: [String]
89+ , orgStateBlockAttributes :: OrgBlockAttributes
90+ , orgStateEmphasisCharStack :: [Char]
91+ , orgStateEmphasisNewlines :: Maybe Int
92+ , orgStateLastForbiddenCharPos :: Maybe SourcePos
93+ , orgStateLastPreCharPos :: Maybe SourcePos
94+ , orgStateLastStrPos :: Maybe SourcePos
95+ , orgStateLinkFormatters :: OrgLinkFormatters
96+ , orgStateMeta :: Meta
97+ , orgStateMeta' :: F Meta
98+ , orgStateNotes' :: OrgNoteTable
99+ }
100+
101+instance HasReaderOptions OrgParserState where
102+ extractReaderOptions = orgStateOptions
103+
104+instance HasMeta OrgParserState where
105+ setMeta field val st =
106+ st{ orgStateMeta = setMeta field val $ orgStateMeta st }
107+ deleteMeta field st =
108+ st{ orgStateMeta = deleteMeta field $ orgStateMeta st }
109+
110+instance HasLastStrPosition OrgParserState where
111+ getLastStrPos = orgStateLastStrPos
112+ setLastStrPos pos st = st{ orgStateLastStrPos = Just pos }
113+
114+instance Default OrgParserState where
115+ def = defaultOrgParserState
116+
117+defaultOrgParserState :: OrgParserState
118+defaultOrgParserState = OrgParserState
119+ { orgStateOptions = def
120+ , orgStateAnchorIds = []
121+ , orgStateBlockAttributes = M.empty
122+ , orgStateEmphasisCharStack = []
123+ , orgStateEmphasisNewlines = Nothing
124+ , orgStateLastForbiddenCharPos = Nothing
125+ , orgStateLastPreCharPos = Nothing
126+ , orgStateLastStrPos = Nothing
127+ , orgStateLinkFormatters = M.empty
128+ , orgStateMeta = nullMeta
129+ , orgStateMeta' = return nullMeta
130+ , orgStateNotes' = []
131+ }
132+
133+recordAnchorId :: String -> OrgParser ()
134+recordAnchorId i = updateState $ \s ->
135+ s{ orgStateAnchorIds = i : (orgStateAnchorIds s) }
136+
137+addBlockAttribute :: String -> String -> OrgParser ()
138+addBlockAttribute key val = updateState $ \s ->
139+ let attrs = orgStateBlockAttributes s
140+ in s{ orgStateBlockAttributes = M.insert key val attrs }
141+
142+lookupBlockAttribute :: String -> OrgParser (Maybe String)
143+lookupBlockAttribute key =
144+ M.lookup key . orgStateBlockAttributes <$> getState
145+
146+resetBlockAttributes :: OrgParser ()
147+resetBlockAttributes = updateState $ \s ->
148+ s{ orgStateBlockAttributes = orgStateBlockAttributes def }
149+
150+updateLastForbiddenCharPos :: OrgParser ()
151+updateLastForbiddenCharPos = getPosition >>= \p ->
152+ updateState $ \s -> s{ orgStateLastForbiddenCharPos = Just p}
153+
154+updateLastPreCharPos :: OrgParser ()
155+updateLastPreCharPos = getPosition >>= \p ->
156+ updateState $ \s -> s{ orgStateLastPreCharPos = Just p}
157+
158+pushToInlineCharStack :: Char -> OrgParser ()
159+pushToInlineCharStack c = updateState $ \s ->
160+ s{ orgStateEmphasisCharStack = c:orgStateEmphasisCharStack s }
161+
162+popInlineCharStack :: OrgParser ()
163+popInlineCharStack = updateState $ \s ->
164+ s{ orgStateEmphasisCharStack = drop 1 . orgStateEmphasisCharStack $ s }
165+
166+surroundingEmphasisChar :: OrgParser [Char]
167+surroundingEmphasisChar =
168+ take 1 . drop 1 . orgStateEmphasisCharStack <$> getState
169+
170+startEmphasisNewlinesCounting :: Int -> OrgParser ()
171+startEmphasisNewlinesCounting maxNewlines = updateState $ \s ->
172+ s{ orgStateEmphasisNewlines = Just maxNewlines }
173+
174+decEmphasisNewlinesCount :: OrgParser ()
175+decEmphasisNewlinesCount = updateState $ \s ->
176+ s{ orgStateEmphasisNewlines = (\n -> n - 1) <$> orgStateEmphasisNewlines s }
177+
178+newlinesCountWithinLimits :: OrgParser Bool
179+newlinesCountWithinLimits = do
180+ st <- getState
181+ return $ ((< 0) <$> orgStateEmphasisNewlines st) /= Just True
182+
183+resetEmphasisNewlines :: OrgParser ()
184+resetEmphasisNewlines = updateState $ \s ->
185+ s{ orgStateEmphasisNewlines = Nothing }
186+
187+addLinkFormat :: String
188+ -> (String -> String)
189+ -> OrgParser ()
190+addLinkFormat key formatter = updateState $ \s ->
191+ let fs = orgStateLinkFormatters s
192+ in s{ orgStateLinkFormatters = M.insert key formatter fs }
193+
194+addToNotesTable :: OrgNoteRecord -> OrgParser ()
195+addToNotesTable note = do
196+ oldnotes <- orgStateNotes' <$> getState
197+ updateState $ \s -> s{ orgStateNotes' = note:oldnotes }
198+
199+-- The version Text.Pandoc.Parsing cannot be used, as we need additional parts
200+-- of the state saved and restored.
201+parseFromString :: OrgParser a -> String -> OrgParser a
202+parseFromString parser str' = do
203+ oldLastPreCharPos <- orgStateLastPreCharPos <$> getState
204+ updateState $ \s -> s{ orgStateLastPreCharPos = Nothing }
205+ result <- P.parseFromString parser str'
206+ updateState $ \s -> s{ orgStateLastPreCharPos = oldLastPreCharPos }
207+ return result
208+
209+
210+--
211+-- Adaptions and specializations of parsing utilities
212+--
213+
214+newtype F a = F { unF :: Reader OrgParserState a
215+ } deriving (Monad, Applicative, Functor)
216+
217+runF :: F a -> OrgParserState -> a
218+runF = runReader . unF
219+
220+askF :: F OrgParserState
221+askF = F ask
222+
223+asksF :: (OrgParserState -> a) -> F a
224+asksF f = F $ asks f
225+
226+instance Monoid a => Monoid (F a) where
227+ mempty = return mempty
228+ mappend = liftM2 mappend
229+ mconcat = fmap mconcat . sequence
230+
231+trimInlinesF :: F Inlines -> F Inlines
232+trimInlinesF = liftM trimInlines
233+
234+returnF :: a -> OrgParser (F a)
235+returnF = return . return
236+
237+
238+-- | Like @Text.Parsec.Char.newline@, but causes additional state changes.
239+newline :: OrgParser Char
240+newline =
241+ P.newline
242+ <* updateLastPreCharPos
243+ <* updateLastForbiddenCharPos
244+
245+--
246+-- parsing blocks
247+--
248+
249+parseBlocks :: OrgParser (F Blocks)
250+parseBlocks = mconcat <$> manyTill block eof
251+
252+block :: OrgParser (F Blocks)
253+block = choice [ mempty <$ blanklines
254+ , optionalAttributes $ choice
255+ [ orgBlock
256+ , figure
257+ , table
258+ ]
259+ , example
260+ , drawer
261+ , specialLine
262+ , header
263+ , return <$> hline
264+ , list
265+ , latexFragment
266+ , noteBlock
267+ , paraOrPlain
268+ ] <?> "block"
269+
270+optionalAttributes :: OrgParser (F Blocks) -> OrgParser (F Blocks)
271+optionalAttributes parser = try $
272+ resetBlockAttributes *> parseBlockAttributes *> parser
273+
274+parseBlockAttributes :: OrgParser ()
275+parseBlockAttributes = do
276+ attrs <- many attribute
277+ () <$ mapM (uncurry parseAndAddAttribute) attrs
278+ where
279+ attribute :: OrgParser (String, String)
280+ attribute = try $ do
281+ key <- metaLineStart *> many1Till nonspaceChar (char ':')
282+ val <- skipSpaces *> anyLine
283+ return (map toLower key, val)
284+
285+parseAndAddAttribute :: String -> String -> OrgParser ()
286+parseAndAddAttribute key value = do
287+ let key' = map toLower key
288+ () <$ addBlockAttribute key' value
289+
290+lookupInlinesAttr :: String -> OrgParser (Maybe (F Inlines))
291+lookupInlinesAttr attr = try $ do
292+ val <- lookupBlockAttribute attr
293+ maybe (return Nothing)
294+ (fmap Just . parseFromString parseInlines)
295+ val
296+
297+
298+--
299+-- Org Blocks (#+BEGIN_... / #+END_...)
300+--
301+
302+type BlockProperties = (Int, String) -- (Indentation, Block-Type)
303+
304+orgBlock :: OrgParser (F Blocks)
305+orgBlock = try $ do
306+ blockProp@(_, blkType) <- blockHeaderStart
307+ ($ blockProp) $
308+ case blkType of
309+ "comment" -> withRaw' (const mempty)
310+ "html" -> withRaw' (return . (B.rawBlock blkType))
311+ "latex" -> withRaw' (return . (B.rawBlock blkType))
312+ "ascii" -> withRaw' (return . (B.rawBlock blkType))
313+ "example" -> withRaw' (return . exampleCode)
314+ "quote" -> withParsed (fmap B.blockQuote)
315+ "verse" -> verseBlock
316+ "src" -> codeBlock
317+ _ -> withParsed (fmap $ divWithClass blkType)
318+
319+blockHeaderStart :: OrgParser (Int, String)
320+blockHeaderStart = try $ (,) <$> indent <*> blockType
321+ where
322+ indent = length <$> many spaceChar
323+ blockType = map toLower <$> (stringAnyCase "#+begin_" *> orgArgWord)
324+
325+withRaw' :: (String -> F Blocks) -> BlockProperties -> OrgParser (F Blocks)
326+withRaw' f blockProp = (ignHeaders *> (f <$> rawBlockContent blockProp))
327+
328+withParsed :: (F Blocks -> F Blocks) -> BlockProperties -> OrgParser (F Blocks)
329+withParsed f blockProp = (ignHeaders *> (f <$> parsedBlockContent blockProp))
330+
331+ignHeaders :: OrgParser ()
332+ignHeaders = (() <$ newline) <|> (() <$ anyLine)
333+
334+divWithClass :: String -> Blocks -> Blocks
335+divWithClass cls = B.divWith ("", [cls], [])
336+
337+verseBlock :: BlockProperties -> OrgParser (F Blocks)
338+verseBlock blkProp = try $ do
339+ ignHeaders
340+ content <- rawBlockContent blkProp
341+ fmap B.para . mconcat . intersperse (pure B.linebreak)
342+ <$> mapM (parseFromString parseInlines) (lines content)
343+
344+codeBlock :: BlockProperties -> OrgParser (F Blocks)
345+codeBlock blkProp = do
346+ skipSpaces
347+ (classes, kv) <- codeHeaderArgs <|> (mempty <$ ignHeaders)
348+ id' <- fromMaybe "" <$> lookupBlockAttribute "name"
349+ content <- rawBlockContent blkProp
350+ let codeBlck = B.codeBlockWith ( id', classes, kv ) content
351+ maybe (pure codeBlck) (labelDiv codeBlck) <$> lookupInlinesAttr "caption"
352+ where
353+ labelDiv blk value =
354+ B.divWith nullAttr <$> (mappend <$> labelledBlock value
355+ <*> pure blk)
356+ labelledBlock = fmap (B.plain . B.spanWith ("", ["label"], []))
357+
358+rawBlockContent :: BlockProperties -> OrgParser String
359+rawBlockContent (indent, blockType) = try $
360+ unlines . map commaEscaped <$> manyTill indentedLine blockEnder
361+ where
362+ indentedLine = try $ ("" <$ blankline) <|> (indentWith indent *> anyLine)
363+ blockEnder = try $ indentWith indent *> stringAnyCase ("#+end_" <> blockType)
364+
365+parsedBlockContent :: BlockProperties -> OrgParser (F Blocks)
366+parsedBlockContent blkProps = try $ do
367+ raw <- rawBlockContent blkProps
368+ parseFromString parseBlocks (raw ++ "\n")
369+
370+-- indent by specified number of spaces (or equiv. tabs)
371+indentWith :: Int -> OrgParser String
372+indentWith num = do
373+ tabStop <- getOption readerTabStop
374+ if num < tabStop
375+ then count num (char ' ')
376+ else choice [ try (count num (char ' '))
377+ , try (char '\t' >> count (num - tabStop) (char ' ')) ]
378+
379+type SwitchOption = (Char, Maybe String)
380+
381+orgArgWord :: OrgParser String
382+orgArgWord = many1 orgArgWordChar
383+
384+-- | Parse code block arguments
385+-- TODO: We currently don't handle switches.
386+codeHeaderArgs :: OrgParser ([String], [(String, String)])
387+codeHeaderArgs = try $ do
388+ language <- skipSpaces *> orgArgWord
389+ _ <- skipSpaces *> (try $ switch `sepBy` (many1 spaceChar))
390+ parameters <- manyTill blockOption newline
391+ let pandocLang = translateLang language
392+ return $
393+ if hasRundocParameters parameters
394+ then ( [ pandocLang, rundocBlockClass ]
395+ , map toRundocAttrib (("language", language) : parameters)
396+ )
397+ else ([ pandocLang ], parameters)
398+ where hasRundocParameters = not . null
399+
400+switch :: OrgParser SwitchOption
401+switch = try $ simpleSwitch <|> lineNumbersSwitch
402+ where
403+ simpleSwitch = (\c -> (c, Nothing)) <$> (oneOf "-+" *> letter)
404+ lineNumbersSwitch = (\ls -> ('l', Just ls)) <$>
405+ (string "-l \"" *> many1Till nonspaceChar (char '"'))
406+
407+translateLang :: String -> String
408+translateLang "C" = "c"
409+translateLang "C++" = "cpp"
410+translateLang "emacs-lisp" = "commonlisp" -- emacs lisp is not supported
411+translateLang "js" = "javascript"
412+translateLang "lisp" = "commonlisp"
413+translateLang "R" = "r"
414+translateLang "sh" = "bash"
415+translateLang "sqlite" = "sql"
416+translateLang cs = cs
417+
418+-- | Prefix used for Rundoc classes and arguments.
419+rundocPrefix :: String
420+rundocPrefix = "rundoc-"
421+
422+-- | The class-name used to mark rundoc blocks.
423+rundocBlockClass :: String
424+rundocBlockClass = rundocPrefix ++ "block"
425+
426+blockOption :: OrgParser (String, String)
427+blockOption = try $ (,) <$> orgArgKey <*> orgParamValue
428+
429+inlineBlockOption :: OrgParser (String, String)
430+inlineBlockOption = try $ (,) <$> orgArgKey <*> orgInlineParamValue
431+
432+orgArgKey :: OrgParser String
433+orgArgKey = try $
434+ skipSpaces *> char ':'
435+ *> many1 orgArgWordChar
436+
437+orgParamValue :: OrgParser String
438+orgParamValue = try $
439+ skipSpaces *> many1 (noneOf "\t\n\r ") <* skipSpaces
440+
441+orgInlineParamValue :: OrgParser String
442+orgInlineParamValue = try $
443+ skipSpaces *> many1 (noneOf "\t\n\r ]") <* skipSpaces
444+
445+orgArgWordChar :: OrgParser Char
446+orgArgWordChar = alphaNum <|> oneOf "-_"
447+
448+toRundocAttrib :: (String, String) -> (String, String)
449+toRundocAttrib = first ("rundoc-" ++)
450+
451+commaEscaped :: String -> String
452+commaEscaped (',':cs@('*':_)) = cs
453+commaEscaped (',':cs@('#':'+':_)) = cs
454+commaEscaped cs = cs
455+
456+example :: OrgParser (F Blocks)
457+example = try $ do
458+ return . return . exampleCode =<< unlines <$> many1 exampleLine
459+
460+exampleCode :: String -> Blocks
461+exampleCode = B.codeBlockWith ("", ["example"], [])
462+
463+exampleLine :: OrgParser String
464+exampleLine = try $ string ": " *> anyLine
465+
466+-- Drawers for properties or a logbook
467+drawer :: OrgParser (F Blocks)
468+drawer = try $ do
469+ drawerStart
470+ manyTill drawerLine (try drawerEnd)
471+ return mempty
472+
473+drawerStart :: OrgParser String
474+drawerStart = try $
475+ skipSpaces *> drawerName <* skipSpaces <* P.newline
476+ where drawerName = try $ char ':' *> validDrawerName <* char ':'
477+ validDrawerName = stringAnyCase "PROPERTIES"
478+ <|> stringAnyCase "LOGBOOK"
479+
480+drawerLine :: OrgParser String
481+drawerLine = try anyLine
482+
483+drawerEnd :: OrgParser String
484+drawerEnd = try $
485+ skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* P.newline
486+
487+
488+--
489+-- Figures
490+--
491+
492+-- Figures (Image on a line by itself, preceded by name and/or caption)
493+figure :: OrgParser (F Blocks)
494+figure = try $ do
495+ (cap, nam) <- nameAndCaption
496+ src <- skipSpaces *> selfTarget <* skipSpaces <* P.newline
497+ guard (isImageFilename src)
498+ return $ do
499+ cap' <- cap
500+ return $ B.para $ B.image src nam cap'
501+ where
502+ nameAndCaption =
503+ do
504+ maybeCap <- lookupInlinesAttr "caption"
505+ maybeNam <- lookupBlockAttribute "name"
506+ guard $ isJust maybeCap || isJust maybeNam
507+ return ( fromMaybe mempty maybeCap
508+ , maybe mempty withFigPrefix maybeNam )
509+ withFigPrefix cs =
510+ if "fig:" `isPrefixOf` cs
511+ then cs
512+ else "fig:" ++ cs
513+
514+--
515+-- Comments, Options and Metadata
516+specialLine :: OrgParser (F Blocks)
517+specialLine = fmap return . try $ metaLine <|> commentLine
518+
519+metaLine :: OrgParser Blocks
520+metaLine = try $ mempty
521+ <$ (metaLineStart *> (optionLine <|> declarationLine))
522+
523+commentLine :: OrgParser Blocks
524+commentLine = try $ commentLineStart *> anyLine *> pure mempty
525+
526+-- The order, in which blocks are tried, makes sure that we're not looking at
527+-- the beginning of a block, so we don't need to check for it
528+metaLineStart :: OrgParser String
529+metaLineStart = try $ mappend <$> many spaceChar <*> string "#+"
530+
531+commentLineStart :: OrgParser String
532+commentLineStart = try $ mappend <$> many spaceChar <*> string "# "
533+
534+declarationLine :: OrgParser ()
535+declarationLine = try $ do
536+ key <- metaKey
537+ inlinesF <- metaInlines
538+ updateState $ \st ->
539+ let meta' = B.setMeta <$> pure key <*> inlinesF <*> pure nullMeta
540+ in st { orgStateMeta' = orgStateMeta' st <> meta' }
541+ return ()
542+
543+metaInlines :: OrgParser (F MetaValue)
544+metaInlines = fmap (MetaInlines . B.toList) <$> inlinesTillNewline
545+
546+metaKey :: OrgParser String
547+metaKey = map toLower <$> many1 (noneOf ": \n\r")
548+ <* char ':'
549+ <* skipSpaces
550+
551+optionLine :: OrgParser ()
552+optionLine = try $ do
553+ key <- metaKey
554+ case key of
555+ "link" -> parseLinkFormat >>= uncurry addLinkFormat
556+ _ -> mzero
557+
558+parseLinkFormat :: OrgParser ((String, String -> String))
559+parseLinkFormat = try $ do
560+ linkType <- (:) <$> letter <*> many (alphaNum <|> oneOf "-_") <* skipSpaces
561+ linkSubst <- parseFormat
562+ return (linkType, linkSubst)
563+
564+-- | An ad-hoc, single-argument-only implementation of a printf-style format
565+-- parser.
566+parseFormat :: OrgParser (String -> String)
567+parseFormat = try $ do
568+ replacePlain <|> replaceUrl <|> justAppend
569+ where
570+ -- inefficient, but who cares
571+ replacePlain = try $ (\x -> concat . flip intersperse x)
572+ <$> sequence [tillSpecifier 's', rest]
573+ replaceUrl = try $ (\x -> concat . flip intersperse x . urlEncode)
574+ <$> sequence [tillSpecifier 'h', rest]
575+ justAppend = try $ (++) <$> rest
576+
577+ rest = manyTill anyChar (eof <|> () <$ oneOf "\n\r")
578+ tillSpecifier c = manyTill (noneOf "\n\r") (try $ string ('%':c:""))
579+
580+--
581+-- Headers
582+--
583+
584+-- | Headers
585+header :: OrgParser (F Blocks)
586+header = try $ do
587+ level <- headerStart
588+ title <- inlinesTillNewline
589+ return $ B.header level <$> title
590+
591+headerStart :: OrgParser Int
592+headerStart = try $
593+ (length <$> many1 (char '*')) <* many1 (char ' ')
594+
595+
596+-- Don't use (or need) the reader wrapper here, we want hline to be
597+-- @show@able. Otherwise we can't use it with @notFollowedBy'@.
598+
599+-- | Horizontal Line (five -- dashes or more)
600+hline :: OrgParser Blocks
601+hline = try $ do
602+ skipSpaces
603+ string "-----"
604+ many (char '-')
605+ skipSpaces
606+ newline
607+ return B.horizontalRule
608+
609+--
610+-- Tables
611+--
612+
613+data OrgTableRow = OrgContentRow (F [Blocks])
614+ | OrgAlignRow [Alignment]
615+ | OrgHlineRow
616+
617+data OrgTable = OrgTable
618+ { orgTableColumns :: Int
619+ , orgTableAlignments :: [Alignment]
620+ , orgTableHeader :: [Blocks]
621+ , orgTableRows :: [[Blocks]]
622+ }
623+
624+table :: OrgParser (F Blocks)
625+table = try $ do
626+ lookAhead tableStart
627+ do
628+ rows <- tableRows
629+ cptn <- fromMaybe (pure "") <$> lookupInlinesAttr "caption"
630+ return $ (<$> cptn) . orgToPandocTable . normalizeTable =<< rowsToTable rows
631+
632+orgToPandocTable :: OrgTable
633+ -> Inlines
634+ -> Blocks
635+orgToPandocTable (OrgTable _ aligns heads lns) caption =
636+ B.table caption (zip aligns $ repeat 0) heads lns
637+
638+tableStart :: OrgParser Char
639+tableStart = try $ skipSpaces *> char '|'
640+
641+tableRows :: OrgParser [OrgTableRow]
642+tableRows = try $ many (tableAlignRow <|> tableHline <|> tableContentRow)
643+
644+tableContentRow :: OrgParser OrgTableRow
645+tableContentRow = try $
646+ OrgContentRow . sequence <$> (tableStart *> manyTill tableContentCell newline)
647+
648+tableContentCell :: OrgParser (F Blocks)
649+tableContentCell = try $
650+ fmap B.plain . trimInlinesF . mconcat <$> many1Till inline endOfCell
651+
652+endOfCell :: OrgParser Char
653+endOfCell = try $ char '|' <|> lookAhead newline
654+
655+tableAlignRow :: OrgParser OrgTableRow
656+tableAlignRow = try $
657+ OrgAlignRow <$> (tableStart *> manyTill tableAlignCell newline)
658+
659+tableAlignCell :: OrgParser Alignment
660+tableAlignCell =
661+ choice [ try $ emptyCell *> return AlignDefault
662+ , try $ skipSpaces
663+ *> char '<'
664+ *> tableAlignFromChar
665+ <* many digit
666+ <* char '>'
667+ <* emptyCell
668+ ] <?> "alignment info"
669+ where emptyCell = try $ skipSpaces *> endOfCell
670+
671+tableAlignFromChar :: OrgParser Alignment
672+tableAlignFromChar = try $ choice [ char 'l' *> return AlignLeft
673+ , char 'c' *> return AlignCenter
674+ , char 'r' *> return AlignRight
675+ ]
676+
677+tableHline :: OrgParser OrgTableRow
678+tableHline = try $
679+ OrgHlineRow <$ (tableStart *> char '-' *> anyLine)
680+
681+rowsToTable :: [OrgTableRow]
682+ -> F OrgTable
683+rowsToTable = foldM (flip rowToContent) zeroTable
684+ where zeroTable = OrgTable 0 mempty mempty mempty
685+
686+normalizeTable :: OrgTable
687+ -> OrgTable
688+normalizeTable (OrgTable cols aligns heads lns) =
689+ let aligns' = fillColumns aligns AlignDefault
690+ heads' = if heads == mempty
691+ then mempty
692+ else fillColumns heads (B.plain mempty)
693+ lns' = map (`fillColumns` B.plain mempty) lns
694+ fillColumns base padding = take cols $ base ++ repeat padding
695+ in OrgTable cols aligns' heads' lns'
696+
697+
698+-- One or more horizontal rules after the first content line mark the previous
699+-- line as a header. All other horizontal lines are discarded.
700+rowToContent :: OrgTableRow
701+ -> OrgTable
702+ -> F OrgTable
703+rowToContent OrgHlineRow t = maybeBodyToHeader t
704+rowToContent (OrgAlignRow as) t = setLongestRow as =<< setAligns as t
705+rowToContent (OrgContentRow rf) t = do
706+ rs <- rf
707+ setLongestRow rs =<< appendToBody rs t
708+
709+setLongestRow :: [a]
710+ -> OrgTable
711+ -> F OrgTable
712+setLongestRow rs t =
713+ return t{ orgTableColumns = max (length rs) (orgTableColumns t) }
714+
715+maybeBodyToHeader :: OrgTable
716+ -> F OrgTable
717+maybeBodyToHeader t = case t of
718+ OrgTable{ orgTableHeader = [], orgTableRows = b:[] } ->
719+ return t{ orgTableHeader = b , orgTableRows = [] }
720+ _ -> return t
721+
722+appendToBody :: [Blocks]
723+ -> OrgTable
724+ -> F OrgTable
725+appendToBody r t = return t{ orgTableRows = orgTableRows t ++ [r] }
726+
727+setAligns :: [Alignment]
728+ -> OrgTable
729+ -> F OrgTable
730+setAligns aligns t = return $ t{ orgTableAlignments = aligns }
731+
732+
733+--
734+-- LaTeX fragments
735+--
736+latexFragment :: OrgParser (F Blocks)
737+latexFragment = try $ do
738+ envName <- latexEnvStart
739+ content <- mconcat <$> manyTill anyLineNewline (latexEnd envName)
740+ return . return $ B.rawBlock "latex" (content `inLatexEnv` envName)
741+ where
742+ c `inLatexEnv` e = mconcat [ "\\begin{", e, "}\n"
743+ , c
744+ , "\\end{", e, "}\n"
745+ ]
746+
747+latexEnvStart :: OrgParser String
748+latexEnvStart = try $ do
749+ skipSpaces *> string "\\begin{"
750+ *> latexEnvName
751+ <* string "}"
752+ <* blankline
753+
754+latexEnd :: String -> OrgParser ()
755+latexEnd envName = try $
756+ () <$ skipSpaces
757+ <* string ("\\end{" ++ envName ++ "}")
758+ <* blankline
759+
760+-- | Parses a LaTeX environment name.
761+latexEnvName :: OrgParser String
762+latexEnvName = try $ do
763+ mappend <$> many1 alphaNum
764+ <*> option "" (string "*")
765+
766+
767+--
768+-- Footnote defintions
769+--
770+noteBlock :: OrgParser (F Blocks)
771+noteBlock = try $ do
772+ ref <- noteMarker <* skipSpaces
773+ content <- mconcat <$> blocksTillHeaderOrNote
774+ addToNotesTable (ref, content)
775+ return mempty
776+ where
777+ blocksTillHeaderOrNote =
778+ many1Till block (eof <|> () <$ lookAhead noteMarker
779+ <|> () <$ lookAhead headerStart)
780+
781+-- Paragraphs or Plain text
782+paraOrPlain :: OrgParser (F Blocks)
783+paraOrPlain = try $
784+ parseInlines <**> (fmap <$> option B.plain (try $ newline *> pure B.para))
785+
786+inlinesTillNewline :: OrgParser (F Inlines)
787+inlinesTillNewline = trimInlinesF . mconcat <$> manyTill inline newline
788+
789+
790+--
791+-- list blocks
792+--
793+
794+list :: OrgParser (F Blocks)
795+list = choice [ definitionList, bulletList, orderedList ] <?> "list"
796+
797+definitionList :: OrgParser (F Blocks)
798+definitionList = fmap B.definitionList . fmap compactify'DL . sequence
799+ <$> many1 (definitionListItem bulletListStart)
800+
801+bulletList :: OrgParser (F Blocks)
802+bulletList = fmap B.bulletList . fmap compactify' . sequence
803+ <$> many1 (listItem bulletListStart)
804+
805+orderedList :: OrgParser (F Blocks)
806+orderedList = fmap B.orderedList . fmap compactify' . sequence
807+ <$> many1 (listItem orderedListStart)
808+
809+genericListStart :: OrgParser String
810+ -> OrgParser Int
811+genericListStart listMarker = try $
812+ (+) <$> (length <$> many spaceChar)
813+ <*> (length <$> listMarker <* many1 spaceChar)
814+
815+-- parses bullet list start and returns its length (excl. following whitespace)
816+bulletListStart :: OrgParser Int
817+bulletListStart = genericListStart bulletListMarker
818+ where bulletListMarker = pure <$> oneOf "*-+"
819+
820+orderedListStart :: OrgParser Int
821+orderedListStart = genericListStart orderedListMarker
822+ -- Ordered list markers allowed in org-mode
823+ where orderedListMarker = mappend <$> many1 digit <*> (pure <$> oneOf ".)")
824+
825+definitionListItem :: OrgParser Int
826+ -> OrgParser (F (Inlines, [Blocks]))
827+definitionListItem parseMarkerGetLength = try $ do
828+ markerLength <- parseMarkerGetLength
829+ term <- manyTill (noneOf "\n\r") (try $ string "::")
830+ line1 <- anyLineNewline
831+ blank <- option "" ("\n" <$ blankline)
832+ cont <- concat <$> many (listContinuation markerLength)
833+ term' <- parseFromString inline term
834+ contents' <- parseFromString parseBlocks $ line1 ++ blank ++ cont
835+ return $ (,) <$> term' <*> fmap (:[]) contents'
836+
837+
838+-- parse raw text for one list item, excluding start marker and continuations
839+listItem :: OrgParser Int
840+ -> OrgParser (F Blocks)
841+listItem start = try $ do
842+ markerLength <- try start
843+ firstLine <- anyLineNewline
844+ blank <- option "" ("\n" <$ blankline)
845+ rest <- concat <$> many (listContinuation markerLength)
846+ parseFromString parseBlocks $ firstLine ++ blank ++ rest
847+
848+-- continuation of a list item - indented and separated by blankline or endline.
849+-- Note: nested lists are parsed as continuations.
850+listContinuation :: Int
851+ -> OrgParser String
852+listContinuation markerLength = try $
853+ notFollowedBy' blankline
854+ *> (mappend <$> (concat <$> many1 listLine)
855+ <*> many blankline)
856+ where listLine = try $ indentWith markerLength *> anyLineNewline
857+
858+anyLineNewline :: OrgParser String
859+anyLineNewline = (++ "\n") <$> anyLine
860+
861+
862+--
863+-- inline
864+--
865+
866+inline :: OrgParser (F Inlines)
867+inline =
868+ choice [ whitespace
869+ , linebreak
870+ , cite
871+ , footnote
872+ , linkOrImage
873+ , anchor
874+ , inlineCodeBlock
875+ , str
876+ , endline
877+ , emph
878+ , strong
879+ , strikeout
880+ , underline
881+ , code
882+ , math
883+ , displayMath
884+ , verbatim
885+ , subscript
886+ , superscript
887+ , inlineLaTeX
888+ , symbol
889+ ] <* (guard =<< newlinesCountWithinLimits)
890+ <?> "inline"
891+
892+parseInlines :: OrgParser (F Inlines)
893+parseInlines = trimInlinesF . mconcat <$> many1 inline
894+
895+-- treat these as potentially non-text when parsing inline:
896+specialChars :: [Char]
897+specialChars = "\"$'()*+-./:<=>[\\]^_{|}~"
898+
899+
900+whitespace :: OrgParser (F Inlines)
901+whitespace = pure B.space <$ skipMany1 spaceChar
902+ <* updateLastPreCharPos
903+ <* updateLastForbiddenCharPos
904+ <?> "whitespace"
905+
906+linebreak :: OrgParser (F Inlines)
907+linebreak = try $ pure B.linebreak <$ string "\\\\" <* skipSpaces <* newline
908+
909+str :: OrgParser (F Inlines)
910+str = return . B.str <$> many1 (noneOf $ specialChars ++ "\n\r ")
911+ <* updateLastStrPos
912+
913+-- | An endline character that can be treated as a space, not a structural
914+-- break. This should reflect the values of the Emacs variable
915+-- @org-element-pagaraph-separate@.
916+endline :: OrgParser (F Inlines)
917+endline = try $ do
918+ newline
919+ notFollowedBy blankline
920+ notFollowedBy' exampleLine
921+ notFollowedBy' hline
922+ notFollowedBy' noteMarker
923+ notFollowedBy' tableStart
924+ notFollowedBy' drawerStart
925+ notFollowedBy' headerStart
926+ notFollowedBy' metaLineStart
927+ notFollowedBy' latexEnvStart
928+ notFollowedBy' commentLineStart
929+ notFollowedBy' bulletListStart
930+ notFollowedBy' orderedListStart
931+ decEmphasisNewlinesCount
932+ guard =<< newlinesCountWithinLimits
933+ updateLastPreCharPos
934+ return . return $ B.space
935+
936+cite :: OrgParser (F Inlines)
937+cite = try $ do
938+ guardEnabled Ext_citations
939+ (cs, raw) <- withRaw normalCite
940+ return $ (flip B.cite (B.text raw)) <$> cs
941+
942+normalCite :: OrgParser (F [Citation])
943+normalCite = try $ char '['
944+ *> skipSpaces
945+ *> citeList
946+ <* skipSpaces
947+ <* char ']'
948+
949+citeList :: OrgParser (F [Citation])
950+citeList = sequence <$> sepBy1 citation (try $ char ';' *> skipSpaces)
951+
952+citation :: OrgParser (F Citation)
953+citation = try $ do
954+ pref <- prefix
955+ (suppress_author, key) <- citeKey
956+ suff <- suffix
957+ return $ do
958+ x <- pref
959+ y <- suff
960+ return $ Citation{ citationId = key
961+ , citationPrefix = B.toList x
962+ , citationSuffix = B.toList y
963+ , citationMode = if suppress_author
964+ then SuppressAuthor
965+ else NormalCitation
966+ , citationNoteNum = 0
967+ , citationHash = 0
968+ }
969+ where
970+ prefix = trimInlinesF . mconcat <$>
971+ manyTill inline (char ']' <|> (']' <$ lookAhead citeKey))
972+ suffix = try $ do
973+ hasSpace <- option False (notFollowedBy nonspaceChar >> return True)
974+ skipSpaces
975+ rest <- trimInlinesF . mconcat <$>
976+ many (notFollowedBy (oneOf ";]") *> inline)
977+ return $ if hasSpace
978+ then (B.space <>) <$> rest
979+ else rest
980+
981+footnote :: OrgParser (F Inlines)
982+footnote = try $ inlineNote <|> referencedNote
983+
984+inlineNote :: OrgParser (F Inlines)
985+inlineNote = try $ do
986+ string "[fn:"
987+ ref <- many alphaNum
988+ char ':'
989+ note <- fmap B.para . trimInlinesF . mconcat <$> many1Till inline (char ']')
990+ when (not $ null ref) $
991+ addToNotesTable ("fn:" ++ ref, note)
992+ return $ B.note <$> note
993+
994+referencedNote :: OrgParser (F Inlines)
995+referencedNote = try $ do
996+ ref <- noteMarker
997+ return $ do
998+ notes <- asksF orgStateNotes'
999+ case lookup ref notes of
1000+ Nothing -> return $ B.str $ "[" ++ ref ++ "]"
1001+ Just contents -> do
1002+ st <- askF
1003+ let contents' = runF contents st{ orgStateNotes' = [] }
1004+ return $ B.note contents'
1005+
1006+noteMarker :: OrgParser String
1007+noteMarker = try $ do
1008+ char '['
1009+ choice [ many1Till digit (char ']')
1010+ , (++) <$> string "fn:"
1011+ <*> many1Till (noneOf "\n\r\t ") (char ']')
1012+ ]
1013+
1014+linkOrImage :: OrgParser (F Inlines)
1015+linkOrImage = explicitOrImageLink
1016+ <|> selflinkOrImage
1017+ <|> angleLink
1018+ <|> plainLink
1019+ <?> "link or image"
1020+
1021+explicitOrImageLink :: OrgParser (F Inlines)
1022+explicitOrImageLink = try $ do
1023+ char '['
1024+ srcF <- applyCustomLinkFormat =<< linkTarget
1025+ title <- enclosedRaw (char '[') (char ']')
1026+ title' <- parseFromString (mconcat <$> many inline) title
1027+ char ']'
1028+ return $ do
1029+ src <- srcF
1030+ if isImageFilename src && isImageFilename title
1031+ then pure $ B.link src "" $ B.image title mempty mempty
1032+ else linkToInlinesF src =<< title'
1033+
1034+selflinkOrImage :: OrgParser (F Inlines)
1035+selflinkOrImage = try $ do
1036+ src <- char '[' *> linkTarget <* char ']'
1037+ return $ linkToInlinesF src (B.str src)
1038+
1039+plainLink :: OrgParser (F Inlines)
1040+plainLink = try $ do
1041+ (orig, src) <- uri
1042+ returnF $ B.link src "" (B.str orig)
1043+
1044+angleLink :: OrgParser (F Inlines)
1045+angleLink = try $ do
1046+ char '<'
1047+ link <- plainLink
1048+ char '>'
1049+ return link
1050+
1051+selfTarget :: OrgParser String
1052+selfTarget = try $ char '[' *> linkTarget <* char ']'
1053+
1054+linkTarget :: OrgParser String
1055+linkTarget = enclosedByPair '[' ']' (noneOf "\n\r[]")
1056+
1057+applyCustomLinkFormat :: String -> OrgParser (F String)
1058+applyCustomLinkFormat link = do
1059+ let (linkType, rest) = break (== ':') link
1060+ return $ do
1061+ formatter <- M.lookup linkType <$> asksF orgStateLinkFormatters
1062+ return $ maybe link ($ drop 1 rest) formatter
1063+
1064+
1065+linkToInlinesF :: String -> Inlines -> F Inlines
1066+linkToInlinesF s@('#':_) = pure . B.link s ""
1067+linkToInlinesF s
1068+ | isImageFilename s = const . pure $ B.image s "" ""
1069+ | isUri s = pure . B.link s ""
1070+ | isRelativeUrl s = pure . B.link s ""
1071+linkToInlinesF s = \title -> do
1072+ anchorB <- (s `elem`) <$> asksF orgStateAnchorIds
1073+ if anchorB
1074+ then pure $ B.link ('#':s) "" title
1075+ else pure $ B.emph title
1076+
1077+isRelativeUrl :: String -> Bool
1078+isRelativeUrl s = (':' `notElem` s) && ("./" `isPrefixOf` s)
1079+
1080+isUri :: String -> Bool
1081+isUri s = let (scheme, path) = break (== ':') s
1082+ in all (\c -> isAlphaNum c || c `elem` ".-") scheme
1083+ && not (null path)
1084+
1085+isImageFilename :: String -> Bool
1086+isImageFilename filename =
1087+ any (\x -> ('.':x) `isSuffixOf` filename) imageExtensions &&
1088+ (any (\x -> (x++":") `isPrefixOf` filename) protocols ||
1089+ ':' `notElem` filename)
1090+ where
1091+ imageExtensions = [ "jpeg" , "jpg" , "png" , "gif" , "svg" ]
1092+ protocols = [ "file", "http", "https" ]
1093+
1094+-- | Parse an anchor like @<<anchor-id>>@ and return an empty span with
1095+-- @anchor-id@ set as id. Legal anchors in org-mode are defined through
1096+-- @org-target-regexp@, which is fairly liberal. Since no link is created if
1097+-- @anchor-id@ contains spaces, we are more restrictive in what is accepted as
1098+-- an anchor.
1099+
1100+anchor :: OrgParser (F Inlines)
1101+anchor = try $ do
1102+ anchorId <- parseAnchor
1103+ recordAnchorId anchorId
1104+ returnF $ B.spanWith (solidify anchorId, [], []) mempty
1105+ where
1106+ parseAnchor = string "<<"
1107+ *> many1 (noneOf "\t\n\r<>\"' ")
1108+ <* string ">>"
1109+ <* skipSpaces
1110+
1111+-- | Replace every char but [a-zA-Z0-9_.-:] with a hypen '-'. This mirrors
1112+-- the org function @org-export-solidify-link-text@.
1113+
1114+solidify :: String -> String
1115+solidify = map replaceSpecialChar
1116+ where replaceSpecialChar c
1117+ | isAlphaNum c = c
1118+ | c `elem` "_.-:" = c
1119+ | otherwise = '-'
1120+
1121+-- | Parses an inline code block and marks it as an babel block.
1122+inlineCodeBlock :: OrgParser (F Inlines)
1123+inlineCodeBlock = try $ do
1124+ string "src_"
1125+ lang <- many1 orgArgWordChar
1126+ opts <- option [] $ enclosedByPair '[' ']' inlineBlockOption
1127+ inlineCode <- enclosedByPair '{' '}' (noneOf "\n\r")
1128+ let attrClasses = [translateLang lang, rundocBlockClass]
1129+ let attrKeyVal = map toRundocAttrib (("language", lang) : opts)
1130+ returnF $ B.codeWith ("", attrClasses, attrKeyVal) inlineCode
1131+
1132+enclosedByPair :: Char -- ^ opening char
1133+ -> Char -- ^ closing char
1134+ -> OrgParser a -- ^ parser
1135+ -> OrgParser [a]
1136+enclosedByPair s e p = char s *> many1Till p (char e)
1137+
1138+emph :: OrgParser (F Inlines)
1139+emph = fmap B.emph <$> emphasisBetween '/'
1140+
1141+strong :: OrgParser (F Inlines)
1142+strong = fmap B.strong <$> emphasisBetween '*'
1143+
1144+strikeout :: OrgParser (F Inlines)
1145+strikeout = fmap B.strikeout <$> emphasisBetween '+'
1146+
1147+-- There is no underline, so we use strong instead.
1148+underline :: OrgParser (F Inlines)
1149+underline = fmap B.strong <$> emphasisBetween '_'
1150+
1151+verbatim :: OrgParser (F Inlines)
1152+verbatim = return . B.code <$> verbatimBetween '='
1153+
1154+code :: OrgParser (F Inlines)
1155+code = return . B.code <$> verbatimBetween '~'
1156+
1157+subscript :: OrgParser (F Inlines)
1158+subscript = fmap B.subscript <$> try (char '_' *> subOrSuperExpr)
1159+
1160+superscript :: OrgParser (F Inlines)
1161+superscript = fmap B.superscript <$> try (char '^' *> subOrSuperExpr)
1162+
1163+math :: OrgParser (F Inlines)
1164+math = return . B.math <$> choice [ math1CharBetween '$'
1165+ , mathStringBetween '$'
1166+ , rawMathBetween "\\(" "\\)"
1167+ ]
1168+
1169+displayMath :: OrgParser (F Inlines)
1170+displayMath = return . B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
1171+ , rawMathBetween "$$" "$$"
1172+ ]
1173+symbol :: OrgParser (F Inlines)
1174+symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
1175+ where updatePositions c
1176+ | c `elem` emphasisPreChars = c <$ updateLastPreCharPos
1177+ | c `elem` emphasisForbiddenBorderChars = c <$ updateLastForbiddenCharPos
1178+ | otherwise = return c
1179+
1180+emphasisBetween :: Char
1181+ -> OrgParser (F Inlines)
1182+emphasisBetween c = try $ do
1183+ startEmphasisNewlinesCounting emphasisAllowedNewlines
1184+ res <- enclosedInlines (emphasisStart c) (emphasisEnd c)
1185+ isTopLevelEmphasis <- null . orgStateEmphasisCharStack <$> getState
1186+ when isTopLevelEmphasis
1187+ resetEmphasisNewlines
1188+ return res
1189+
1190+verbatimBetween :: Char
1191+ -> OrgParser String
1192+verbatimBetween c = try $
1193+ emphasisStart c *>
1194+ many1TillNOrLessNewlines 1 (noneOf "\n\r") (emphasisEnd c)
1195+
1196+-- | Parses a raw string delimited by @c@ using Org's math rules
1197+mathStringBetween :: Char
1198+ -> OrgParser String
1199+mathStringBetween c = try $ do
1200+ mathStart c
1201+ body <- many1TillNOrLessNewlines mathAllowedNewlines
1202+ (noneOf (c:"\n\r"))
1203+ (lookAhead $ mathEnd c)
1204+ final <- mathEnd c
1205+ return $ body ++ [final]
1206+
1207+-- | Parse a single character between @c@ using math rules
1208+math1CharBetween :: Char
1209+ -> OrgParser String
1210+math1CharBetween c = try $ do
1211+ char c
1212+ res <- noneOf $ c:mathForbiddenBorderChars
1213+ char c
1214+ eof <|> () <$ lookAhead (oneOf mathPostChars)
1215+ return [res]
1216+
1217+rawMathBetween :: String
1218+ -> String
1219+ -> OrgParser String
1220+rawMathBetween s e = try $ string s *> manyTill anyChar (try $ string e)
1221+
1222+-- | Parses the start (opening character) of emphasis
1223+emphasisStart :: Char -> OrgParser Char
1224+emphasisStart c = try $ do
1225+ guard =<< afterEmphasisPreChar
1226+ guard =<< notAfterString
1227+ char c
1228+ lookAhead (noneOf emphasisForbiddenBorderChars)
1229+ pushToInlineCharStack c
1230+ return c
1231+
1232+-- | Parses the closing character of emphasis
1233+emphasisEnd :: Char -> OrgParser Char
1234+emphasisEnd c = try $ do
1235+ guard =<< notAfterForbiddenBorderChar
1236+ char c
1237+ eof <|> () <$ lookAhead acceptablePostChars
1238+ updateLastStrPos
1239+ popInlineCharStack
1240+ return c
1241+ where acceptablePostChars =
1242+ surroundingEmphasisChar >>= \x -> oneOf (x ++ emphasisPostChars)
1243+
1244+mathStart :: Char -> OrgParser Char
1245+mathStart c = try $
1246+ char c <* notFollowedBy' (oneOf (c:mathForbiddenBorderChars))
1247+
1248+mathEnd :: Char -> OrgParser Char
1249+mathEnd c = try $ do
1250+ res <- noneOf (c:mathForbiddenBorderChars)
1251+ char c
1252+ eof <|> () <$ lookAhead (oneOf mathPostChars)
1253+ return res
1254+
1255+
1256+enclosedInlines :: OrgParser a
1257+ -> OrgParser b
1258+ -> OrgParser (F Inlines)
1259+enclosedInlines start end = try $
1260+ trimInlinesF . mconcat <$> enclosed start end inline
1261+
1262+enclosedRaw :: OrgParser a
1263+ -> OrgParser b
1264+ -> OrgParser String
1265+enclosedRaw start end = try $
1266+ start *> (onSingleLine <|> spanningTwoLines)
1267+ where onSingleLine = try $ many1Till (noneOf "\n\r") end
1268+ spanningTwoLines = try $
1269+ anyLine >>= \f -> mappend (f <> " ") <$> onSingleLine
1270+
1271+-- | Like many1Till, but parses at most @n+1@ lines. @p@ must not consume
1272+-- newlines.
1273+many1TillNOrLessNewlines :: Int
1274+ -> OrgParser Char
1275+ -> OrgParser a
1276+ -> OrgParser String
1277+many1TillNOrLessNewlines n p end = try $
1278+ nMoreLines (Just n) mempty >>= oneOrMore
1279+ where
1280+ nMoreLines Nothing cs = return cs
1281+ nMoreLines (Just 0) cs = try $ (cs ++) <$> finalLine
1282+ nMoreLines k cs = try $ (final k cs <|> rest k cs)
1283+ >>= uncurry nMoreLines
1284+ final _ cs = (\x -> (Nothing, cs ++ x)) <$> try finalLine
1285+ rest m cs = (\x -> (minus1 <$> m, cs ++ x ++ "\n")) <$> try (manyTill p P.newline)
1286+ finalLine = try $ manyTill p end
1287+ minus1 k = k - 1
1288+ oneOrMore cs = guard (not $ null cs) *> return cs
1289+
1290+-- Org allows customization of the way it reads emphasis. We use the defaults
1291+-- here (see, e.g., the Emacs Lisp variable `org-emphasis-regexp-components`
1292+-- for details).
1293+
1294+-- | Chars allowed to occur before emphasis (spaces and newlines are ok, too)
1295+emphasisPreChars :: [Char]
1296+emphasisPreChars = "\t \"'({"
1297+
1298+-- | Chars allowed at after emphasis
1299+emphasisPostChars :: [Char]
1300+emphasisPostChars = "\t\n !\"'),-.:;?\\}"
1301+
1302+-- | Chars not allowed at the (inner) border of emphasis
1303+emphasisForbiddenBorderChars :: [Char]
1304+emphasisForbiddenBorderChars = "\t\n\r \"',"
1305+
1306+-- | The maximum number of newlines within
1307+emphasisAllowedNewlines :: Int
1308+emphasisAllowedNewlines = 1
1309+
1310+-- LaTeX-style math: see `org-latex-regexps` for details
1311+
1312+-- | Chars allowed after an inline ($...$) math statement
1313+mathPostChars :: [Char]
1314+mathPostChars = "\t\n \"'),-.:;?"
1315+
1316+-- | Chars not allowed at the (inner) border of math
1317+mathForbiddenBorderChars :: [Char]
1318+mathForbiddenBorderChars = "\t\n\r ,;.$"
1319+
1320+-- | Maximum number of newlines in an inline math statement
1321+mathAllowedNewlines :: Int
1322+mathAllowedNewlines = 2
1323+
1324+-- | Whether we are right behind a char allowed before emphasis
1325+afterEmphasisPreChar :: OrgParser Bool
1326+afterEmphasisPreChar = do
1327+ pos <- getPosition
1328+ lastPrePos <- orgStateLastPreCharPos <$> getState
1329+ return . fromMaybe True $ (== pos) <$> lastPrePos
1330+
1331+-- | Whether the parser is right after a forbidden border char
1332+notAfterForbiddenBorderChar :: OrgParser Bool
1333+notAfterForbiddenBorderChar = do
1334+ pos <- getPosition
1335+ lastFBCPos <- orgStateLastForbiddenCharPos <$> getState
1336+ return $ lastFBCPos /= Just pos
1337+
1338+-- | Read a sub- or superscript expression
1339+subOrSuperExpr :: OrgParser (F Inlines)
1340+subOrSuperExpr = try $
1341+ choice [ id <$> charsInBalanced '{' '}' (noneOf "\n\r")
1342+ , enclosing ('(', ')') <$> charsInBalanced '(' ')' (noneOf "\n\r")
1343+ , simpleSubOrSuperString
1344+ ] >>= parseFromString (mconcat <$> many inline)
1345+ where enclosing (left, right) s = left : s ++ [right]
1346+
1347+simpleSubOrSuperString :: OrgParser String
1348+simpleSubOrSuperString = try $
1349+ choice [ string "*"
1350+ , mappend <$> option [] ((:[]) <$> oneOf "+-")
1351+ <*> many1 alphaNum
1352+ ]
1353+
1354+inlineLaTeX :: OrgParser (F Inlines)
1355+inlineLaTeX = try $ do
1356+ cmd <- inlineLaTeXCommand
1357+ maybe mzero returnF $ parseAsMath cmd `mplus` parseAsInlineLaTeX cmd
1358+ where
1359+ parseAsMath :: String -> Maybe Inlines
1360+ parseAsMath cs = maybeRight $ B.fromList <$> texMathToPandoc DisplayInline cs
1361+
1362+ parseAsInlineLaTeX :: String -> Maybe Inlines
1363+ parseAsInlineLaTeX cs = maybeRight $ runParser inlineCommand state "" cs
1364+
1365+ state :: ParserState
1366+ state = def{ stateOptions = def{ readerParseRaw = True }}
1367+
1368+maybeRight :: Either a b -> Maybe b
1369+maybeRight = either (const Nothing) Just
1370+
1371+inlineLaTeXCommand :: OrgParser String
1372+inlineLaTeXCommand = try $ do
1373+ rest <- getInput
1374+ case runParser rawLaTeXInline def "source" rest of
1375+ Right (RawInline _ cs) -> do
1376+ let len = length cs
1377+ count len anyChar
1378+ return cs
1379+ _ -> mzero
src/Text/Pandoc/Readers/RST.hs+126−37
@@ -1,5 +1,6 @@
1+{-# LANGUAGE OverloadedStrings #-}
12{-
2−Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
34
45This program is free software; you can redistribute it and/or modify
56it 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
1819
1920{- |
2021 Module : Text.Pandoc.Readers.RST
21− Copyright : Copyright (C) 2006-2010 John MacFarlane
22+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2223 License : GNU GPL, version 2 or above
2324
2425 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,12 +36,13 @@ import Text.Pandoc.Builder (setMeta, fromList)
3536import Text.Pandoc.Shared
3637import Text.Pandoc.Parsing
3738import Text.Pandoc.Options
38−import Control.Monad ( when, liftM, guard, mzero )
39+import Control.Monad ( when, liftM, guard, mzero, mplus )
3940import Data.List ( findIndex, intersperse, intercalate,
4041 transpose, sort, deleteFirstsBy, isSuffixOf )
42+import Data.Maybe (fromMaybe)
4143import qualified Data.Map as M
4244import Text.Printf ( printf )
43−import Control.Applicative ((<$>), (<$), (<*), (*>))
45+import Control.Applicative ((<$>), (<$), (<*), (*>), (<*>))
4446import Text.Pandoc.Builder (Inlines, Blocks, trimInlines, (<>))
4547import qualified Text.Pandoc.Builder as B
4648import Data.Monoid (mconcat, mempty)
@@ -111,15 +113,16 @@ titleTransform (bs, meta) =
111113metaFromDefList :: [([Inline], [[Block]])] -> Meta -> Meta
112114metaFromDefList ds meta = adjustAuthors $ foldr f meta ds
113115 where f (k,v) = setMeta (map toLower $ stringify k) (mconcat $ map fromList v)
114− adjustAuthors (Meta metamap) = Meta $ M.adjust toPlain "author"
116+ adjustAuthors (Meta metamap) = Meta $ M.adjust splitAuthors "author"
115117 $ M.adjust toPlain "date"
116118 $ M.adjust toPlain "title"
117− $ M.adjust splitAuthors "authors"
119+ $ M.mapKeys (\k -> if k == "authors" then "author" else k)
118120 $ metamap
119121 toPlain (MetaBlocks [Para xs]) = MetaInlines xs
120122 toPlain x = x
121− splitAuthors (MetaBlocks [Para xs]) = MetaList $ map MetaInlines
122− $ splitAuthors' xs
123+ splitAuthors (MetaBlocks [Para xs])
124+ = MetaList $ map MetaInlines
125+ $ splitAuthors' xs
123126 splitAuthors x = x
124127 splitAuthors' = map normalizeSpaces .
125128 splitOnSemi . concatMap factorSemi
@@ -183,22 +186,22 @@ block = choice [ codeBlock
183186-- field list
184187--
185188
186−rawFieldListItem :: String -> RSTParser (String, String)
187−rawFieldListItem indent = try $ do
188− string indent
189+rawFieldListItem :: Int -> RSTParser (String, String)
190+rawFieldListItem minIndent = try $ do
191+ indent <- length <$> many (char ' ')
192+ guard $ indent >= minIndent
189193 char ':'
190194 name <- many1Till (noneOf "\n") (char ':')
191195 (() <$ lookAhead newline) <|> skipMany1 spaceChar
192196 first <- anyLine
193− rest <- option "" $ try $ do lookAhead (string indent >> spaceChar)
197+ rest <- option "" $ try $ do lookAhead (count indent (char ' ') >> spaceChar)
194198 indentedBlock
195199 let raw = (if null first then "" else (first ++ "\n")) ++ rest ++ "\n"
196200 return (name, raw)
197201
198−fieldListItem :: String
199− -> RSTParser (Inlines, [Blocks])
200−fieldListItem indent = try $ do
201− (name, raw) <- rawFieldListItem indent
202+fieldListItem :: Int -> RSTParser (Inlines, [Blocks])
203+fieldListItem minIndent = try $ do
204+ (name, raw) <- rawFieldListItem minIndent
202205 let term = B.str name
203206 contents <- parseFromString parseBlocks raw
204207 optional blanklines
@@ -206,7 +209,7 @@ fieldListItem indent = try $ do
206209
207210fieldList :: RSTParser Blocks
208211fieldList = try $ do
209− indent <- lookAhead $ many spaceChar
212+ indent <- length <$> lookAhead (many spaceChar)
210213 items <- many1 $ fieldListItem indent
211214 case items of
212215 [] -> return mempty
@@ -274,7 +277,8 @@ doubleHeader = try $ do
274277 Just ind -> (headerTable, ind + 1)
275278 Nothing -> (headerTable ++ [DoubleHeader c], (length headerTable) + 1)
276279 setState (state { stateHeaderTable = headerTable' })
277− return $ B.header level txt
280+ attr <- registerHeader nullAttr txt
281+ return $ B.headerWith attr level txt
278282
279283-- a header with line on the bottom only
280284singleHeader :: RSTParser Blocks
@@ -294,7 +298,8 @@ singleHeader = try $ do
294298 Just ind -> (headerTable, ind + 1)
295299 Nothing -> (headerTable ++ [SingleHeader c], (length headerTable) + 1)
296300 setState (state { stateHeaderTable = headerTable' })
297− return $ B.header level txt
301+ attr <- registerHeader nullAttr txt
302+ return $ B.headerWith attr level txt
298303
299304--
300305-- hrule block
@@ -344,14 +349,25 @@ lhsCodeBlock = try $ do
344349 getPosition >>= guard . (==1) . sourceColumn
345350 guardEnabled Ext_literate_haskell
346351 optional codeBlockStart
347− lns <- many1 birdTrackLine
348− -- if (as is normal) there is always a space after >, drop it
349− let lns' = if all (\ln -> null ln || take 1 ln == " ") lns
350− then map (drop 1) lns
351− else lns
352+ lns <- latexCodeBlock <|> birdCodeBlock
352353 blanklines
353354 return $ B.codeBlockWith ("", ["sourceCode", "literate", "haskell"], [])
354− $ intercalate "\n" lns'
355+ $ intercalate "\n" lns
356+
357+latexCodeBlock :: Parser [Char] st [[Char]]
358+latexCodeBlock = try $ do
359+ try (latexBlockLine "\\begin{code}")
360+ many1Till anyLine (try $ latexBlockLine "\\end{code}")
361+ where
362+ latexBlockLine s = skipMany spaceChar >> string s >> blankline
363+
364+birdCodeBlock :: Parser [Char] st [[Char]]
365+birdCodeBlock = filterSpace <$> many1 birdTrackLine
366+ where filterSpace lns =
367+ -- if (as is normal) there is always a space after >, drop it
368+ if all (\ln -> null ln || take 1 ln == " ") lns
369+ then map (drop 1) lns
370+ else lns
355371
356372birdTrackLine :: Parser [Char] st [Char]
357373birdTrackLine = char '>' >> anyLine
@@ -506,17 +522,17 @@ directive' = do
506522 skipMany spaceChar
507523 top <- many $ satisfy (/='\n')
508524 <|> try (char '\n' <*
509− notFollowedBy' (rawFieldListItem " ") <*
525+ notFollowedBy' (rawFieldListItem 3) <*
510526 count 3 (char ' ') <*
511527 notFollowedBy blankline)
512528 newline
513− fields <- many $ rawFieldListItem " "
529+ fields <- many $ rawFieldListItem 3
514530 body <- option "" $ try $ blanklines >> indentedBlock
515531 optional blanklines
516532 let body' = body ++ "\n\n"
517533 case label of
518534 "raw" -> return $ B.rawBlock (trim top) (stripTrailingNewlines body)
519− "role" -> return mempty
535+ "role" -> addNewRole top $ map (\(k,v) -> (k, trim v)) fields
520536 "container" -> parseFromString parseBlocks body'
521537 "replace" -> B.para <$> -- consumed by substKey
522538 parseFromString (trimInlines . mconcat <$> many inline)
@@ -561,12 +577,15 @@ directive' = do
561577 role -> role })
562578 "code" -> codeblock (lookup "number-lines" fields) (trim top) body
563579 "code-block" -> codeblock (lookup "number-lines" fields) (trim top) body
580+ "aafig" -> do
581+ let attribs = ("", ["aafig"], map (\(k,v) -> (k, trimr v)) fields)
582+ return $ B.codeBlockWith attribs $ stripTrailingNewlines body
564583 "math" -> return $ B.para $ mconcat $ map B.displayMath
565584 $ toChunks $ top ++ "\n\n" ++ body
566585 "figure" -> do
567586 (caption, legend) <- parseFromString extractCaption body'
568587 let src = escapeURI $ trim top
569− return $ B.para (B.image src "" caption) <> legend
588+ return $ B.para (B.image src "fig:" caption) <> legend
570589 "image" -> do
571590 let src = escapeURI $ trim top
572591 let alt = B.str $ maybe "image" trim $ lookup "alt" fields
@@ -577,7 +596,38 @@ directive' = do
577596 Nothing -> B.image src "" alt
578597 _ -> return mempty
579598
580−-- Can contain haracter codes as decimal numbers or
599+-- TODO:
600+-- - Silently ignores illegal fields
601+-- - Silently drops classes
602+-- - Only supports :format: fields with a single format for :raw: roles,
603+-- change Text.Pandoc.Definition.Format to fix
604+addNewRole :: String -> [(String, String)] -> RSTParser Blocks
605+addNewRole roleString fields = do
606+ (role, parentRole) <- parseFromString inheritedRole roleString
607+ customRoles <- stateRstCustomRoles <$> getState
608+ baseRole <- case M.lookup parentRole customRoles of
609+ Just (base, _, _) -> return base
610+ Nothing -> return parentRole
611+
612+ let fmt = if baseRole == "raw" then lookup "format" fields else Nothing
613+ annotate = maybe id addLanguage $
614+ if baseRole == "code"
615+ then lookup "language" fields
616+ else Nothing
617+
618+ updateState $ \s -> s {
619+ stateRstCustomRoles =
620+ M.insert role (baseRole, fmt, (,) parentRole . annotate) customRoles
621+ }
622+
623+ return $ B.singleton Null
624+ where
625+ addLanguage lang (ident, classes, keyValues) =
626+ (ident, "sourceCode" : lang : classes, keyValues)
627+ inheritedRole =
628+ (,) <$> roleNameEndingIn (char '(') <*> roleNameEndingIn (char ')')
629+
630+-- Can contain character codes as decimal numbers or
581631-- hexadecimal numbers, prefixed by 0x, x, \x, U+, u, or \u
582632-- or as XML-style hexadecimal character entities, e.g. &#x1a2b;
583633-- or text, which is used as-is. Comments start with ..
@@ -916,17 +966,56 @@ strong = B.strong . trimInlines . mconcat <$>
916966-- Note, this doesn't precisely implement the complex rule in
917967-- http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
918968-- but it should be good enough for most purposes
969+--
970+-- TODO:
971+-- - Classes are silently discarded in addNewRole
972+-- - Lacks sensible implementation for title-reference (which is the default)
973+-- - Allows direct use of the :raw: role, rST only allows inherited use.
919974interpretedRole :: RSTParser Inlines
920975interpretedRole = try $ do
921976 (role, contents) <- roleBefore <|> roleAfter
922− case role of
923− "sup" -> return $ B.superscript $ B.str contents
924− "sub" -> return $ B.subscript $ B.str contents
925− "math" -> return $ B.math contents
926− _ -> return $ B.str contents --unknown
977+ renderRole contents Nothing role nullAttr
978+
979+renderRole :: String -> Maybe String -> String -> Attr -> RSTParser Inlines
980+renderRole contents fmt role attr = case role of
981+ "sup" -> return $ B.superscript $ B.str contents
982+ "superscript" -> return $ B.superscript $ B.str contents
983+ "sub" -> return $ B.subscript $ B.str contents
984+ "subscript" -> return $ B.subscript $ B.str contents
985+ "emphasis" -> return $ B.emph $ B.str contents
986+ "strong" -> return $ B.strong $ B.str contents
987+ "rfc-reference" -> return $ rfcLink contents
988+ "RFC" -> return $ rfcLink contents
989+ "pep-reference" -> return $ pepLink contents
990+ "PEP" -> return $ pepLink contents
991+ "literal" -> return $ B.str contents
992+ "math" -> return $ B.math contents
993+ "title-reference" -> titleRef contents
994+ "title" -> titleRef contents
995+ "t" -> titleRef contents
996+ "code" -> return $ B.codeWith attr contents
997+ "raw" -> return $ B.rawInline (fromMaybe "" fmt) contents
998+ custom -> do
999+ customRole <- stateRstCustomRoles <$> getState
1000+ case M.lookup custom customRole of
1001+ Just (_, newFmt, inherit) -> let
1002+ fmtStr = fmt `mplus` newFmt
1003+ (newRole, newAttr) = inherit attr
1004+ in renderRole contents fmtStr newRole newAttr
1005+ Nothing -> return $ B.str contents -- Undefined role
1006+ where
1007+ titleRef ref = return $ B.str ref -- FIXME: Not a sensible behaviour
1008+ rfcLink rfcNo = B.link rfcUrl ("RFC " ++ rfcNo) $ B.str ("RFC " ++ rfcNo)
1009+ where rfcUrl = "http://www.faqs.org/rfcs/rfc" ++ rfcNo ++ ".html"
1010+ pepLink pepNo = B.link pepUrl ("PEP " ++ pepNo) $ B.str ("PEP " ++ pepNo)
1011+ where padNo = replicate (4 - length pepNo) '0' ++ pepNo
1012+ pepUrl = "http://www.python.org/dev/peps/pep-" ++ padNo ++ "/"
1013+
1014+roleNameEndingIn :: RSTParser Char -> RSTParser String
1015+roleNameEndingIn end = many1Till (letter <|> char '-') end
9271016
9281017roleMarker :: RSTParser String
929−roleMarker = char ':' *> many1Till (letter <|> char '-') (char ':')
1018+roleMarker = char ':' *> roleNameEndingIn (char ':')
9301019
9311020roleBefore :: RSTParser (String,String)
9321021roleBefore = try $ do
@@ -1055,7 +1144,7 @@ smart :: RSTParser Inlines
10551144smart = do
10561145 getOption readerSmart >>= guard
10571146 doubleQuoted <|> singleQuoted <|>
1058− choice (map (B.singleton <$>) [apostrophe, dash, ellipses])
1147+ choice [apostrophe, dash, ellipses]
10591148
10601149singleQuoted :: RSTParser Inlines
10611150singleQuoted = try $ do
src/Text/Pandoc/Readers/TeXMath.hs+22−88
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2007-2010 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2007-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.Readers.TeXMath
21− Copyright : Copyright (C) 2007-2010 John MacFarlane
21+ Copyright : Copyright (C) 2007-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -27,96 +27,30 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2727
2828Conversion of TeX math to a list of 'Pandoc' inline elements.
2929-}
30−module Text.Pandoc.Readers.TeXMath ( readTeXMath ) where
30+module Text.Pandoc.Readers.TeXMath ( readTeXMath, readTeXMath' ) where
3131
3232import Text.Pandoc.Definition
33−import Text.TeXMath.Types
34−import Text.TeXMath.Parser
33+import Text.TeXMath
3534
3635-- | Converts a raw TeX math formula to a list of 'Pandoc' inlines.
37−-- Defaults to raw formula between @$@ characters if entire formula
36+-- Defaults to raw formula between @$@ or @$$@ characters if entire formula
3837-- can't be converted.
38+readTeXMath' :: MathType
39+ -> String -- ^ String to parse (assumes @'\n'@ line endings)
40+ -> [Inline]
41+readTeXMath' mt inp = case texMathToPandoc dt inp of
42+ Left _ -> [Str (delim ++ inp ++ delim)]
43+ Right res -> res
44+ where (dt, delim) = case mt of
45+ DisplayMath -> (DisplayBlock, "$$")
46+ InlineMath -> (DisplayInline, "$")
47+
48+{-# DEPRECATED readTeXMath "Use readTeXMath' from Text.Pandoc.JSON instead" #-}
49+-- | Converts a raw TeX math formula to a list of 'Pandoc' inlines.
50+-- Defaults to raw formula between @$@ characters if entire formula
51+-- can't be converted. (This is provided for backwards compatibility;
52+-- it is better to use @readTeXMath'@, which properly distinguishes
53+-- between display and inline math.)
3954readTeXMath :: String -- ^ String to parse (assumes @'\n'@ line endings)
4055 -> [Inline]
41−readTeXMath inp = case texMathToPandoc inp of
42− Left _ -> [Str ("$" ++ inp ++ "$")]
43− Right res -> res
44−
45−texMathToPandoc :: String -> Either String [Inline]
46−texMathToPandoc inp = inp `seq`
47− case parseFormula inp of
48− Left err -> Left err
49− Right exps -> case expsToInlines exps of
50− Nothing -> Left "Formula too complex for [Inline]"
51− Just r -> Right r
52−
53−expsToInlines :: [Exp] -> Maybe [Inline]
54−expsToInlines xs = do
55− res <- mapM expToInlines xs
56− return (concat res)
57−
58−expToInlines :: Exp -> Maybe [Inline]
59−expToInlines (ENumber s) = Just [Str s]
60−expToInlines (EIdentifier s) = Just [Emph [Str s]]
61−expToInlines (EMathOperator s) = Just [Str s]
62−expToInlines (ESymbol t s) = Just $ addSpace t (Str s)
63− where addSpace Op x = [x, thinspace]
64− addSpace Bin x = [medspace, x, medspace]
65− addSpace Rel x = [widespace, x, widespace]
66− addSpace Pun x = [x, thinspace]
67− addSpace _ x = [x]
68− thinspace = Str "\x2006"
69− medspace = Str "\x2005"
70− widespace = Str "\x2004"
71−expToInlines (EStretchy x) = expToInlines x
72−expToInlines (EDelimited start end xs) = do
73− xs' <- mapM expToInlines xs
74− return $ [Str start] ++ concat xs' ++ [Str end]
75−expToInlines (EGrouped xs) = expsToInlines xs
76−expToInlines (ESpace "0.167em") = Just [Str "\x2009"]
77−expToInlines (ESpace "0.222em") = Just [Str "\x2005"]
78−expToInlines (ESpace "0.278em") = Just [Str "\x2004"]
79−expToInlines (ESpace "0.333em") = Just [Str "\x2004"]
80−expToInlines (ESpace "1em") = Just [Str "\x2001"]
81−expToInlines (ESpace "2em") = Just [Str "\x2001\x2001"]
82−expToInlines (ESpace _) = Just [Str " "]
83−expToInlines (EBinary _ _ _) = Nothing
84−expToInlines (ESub x y) = do
85− x' <- expToInlines x
86− y' <- expToInlines y
87− return $ x' ++ [Subscript y']
88−expToInlines (ESuper x y) = do
89− x' <- expToInlines x
90− y' <- expToInlines y
91− return $ x' ++ [Superscript y']
92−expToInlines (ESubsup x y z) = do
93− x' <- expToInlines x
94− y' <- expToInlines y
95− z' <- expToInlines z
96− return $ x' ++ [Subscript y'] ++ [Superscript z']
97−expToInlines (EDown x y) = expToInlines (ESub x y)
98−expToInlines (EUp x y) = expToInlines (ESuper x y)
99−expToInlines (EDownup x y z) = expToInlines (ESubsup x y z)
100−expToInlines (EText TextNormal x) = Just [Str x]
101−expToInlines (EText TextBold x) = Just [Strong [Str x]]
102−expToInlines (EText TextMonospace x) = Just [Code nullAttr x]
103−expToInlines (EText TextItalic x) = Just [Emph [Str x]]
104−expToInlines (EText _ x) = Just [Str x]
105−expToInlines (EOver (EGrouped [EIdentifier [c]]) (ESymbol Accent [accent])) =
106− case accent of
107− '\x203E' -> Just [Emph [Str [c,'\x0304']]] -- bar
108− '\x00B4' -> Just [Emph [Str [c,'\x0301']]] -- acute
109− '\x0060' -> Just [Emph [Str [c,'\x0300']]] -- grave
110− '\x02D8' -> Just [Emph [Str [c,'\x0306']]] -- breve
111− '\x02C7' -> Just [Emph [Str [c,'\x030C']]] -- check
112− '.' -> Just [Emph [Str [c,'\x0307']]] -- dot
113− '\x00B0' -> Just [Emph [Str [c,'\x030A']]] -- ring
114− '\x20D7' -> Just [Emph [Str [c,'\x20D7']]] -- arrow right
115− '\x20D6' -> Just [Emph [Str [c,'\x20D6']]] -- arrow left
116− '\x005E' -> Just [Emph [Str [c,'\x0302']]] -- hat
117− '\x0302' -> Just [Emph [Str [c,'\x0302']]] -- hat
118− '~' -> Just [Emph [Str [c,'\x0303']]] -- tilde
119− _ -> Nothing
120−expToInlines _ = Nothing
121−
122−
56+readTeXMath = readTeXMath' InlineMath
src/Text/Pandoc/Readers/Textile.hs+203−161
@@ -1,5 +1,6 @@
11{-
2−Copyright (C) 2010 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
2+Copyright (C) 2010-2014 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
3+ and John MacFarlane
34
45This program is free software; you can redistribute it and/or modify
56it 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
1819
1920{- |
2021 Module : Text.Pandoc.Readers.Textile
21− Copyright : Copyright (C) 2010-2012 Paul Rivier and John MacFarlane
22+ Copyright : Copyright (C) 2010-2014 Paul Rivier and John MacFarlane
2223 License : GNU GPL, version 2 or above
2324
2425 Maintainer : Paul Rivier <paul*rivier#demotera*com>
@@ -50,18 +51,22 @@ TODO : refactor common patterns across readers :
5051
5152
5253module Text.Pandoc.Readers.Textile ( readTextile) where
53−
5454import Text.Pandoc.Definition
55−import Text.Pandoc.Shared
55+import Text.Pandoc.Builder (Inlines, Blocks, trimInlines)
56+import qualified Text.Pandoc.Builder as B
5657import Text.Pandoc.Options
5758import Text.Pandoc.Parsing
5859import Text.Pandoc.Readers.HTML ( htmlTag, isInlineTag, isBlockTag )
5960import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXBlock )
61+import Text.HTML.TagSoup (parseTags, innerText, fromAttrib, Tag(..))
6062import Text.HTML.TagSoup.Match
6163import Data.List ( intercalate )
62−import Data.Char ( digitToInt, isUpper )
63−import Control.Monad ( guard, liftM )
64−import Control.Applicative ((<$>), (*>), (<*))
64+import Data.Char ( digitToInt, isUpper)
65+import Control.Monad ( guard, liftM, when )
66+import Text.Printf
67+import Control.Applicative ((<$>), (*>), (<*), (<$))
68+import Data.Monoid
69+import Debug.Trace (trace)
6570
6671-- | Parse a Textile text and return a Pandoc document.
6772readTextile :: ReaderOptions -- ^ Reader options
@@ -93,7 +98,7 @@ parseTextile = do
9398 updateState $ \s -> s { stateNotes = reverse reversedNotes }
9499 -- now parse it for real...
95100 blocks <- parseBlocks
96− return $ Pandoc nullMeta blocks -- FIXME
101+ return $ Pandoc nullMeta (B.toList blocks) -- FIXME
97102
98103noteMarker :: Parser [Char] ParserState [Char]
99104noteMarker = skipMany spaceChar >> string "fn" >> manyTill digit (char '.')
@@ -113,11 +118,11 @@ noteBlock = try $ do
113118 return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
114119
115120-- | Parse document blocks
116−parseBlocks :: Parser [Char] ParserState [Block]
117−parseBlocks = manyTill block eof
121+parseBlocks :: Parser [Char] ParserState Blocks
122+parseBlocks = mconcat <$> manyTill block eof
118123
119124-- | Block parsers list tried in definition order
120−blockParsers :: [Parser [Char] ParserState Block]
125+blockParsers :: [Parser [Char] ParserState Blocks]
121126blockParsers = [ codeBlock
122127 , header
123128 , blockQuote
@@ -128,32 +133,45 @@ blockParsers = [ codeBlock
128133 , rawLaTeXBlock'
129134 , maybeExplicitBlock "table" table
130135 , maybeExplicitBlock "p" para
136+ , endBlock
131137 ]
132138
133−-- | Any block in the order of definition of blockParsers
134−block :: Parser [Char] ParserState Block
135−block = choice blockParsers <?> "block"
139+endBlock :: Parser [Char] ParserState Blocks
140+endBlock = string "\n\n" >> return mempty
136141
137−commentBlock :: Parser [Char] ParserState Block
142+-- | Any block in the order of definition of blockParsers
143+block :: Parser [Char] ParserState Blocks
144+block = do
145+ res <- choice blockParsers <?> "block"
146+ pos <- getPosition
147+ tr <- getOption readerTrace
148+ when tr $
149+ trace (printf "line %d: %s" (sourceLine pos)
150+ (take 60 $ show $ B.toList res)) (return ())
151+ return res
152+
153+commentBlock :: Parser [Char] ParserState Blocks
138154commentBlock = try $ do
139155 string "###."
140156 manyTill anyLine blanklines
141− return Null
157+ return mempty
142158
143−codeBlock :: Parser [Char] ParserState Block
159+codeBlock :: Parser [Char] ParserState Blocks
144160codeBlock = codeBlockBc <|> codeBlockPre
145161
146−codeBlockBc :: Parser [Char] ParserState Block
162+codeBlockBc :: Parser [Char] ParserState Blocks
147163codeBlockBc = try $ do
148164 string "bc. "
149165 contents <- manyTill anyLine blanklines
150− return $ CodeBlock ("",[],[]) $ unlines contents
166+ return $ B.codeBlock (unlines contents)
151167
152168-- | Code Blocks in Textile are between <pre> and </pre>
153−codeBlockPre :: Parser [Char] ParserState Block
169+codeBlockPre :: Parser [Char] ParserState Blocks
154170codeBlockPre = try $ do
155− htmlTag (tagOpen (=="pre") null)
156− result' <- manyTill anyChar (try $ htmlTag (tagClose (=="pre")) >> blockBreak)
171+ (t@(TagOpen _ attrs),_) <- htmlTag (tagOpen (=="pre") (const True))
172+ result' <- (innerText . parseTags) `fmap` -- remove internal tags
173+ manyTill anyChar (htmlTag (tagClose (=="pre")))
174+ optional blanklines
157175 -- drop leading newline if any
158176 let result'' = case result' of
159177 '\n':xs -> xs
@@ -162,28 +180,32 @@ codeBlockPre = try $ do
162180 let result''' = case reverse result'' of
163181 '\n':_ -> init result''
164182 _ -> result''
165− return $ CodeBlock ("",[],[]) result'''
183+ let classes = words $ fromAttrib "class" t
184+ let ident = fromAttrib "id" t
185+ let kvs = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
186+ return $ B.codeBlockWith (ident,classes,kvs) result'''
166187
167188-- | Header of the form "hN. content" with N in 1..6
168−header :: Parser [Char] ParserState Block
189+header :: Parser [Char] ParserState Blocks
169190header = try $ do
170191 char 'h'
171192 level <- digitToInt <$> oneOf "123456"
172193 attr <- attributes
173194 char '.'
174− whitespace
175− name <- normalizeSpaces <$> manyTill inline blockBreak
176− return $ Header level attr name
195+ lookAhead whitespace
196+ name <- trimInlines . mconcat <$> manyTill inline blockBreak
197+ attr' <- registerHeader attr name
198+ return $ B.headerWith attr' level name
177199
178200-- | Blockquote of the form "bq. content"
179−blockQuote :: Parser [Char] ParserState Block
201+blockQuote :: Parser [Char] ParserState Blocks
180202blockQuote = try $ do
181203 string "bq" >> attributes >> char '.' >> whitespace
182− BlockQuote . singleton <$> para
204+ B.blockQuote <$> para
183205
184206-- Horizontal rule
185207
186−hrule :: Parser [Char] st Block
208+hrule :: Parser [Char] st Blocks
187209hrule = try $ do
188210 skipSpaces
189211 start <- oneOf "-*"
@@ -191,62 +213,62 @@ hrule = try $ do
191213 skipMany (spaceChar <|> char start)
192214 newline
193215 optional blanklines
194− return HorizontalRule
216+ return B.horizontalRule
195217
196218-- Lists handling
197219
198220-- | Can be a bullet list or an ordered list. This implementation is
199221-- strict in the nesting, sublist must start at exactly "parent depth
200222-- plus one"
201−anyList :: Parser [Char] ParserState Block
223+anyList :: Parser [Char] ParserState Blocks
202224anyList = try $ anyListAtDepth 1 <* blanklines
203225
204226-- | This allow one type of list to be nested into an other type,
205227-- provided correct nesting
206−anyListAtDepth :: Int -> Parser [Char] ParserState Block
228+anyListAtDepth :: Int -> Parser [Char] ParserState Blocks
207229anyListAtDepth depth = choice [ bulletListAtDepth depth,
208230 orderedListAtDepth depth,
209231 definitionList ]
210232
211233-- | Bullet List of given depth, depth being the number of leading '*'
212−bulletListAtDepth :: Int -> Parser [Char] ParserState Block
213−bulletListAtDepth depth = try $ BulletList <$> many1 (bulletListItemAtDepth depth)
234+bulletListAtDepth :: Int -> Parser [Char] ParserState Blocks
235+bulletListAtDepth depth = try $ B.bulletList <$> many1 (bulletListItemAtDepth depth)
214236
215237-- | Bullet List Item of given depth, depth being the number of
216238-- leading '*'
217−bulletListItemAtDepth :: Int -> Parser [Char] ParserState [Block]
239+bulletListItemAtDepth :: Int -> Parser [Char] ParserState Blocks
218240bulletListItemAtDepth = genericListItemAtDepth '*'
219241
220242-- | Ordered List of given depth, depth being the number of
221243-- leading '#'
222−orderedListAtDepth :: Int -> Parser [Char] ParserState Block
244+orderedListAtDepth :: Int -> Parser [Char] ParserState Blocks
223245orderedListAtDepth depth = try $ do
224246 items <- many1 (orderedListItemAtDepth depth)
225− return (OrderedList (1, DefaultStyle, DefaultDelim) items)
247+ return $ B.orderedList items
226248
227249-- | Ordered List Item of given depth, depth being the number of
228250-- leading '#'
229−orderedListItemAtDepth :: Int -> Parser [Char] ParserState [Block]
251+orderedListItemAtDepth :: Int -> Parser [Char] ParserState Blocks
230252orderedListItemAtDepth = genericListItemAtDepth '#'
231253
232254-- | Common implementation of list items
233−genericListItemAtDepth :: Char -> Int -> Parser [Char] ParserState [Block]
255+genericListItemAtDepth :: Char -> Int -> Parser [Char] ParserState Blocks
234256genericListItemAtDepth c depth = try $ do
235257 count depth (char c) >> attributes >> whitespace
236− p <- many listInline
258+ p <- mconcat <$> many listInline
237259 newline
238− sublist <- option [] (singleton <$> anyListAtDepth (depth + 1))
239− return (Plain p : sublist)
260+ sublist <- option mempty (anyListAtDepth (depth + 1))
261+ return $ (B.plain p) <> sublist
240262
241263-- | A definition list is a set of consecutive definition items
242−definitionList :: Parser [Char] ParserState Block
243−definitionList = try $ DefinitionList <$> many1 definitionListItem
264+definitionList :: Parser [Char] ParserState Blocks
265+definitionList = try $ B.definitionList <$> many1 definitionListItem
244266
245267-- | List start character.
246268listStart :: Parser [Char] st Char
247269listStart = oneOf "*#-"
248270
249−listInline :: Parser [Char] ParserState Inline
271+listInline :: Parser [Char] ParserState Inlines
250272listInline = try (notFollowedBy newline >> inline)
251273 <|> try (endline <* notFollowedBy listStart)
252274
@@ -254,16 +276,16 @@ listInline = try (notFollowedBy newline >> inline)
254276-- the term defined, then spaces and ":=". The definition follows, on
255277-- the same single line, or spaned on multiple line, after a line
256278-- break.
257−definitionListItem :: Parser [Char] ParserState ([Inline], [[Block]])
279+definitionListItem :: Parser [Char] ParserState (Inlines, [Blocks])
258280definitionListItem = try $ do
259281 string "- "
260− term <- many1Till inline (try (whitespace >> string ":="))
282+ term <- mconcat <$> many1Till inline (try (whitespace >> string ":="))
261283 def' <- multilineDef <|> inlineDef
262284 return (term, def')
263− where inlineDef :: Parser [Char] ParserState [[Block]]
264− inlineDef = liftM (\d -> [[Plain d]])
265− $ optional whitespace >> many listInline <* newline
266− multilineDef :: Parser [Char] ParserState [[Block]]
285+ where inlineDef :: Parser [Char] ParserState [Blocks]
286+ inlineDef = liftM (\d -> [B.plain d])
287+ $ optional whitespace >> (trimInlines . mconcat <$> many listInline) <* newline
288+ multilineDef :: Parser [Char] ParserState [Blocks]
267289 multilineDef = try $ do
268290 optional whitespace >> newline
269291 s <- many1Till anyChar (try (string "=:" >> newline))
@@ -275,64 +297,62 @@ definitionListItem = try $ do
275297-- blocks support, we have to lookAhead for a rawHtmlBlock.
276298blockBreak :: Parser [Char] ParserState ()
277299blockBreak = try (newline >> blanklines >> return ()) <|>
278− (lookAhead rawHtmlBlock >> return ())
300+ try (optional spaces >> lookAhead rawHtmlBlock >> return ())
279301
280302-- raw content
281303
282304-- | A raw Html Block, optionally followed by blanklines
283−rawHtmlBlock :: Parser [Char] ParserState Block
305+rawHtmlBlock :: Parser [Char] ParserState Blocks
284306rawHtmlBlock = try $ do
285307 (_,b) <- htmlTag isBlockTag
286308 optional blanklines
287− return $ RawBlock "html" b
309+ return $ B.rawBlock "html" b
288310
289311-- | Raw block of LaTeX content
290−rawLaTeXBlock' :: Parser [Char] ParserState Block
312+rawLaTeXBlock' :: Parser [Char] ParserState Blocks
291313rawLaTeXBlock' = do
292314 guardEnabled Ext_raw_tex
293− RawBlock "latex" <$> (rawLaTeXBlock <* spaces)
315+ B.rawBlock "latex" <$> (rawLaTeXBlock <* spaces)
294316
295317
296318-- | In textile, paragraphs are separated by blank lines.
297−para :: Parser [Char] ParserState Block
298−para = try $ Para . normalizeSpaces <$> manyTill inline blockBreak
299−
319+para :: Parser [Char] ParserState Blocks
320+para = B.para . trimInlines . mconcat <$> manyTill inline blockBreak
300321
301322-- Tables
302323
303324-- | A table cell spans until a pipe |
304−tableCell :: Parser [Char] ParserState TableCell
325+tableCell :: Parser [Char] ParserState Blocks
305326tableCell = do
306327 c <- many1 (noneOf "|\n")
307− content <- parseFromString (many1 inline) c
308− return $ [ Plain $ normalizeSpaces content ]
328+ content <- trimInlines . mconcat <$> parseFromString (many1 inline) c
329+ return $ B.plain content
309330
310331-- | A table row is made of many table cells
311−tableRow :: Parser [Char] ParserState [TableCell]
332+tableRow :: Parser [Char] ParserState [Blocks]
312333tableRow = try $ ( char '|' *>
313334 (endBy1 tableCell (optional blankline *> char '|')) <* newline)
314335
315336-- | Many table rows
316−tableRows :: Parser [Char] ParserState [[TableCell]]
337+tableRows :: Parser [Char] ParserState [[Blocks]]
317338tableRows = many1 tableRow
318339
319340-- | Table headers are made of cells separated by a tag "|_."
320−tableHeaders :: Parser [Char] ParserState [TableCell]
341+tableHeaders :: Parser [Char] ParserState [Blocks]
321342tableHeaders = let separator = (try $ string "|_.") in
322343 try $ ( separator *> (sepBy1 tableCell separator) <* char '|' <* newline )
323344
324345-- | A table with an optional header. Current implementation can
325346-- handle tables with and without header, but will parse cells
326347-- alignment attributes as content.
327−table :: Parser [Char] ParserState Block
348+table :: Parser [Char] ParserState Blocks
328349table = try $ do
329− headers <- option [] tableHeaders
350+ headers <- option mempty tableHeaders
330351 rows <- tableRows
331352 blanklines
332353 let nbOfCols = max (length headers) (length $ head rows)
333− return $ Table []
334− (replicate nbOfCols AlignDefault)
335− (replicate nbOfCols 0.0)
354+ return $ B.table mempty
355+ (zip (replicate nbOfCols AlignDefault) (replicate nbOfCols 0.0))
336356 headers
337357 rows
338358
@@ -340,8 +360,8 @@ table = try $ do
340360-- | Blocks like 'p' and 'table' do not need explicit block tag.
341361-- However, they can be used to set HTML/CSS attributes when needed.
342362maybeExplicitBlock :: String -- ^ block tag name
343− -> Parser [Char] ParserState Block -- ^ implicit block
344− -> Parser [Char] ParserState Block
363+ -> Parser [Char] ParserState Blocks -- ^ implicit block
364+ -> Parser [Char] ParserState Blocks
345365maybeExplicitBlock name blk = try $ do
346366 optional $ try $ string name >> attributes >> char '.' >>
347367 optional whitespace >> optional endline
@@ -355,73 +375,74 @@ maybeExplicitBlock name blk = try $ do
355375
356376
357377-- | Any inline element
358−inline :: Parser [Char] ParserState Inline
359−inline = choice inlineParsers <?> "inline"
378+inline :: Parser [Char] ParserState Inlines
379+inline = do
380+ choice inlineParsers <?> "inline"
360381
361382-- | Inline parsers tried in order
362−inlineParsers :: [Parser [Char] ParserState Inline]
383+inlineParsers :: [Parser [Char] ParserState Inlines]
363384inlineParsers = [ str
364385 , whitespace
365386 , endline
366387 , code
367388 , escapedInline
368− , htmlSpan
389+ , inlineMarkup
390+ , groupedInlineMarkup
369391 , rawHtmlInline
370392 , rawLaTeXInline'
371393 , note
372− , try $ (char '[' *> inlineMarkup <* char ']')
373− , inlineMarkup
374394 , link
375395 , image
376396 , mark
377− , (Str . (:[])) <$> characterReference
397+ , (B.str . (:[])) <$> characterReference
378398 , smartPunctuation inline
379399 , symbol
380400 ]
381401
382402-- | Inline markups
383−inlineMarkup :: Parser [Char] ParserState Inline
384−inlineMarkup = choice [ simpleInline (string "??") (Cite [])
385− , simpleInline (string "**") Strong
386− , simpleInline (string "__") Emph
387− , simpleInline (char '*') Strong
388− , simpleInline (char '_') Emph
389− , simpleInline (char '+') Emph -- approximates underline
390− , simpleInline (char '-' <* notFollowedBy (char '-')) Strikeout
391− , simpleInline (char '^') Superscript
392− , simpleInline (char '~') Subscript
403+inlineMarkup :: Parser [Char] ParserState Inlines
404+inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
405+ , simpleInline (string "**") B.strong
406+ , simpleInline (string "__") B.emph
407+ , simpleInline (char '*') B.strong
408+ , simpleInline (char '_') B.emph
409+ , simpleInline (char '+') B.emph -- approximates underline
410+ , simpleInline (char '-' <* notFollowedBy (char '-')) B.strikeout
411+ , simpleInline (char '^') B.superscript
412+ , simpleInline (char '~') B.subscript
413+ , simpleInline (char '%') id
393414 ]
394415
395416-- | Trademark, registered, copyright
396−mark :: Parser [Char] st Inline
417+mark :: Parser [Char] st Inlines
397418mark = try $ char '(' >> (try tm <|> try reg <|> copy)
398419
399−reg :: Parser [Char] st Inline
420+reg :: Parser [Char] st Inlines
400421reg = do
401422 oneOf "Rr"
402423 char ')'
403− return $ Str "\174"
424+ return $ B.str "\174"
404425
405−tm :: Parser [Char] st Inline
426+tm :: Parser [Char] st Inlines
406427tm = do
407428 oneOf "Tt"
408429 oneOf "Mm"
409430 char ')'
410− return $ Str "\8482"
431+ return $ B.str "\8482"
411432
412−copy :: Parser [Char] st Inline
433+copy :: Parser [Char] st Inlines
413434copy = do
414435 oneOf "Cc"
415436 char ')'
416− return $ Str "\169"
437+ return $ B.str "\169"
417438
418−note :: Parser [Char] ParserState Inline
439+note :: Parser [Char] ParserState Inlines
419440note = try $ do
420441 ref <- (char '[' *> many1 digit <* char ']')
421442 notes <- stateNotes <$> getState
422443 case lookup ref notes of
423444 Nothing -> fail "note not found"
424− Just raw -> liftM Note $ parseFromString parseBlocks raw
445+ Just raw -> B.note <$> parseFromString parseBlocks raw
425446
426447-- | Special chars
427448markupChars :: [Char]
@@ -442,7 +463,7 @@ wordBoundaries = markupChars ++ stringBreakers
442463hyphenedWords :: Parser [Char] ParserState String
443464hyphenedWords = do
444465 x <- wordChunk
445− xs <- many (try $ char '-' >> wordChunk)
466+ xs <- many (try $ char '-' >> wordChunk)
446467 return $ intercalate "-" (x:xs)
447468
448469wordChunk :: Parser [Char] ParserState String
@@ -454,99 +475,99 @@ wordChunk = try $ do
454475 return $ hd:tl
455476
456477-- | Any string
457−str :: Parser [Char] ParserState Inline
478+str :: Parser [Char] ParserState Inlines
458479str = do
459480 baseStr <- hyphenedWords
460481 -- RedCloth compliance : if parsed word is uppercase and immediatly
461482 -- followed by parens, parens content is unconditionally word acronym
462483 fullStr <- option baseStr $ try $ do
463484 guard $ all isUpper baseStr
464− acro <- enclosed (char '(') (char ')') anyChar
485+ acro <- enclosed (char '(') (char ')') anyChar'
465486 return $ concat [baseStr, " (", acro, ")"]
466487 updateLastStrPos
467− return $ Str fullStr
468−
469−-- | Textile allows HTML span infos, we discard them
470−htmlSpan :: Parser [Char] ParserState Inline
471−htmlSpan = try $ Str <$> ( char '%' *> attributes *> manyTill anyChar (char '%') )
488+ return $ B.str fullStr
472489
473490-- | Some number of space chars
474−whitespace :: Parser [Char] ParserState Inline
475−whitespace = many1 spaceChar >> return Space <?> "whitespace"
491+whitespace :: Parser [Char] ParserState Inlines
492+whitespace = many1 spaceChar >> return B.space <?> "whitespace"
476493
477494-- | In Textile, an isolated endline character is a line break
478−endline :: Parser [Char] ParserState Inline
495+endline :: Parser [Char] ParserState Inlines
479496endline = try $ do
480497 newline >> notFollowedBy blankline
481− return LineBreak
498+ return B.linebreak
482499
483−rawHtmlInline :: Parser [Char] ParserState Inline
484−rawHtmlInline = RawInline "html" . snd <$> htmlTag isInlineTag
500+rawHtmlInline :: Parser [Char] ParserState Inlines
501+rawHtmlInline = B.rawInline "html" . snd <$> htmlTag isInlineTag
485502
486503-- | Raw LaTeX Inline
487−rawLaTeXInline' :: Parser [Char] ParserState Inline
504+rawLaTeXInline' :: Parser [Char] ParserState Inlines
488505rawLaTeXInline' = try $ do
489506 guardEnabled Ext_raw_tex
490− rawLaTeXInline
507+ B.singleton <$> rawLaTeXInline
491508
492509-- | Textile standard link syntax is "label":target. But we
493510-- can also have ["label":target].
494−link :: Parser [Char] ParserState Inline
495−link = linkB <|> linkNoB
496−
497−linkNoB :: Parser [Char] ParserState Inline
498−linkNoB = try $ do
499− name <- surrounded (char '"') inline
500− char ':'
501− let stopChars = "!.,;:"
502− url <- manyTill nonspaceChar (lookAhead $ space <|> try (oneOf stopChars >> (space <|> newline)))
503− let name' = if name == [Str "$"] then [Str url] else name
504− return $ Link name' (url, "")
505−
506−linkB :: Parser [Char] ParserState Inline
507−linkB = try $ do
508− char '['
509− name <- surrounded (char '"') inline
511+link :: Parser [Char] ParserState Inlines
512+link = try $ do
513+ bracketed <- (True <$ char '[') <|> return False
514+ char '"' *> notFollowedBy (oneOf " \t\n\r")
515+ attr <- attributes
516+ name <- trimInlines . mconcat <$>
517+ withQuoteContext InDoubleQuote (many1Till inline (char '"'))
510518 char ':'
511− url <- manyTill nonspaceChar (char ']')
512− let name' = if name == [Str "$"] then [Str url] else name
513− return $ Link name' (url, "")
519+ let stop = if bracketed
520+ then char ']'
521+ else lookAhead $ space <|>
522+ try (oneOf "!.,;:" *> (space <|> newline))
523+ url <- manyTill nonspaceChar stop
524+ let name' = if B.toList name == [Str "$"] then B.str url else name
525+ return $ if attr == nullAttr
526+ then B.link url "" name'
527+ else B.spanWith attr $ B.link url "" name'
514528
515529-- | image embedding
516−image :: Parser [Char] ParserState Inline
530+image :: Parser [Char] ParserState Inlines
517531image = try $ do
518532 char '!' >> notFollowedBy space
519− src <- manyTill anyChar (lookAhead $ oneOf "!(")
520− alt <- option "" (try $ (char '(' >> manyTill anyChar (char ')')))
533+ src <- manyTill anyChar' (lookAhead $ oneOf "!(")
534+ alt <- option "" (try $ (char '(' >> manyTill anyChar' (char ')')))
521535 char '!'
522− return $ Image [Str alt] (src, alt)
536+ return $ B.image src alt (B.str alt)
523537
524−escapedInline :: Parser [Char] ParserState Inline
538+escapedInline :: Parser [Char] ParserState Inlines
525539escapedInline = escapedEqs <|> escapedTag
526540
527−escapedEqs :: Parser [Char] ParserState Inline
528−escapedEqs = Str <$> (try $ string "==" *> manyTill anyChar (try $ string "=="))
541+escapedEqs :: Parser [Char] ParserState Inlines
542+escapedEqs = B.str <$>
543+ (try $ string "==" *> manyTill anyChar' (try $ string "=="))
529544
530545-- | literal text escaped btw <notextile> tags
531−escapedTag :: Parser [Char] ParserState Inline
532−escapedTag = Str <$>
533− (try $ string "<notextile>" *> manyTill anyChar (try $ string "</notextile>"))
546+escapedTag :: Parser [Char] ParserState Inlines
547+escapedTag = B.str <$>
548+ (try $ string "<notextile>" *>
549+ manyTill anyChar' (try $ string "</notextile>"))
534550
535551-- | Any special symbol defined in wordBoundaries
536−symbol :: Parser [Char] ParserState Inline
537−symbol = Str . singleton <$> (oneOf wordBoundaries <|> oneOf markupChars)
552+symbol :: Parser [Char] ParserState Inlines
553+symbol = B.str . singleton <$> (oneOf wordBoundaries <|> oneOf markupChars)
538554
539555-- | Inline code
540−code :: Parser [Char] ParserState Inline
556+code :: Parser [Char] ParserState Inlines
541557code = code1 <|> code2
542558
543−code1 :: Parser [Char] ParserState Inline
544−code1 = Code nullAttr <$> surrounded (char '@') anyChar
559+-- any character except a newline before a blank line
560+anyChar' :: Parser [Char] ParserState Char
561+anyChar' =
562+ satisfy (/='\n') <|> (try $ char '\n' <* notFollowedBy blankline)
563+
564+code1 :: Parser [Char] ParserState Inlines
565+code1 = B.code <$> surrounded (char '@') anyChar'
545566
546−code2 :: Parser [Char] ParserState Inline
567+code2 :: Parser [Char] ParserState Inlines
547568code2 = do
548569 htmlTag (tagOpen (=="tt") null)
549− Code nullAttr <$> manyTill anyChar (try $ htmlTag $ tagClose (=="tt"))
570+ B.code <$> manyTill anyChar' (try $ htmlTag $ tagClose (=="tt"))
550571
551572-- | Html / CSS attributes
552573attributes :: Parser [Char] ParserState Attr
@@ -558,7 +579,7 @@ attribute = classIdAttr <|> styleAttr <|> langAttr
558579classIdAttr :: Parser [Char] ParserState (Attr -> Attr)
559580classIdAttr = try $ do -- (class class #id)
560581 char '('
561− ws <- words `fmap` manyTill anyChar (char ')')
582+ ws <- words `fmap` manyTill anyChar' (char ')')
562583 case reverse ws of
563584 [] -> return $ \(_,_,keyvals) -> ("",[],keyvals)
564585 (('#':ident'):classes') -> return $ \(_,_,keyvals) ->
@@ -568,28 +589,49 @@ classIdAttr = try $ do -- (class class #id)
568589
569590styleAttr :: Parser [Char] ParserState (Attr -> Attr)
570591styleAttr = do
571− style <- try $ enclosed (char '{') (char '}') anyChar
592+ style <- try $ enclosed (char '{') (char '}') anyChar'
572593 return $ \(id',classes,keyvals) -> (id',classes,("style",style):keyvals)
573594
574595langAttr :: Parser [Char] ParserState (Attr -> Attr)
575596langAttr = do
576− lang <- try $ enclosed (char '[') (char ']') anyChar
597+ lang <- try $ enclosed (char '[') (char ']') alphaNum
577598 return $ \(id',classes,keyvals) -> (id',classes,("lang",lang):keyvals)
578599
579600-- | Parses material surrounded by a parser.
580601surrounded :: Parser [Char] st t -- ^ surrounding parser
581602 -> Parser [Char] st a -- ^ content parser (to be used repeatedly)
582603 -> Parser [Char] st [a]
583−surrounded border = enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
604+surrounded border =
605+ enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
584606
585−-- | Inlines are most of the time of the same form
586607simpleInline :: Parser [Char] ParserState t -- ^ surrounding parser
587− -> ([Inline] -> Inline) -- ^ Inline constructor
588− -> Parser [Char] ParserState Inline -- ^ content parser (to be used repeatedly)
589−simpleInline border construct = surrounded border (inlineWithAttribute) >>=
590− return . construct . normalizeSpaces
591− where inlineWithAttribute = (try $ optional attributes) >> inline
608+ -> (Inlines -> Inlines) -- ^ Inline constructor
609+ -> Parser [Char] ParserState Inlines -- ^ content parser (to be used repeatedly)
610+simpleInline border construct = try $ do
611+ st <- getState
612+ pos <- getPosition
613+ let afterString = stateLastStrPos st == Just pos
614+ guard $ not afterString
615+ border *> notFollowedBy (oneOf " \t\n\r")
616+ attr <- attributes
617+ body <- trimInlines . mconcat <$>
618+ withQuoteContext InSingleQuote
619+ (manyTill inline (try border <* notFollowedBy alphaNum))
620+ return $ construct $
621+ if attr == nullAttr
622+ then body
623+ else B.spanWith attr body
624+
625+groupedInlineMarkup :: Parser [Char] ParserState Inlines
626+groupedInlineMarkup = try $ do
627+ char '['
628+ sp1 <- option mempty $ B.space <$ whitespace
629+ result <- withQuoteContext InSingleQuote inlineMarkup
630+ sp2 <- option mempty $ B.space <$ whitespace
631+ char ']'
632+ return $ sp1 <> result <> sp2
592633
593634-- | Create a singleton list
594635singleton :: a -> [a]
595636singleton x = [x]
637+
src/Text/Pandoc/SelfContained.hs+18−15
@@ -1,6 +1,6 @@
11{-# LANGUAGE OverloadedStrings #-}
22{-
3−Copyright (C) 2011 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2011-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Text.Pandoc.SelfContained
22− Copyright : Copyright (C) 2011 John MacFarlane
22+ Copyright : Copyright (C) 2011-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -32,7 +32,7 @@ the HTML using data URIs.
3232-}
3333module Text.Pandoc.SelfContained ( makeSelfContained ) where
3434import Text.HTML.TagSoup
35−import Network.URI (isAbsoluteURI, escapeURIString)
35+import Network.URI (isURI, escapeURIString)
3636import Data.ByteString.Base64
3737import qualified Data.ByteString.Char8 as B
3838import Data.ByteString (ByteString)
@@ -40,7 +40,7 @@ import System.FilePath (takeExtension, dropExtension, takeDirectory, (</>))
4040import Data.Char (toLower, isAscii, isAlphaNum)
4141import Codec.Compression.GZip as Gzip
4242import qualified Data.ByteString.Lazy as L
43−import Text.Pandoc.Shared (renderTags', openURL, readDataFile)
43+import Text.Pandoc.Shared (renderTags', openURL, readDataFile, err)
4444import Text.Pandoc.UTF8 (toString, fromString)
4545import Text.Pandoc.MIME (getMimeType)
4646import System.Directory (doesFileExist)
@@ -50,14 +50,16 @@ isOk c = isAscii c && isAlphaNum c
5050
5151convertTag :: Maybe FilePath -> Tag String -> IO (Tag String)
5252convertTag userdata t@(TagOpen tagname as)
53− | tagname `elem` ["img", "embed", "video", "input", "audio", "source"] =
54− case fromAttrib "src" t of
55− [] -> return t
56− src -> do
57− (raw, mime) <- getRaw userdata (fromAttrib "type" t) src
58− let enc = "data:" ++ mime ++ ";base64," ++ toString (encode raw)
59− return $ TagOpen tagname
60− (("src",enc) : [(x,y) | (x,y) <- as, x /= "src"])
53+ | tagname `elem` ["img", "embed", "video", "input", "audio", "source"] = do
54+ as' <- mapM processAttribute as
55+ return $ TagOpen tagname as'
56+ where processAttribute (x,y) =
57+ if x == "src" || x == "href" || x == "poster"
58+ then do
59+ (raw, mime) <- getRaw userdata (fromAttrib "type" t) y
60+ let enc = "data:" ++ mime ++ ";base64," ++ toString (encode raw)
61+ return (x, enc)
62+ else return (x,y)
6163convertTag userdata t@(TagOpen "script" as) =
6264 case fromAttrib "src" t of
6365 [] -> return t
@@ -86,7 +88,7 @@ cssURLs userdata d orig =
8688 "\"" -> B.takeWhile (/='"') $ B.drop 1 u
8789 "'" -> B.takeWhile (/='\'') $ B.drop 1 u
8890 _ -> u
89− let url' = if isAbsoluteURI url
91+ let url' = if isURI url
9092 then url
9193 else d </> url
9294 (raw, mime) <- getRaw userdata "" url'
@@ -97,8 +99,8 @@ cssURLs userdata d orig =
9799
98100getItem :: Maybe FilePath -> String -> IO (ByteString, Maybe String)
99101getItem userdata f =
100− if isAbsoluteURI f
101− then openURL f
102+ if isURI f
103+ then openURL f >>= either handleErr return
102104 else do
103105 -- strip off trailing query or fragment part, if relative URL.
104106 -- this is needed for things like cmunrm.eot?#iefix,
@@ -110,6 +112,7 @@ getItem userdata f =
110112 exists <- doesFileExist f'
111113 cont <- if exists then B.readFile f' else readDataFile userdata f'
112114 return (cont, mime)
115+ where handleErr e = err 61 $ "Failed to retrieve " ++ f ++ "\n" ++ show e
113116
114117getRaw :: Maybe FilePath -> String -> String -> IO (ByteString, String)
115118getRaw userdata mimetype src = do
src/Text/Pandoc/Shared.hs+137−47
@@ -1,6 +1,7 @@
1−{-# LANGUAGE DeriveDataTypeable, CPP #-}
1+{-# LANGUAGE DeriveDataTypeable, CPP, MultiParamTypeClasses,
2+ FlexibleContexts, ScopedTypeVariables #-}
23{-
3−Copyright (C) 2006-2013 John MacFarlane <jgm@berkeley.edu>
4+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
45
56This program is free software; you can redistribute it and/or modify
67it 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
1920
2021{- |
2122 Module : Text.Pandoc.Shared
22− Copyright : Copyright (C) 2006-2013 John MacFarlane
23+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2324 License : GNU GPL, version 2 or above
2425
2526 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,6 +35,7 @@ module Text.Pandoc.Shared (
3435 splitByIndices,
3536 splitStringByIndices,
3637 substitute,
38+ ordNub,
3739 -- * Text processing
3840 backslashEscapes,
3941 escapeStringUsing,
@@ -51,10 +53,12 @@ module Text.Pandoc.Shared (
5153 -- * Pandoc block and inline list processing
5254 orderedListMarkers,
5355 normalizeSpaces,
56+ extractSpaces,
5457 normalize,
5558 stringify,
5659 compactify,
5760 compactify',
61+ compactify'DL,
5862 Element (..),
5963 hierarchicalize,
6064 uniqueIdent,
@@ -79,8 +83,9 @@ module Text.Pandoc.Shared (
7983 ) where
8084
8185import Text.Pandoc.Definition
86+import Text.Pandoc.Walk
8287import Text.Pandoc.Generic
83−import Text.Pandoc.Builder (Blocks, ToMetaValue(..))
88+import Text.Pandoc.Builder (Inlines, Blocks, ToMetaValue(..))
8489import qualified Text.Pandoc.Builder as B
8590import qualified Text.Pandoc.UTF8 as UTF8
8691import System.Environment (getProgName)
@@ -89,12 +94,15 @@ import Data.Char ( toLower, isLower, isUpper, isAlpha,
8994 isLetter, isDigit, isSpace )
9095import Data.List ( find, isPrefixOf, intercalate )
9196import qualified Data.Map as M
92−import Network.URI ( escapeURIString, isAbsoluteURI, unEscapeString )
97+import Network.URI ( escapeURIString, isURI, nonStrictRelativeTo,
98+ unEscapeString, parseURIReference )
99+import qualified Data.Set as Set
93100import System.Directory
94101import Text.Pandoc.MIME (getMimeType)
95102import System.FilePath ( (</>), takeExtension, dropExtension )
96103import Data.Generics (Typeable, Data)
97104import qualified Control.Monad.State as S
105+import qualified Control.Exception as E
98106import Control.Monad (msum, unless)
99107import Text.Pandoc.Pretty (charWidth)
100108import System.Locale (defaultTimeLocale)
@@ -103,8 +111,10 @@ import System.IO (stderr)
103111import Text.HTML.TagSoup (renderTagsOptions, RenderOptions(..), Tag(..),
104112 renderOptions)
105113import qualified Data.ByteString as BS
106−import Data.ByteString.Lazy (toChunks)
107114import qualified Data.ByteString.Char8 as B8
115+import Text.Pandoc.Compat.Monoid
116+import Data.ByteString.Base64 (decodeLenient)
117+import Data.Sequence (ViewR(..), ViewL(..), viewl, viewr)
108118
109119#ifdef EMBED_DATA_FILES
110120import Text.Pandoc.Data (dataFiles)
@@ -112,10 +122,16 @@ import System.FilePath ( joinPath, splitDirectories )
112122#else
113123import Paths_pandoc (getDataFileName)
114124#endif
115−#ifdef HTTP_CONDUIT
116−import Network.HTTP.Conduit (httpLbs, parseUrl, withManager,
117− responseBody, responseHeaders)
125+#ifdef HTTP_CLIENT
126+import Data.ByteString.Lazy (toChunks)
127+import Network.HTTP.Client (httpLbs, parseUrl, withManager,
128+ responseBody, responseHeaders,
129+ Request(port,host))
130+import Network.HTTP.Client.Internal (addProxy)
131+import Network.HTTP.Client.TLS (tlsManagerSettings)
132+import System.Environment (getEnv)
118133import Network.HTTP.Types.Header ( hContentType)
134+import Network (withSocketsDo)
119135#else
120136import Network.URI (parseURI)
121137import Network.HTTP (findHeader, rspBody,
@@ -162,6 +178,13 @@ substitute target replacement lst@(x:xs) =
162178 then replacement ++ substitute target replacement (drop (length target) lst)
163179 else x : substitute target replacement xs
164180
181+ordNub :: (Ord a) => [a] -> [a]
182+ordNub l = go Set.empty l
183+ where
184+ go _ [] = []
185+ go s (x:xs) = if x `Set.member` s then go s xs
186+ else x : go (Set.insert x s) xs
187+
165188--
166189-- Text processing
167190--
@@ -225,9 +248,9 @@ toRomanNumeral x =
225248 _ | x >= 50 -> "L" ++ toRomanNumeral (x - 50)
226249 _ | x >= 40 -> "XL" ++ toRomanNumeral (x - 40)
227250 _ | x >= 10 -> "X" ++ toRomanNumeral (x - 10)
228− _ | x >= 9 -> "IX" ++ toRomanNumeral (x - 5)
251+ _ | x == 9 -> "IX"
229252 _ | x >= 5 -> "V" ++ toRomanNumeral (x - 5)
230− _ | x >= 4 -> "IV" ++ toRomanNumeral (x - 4)
253+ _ | x == 4 -> "IV"
231254 _ | x >= 1 -> "I" ++ toRomanNumeral (x - 1)
232255 _ -> ""
233256
@@ -265,7 +288,7 @@ normalizeDate s = fmap (formatTime defaultTimeLocale "%F")
265288 (msum $ map (\fs -> parsetimeWith fs s) formats :: Maybe Day)
266289 where parsetimeWith = parseTime defaultTimeLocale
267290 formats = ["%x","%m/%d/%Y", "%D","%F", "%d %b %Y",
268− "%d %B %Y", "%b. %d, %Y", "%B %d, %Y"]
291+ "%d %B %Y", "%b. %d, %Y", "%B %d, %Y", "%Y"]
269292
270293--
271294-- Pandoc block and inline list processing
@@ -310,6 +333,20 @@ isSpaceOrEmpty Space = True
310333isSpaceOrEmpty (Str "") = True
311334isSpaceOrEmpty _ = False
312335
336+-- | Extract the leading and trailing spaces from inside an inline element
337+-- and place them outside the element.
338+
339+extractSpaces :: (Inlines -> Inlines) -> Inlines -> Inlines
340+extractSpaces f is =
341+ let contents = B.unMany is
342+ left = case viewl contents of
343+ (Space :< _) -> B.space
344+ _ -> mempty
345+ right = case viewr contents of
346+ (_ :> Space) -> B.space
347+ _ -> mempty in
348+ (left <> f (B.trimInlines . B.Many $ contents) <> right)
349+
313350-- | Normalize @Pandoc@ document, consolidating doubled 'Space's,
314351-- combining adjacent 'Str's and 'Emph's, remove 'Null's and
315352-- empty elements, etc.
@@ -380,9 +417,11 @@ consolidateInlines (Code a1 x : Code a2 y : zs) | a1 == a2 =
380417consolidateInlines (x : xs) = x : consolidateInlines xs
381418consolidateInlines [] = []
382419
383−-- | Convert list of inlines to a string with formatting removed.
384−stringify :: [Inline] -> String
385−stringify = queryWith go
420+-- | Convert pandoc structure to a string with formatting removed.
421+-- Footnotes are skipped (since we don't want their contents in link
422+-- labels).
423+stringify :: Walkable Inline a => a -> String
424+stringify = query go . walk deNote
386425 where go :: Inline -> [Char]
387426 go Space = " "
388427 go (Str x) = x
@@ -390,6 +429,8 @@ stringify = queryWith go
390429 go (Math _ x) = x
391430 go LineBreak = " "
392431 go _ = ""
432+ deNote (Note _) = Str ""
433+ deNote x = x
393434
394435-- | Change final list item from @Para@ to @Plain@ if the list contains
395436-- no other @Para@ blocks.
@@ -422,6 +463,21 @@ compactify' items =
422463 _ -> items
423464 _ -> items
424465
466+-- | Like @compactify'@, but akts on items of definition lists.
467+compactify'DL :: [(Inlines, [Blocks])] -> [(Inlines, [Blocks])]
468+compactify'DL items =
469+ let defs = concatMap snd items
470+ defBlocks = reverse $ concatMap B.toList defs
471+ in case defBlocks of
472+ (Para x:_) -> if not $ any isPara (drop 1 defBlocks)
473+ then let (t,ds) = last items
474+ lastDef = B.toList $ last ds
475+ ds' = init ds ++
476+ [B.fromList $ init lastDef ++ [Plain x]]
477+ in init items ++ [(t, ds')]
478+ else items
479+ _ -> items
480+
425481isPara :: Block -> Bool
426482isPara (Para _) = True
427483isPara _ = False
@@ -432,6 +488,29 @@ data Element = Blk Block
432488 -- lvl num attributes label contents
433489 deriving (Eq, Read, Show, Typeable, Data)
434490
491+instance Walkable Inline Element where
492+ walk f (Blk x) = Blk (walk f x)
493+ walk f (Sec lev nums attr ils elts) = Sec lev nums attr (walk f ils) (walk f elts)
494+ walkM f (Blk x) = Blk `fmap` walkM f x
495+ walkM f (Sec lev nums attr ils elts) = do
496+ ils' <- walkM f ils
497+ elts' <- walkM f elts
498+ return $ Sec lev nums attr ils' elts'
499+ query f (Blk x) = query f x
500+ query f (Sec _ _ _ ils elts) = query f ils <> query f elts
501+
502+instance Walkable Block Element where
503+ walk f (Blk x) = Blk (walk f x)
504+ walk f (Sec lev nums attr ils elts) = Sec lev nums attr (walk f ils) (walk f elts)
505+ walkM f (Blk x) = Blk `fmap` walkM f x
506+ walkM f (Sec lev nums attr ils elts) = do
507+ ils' <- walkM f ils
508+ elts' <- walkM f elts
509+ return $ Sec lev nums attr ils' elts'
510+ query f (Blk x) = query f x
511+ query f (Sec _ _ _ ils elts) = query f ils <> query f elts
512+
513+
435514-- | Convert Pandoc inline list to plain text identifier. HTML
436515-- identifiers must start with a letter, and may contain only
437516-- letters, digits, and the characters _-.
@@ -492,14 +571,14 @@ isHeaderBlock _ = False
492571
493572-- | Shift header levels up or down.
494573headerShift :: Int -> Pandoc -> Pandoc
495−headerShift n = bottomUp shift
574+headerShift n = walk shift
496575 where shift :: Block -> Block
497576 shift (Header level attr inner) = Header (level + n) attr inner
498577 shift x = x
499578
500579-- | Detect if a list is tight.
501580isTightList :: [[Block]] -> Bool
502−isTightList = and . map firstIsPlain
581+isTightList = all firstIsPlain
503582 where firstIsPlain (Plain _ : _) = True
504583 firstIsPlain _ = False
505584
@@ -512,8 +591,10 @@ addMetaField :: ToMetaValue a
512591 -> Meta
513592addMetaField key val (Meta meta) =
514593 Meta $ M.insertWith combine key (toMetaValue val) meta
515− where combine newval (MetaList xs) = MetaList (xs ++ [newval])
594+ where combine newval (MetaList xs) = MetaList (xs ++ tolist newval)
516595 combine newval x = MetaList [x, newval]
596+ tolist (MetaList ys) = ys
597+ tolist y = [y]
517598
518599-- | Create 'Meta' from old-style title, authors, date. This is
519600-- provided to ease the transition from the old API.
@@ -531,14 +612,10 @@ makeMeta title authors date =
531612-- | Render HTML tags.
532613renderTags' :: [Tag String] -> String
533614renderTags' = renderTagsOptions
534− renderOptions{ optMinimize = \x ->
535− let y = map toLower x
536− in y == "hr" || y == "br" ||
537− y == "img" || y == "meta" ||
538− y == "link"
539− , optRawTag = \x ->
540− let y = map toLower x
541− in y == "script" || y == "style" }
615+ renderOptions{ optMinimize = matchTags ["hr", "br", "img",
616+ "meta", "link"]
617+ , optRawTag = matchTags ["script", "style"] }
618+ where matchTags = \tags -> flip elem tags . map toLower
542619
543620--
544621-- File handling
@@ -557,8 +634,7 @@ readDefaultDataFile :: FilePath -> IO BS.ByteString
557634readDefaultDataFile fname =
558635#ifdef EMBED_DATA_FILES
559636 case lookup (makeCanonical fname) dataFiles of
560− Nothing -> ioError $ userError
561− $ "Data file `" ++ fname ++ "' does not exist"
637+ Nothing -> err 97 $ "Could not find data file " ++ fname
562638 Just contents -> return contents
563639 where makeCanonical = joinPath . transformPathParts . splitDirectories
564640 transformPathParts = reverse . foldl go []
@@ -566,7 +642,12 @@ readDefaultDataFile fname =
566642 go (_:as) ".." = as
567643 go as x = x : as
568644#else
569− getDataFileName ("data" </> fname) >>= BS.readFile
645+ getDataFileName ("data" </> fname) >>= checkExistence >>= BS.readFile
646+ where checkExistence fn = do
647+ exists <- doesFileExist fn
648+ if exists
649+ then return fn
650+ else err 97 ("Could not find data file " ++ fname)
570651#endif
571652
572653-- | Read file from specified user data directory or, if not found there, from
@@ -586,34 +667,45 @@ readDataFileUTF8 userDir fname =
586667
587668-- | Fetch an image or other item from the local filesystem or the net.
588669-- Returns raw content and maybe mime type.
589−fetchItem :: String -> String -> IO (BS.ByteString, Maybe String)
590−fetchItem sourceDir s =
591− case s of
592− _ | isAbsoluteURI s -> openURL s
593− | isAbsoluteURI sourceDir -> openURL $ sourceDir ++ "/" ++ s
594− | otherwise -> do
670+fetchItem :: Maybe String -> String
671+ -> IO (Either E.SomeException (BS.ByteString, Maybe String))
672+fetchItem sourceURL s
673+ | isURI s = openURL s
674+ | otherwise =
675+ case sourceURL >>= parseURIReference of
676+ Just u -> case parseURIReference s of
677+ Just s' -> openURL $ show $
678+ s' `nonStrictRelativeTo` u
679+ Nothing -> openURL $ show u ++ "/" ++ s
680+ Nothing -> E.try readLocalFile
681+ where readLocalFile = do
595682 let mime = case takeExtension s of
596− ".gz" -> getMimeType $ dropExtension s
597− x -> getMimeType x
598− let f = sourceDir </> s
599− cont <- BS.readFile f
683+ ".gz" -> getMimeType $ dropExtension s
684+ x -> getMimeType x
685+ cont <- BS.readFile s
600686 return (cont, mime)
601687
602688-- | Read from a URL and return raw data and maybe mime type.
603−openURL :: String -> IO (BS.ByteString, Maybe String)
689+openURL :: String -> IO (Either E.SomeException (BS.ByteString, Maybe String))
604690openURL u
605691 | "data:" `isPrefixOf` u =
606692 let mime = takeWhile (/=',') $ drop 5 u
607693 contents = B8.pack $ unEscapeString $ drop 1 $ dropWhile (/=',') u
608− in return (contents, Just mime)
609−#ifdef HTTP_CONDUIT
610− | otherwise = do
694+ in return $ Right (decodeLenient contents, Just mime)
695+#ifdef HTTP_CLIENT
696+ | otherwise = withSocketsDo $ E.try $ do
611697 req <- parseUrl u
612− resp <- withManager $ httpLbs req
698+ (proxy :: Either E.SomeException String) <- E.try $ getEnv "http_proxy"
699+ let req' = case proxy of
700+ Left _ -> req
701+ Right pr -> case parseUrl pr of
702+ Just r -> addProxy (host r) (port r) req
703+ Nothing -> req
704+ resp <- withManager tlsManagerSettings $ httpLbs req'
613705 return (BS.concat $ toChunks $ responseBody resp,
614706 UTF8.toString `fmap` lookup hContentType (responseHeaders resp))
615707#else
616− | otherwise = getBodyAndMimeType `fmap` browse
708+ | otherwise = E.try $ getBodyAndMimeType `fmap` browse
617709 (do S.liftIO $ UTF8.hPutStrLn stderr $ "Fetching " ++ u ++ "..."
618710 setOutHandler $ const (return ())
619711 setAllowRedirects True
@@ -651,5 +743,3 @@ safeRead s = case reads s of
651743 (d,x):_
652744 | all isSpace x -> return d
653745 _ -> fail $ "Could not read `" ++ s ++ "'"
654−
655−
src/Text/Pandoc/Slides.hs+8−3
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2012 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.Slides
21− Copyright : Copyright (C) 2012 John MacFarlane
21+ Copyright : Copyright (C) 2012-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -46,13 +46,18 @@ getSlideLevel = go 6
4646
4747-- | Prepare a block list to be passed to hierarchicalize.
4848prepSlides :: Int -> [Block] -> [Block]
49−prepSlides slideLevel = ensureStartWithH . splitHrule
49+prepSlides slideLevel = ensureStartWithH . splitHrule . extractRefsHeader
5050 where splitHrule (HorizontalRule : Header n attr xs : ys)
5151 | n == slideLevel = Header slideLevel attr xs : splitHrule ys
5252 splitHrule (HorizontalRule : xs) = Header slideLevel nullAttr [Str "\0"] :
5353 splitHrule xs
5454 splitHrule (x : xs) = x : splitHrule xs
5555 splitHrule [] = []
56+ extractRefsHeader bs =
57+ case reverse bs of
58+ (Div ("",["references"],[]) (Header n attrs xs : ys) : zs)
59+ -> reverse zs ++ (Header n attrs xs : [Div ("",["references"],[]) ys])
60+ _ -> bs
5661 ensureStartWithH bs@(Header n _ _:_)
5762 | n <= slideLevel = bs
5863 ensureStartWithH bs = Header slideLevel nullAttr [Str "\0"] : bs
src/Text/Pandoc/Templates.hs+48−40
@@ -1,7 +1,7 @@
11{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, CPP,
22 OverloadedStrings, GeneralizedNewtypeDeriving #-}
33{-
4−Copyright (C) 2009-2013 John MacFarlane <jgm@berkeley.edu>
4+Copyright (C) 2009-2014 John MacFarlane <jgm@berkeley.edu>
55
66This program is free software; you can redistribute it and/or modify
77it 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
2020
2121{- |
2222 Module : Text.Pandoc.Templates
23− Copyright : Copyright (C) 2009-2013 John MacFarlane
23+ Copyright : Copyright (C) 2009-2014 John MacFarlane
2424 License : GNU GPL, version 2 or above
2525
2626 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -96,14 +96,14 @@ module Text.Pandoc.Templates ( renderTemplate
9696import Data.Char (isAlphaNum)
9797import Control.Monad (guard, when)
9898import Data.Aeson (ToJSON(..), Value(..))
99−import qualified Data.Attoparsec.Text as A
100−import Data.Attoparsec.Text (Parser)
99+import qualified Text.Parsec as P
100+import Text.Parsec.Text (Parser)
101101import Control.Applicative
102102import qualified Data.Text as T
103103import Data.Text (Text)
104104import Data.Text.Encoding (encodeUtf8)
105−import Data.Monoid ((<>), Monoid(..))
106−import Data.List (intersperse, nub)
105+import Text.Pandoc.Compat.Monoid ((<>), Monoid(..))
106+import Data.List (intersperse)
107107import System.FilePath ((</>), (<.>))
108108import qualified Data.Map as M
109109import qualified Data.HashMap.Strict as H
@@ -116,7 +116,8 @@ import Text.Blaze.Internal (preEscapedText)
116116import Text.Blaze (preEscapedText, Html)
117117#endif
118118import Data.ByteString.Lazy (ByteString, fromChunks)
119−import Text.Pandoc.Shared (readDataFileUTF8)
119+import Text.Pandoc.Shared (readDataFileUTF8, ordNub)
120+import Data.Vector ((!?))
120121
121122-- | Get default template for the specified writer.
122123getDefaultTemplate :: (Maybe FilePath) -- ^ User data directory to search first
@@ -162,7 +163,7 @@ varListToJSON assoc = toJSON $ M.fromList assoc'
162163 where assoc' = [(T.pack k, toVal [T.pack z | (y,z) <- assoc,
163164 not (null z),
164165 y == k])
165− | k <- nub $ map fst assoc ]
166+ | k <- ordNub $ map fst assoc ]
166167 toVal [x] = toJSON x
167168 toVal [] = Null
168169 toVal xs = toJSON xs
@@ -171,7 +172,10 @@ renderTemplate :: (ToJSON a, TemplateTarget b) => Template -> a -> b
171172renderTemplate (Template f) context = toTarget $ f $ toJSON context
172173
173174compileTemplate :: Text -> Either String Template
174−compileTemplate template = A.parseOnly pTemplate template
175+compileTemplate template =
176+ case P.parse (pTemplate <* P.eof) "template" template of
177+ Left e -> Left (show e)
178+ Right x -> Right x
175179
176180-- | Like 'renderTemplate', but compiles the template first,
177181-- raising an error if compilation fails.
@@ -185,10 +189,11 @@ var = Template . resolveVar
185189resolveVar :: Variable -> Value -> Text
186190resolveVar var' val =
187191 case multiLookup var' val of
188− Just (Array vec) -> mconcat $ map (resolveVar []) $ toList vec
192+ Just (Array vec) -> maybe mempty (resolveVar []) $ vec !? 0
189193 Just (String t) -> T.stripEnd t
190194 Just (Number n) -> T.pack $ show n
191195 Just (Bool True) -> "true"
196+ Just (Object _) -> "true"
192197 Just _ -> mempty
193198 Nothing -> mempty
194199
@@ -212,7 +217,7 @@ iter var' template sep = Template $ \val -> unTemplate
212217 Just (Array vec) -> mconcat $ intersperse sep
213218 $ map (setVar template var')
214219 $ toList vec
215− Just x -> setVar template var' x
220+ Just x -> cond var' (setVar template var' x) mempty
216221 Nothing -> mempty) val
217222
218223setVar :: Template -> Variable -> Value -> Template
@@ -228,7 +233,7 @@ replaceVar _ _ old = old
228233
229234pTemplate :: Parser Template
230235pTemplate = do
231− sp <- A.option mempty pInitialSpace
236+ sp <- P.option mempty pInitialSpace
232237 rest <- mconcat <$> many (pConditional <|>
233238 pFor <|>
234239 pNewline <|>
@@ -237,40 +242,43 @@ pTemplate = do
237242 pEscapedDollar)
238243 return $ sp <> rest
239244
245+takeWhile1 :: (Char -> Bool) -> Parser Text
246+takeWhile1 f = T.pack <$> P.many1 (P.satisfy f)
247+
240248pLit :: Parser Template
241−pLit = lit <$> A.takeWhile1 (\x -> x /='$' && x /= '\n')
249+pLit = lit <$> takeWhile1 (\x -> x /='$' && x /= '\n')
242250
243251pNewline :: Parser Template
244252pNewline = do
245− A.char '\n'
246− sp <- A.option mempty pInitialSpace
253+ P.char '\n'
254+ sp <- P.option mempty pInitialSpace
247255 return $ lit "\n" <> sp
248256
249257pInitialSpace :: Parser Template
250258pInitialSpace = do
251− sps <- A.takeWhile1 (==' ')
259+ sps <- takeWhile1 (==' ')
252260 let indentVar = if T.null sps
253261 then id
254262 else indent (T.length sps)
255− v <- A.option mempty $ indentVar <$> pVar
263+ v <- P.option mempty $ indentVar <$> pVar
256264 return $ lit sps <> v
257265
258266pEscapedDollar :: Parser Template
259−pEscapedDollar = lit "$" <$ A.string "$$"
267+pEscapedDollar = lit "$" <$ P.try (P.string "$$")
260268
261269pVar :: Parser Template
262−pVar = var <$> (A.char '$' *> pIdent <* A.char '$')
270+pVar = var <$> (P.try $ P.char '$' *> pIdent <* P.char '$')
263271
264272pIdent :: Parser [Text]
265273pIdent = do
266274 first <- pIdentPart
267− rest <- many (A.char '.' *> pIdentPart)
275+ rest <- many (P.char '.' *> pIdentPart)
268276 return (first:rest)
269277
270278pIdentPart :: Parser Text
271−pIdentPart = do
272− first <- A.letter
273− rest <- A.takeWhile (\c -> isAlphaNum c || c == '_' || c == '-')
279+pIdentPart = P.try $ do
280+ first <- P.letter
281+ rest <- T.pack <$> P.many (P.satisfy (\c -> isAlphaNum c || c == '_' || c == '-'))
274282 let id' = T.singleton first <> rest
275283 guard $ id' `notElem` reservedWords
276284 return id'
@@ -279,38 +287,38 @@ reservedWords :: [Text]
279287reservedWords = ["else","endif","for","endfor","sep"]
280288
281289skipEndline :: Parser ()
282−skipEndline = A.skipWhile (`elem` " \t") >> A.char '\n' >> return ()
290+skipEndline = P.try $ P.skipMany (P.satisfy (`elem` " \t")) >> P.char '\n' >> return ()
283291
284292pConditional :: Parser Template
285293pConditional = do
286− A.string "$if("
294+ P.try $ P.string "$if("
287295 id' <- pIdent
288− A.string ")$"
296+ P.string ")$"
289297 -- if newline after the "if", then a newline after "endif" will be swallowed
290− multiline <- A.option False (True <$ skipEndline)
298+ multiline <- P.option False (True <$ skipEndline)
291299 ifContents <- pTemplate
292− elseContents <- A.option mempty $
293− do A.string "$else$"
294− when multiline $ A.option () skipEndline
300+ elseContents <- P.option mempty $ P.try $
301+ do P.string "$else$"
302+ when multiline $ P.option () skipEndline
295303 pTemplate
296− A.string "$endif$"
297− when multiline $ A.option () skipEndline
304+ P.string "$endif$"
305+ when multiline $ P.option () skipEndline
298306 return $ cond id' ifContents elseContents
299307
300308pFor :: Parser Template
301309pFor = do
302− A.string "$for("
310+ P.try $ P.string "$for("
303311 id' <- pIdent
304− A.string ")$"
312+ P.string ")$"
305313 -- if newline after the "for", then a newline after "endfor" will be swallowed
306− multiline <- A.option False $ skipEndline >> return True
314+ multiline <- P.option False $ skipEndline >> return True
307315 contents <- pTemplate
308− sep <- A.option mempty $
309− do A.string "$sep$"
310− when multiline $ A.option () skipEndline
316+ sep <- P.option mempty $
317+ do P.try $ P.string "$sep$"
318+ when multiline $ P.option () skipEndline
311319 pTemplate
312− A.string "$endfor$"
313− when multiline $ A.option () skipEndline
320+ P.string "$endfor$"
321+ when multiline $ P.option () skipEndline
314322 return $ iter id' contents sep
315323
316324indent :: Int -> Template -> Template
src/Text/Pandoc/UTF8.hs+4−4
@@ -1,5 +1,6 @@
1+{-# LANGUAGE CPP #-}
12{-
2−Copyright (C) 2010 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2010-2014 John MacFarlane <jgm@berkeley.edu>
34
45This program is free software; you can redistribute it and/or modify
56it 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
1819
1920{- |
2021 Module : Text.Pandoc.UTF8
21− Copyright : Copyright (C) 2010 John MacFarlane
22+ Copyright : Copyright (C) 2010-2014 John MacFarlane
2223 License : GNU GPL, version 2 or above
2324
2425 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -50,8 +51,7 @@ import System.IO hiding (readFile, writeFile, getContents,
5051#if MIN_VERSION_base(4,6,0)
5152import Prelude hiding (readFile, writeFile, getContents, putStr, putStrLn)
5253#else
53−import Prelude hiding (readFile, writeFile, getContents, putStr, putStrLn,
54− catch)
54+import Prelude hiding (readFile, writeFile, getContents, putStr, putStrLn)
5555#endif
5656import qualified System.IO as IO
5757import qualified Data.ByteString.Char8 as B
src/Text/Pandoc/UUID.hs+2−2
@@ -1,5 +1,5 @@
11{-
2−Copyright (C) 2010 John MacFarlane <jgm@berkeley.edu>
2+Copyright (C) 2010-2014 John MacFarlane <jgm@berkeley.edu>
33
44This program is free software; you can redistribute it and/or modify
55it 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
1818
1919{- |
2020 Module : Text.Pandoc.UUID
21− Copyright : Copyright (C) 2010 John MacFarlane
21+ Copyright : Copyright (C) 2010-2014 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
src/Text/Pandoc/Writers/AsciiDoc.hs+14−6
@@ -1,6 +1,6 @@
11{-# LANGUAGE OverloadedStrings #-}
22{-
3−Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Text.Pandoc.Writers.AsciiDoc
22− Copyright : Copyright (C) 2006-2010 John MacFarlane
22+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -132,7 +132,9 @@ blockToAsciiDoc opts (Para inlines) = do
132132 then text "\\"
133133 else empty
134134 return $ esc <> contents <> blankline
135−blockToAsciiDoc _ (RawBlock _ _) = return empty
135+blockToAsciiDoc _ (RawBlock f s)
136+ | f == "asciidoc" = return $ text s
137+ | otherwise = return empty
136138blockToAsciiDoc _ HorizontalRule =
137139 return $ blankline <> text "'''''" <> blankline
138140blockToAsciiDoc opts (Header level (ident,_,_) inlines) = do
@@ -215,7 +217,9 @@ blockToAsciiDoc opts (Table caption aligns widths headers rows) = do
215217 let makeCell [Plain x] = do d <- blockListToAsciiDoc opts [Plain x]
216218 return $ text "|" <> chomp d
217219 makeCell [Para x] = makeCell [Plain x]
218− makeCell _ = return $ text "|" <> "[multiblock cell omitted]"
220+ makeCell [] = return $ text "|"
221+ makeCell bs = do d <- blockListToAsciiDoc opts bs
222+ return $ text "a|" $$ d
219223 let makeRow cells = hsep `fmap` mapM makeCell cells
220224 rows' <- mapM makeRow rows
221225 head' <- makeRow headers
@@ -225,7 +229,7 @@ blockToAsciiDoc opts (Table caption aligns widths headers rows) = do
225229 else 100000
226230 let maxwidth = maximum $ map offset (head':rows')
227231 let body = if maxwidth > colwidth then vsep rows' else vcat rows'
228− let border = text $ "|" ++ replicate ((min maxwidth colwidth) - 1) '='
232+ let border = text $ "|" ++ replicate (max 5 (min maxwidth colwidth) - 1) '='
229233 return $
230234 caption'' $$ tablespec $$ border $$ head'' $$ body $$ border $$ blankline
231235blockToAsciiDoc opts (BulletList items) = do
@@ -246,6 +250,7 @@ blockToAsciiDoc opts (OrderedList (_start, sty, _delim) items) = do
246250blockToAsciiDoc opts (DefinitionList items) = do
247251 contents <- mapM (definitionListItemToAsciiDoc opts) items
248252 return $ cat contents <> blankline
253+blockToAsciiDoc opts (Div _ bs) = blockListToAsciiDoc opts bs
249254
250255-- | Convert bullet list item (list of blocks) to asciidoc.
251256bulletListItemToAsciiDoc :: WriterOptions -> [Block] -> State WriterState Doc
@@ -346,7 +351,9 @@ inlineToAsciiDoc _ (Math InlineMath str) =
346351 return $ "latexmath:[$" <> text str <> "$]"
347352inlineToAsciiDoc _ (Math DisplayMath str) =
348353 return $ "latexmath:[\\[" <> text str <> "\\]]"
349−inlineToAsciiDoc _ (RawInline _ _) = return empty
354+inlineToAsciiDoc _ (RawInline f s)
355+ | f == "asciidoc" = return $ text s
356+ | otherwise = return empty
350357inlineToAsciiDoc _ (LineBreak) = return $ " +" <> cr
351358inlineToAsciiDoc _ Space = return space
352359inlineToAsciiDoc opts (Cite _ lst) = inlineListToAsciiDoc opts lst
@@ -383,3 +390,4 @@ inlineToAsciiDoc opts (Note [Plain inlines]) = do
383390 return $ text "footnote:[" <> contents <> "]"
384391-- asciidoc can't handle blank lines in notes
385392inlineToAsciiDoc _ (Note _) = return "[multiblock footnote omitted]"
393+inlineToAsciiDoc opts (Span _ ils) = inlineListToAsciiDoc opts ils
src/Text/Pandoc/Writers/ConTeXt.hs+15−19
@@ -1,6 +1,6 @@
11{-# LANGUAGE OverloadedStrings #-}
22{-
3−Copyright (C) 2007-2010 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2007-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Text.Pandoc.Writers.ConTeXt
22− Copyright : Copyright (C) 2007-2010 John MacFarlane
22+ Copyright : Copyright (C) 2007-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -33,9 +33,9 @@ import Text.Pandoc.Definition
3333import Text.Pandoc.Shared
3434import Text.Pandoc.Writers.Shared
3535import Text.Pandoc.Options
36−import Text.Pandoc.Generic (queryWith)
36+import Text.Pandoc.Walk (query)
3737import Text.Printf ( printf )
38−import Data.List ( intercalate, isPrefixOf )
38+import Data.List ( intercalate )
3939import Control.Monad.State
4040import Text.Pandoc.Pretty
4141import Text.Pandoc.Templates ( renderTemplate' )
@@ -130,7 +130,7 @@ blockToConTeXt (Plain lst) = inlineListToConTeXt lst
130130-- title beginning with fig: indicates that the image is a figure
131131blockToConTeXt (Para [Image txt (src,'f':'i':'g':':':_)]) = do
132132 capt <- inlineListToConTeXt txt
133− return $ blankline $$ "\\placefigure[here,nonumber]" <> braces capt <>
133+ return $ blankline $$ "\\placefigure" <> braces capt <>
134134 braces ("\\externalfigure" <> brackets (text src)) <> blankline
135135blockToConTeXt (Para lst) = do
136136 contents <- inlineListToConTeXt lst
@@ -143,6 +143,7 @@ blockToConTeXt (CodeBlock _ str) =
143143 -- blankline because \stoptyping can't have anything after it, inc. '}'
144144blockToConTeXt (RawBlock "context" str) = return $ text str <> blankline
145145blockToConTeXt (RawBlock _ _ ) = return empty
146+blockToConTeXt (Div _ bs) = blockListToConTeXt bs
146147blockToConTeXt (BulletList lst) = do
147148 contents <- mapM listItemToConTeXt lst
148149 return $ ("\\startitemize" <> if isTightList lst
@@ -204,9 +205,9 @@ blockToConTeXt (Table caption aligns widths heads rows) = do
204205 else liftM ($$ "\\HL") $ tableRowToConTeXt heads
205206 captionText <- inlineListToConTeXt caption
206207 rows' <- mapM tableRowToConTeXt rows
207− return $ "\\placetable" <> brackets ("here" <> if null caption
208− then ",none"
209− else "")
208+ return $ "\\placetable" <> (if null caption
209+ then brackets "none"
210+ else empty)
210211 <> braces captionText $$
211212 "\\starttable" <> brackets (text colDescriptors) $$
212213 "\\HL" $$ headers $$
@@ -282,14 +283,6 @@ inlineToConTeXt (RawInline "tex" str) = return $ text str
282283inlineToConTeXt (RawInline _ _) = return empty
283284inlineToConTeXt (LineBreak) = return $ text "\\crlf" <> cr
284285inlineToConTeXt Space = return space
285−-- autolink
286−inlineToConTeXt (Link [Str str] (src, tit))
287− | if "mailto:" `isPrefixOf` src
288− then src == escapeURI ("mailto:" ++ str)
289− else src == escapeURI str =
290− inlineToConTeXt (Link
291− [RawInline "context" "\\hyphenatedurl{", Str str, RawInline "context" "}"]
292− (src, tit))
293286-- Handle HTML-like internal document references to sections
294287inlineToConTeXt (Link txt (('#' : ref), _)) = do
295288 opts <- gets stOptions
@@ -304,6 +297,7 @@ inlineToConTeXt (Link txt (('#' : ref), _)) = do
304297 <> brackets (text ref)
305298
306299inlineToConTeXt (Link txt (src, _)) = do
300+ let isAutolink = txt == [Str src]
307301 st <- get
308302 let next = stNextRef st
309303 put $ st {stNextRef = next + 1}
@@ -312,8 +306,9 @@ inlineToConTeXt (Link txt (src, _)) = do
312306 return $ "\\useURL"
313307 <> brackets (text ref)
314308 <> brackets (text $ escapeStringUsing [('#',"\\#"),('%',"\\%")] src)
315− <> brackets empty
316− <> brackets label
309+ <> (if isAutolink
310+ then empty
311+ else brackets empty <> brackets label)
317312 <> "\\from"
318313 <> brackets (text ref)
319314inlineToConTeXt (Image _ (src, _)) = do
@@ -325,11 +320,12 @@ inlineToConTeXt (Note contents) = do
325320 contents' <- blockListToConTeXt contents
326321 let codeBlock x@(CodeBlock _ _) = [x]
327322 codeBlock _ = []
328− let codeBlocks = queryWith codeBlock contents
323+ let codeBlocks = query codeBlock contents
329324 return $ if null codeBlocks
330325 then text "\\footnote{" <> nest 2 contents' <> char '}'
331326 else text "\\startbuffer " <> nest 2 contents' <>
332327 text "\\stopbuffer\\footnote{\\getbuffer}"
328+inlineToConTeXt (Span _ ils) = inlineListToConTeXt ils
333329
334330-- | Craft the section header, inserting the secton reference, if supplied.
335331sectionHeader :: Attr
src/Text/Pandoc/Writers/Custom.hs+16−3
@@ -1,6 +1,6 @@
11{-# LANGUAGE OverlappingInstances, FlexibleInstances, OverloadedStrings #-}
22{-# OPTIONS_GHC -fno-warn-orphans #-}
3−{- Copyright (C) 2012 John MacFarlane <jgm@berkeley.edu>
3+{- Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
44
55This program is free software; you can redistribute it and/or modify
66it 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
1919
2020{- |
2121 Module : Text.Pandoc.Writers.Custom
22− Copyright : Copyright (C) 2012 John MacFarlane
22+ Copyright : Copyright (C) 2012-2014 John MacFarlane
2323 License : GNU GPL, version 2 or above
2424
2525 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -33,6 +33,7 @@ module Text.Pandoc.Writers.Custom ( writeCustom ) where
3333import Text.Pandoc.Definition
3434import Text.Pandoc.Options
3535import Data.List ( intersperse )
36+import Data.Char ( toLower )
3637import Scripting.Lua (LuaState, StackValue, callfunc)
3738import qualified Scripting.Lua as Lua
3839import Text.Pandoc.UTF8 (fromString, toString)
@@ -78,6 +79,11 @@ instance StackValue a => StackValue [a] where
7879 return (Just lst)
7980 valuetype _ = Lua.TTABLE
8081
82+instance StackValue Format where
83+ push lua (Format f) = Lua.push lua (map toLower f)
84+ peek l n = fmap Format `fmap` Lua.peek l n
85+ valuetype _ = Lua.TSTRING
86+
8187instance (StackValue a, StackValue b) => StackValue (M.Map a b) where
8288 push lua m = do
8389 let xs = M.toList m
@@ -110,12 +116,14 @@ instance StackValue [Block] where
110116instance StackValue MetaValue where
111117 push l (MetaMap m) = Lua.push l m
112118 push l (MetaList xs) = Lua.push l xs
119+ push l (MetaBool x) = Lua.push l x
113120 push l (MetaString s) = Lua.push l s
114121 push l (MetaInlines ils) = Lua.push l ils
115122 push l (MetaBlocks bs) = Lua.push l bs
116123 peek _ _ = undefined
117124 valuetype (MetaMap _) = Lua.TTABLE
118125 valuetype (MetaList _) = Lua.TTABLE
126+ valuetype (MetaBool _) = Lua.TBOOLEAN
119127 valuetype (MetaString _) = Lua.TSTRING
120128 valuetype (MetaInlines _) = Lua.TSTRING
121129 valuetype (MetaBlocks _) = Lua.TSTRING
@@ -123,7 +131,7 @@ instance StackValue MetaValue where
123131-- | Convert Pandoc to custom markup.
124132writeCustom :: FilePath -> WriterOptions -> Pandoc -> IO String
125133writeCustom luaFile opts doc = do
126− luaScript <- readFile luaFile
134+ luaScript <- C8.unpack `fmap` C8.readFile luaFile
127135 lua <- Lua.newstate
128136 Lua.openlibs lua
129137 Lua.loadstring lua luaScript "custom"
@@ -176,6 +184,9 @@ blockToCustom lua (OrderedList (num,sty,delim) items) =
176184blockToCustom lua (DefinitionList items) =
177185 callfunc lua "DefinitionList" items
178186
187+blockToCustom lua (Div attr items) =
188+ callfunc lua "Div" items (attrToMap attr)
189+
179190-- | Convert list of Pandoc block elements to Custom.
180191blockListToCustom :: LuaState -- ^ Options
181192 -> [Block] -- ^ List of block elements
@@ -238,3 +249,5 @@ inlineToCustom lua (Image alt (src,tit)) =
238249
239250inlineToCustom lua (Note contents) = callfunc lua "Note" contents
240251
252+inlineToCustom lua (Span attr items) =
253+ callfunc lua "Span" items (attrToMap attr)
src/Text/Pandoc/Writers/Docbook.hs+43−21
@@ -1,5 +1,6 @@
1+{-# LANGUAGE OverloadedStrings #-}
12{-
2−Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
3+Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
34
45This program is free software; you can redistribute it and/or modify
56it 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
1819
1920{- |
2021 Module : Text.Pandoc.Writers.Docbook
21− Copyright : Copyright (C) 2006-2010 John MacFarlane
22+ Copyright : Copyright (C) 2006-2014 John MacFarlane
2223 License : GNU GPL, version 2 or above
2324
2425 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,12 +32,14 @@ module Text.Pandoc.Writers.Docbook ( writeDocbook) where
3132import Text.Pandoc.Definition
3233import Text.Pandoc.XML
3334import Text.Pandoc.Shared
35+import Text.Pandoc.Walk
3436import Text.Pandoc.Writers.Shared
3537import Text.Pandoc.Options
3638import Text.Pandoc.Templates (renderTemplate')
3739import Text.Pandoc.Readers.TeXMath
3840import Data.List ( isPrefixOf, intercalate, isSuffixOf )
3941import Data.Char ( toLower )
42+import Data.Monoid ( Any(..) )
4043import Text.Pandoc.Highlighting ( languages, languagesByExtension )
4144import Text.Pandoc.Pretty
4245import qualified Text.Pandoc.Builder as B
@@ -84,8 +87,9 @@ writeDocbook opts (Pandoc meta blocks) =
8487 auths' = map (authorToDocbook opts) $ docAuthors meta
8588 meta' = B.setMeta "author" auths' meta
8689 Just metadata = metaToJSON opts
87− (Just . render colwidth . blocksToDocbook opts)
88− (Just . render colwidth . inlinesToDocbook opts)
90+ (Just . render colwidth . (vcat .
91+ (map (elementToDocbook opts' startLvl)) . hierarchicalize))
92+ (Just . render colwidth . inlinesToDocbook opts')
8993 meta'
9094 main = render' $ vcat (map (elementToDocbook opts' startLvl) elements)
9195 context = defField "body" main
@@ -148,6 +152,7 @@ listItemToDocbook opts item =
148152-- | Convert a Pandoc block element to Docbook.
149153blockToDocbook :: WriterOptions -> Block -> Doc
150154blockToDocbook _ Null = empty
155+blockToDocbook opts (Div _ bs) = blocksToDocbook opts $ map plainToPara bs
151156blockToDocbook _ (Header _ _ _) = empty -- should not occur after hierarchicalize
152157blockToDocbook opts (Plain lst) = inlinesToDocbook opts lst
153158-- title beginning with fig: indicates that the image is a figure
@@ -162,8 +167,9 @@ blockToDocbook opts (Para [Image txt (src,'f':'i':'g':':':_)]) =
162167 (inTagsIndented "imageobject"
163168 (selfClosingTag "imagedata" [("fileref",src)])) $$
164169 inTagsSimple "textobject" (inTagsSimple "phrase" alt))
165−blockToDocbook opts (Para lst) =
166− inTagsIndented "para" $ inlinesToDocbook opts lst
170+blockToDocbook opts (Para lst)
171+ | hasLineBreaks lst = flush $ nowrap $ inTagsSimple "literallayout" $ inlinesToDocbook opts lst
172+ | otherwise = inTagsIndented "para" $ inlinesToDocbook opts lst
167173blockToDocbook opts (BlockQuote blocks) =
168174 inTagsIndented "blockquote" $ blocksToDocbook opts blocks
169175blockToDocbook _ (CodeBlock (_,classes,_) str) =
@@ -179,10 +185,11 @@ blockToDocbook _ (CodeBlock (_,classes,_) str) =
179185 else languagesByExtension . map toLower $ s
180186 langs = concatMap langsFrom classes
181187blockToDocbook opts (BulletList lst) =
182− inTagsIndented "itemizedlist" $ listItemsToDocbook opts lst
188+ let attribs = [("spacing", "compact") | isTightList lst]
189+ in inTags True "itemizedlist" attribs $ listItemsToDocbook opts lst
183190blockToDocbook _ (OrderedList _ []) = empty
184191blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) =
185− let attribs = case numstyle of
192+ let numeration = case numstyle of
186193 DefaultStyle -> []
187194 Decimal -> [("numeration", "arabic")]
188195 Example -> [("numeration", "arabic")]
@@ -190,18 +197,21 @@ blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) =
190197 LowerAlpha -> [("numeration", "loweralpha")]
191198 UpperRoman -> [("numeration", "upperroman")]
192199 LowerRoman -> [("numeration", "lowerroman")]
193− items = if start == 1
194− then listItemsToDocbook opts (first:rest)
195− else (inTags True "listitem" [("override",show start)]
196− (blocksToDocbook opts $ map plainToPara first)) $$
197− listItemsToDocbook opts rest
200+ spacing = [("spacing", "compact") | isTightList (first:rest)]
201+ attribs = numeration ++ spacing
202+ items = if start == 1
203+ then listItemsToDocbook opts (first:rest)
204+ else (inTags True "listitem" [("override",show start)]
205+ (blocksToDocbook opts $ map plainToPara first)) $$
206+ listItemsToDocbook opts rest
198207 in inTags True "orderedlist" attribs items
199208blockToDocbook opts (DefinitionList lst) =
200− inTagsIndented "variablelist" $ deflistItemsToDocbook opts lst
201−blockToDocbook _ (RawBlock "docbook" str) = text str -- raw XML block
202−-- we allow html for compatibility with earlier versions of pandoc
203−blockToDocbook _ (RawBlock "html" str) = text str -- raw XML block
204−blockToDocbook _ (RawBlock _ _) = empty
209+ let attribs = [("spacing", "compact") | isTightList $ concatMap snd lst]
210+ in inTags True "variablelist" attribs $ deflistItemsToDocbook opts lst
211+blockToDocbook _ (RawBlock f str)
212+ | f == "docbook" = text str -- raw XML block
213+ | f == "html" = text str -- allow html for backwards compatibility
214+ | otherwise = empty
205215blockToDocbook _ HorizontalRule = empty -- not semantic
206216blockToDocbook opts (Table caption aligns widths headers rows) =
207217 let captionDoc = if null caption
@@ -223,6 +233,16 @@ blockToDocbook opts (Table caption aligns widths headers rows) =
223233 (inTags True "tgroup" [("cols", show (length headers))] $
224234 coltags $$ head' $$ body')
225235
236+hasLineBreaks :: [Inline] -> Bool
237+hasLineBreaks = getAny . query isLineBreak . walk removeNote
238+ where
239+ removeNote :: Inline -> Inline
240+ removeNote (Note _) = Str ""
241+ removeNote x = x
242+ isLineBreak :: Inline -> Any
243+ isLineBreak LineBreak = Any True
244+ isLineBreak _ = Any False
245+
226246alignmentToString :: Alignment -> [Char]
227247alignmentToString alignment = case alignment of
228248 AlignLeft -> "left"
@@ -267,6 +287,8 @@ inlineToDocbook opts (Quoted _ lst) =
267287 inTagsSimple "quote" $ inlinesToDocbook opts lst
268288inlineToDocbook opts (Cite _ lst) =
269289 inlinesToDocbook opts lst
290+inlineToDocbook opts (Span _ ils) =
291+ inlinesToDocbook opts ils
270292inlineToDocbook _ (Code _ str) =
271293 inTagsSimple "literal" $ text (escapeStringForXML str)
272294inlineToDocbook opts (Math t str)
@@ -277,8 +299,8 @@ inlineToDocbook opts (Math t str)
277299 $ fixNS
278300 $ removeAttr r
279301 Left _ -> inlinesToDocbook opts
280− $ readTeXMath str
281− | otherwise = inlinesToDocbook opts $ readTeXMath str
302+ $ readTeXMath' t str
303+ | otherwise = inlinesToDocbook opts $ readTeXMath' t str
282304 where (dt, tagtype) = case t of
283305 InlineMath -> (DisplayInline,"inlineequation")
284306 DisplayMath -> (DisplayBlock,"informalequation")
@@ -288,7 +310,7 @@ inlineToDocbook opts (Math t str)
288310 fixNS = everywhere (mkT fixNS')
289311inlineToDocbook _ (RawInline f x) | f == "html" || f == "docbook" = text x
290312 | otherwise = empty
291−inlineToDocbook _ LineBreak = flush $ inTagsSimple "literallayout" (text "\n")
313+inlineToDocbook _ LineBreak = text "\n"
292314inlineToDocbook _ Space = space
293315inlineToDocbook opts (Link txt (src, _)) =
294316 if isPrefixOf "mailto:" src
src/Text/Pandoc/Writers/Docx.hs+199−126

This diff is too big to show here.

src/Text/Pandoc/Writers/EPUB.hs+780−138

This diff is too big to show here.

src/Text/Pandoc/Writers/FB2.hs+11−6

This diff is too big to show here.

src/Text/Pandoc/Writers/HTML.hs+105−53

This diff is too big to show here.

src/Text/Pandoc/Writers/Haddock.hsnew file+346

This diff is too big to show here.

src/Text/Pandoc/Writers/ICML.hsnew file+525

This diff is too big to show here.

src/Text/Pandoc/Writers/LaTeX.hs+263−126

This diff is too big to show here.

src/Text/Pandoc/Writers/Man.hs+14−9

This diff is too big to show here.

src/Text/Pandoc/Writers/Markdown.hs+107−61

This diff is too big to show here.

src/Text/Pandoc/Writers/MediaWiki.hs+60−53

This diff is too big to show here.

src/Text/Pandoc/Writers/Native.hs+2−2

This diff is too big to show here.

src/Text/Pandoc/Writers/ODT.hs+63−22

This diff is too big to show here.

src/Text/Pandoc/Writers/OPML.hs+2−2

This diff is too big to show here.

src/Text/Pandoc/Writers/OpenDocument.hs+43−22

This diff is too big to show here.

src/Text/Pandoc/Writers/Org.hs+15−4

This diff is too big to show here.

src/Text/Pandoc/Writers/RST.hs+34−15

This diff is too big to show here.

src/Text/Pandoc/Writers/RTF.hs+18−13

This diff is too big to show here.

src/Text/Pandoc/Writers/Shared.hs+48−4

This diff is too big to show here.

src/Text/Pandoc/Writers/Texinfo.hs+21−17

This diff is too big to show here.

src/Text/Pandoc/Writers/Textile.hs+19−11

This diff is too big to show here.

src/Text/Pandoc/XML.hs+3−3

This diff is too big to show here.

tests/MarkdownTest_1.0.3/MarkdownTest.pldeleted−176

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Amps and angle encoding.htmldeleted−17

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Amps and angle encoding.textdeleted−21

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Auto links.htmldeleted−18

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Auto links.textdeleted−13

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Backslash escapes.htmldeleted−118

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Backslash escapes.textdeleted−120

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.htmldeleted−15

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.textdeleted−11

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Code Blocks.htmldeleted−18

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Code Blocks.textdeleted−14

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Code Spans.htmldeleted−6

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Code Spans.textdeleted−6

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.htmldeleted−8

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.textdeleted−8

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Horizontal rules.htmldeleted−71

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Horizontal rules.textdeleted−67

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).htmldeleted−15

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).textdeleted−15

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).htmldeleted−72

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).textdeleted−69

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Inline HTML comments.htmldeleted−13

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Inline HTML comments.textdeleted−13

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Links, inline style.htmldeleted−11

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Links, inline style.textdeleted−12

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Links, reference style.htmldeleted−52

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Links, reference style.textdeleted−71

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Links, shortcut references.htmldeleted−9

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Links, shortcut references.textdeleted−20

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Literal quotes in titles.htmldeleted−3

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Literal quotes in titles.textdeleted−7

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.htmldeleted−314

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.textdeleted−306

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.htmldeleted−942

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.textdeleted−888

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Nested blockquotes.htmldeleted−9

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Nested blockquotes.textdeleted−5

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.htmldeleted−148

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.textdeleted−131

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Strong and em together.htmldeleted−7

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Strong and em together.textdeleted−7

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Tabs.htmldeleted−25

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Tabs.textdeleted−21

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Tidyness.htmldeleted−8

This diff is too big to show here.

tests/MarkdownTest_1.0.3/Tests/Tidyness.textdeleted−5

This diff is too big to show here.

tests/Tests/Arbitrary.hs+9−10

This diff is too big to show here.

tests/Tests/Old.hs+13−20

This diff is too big to show here.

tests/Tests/Readers/Docx.hsnew file+160

This diff is too big to show here.

tests/Tests/Readers/LaTeX.hs+31−24

This diff is too big to show here.

tests/Tests/Readers/Markdown.hs+20−3

This diff is too big to show here.

tests/Tests/Readers/Org.hsnew file+994

This diff is too big to show here.

tests/Tests/Walk.hsnew file+47

This diff is too big to show here.

tests/Tests/Writers/AsciiDoc.hsnew file+37

This diff is too big to show here.

tests/Tests/Writers/Docbook.hsnew file+229

This diff is too big to show here.

tests/Tests/Writers/HTML.hs+1−4

This diff is too big to show here.

tests/Tests/Writers/LaTeX.hs+31−1

This diff is too big to show here.

tests/Tests/Writers/Markdown.hs+4

This diff is too big to show here.

tests/biblio.bibdeleted−26

This diff is too big to show here.

tests/chicago-author-date.csldeleted−458

This diff is too big to show here.

tests/docbook-reader.docbook+10−8

This diff is too big to show here.

tests/docx.block_quotes.docxnew file

Binary file not shown.

tests/docx.block_quotes_parse_indent.nativenew file+8

This diff is too big to show here.

tests/docx.codeblock.docxnew file

Binary file not shown.

tests/docx.codeblock.nativenew file+3

This diff is too big to show here.

tests/docx.deep_normalize.docxnew file

Binary file not shown.

tests/docx.deep_normalize.nativenew file+6

This diff is too big to show here.

tests/docx.definition_list.docxnew file

Binary file not shown.

tests/docx.definition_list.nativenew file+7

This diff is too big to show here.

tests/docx.headers.docxnew file

Binary file not shown.

tests/docx.headers.nativenew file+5

This diff is too big to show here.

tests/docx.image.docxnew file

Binary file not shown.

tests/docx.image_no_embed.nativenew file+2

This diff is too big to show here.

tests/docx.inline_code.docxnew file

Binary file not shown.

tests/docx.inline_code.nativenew file+1

This diff is too big to show here.

tests/docx.inline_formatting.docxnew file

Binary file not shown.

tests/docx.inline_formatting.nativenew file+5

This diff is too big to show here.

tests/docx.links.docxnew file

Binary file not shown.

tests/docx.links.nativenew file+6

This diff is too big to show here.

tests/docx.lists.docxnew file

Binary file not shown.

tests/docx.lists.nativenew file+18

This diff is too big to show here.

tests/docx.normalize.docxnew file

Binary file not shown.

tests/docx.normalize.nativenew file+2

This diff is too big to show here.

tests/docx.notes.docxnew file

Binary file not shown.

tests/docx.notes.nativenew file+2

This diff is too big to show here.

tests/docx.tables.docxnew file

Binary file not shown.

tests/docx.tables.nativenew file+24

This diff is too big to show here.

tests/docx.tabs.docxnew file

Binary file not shown.

tests/docx.tabs.nativenew file+2

This diff is too big to show here.

tests/docx.track_changes_deletion.docxnew file

Binary file not shown.

tests/docx.track_changes_deletion_accept.nativenew file+1

This diff is too big to show here.

tests/docx.track_changes_deletion_all.nativenew file+1

This diff is too big to show here.

tests/docx.track_changes_deletion_reject.nativenew file+1

This diff is too big to show here.

tests/docx.track_changes_insertion.docxnew file

Binary file not shown.

tests/docx.track_changes_insertion_accept.nativenew file+1

This diff is too big to show here.

tests/docx.track_changes_insertion_all.nativenew file+1

This diff is too big to show here.

tests/docx.track_changes_insertion_reject.nativenew file+1

This diff is too big to show here.

tests/docx.trailing_spaces_in_formatting.docxnew file

Binary file not shown.

tests/docx.trailing_spaces_in_formatting.nativenew file+1

This diff is too big to show here.

tests/docx.unicode.docxnew file

Binary file not shown.

tests/docx.unicode.nativenew file+1

This diff is too big to show here.

tests/haddock-reader.haddock+10−10

This diff is too big to show here.

tests/haddock-reader.native+8−8

This diff is too big to show here.

tests/html-reader.html+24

This diff is too big to show here.

tests/html-reader.native+87−71

This diff is too big to show here.

tests/ieee.csldeleted−302

This diff is too big to show here.

tests/latex-reader.native+35−35

This diff is too big to show here.

tests/lhs-test.html+2−2

This diff is too big to show here.

tests/lhs-test.html+lhs+2−2

This diff is too big to show here.

tests/lhs-test.latex+5−6

This diff is too big to show here.

tests/lhs-test.latex+lhs+4−5

This diff is too big to show here.

tests/lhs-test.markdown+2−2

This diff is too big to show here.

tests/lhs-test.native+1−1

This diff is too big to show here.

tests/markdown-citations.chicago-author-date.txtdeleted−45

This diff is too big to show here.

tests/markdown-citations.ieee.txtdeleted−45

This diff is too big to show here.

tests/markdown-citations.mhra.txtdeleted−63

This diff is too big to show here.

tests/markdown-citations.nativenew file+17

This diff is too big to show here.

tests/markdown-reader-more.native+12−7

This diff is too big to show here.

tests/markdown-reader-more.txt+12

This diff is too big to show here.

tests/mediawiki-reader.native+49−43

This diff is too big to show here.

tests/mediawiki-reader.wiki+9−2

This diff is too big to show here.

tests/mhra.csldeleted−399

This diff is too big to show here.

tests/opml-reader.native+1−1

This diff is too big to show here.

tests/pipe-tables.native+9−1

This diff is too big to show here.

tests/pipe-tables.txt+10

This diff is too big to show here.

tests/rst-reader.native+43−33

This diff is too big to show here.

tests/rst-reader.rst+24

This diff is too big to show here.

tests/tables.asciidoc+4−7

This diff is too big to show here.

tests/tables.context+7−7

This diff is too big to show here.

tests/tables.haddocknew file+77

This diff is too big to show here.

tests/tables.html+6

This diff is too big to show here.

tests/tables.icmlnew file+748

This diff is too big to show here.

tests/tables.latex+77−77

This diff is too big to show here.

tests/tables.mediawiki+125−191

This diff is too big to show here.

tests/tables.rtf+92−92

This diff is too big to show here.

tests/test-pandoc.hs+15−1

This diff is too big to show here.

tests/testsuite.native+13−23

This diff is too big to show here.

tests/testsuite.txt+6−6

This diff is too big to show here.

tests/textile-reader.native+83−84

This diff is too big to show here.

tests/textile-reader.textile+3−3

This diff is too big to show here.

tests/writer.context+8−7

This diff is too big to show here.

tests/writer.docbook+57−67

This diff is too big to show here.

tests/writer.fb2+1−1

This diff is too big to show here.

tests/writer.haddocknew file+660

This diff is too big to show here.

tests/writer.html+7−13

This diff is too big to show here.

tests/writer.icmlnew file+3023

This diff is too big to show here.

tests/writer.latex+9−19

This diff is too big to show here.

tests/writer.man+1−1

This diff is too big to show here.

tests/writer.markdown+23−6

This diff is too big to show here.

tests/writer.mediawiki+20−8

This diff is too big to show here.

tests/writer.native+13−23

This diff is too big to show here.

tests/writer.opendocument+88−75

This diff is too big to show here.

tests/writer.opml+6−6

This diff is too big to show here.

tests/writer.org+31−6

This diff is too big to show here.

tests/writer.plain+5

This diff is too big to show here.

tests/writer.rst+30−5

This diff is too big to show here.

tests/writer.rtf+1−1

This diff is too big to show here.

tests/writer.textile+26−5

This diff is too big to show here.

windows/make-windows-installer.bat+11−9

This diff is too big to show here.

windows/pandoc.wxs+12−1

This diff is too big to show here.