diff options
196 files changed, 12748 insertions, 1869 deletions
diff --git a/.travis.yml b/.travis.yml index c5c735a9e..ee594e6de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -127,7 +127,7 @@ script: stack) ulimit -n 4096 stack config set system-ghc --global true - stack --no-terminal $ARGS test --fast --flag 'aeson:fast' --flag pandoc:embed_data_files --haddock --no-haddock-deps --ghc-options="$OPTS" + stack --no-terminal $ARGS test --fast --flag 'aeson:fast' --flag pandoc:embed_data_files --haddock --no-haddock-deps --ghc-options="$OPTS" --test-arguments='--hide-successes' ;; cabal) cabal sdist --output-directory=sourcedist && \ diff --git a/AUTHORS.md b/AUTHORS.md index c2d236983..f76610f84 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,5 +1,6 @@ # Contributors +- Anabra - Arata Mizuki - Aaron Wolen - Albert Krewinkel @@ -49,6 +50,7 @@ - Emily Eisenberg - Eric Kow - Eric Seidel +- Étienne Bersac - Felix Yan - Florian Eitel - Francesco Occhipinti @@ -188,6 +190,7 @@ - lwolfsonkin - nkalvi - oltolm +- quasicomputational - qerub - robabla - roblabla diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1145dd835..11a0c9c94 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -205,6 +205,10 @@ placed in the source directory): Profiling --------- +To diagnose a performance issue with parsing, first try using +the `--trace` option. This will give you a record of when block +parsers succeed, so you can spot backtracking issues. + To use the GHC profiler with cabal: cabal clean @@ -69,8 +69,9 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- -Pandoc's templates (in `data/templates`) are dual-licensed GPL (v2 or -higher, same as pandoc) and the BSD 3-clause license. +Pandoc's templates (in `data/templates`) are dual-licensed as either +GPL (v2 or higher, same as pandoc) or (at your option) the BSD +3-clause license. Copyright (c) 2014--2018, John MacFarlane @@ -119,6 +120,24 @@ Copyright (C) 2010-2018 Paul Rivier and John MacFarlane Released under the GNU General Public License version 2 or later. ---------------------------------------------------------------------- +src/Text/Pandoc/Readers/TikiWiki.hs +Copyright (C) 2017 Robin Lee Powell + +Released under the GNU General Public License version 2. + +---------------------------------------------------------------------- +src/Text/Pandoc/Readers/JATS.hs +Copyright (C) 2017-2018 Hamish Mackenzie + +Released under the GNU General Public License version 2 or later. + +---------------------------------------------------------------------- +src/Text/Pandoc/Readers/EPUB.hs +Copyright (C) 2014-2018 Matthew Pickering + +Released under the GNU General Public License version 2 or later. + +---------------------------------------------------------------------- src/Text/Pandoc/Readers/Org.hs src/Text/Pandoc/Readers/Org/* test/Tests/Readers/Org/* diff --git a/MANUAL.txt b/MANUAL.txt index 08641599e..98607df76 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -13,37 +13,19 @@ Description Pandoc is a [Haskell] library for converting from one markup format to another, and a command-line tool that uses this library. -Pandoc can read [Markdown], [CommonMark], [PHP Markdown Extra], -[GitHub-Flavored Markdown], [MultiMarkdown], and (subsets of) [Textile], -[reStructuredText], [HTML], [LaTeX], [MediaWiki markup], [TWiki -markup], [TikiWiki markup], [Creole 1.0], [Haddock markup], [OPML], -[Emacs Org mode], [DocBook], [JATS], [Muse], [txt2tags], [Vimwiki], -[EPUB], [ODT], and [Word docx]. - -Pandoc can write plain text, [Markdown], -[CommonMark], [PHP Markdown Extra], [GitHub-Flavored Markdown], -[MultiMarkdown], [reStructuredText], [XHTML], [HTML5], [LaTeX] -\(including [`beamer`] slide shows\), [ConTeXt], [RTF], [OPML], -[DocBook], [JATS], [OpenDocument], [ODT], [Word docx], [GNU Texinfo], -[MediaWiki markup], [DokuWiki markup], [ZimWiki markup], [Haddock -markup], [EPUB] \(v2 or v3\), [FictionBook2], [Textile], [groff man], -[groff ms], [Emacs Org mode], [AsciiDoc], [InDesign ICML], [TEI -Simple], [Muse], [PowerPoint] slide shows and [Slidy], [Slideous], -[DZSlides], [reveal.js] or [S5] HTML slide shows. It can also produce -[PDF] output on systems where LaTeX, ConTeXt, `pdfroff`, -`wkhtmltopdf`, `prince`, or `weasyprint` is installed. +Pandoc can convert between numerous markup and word processing formats, +including, but not limited to, various flavors of [Markdown], [HTML], +[LaTeX] and [Word docx]. For the full lists of input and output formats, +see the `--from` and `--to` [options below][General options]. +Pandoc can also produce [PDF] output: see [creating a PDF], below. Pandoc's enhanced version of Markdown includes syntax for [tables], -[definition lists], [metadata blocks], [`Div` blocks][Extension: -`fenced_divs`], [footnotes] and [citations], embedded -[LaTeX][Extension: `raw_tex`] (including [math]), [Markdown inside HTML -block elements][Extension: `markdown_in_html_blocks`], and much more. -These enhancements, described further under [Pandoc's Markdown], -can be disabled using the `markdown_strict` format. +[definition lists], [metadata blocks], [footnotes], [citations], [math], +and much more. See below under [Pandoc's Markdown]. Pandoc has a modular design: it consists of a set of readers, which parse text in a given format and produce a native representation of the document -(like an _abstract syntax tree_ or AST), and a set of writers, which convert +(an _abstract syntax tree_ or AST), and a set of writers, which convert this native representation into a target format. Thus, adding an input or output format requires only adding a reader or writer. Users can also run custom [pandoc filters] to modify the intermediate AST. @@ -58,56 +40,6 @@ model. While conversions from pandoc's Markdown to all formats aspire to be perfect, conversions from formats more expressive than pandoc's Markdown can be expected to be lossy. -[Markdown]: http://daringfireball.net/projects/markdown/ -[CommonMark]: http://commonmark.org -[PHP Markdown Extra]: https://michelf.ca/projects/php-markdown/extra/ -[GitHub-Flavored Markdown]: https://help.github.com/articles/github-flavored-markdown/ -[MultiMarkdown]: http://fletcherpenney.net/multimarkdown/ -[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html -[S5]: http://meyerweb.com/eric/tools/s5/ -[Slidy]: http://www.w3.org/Talks/Tools/Slidy/ -[Slideous]: http://goessner.net/articles/slideous/ -[HTML]: http://www.w3.org/html/ -[HTML5]: http://www.w3.org/TR/html5/ -[polyglot markup]: https://www.w3.org/TR/html-polyglot/ -[XHTML]: http://www.w3.org/TR/xhtml1/ -[LaTeX]: http://latex-project.org -[`beamer`]: https://ctan.org/pkg/beamer -[Beamer User's Guide]: http://ctan.math.utah.edu/ctan/tex-archive/macros/latex/contrib/beamer/doc/beameruserguide.pdf -[ConTeXt]: http://www.contextgarden.net/ -[RTF]: http://en.wikipedia.org/wiki/Rich_Text_Format -[DocBook]: http://docbook.org -[JATS]: https://jats.nlm.nih.gov -[txt2tags]: http://txt2tags.org -[EPUB]: http://idpf.org/epub -[OPML]: http://dev.opml.org/spec2.html -[OpenDocument]: http://opendocument.xml.org -[ODT]: http://en.wikipedia.org/wiki/OpenDocument -[Textile]: http://redcloth.org/textile -[MediaWiki markup]: https://www.mediawiki.org/wiki/Help:Formatting -[DokuWiki markup]: https://www.dokuwiki.org/dokuwiki -[ZimWiki markup]: http://zim-wiki.org/manual/Help/Wiki_Syntax.html -[TWiki markup]: http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules -[TikiWiki markup]: https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax -[Haddock markup]: https://www.haskell.org/haddock/doc/html/ch03s08.html -[Creole 1.0]: http://www.wikicreole.org/wiki/Creole1.0 -[groff man]: http://man7.org/linux/man-pages/man7/groff_man.7.html -[groff ms]: http://man7.org/linux/man-pages/man7/groff_ms.7.html -[Haskell]: https://www.haskell.org -[GNU Texinfo]: http://www.gnu.org/software/texinfo/ -[Emacs Org mode]: http://orgmode.org -[AsciiDoc]: http://www.methods.co.nz/asciidoc/ -[DZSlides]: http://paulrouget.com/dzslides/ -[Word docx]: https://en.wikipedia.org/wiki/Office_Open_XML -[PDF]: https://www.adobe.com/pdf/ -[reveal.js]: http://lab.hakim.se/reveal-js/ -[FictionBook2]: http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1 -[InDesign ICML]: http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf -[TEI Simple]: https://github.com/TEIC/TEI-Simple -[Muse]: https://amusewiki.org/library/manual -[PowerPoint]: https://en.wikipedia.org/wiki/Microsoft_PowerPoint -[Vimwiki]: https://vimwiki.github.io - Using `pandoc` -------------- @@ -283,20 +215,41 @@ General options `-f` *FORMAT*, `-r` *FORMAT*, `--from=`*FORMAT*, `--read=`*FORMAT* -: Specify input format. *FORMAT* can be `native` (native Haskell), - `json` (JSON version of native AST), `markdown` (pandoc's - extended Markdown), `markdown_strict` (original unextended - Markdown), `markdown_phpextra` (PHP Markdown Extra), - `markdown_mmd` (MultiMarkdown), `gfm` (GitHub-Flavored Markdown), - `commonmark` (CommonMark Markdown), `textile` (Textile), `rst` - (reStructuredText), `html` (HTML), `docbook` (DocBook), `t2t` - (txt2tags), `docx` (docx), `odt` (ODT), `epub` (EPUB), `opml` (OPML), - `org` (Emacs Org mode), `mediawiki` (MediaWiki markup), `twiki` (TWiki - markup), `tikiwiki` (TikiWiki markup), `creole` (Creole 1.0), - `haddock` (Haddock markup), or `latex` (LaTeX). - (`markdown_github` provides deprecated and less accurate support - for Github-Flavored Markdown; please use `gfm` instead, unless you - need to use extensions other than `smart`.) +: Specify input format. *FORMAT* can be: + + ::: {#input-formats} + - `commonmark` ([CommonMark] Markdown) + - `creole` ([Creole 1.0]) + - `docbook` ([DocBook]) + - `docx` ([Word docx]) + - `epub` ([EPUB]) + - `gfm` ([GitHub-Flavored Markdown]), + or `markdown_github`, which provides deprecated and less accurate + support for Github-Flavored Markdown; please use `gfm` instead, + unless you need to use extensions other than `smart`. + - `haddock` ([Haddock markup]) + - `html` ([HTML]) + - `jats` ([JATS] XML) + - `json` (JSON version of native AST) + - `latex` ([LaTeX]) + - `markdown` ([Pandoc's Markdown]) + - `markdown_mmd` ([MultiMarkdown]) + - `markdown_phpextra` ([PHP Markdown Extra]) + - `markdown_strict` (original unextended [Markdown]) + - `mediawiki` ([MediaWiki markup]) + - `muse` ([Muse]) + - `native` (native Haskell) + - `odt` ([ODT]) + - `opml` ([OPML]) + - `org` ([Emacs Org mode]) + - `rst` ([reStructuredText]) + - `t2t` ([txt2tags]) + - `textile` ([Textile]) + - `tikiwiki` ([TikiWiki markup]) + - `twiki` ([TWiki markup]) + - `vimwiki` ([Vimwiki]) + ::: + Extensions can be individually enabled or disabled by appending `+EXTENSION` or `-EXTENSION` to the format name. See [Extensions] below, for a list of extensions and @@ -305,34 +258,64 @@ General options `-t` *FORMAT*, `-w` *FORMAT*, `--to=`*FORMAT*, `--write=`*FORMAT* -: Specify output format. *FORMAT* can be `native` (native Haskell), - `json` (JSON version of native AST), `plain` (plain text), - `markdown` (pandoc's extended Markdown), `markdown_strict` - (original unextended Markdown), `markdown_phpextra` (PHP Markdown - Extra), `markdown_mmd` (MultiMarkdown), `gfm` (GitHub-Flavored - Markdown), `commonmark` (CommonMark Markdown), `rst` - (reStructuredText), `html4` (XHTML 1.0 Transitional), `html` or - `html5` (HTML5/XHTML [polyglot markup]), `latex` (LaTeX), `beamer` - (LaTeX beamer slide show), `context` (ConTeXt), `man` (groff man), - `mediawiki` (MediaWiki markup), `dokuwiki` (DokuWiki markup), - `zimwiki` (ZimWiki markup), `textile` (Textile), `org` (Emacs Org - mode), `texinfo` (GNU Texinfo), `opml` (OPML), `docbook` or - `docbook4` (DocBook 4), `docbook5` (DocBook 5), `jats` (JATS XML), - `opendocument` (OpenDocument), `odt` (OpenOffice text document), - `docx` (Word docx), `haddock` (Haddock markup), `rtf` (rich text - format), `epub2` (EPUB v2 book), `epub` or `epub3` (EPUB v3), - `fb2` (FictionBook2 e-book), `asciidoc` (AsciiDoc), `icml` - (InDesign ICML), `tei` (TEI Simple), `slidy` (Slidy HTML and - JavaScript slide show), `slideous` (Slideous HTML and JavaScript - slide show), `dzslides` (DZSlides HTML5 + JavaScript slide show), - `revealjs` (reveal.js HTML5 + JavaScript slide show), `s5` (S5 - HTML and JavaScript slide show), `pptx` (PowerPoint slide show) or - the path of a custom lua writer (see [Custom writers], - below). (`markdown_github` provides deprecated and less accurate - support for Github-Flavored Markdown; please use `gfm` instead, - unless you use extensions that do not work with `gfm`.) Note that - `odt`, `docx`, and `epub` output will not be directed to *stdout* - unless forced with `-o -`. Extensions can be individually enabled or +: Specify output format. *FORMAT* can be: + + ::: {#output-formats} + - `asciidoc` ([AsciiDoc]) + - `beamer` ([LaTeX beamer][`beamer`] slide show) + - `commonmark` ([CommonMark] Markdown) + - `context` ([ConTeXt]) + - `docbook` or `docbook4` ([DocBook] 4) + - `docbook5` (DocBook 5) + - `docx` ([Word docx]) + - `dokuwiki` ([DokuWiki markup]) + - `epub` or `epub3` ([EPUB] v3 book) + - `epub2` (EPUB v2) + - `fb2` ([FictionBook2] e-book) + - `gfm` ([GitHub-Flavored Markdown]), + or `markdown_github`, which provides deprecated and less accurate + support for Github-Flavored Markdown; please use `gfm` instead, + unless you use extensions that do not work with `gfm`. + - `haddock` ([Haddock markup]) + - `html` or `html5` ([HTML], i.e. [HTML5]/XHTML [polyglot markup]) + - `html4` ([XHTML] 1.0 Transitional) + - `icml` ([InDesign ICML]) + - `jats` ([JATS] XML) + - `json` (JSON version of native AST) + - `latex` ([LaTeX]) + - `man` ([groff man]) + - `markdown` ([Pandoc's Markdown]) + - `markdown_mmd` ([MultiMarkdown]) + - `markdown_phpextra` ([PHP Markdown Extra]) + - `markdown_strict` (original unextended [Markdown]) + - `mediawiki` ([MediaWiki markup]) + - `ms` ([groff ms]) + - `muse` ([Muse]), + - `native` (native Haskell), + - `odt` ([OpenOffice text document][ODT]) + - `opml` ([OPML]) + - `opendocument` ([OpenDocument]) + - `org` ([Emacs Org mode]) + - `plain` (plain text), + - `pptx` ([PowerPoint] slide show) + - `rst` ([reStructuredText]) + - `rtf` ([Rich Text Format]) + - `texinfo` ([GNU Texinfo]) + - `textile` ([Textile]) + - `slideous` ([Slideous] HTML and JavaScript slide show) + - `slidy` ([Slidy] HTML and JavaScript slide show) + - `dzslides` ([DZSlides] HTML5 + JavaScript slide show), + - `revealjs` ([reveal.js] HTML5 + JavaScript slide show) + - `s5` ([S5] HTML and JavaScript slide show) + - `tei` ([TEI Simple]) + - `zimwiki` ([ZimWiki markup]) + - the path of a custom lua writer, see [Custom writers] below + ::: + + Note that `odt`, `docx`, and `epub` output will not be directed + to *stdout* unless forced with `-o -`. + + Extensions can be individually enabled or disabled by appending `+EXTENSION` or `-EXTENSION` to the format name. See [Extensions] below, for a list of extensions and their names. See `--list-output-formats` and `--list-extensions`, below. @@ -424,6 +407,56 @@ General options : Show usage message. +[Markdown]: http://daringfireball.net/projects/markdown/ +[CommonMark]: http://commonmark.org +[PHP Markdown Extra]: https://michelf.ca/projects/php-markdown/extra/ +[GitHub-Flavored Markdown]: https://help.github.com/articles/github-flavored-markdown/ +[MultiMarkdown]: http://fletcherpenney.net/multimarkdown/ +[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html +[S5]: http://meyerweb.com/eric/tools/s5/ +[Slidy]: http://www.w3.org/Talks/Tools/Slidy/ +[Slideous]: http://goessner.net/articles/slideous/ +[HTML]: http://www.w3.org/html/ +[HTML5]: http://www.w3.org/TR/html5/ +[polyglot markup]: https://www.w3.org/TR/html-polyglot/ +[XHTML]: http://www.w3.org/TR/xhtml1/ +[LaTeX]: http://latex-project.org +[`beamer`]: https://ctan.org/pkg/beamer +[Beamer User's Guide]: http://ctan.math.utah.edu/ctan/tex-archive/macros/latex/contrib/beamer/doc/beameruserguide.pdf +[ConTeXt]: http://www.contextgarden.net/ +[Rich Text Format]: http://en.wikipedia.org/wiki/Rich_Text_Format +[DocBook]: http://docbook.org +[JATS]: https://jats.nlm.nih.gov +[txt2tags]: http://txt2tags.org +[EPUB]: http://idpf.org/epub +[OPML]: http://dev.opml.org/spec2.html +[OpenDocument]: http://opendocument.xml.org +[ODT]: http://en.wikipedia.org/wiki/OpenDocument +[Textile]: http://redcloth.org/textile +[MediaWiki markup]: https://www.mediawiki.org/wiki/Help:Formatting +[DokuWiki markup]: https://www.dokuwiki.org/dokuwiki +[ZimWiki markup]: http://zim-wiki.org/manual/Help/Wiki_Syntax.html +[TWiki markup]: http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules +[TikiWiki markup]: https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax +[Haddock markup]: https://www.haskell.org/haddock/doc/html/ch03s08.html +[Creole 1.0]: http://www.wikicreole.org/wiki/Creole1.0 +[groff man]: http://man7.org/linux/man-pages/man7/groff_man.7.html +[groff ms]: http://man7.org/linux/man-pages/man7/groff_ms.7.html +[Haskell]: https://www.haskell.org +[GNU Texinfo]: http://www.gnu.org/software/texinfo/ +[Emacs Org mode]: http://orgmode.org +[AsciiDoc]: http://www.methods.co.nz/asciidoc/ +[DZSlides]: http://paulrouget.com/dzslides/ +[Word docx]: https://en.wikipedia.org/wiki/Office_Open_XML +[PDF]: https://www.adobe.com/pdf/ +[reveal.js]: http://lab.hakim.se/reveal-js/ +[FictionBook2]: http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1 +[InDesign ICML]: http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf +[TEI Simple]: https://github.com/TEIC/TEI-Simple +[Muse]: https://amusewiki.org/library/manual +[PowerPoint]: https://en.wikipedia.org/wiki/Microsoft_PowerPoint +[Vimwiki]: https://vimwiki.github.io + Reader options -------------- @@ -521,6 +554,14 @@ Reader options return {{Str = expand_hello_world}} + In order of preference, pandoc will look for lua filters in + + 1. a specified full or relative path (executable or + non-executable) + + 2. `$DATADIR/filters` (executable or non-executable) + where `$DATADIR` is the user data directory (see + `--data-dir`, above). `-M` *KEY*[`=`*VAL*], `--metadata=`*KEY*[`:`*VAL*] @@ -797,9 +838,10 @@ Options affecting specific writers `--ascii` -: Use only ASCII characters in output. Currently supported only for - HTML and DocBook output (which uses numerical entities instead of - UTF-8 when this option is selected). +: Use only ASCII characters in output. Currently supported for + XML and HTML formats (which use numerical entities instead of + UTF-8 when this option is selected) and for groff ms and man + (which use hexadecimal escapes). `--reference-links` @@ -1173,54 +1215,8 @@ of the following options. not specified, a link to the KaTeX CDN will be inserted. Note that this option does not imply `--katex`. -`-m` [*URL*], `--latexmathml`[`=`*URL*] - -: *Deprecated.* - Use the [LaTeXMathML] script to display embedded TeX math in HTML output. - TeX math will be displayed between `$` or `$$` characters and put in - `<span>` tags with class `LaTeX`. The LaTeXMathML JavaScript will then - change it to MathML. Note that currently only Firefox and Safari - (and select e-book readers) natively support MathML. - To insert a link the `LaTeXMathML.js` script, provide a *URL*. - -`--jsmath`[`=`*URL*] - -: *Deprecated.* - Use [jsMath] (the predecessor of MathJax) to display embedded TeX - math in HTML output. TeX math will be put inside `<span>` tags - (for inline math) or `<div>` tags (for display math) with class - `math` and rendered by the jsMath script. The *URL* should point to - the script (e.g. `jsMath/easy/load.js`); if provided, it will be linked - to in the header of standalone HTML documents. If a *URL* is not provided, - no link to the jsMath load script will be inserted; it is then - up to the author to provide such a link in the HTML template. - -`--gladtex` - -: *Deprecated.* - Enclose TeX math in `<eq>` tags in HTML output. The resulting HTML - can then be processed by [gladTeX] to produce images of the typeset - formulas and an HTML file with links to these images. - So, the procedure is: - - pandoc -s --gladtex input.md -o myfile.htex - gladtex -d myfile-images myfile.htex - # produces myfile.html and images in myfile-images - -`--mimetex`[`=`*URL*] - -: *Deprecated.* - Render TeX math using the [mimeTeX] CGI script, which generates an - image for each TeX formula. This should work in all browsers. If - *URL* is not specified, it is assumed that the script is at - `/cgi-bin/mimetex.cgi`. - [MathML]: http://www.w3.org/Math/ -[LaTeXMathML]: http://math.etsu.edu/LaTeXMathML/ -[jsMath]: http://www.math.union.edu/~dpvc/jsmath/ [MathJax]: https://www.mathjax.org -[gladTeX]: http://ans.hsh.no/home/mgg/gladtex/ -[mimeTeX]: http://www.forkosh.com/mimetex.html [KaTeX]: https://github.com/Khan/KaTeX Options for wrapper scripts @@ -1986,7 +1982,7 @@ input formats : `docx`, `html` output formats -: `markdown`, `docx`, `odt`, `opendocument`, `html` +: `docx`, `odt`, `opendocument`, `html` #### Extension: `styles` #### {#ext-styles} @@ -54,9 +54,9 @@ debpkg: man/pandoc.1 macospkg: man/pandoc.1 ./macos/make_macos_package.sh -winpkg: pandoc-$(version)-windows.msi pandoc-$(version)-windows.zip +winpkg: pandoc-$(version)-windows-i386.msi pandoc-$(version)-windows-i386.zip pandoc-$(version)-windows-x86_64.msi pandoc-$(version)-windows-x86_64.zip -pandoc-$(version)-windows.zip: pandoc-$(version)-windows.msi +pandoc-$(version)-windows-%.zip: pandoc-$(version)-windows-%.msi -rm -rf wintmp && \ msiextract -C wintmp $< && \ cd wintmp/"Program Files" && \ @@ -66,10 +66,17 @@ pandoc-$(version)-windows.zip: pandoc-$(version)-windows.msi cd ../.. && \ rm -rf wintmp -pandoc-$(version)-windows.msi: - wget 'https://ci.appveyor.com/api/projects/jgm/pandoc/artifacts/windows/pandoc-windows-i386.msi?branch=$(BRANCH)' -O pandoc.msi && \ - osslsigncode sign -pkcs12 ~/Private/ComodoCodeSigning.exp2019.p12 -in pandoc.msi -i http://johnmacfarlane.net/ -t http://timestamp.comodoca.com/ -out $@ -askpass - rm pandoc.msi +pandoc-$(version)-windows-%.msi: pandoc-windows-%.msi + osslsigncode sign -pkcs12 ~/Private/ComodoCodeSigning.exp2019.p12 -in $< -i http://johnmacfarlane.net/ -t http://timestamp.comodoca.com/ -out $@ -askpass + rm $< + +pandoc-windows-i386.msi: + JOBID=$(shell curl 'https://ci.appveyor.com/api/projects/jgm/pandoc' | jq -r '.build.jobs[0].jobId') && \ + wget "https://ci.appveyor.com/api/buildjobs/$$JOBID/artifacts/windows%2F$@" -O $@ + +pandoc-windows-x86_64.msi: + JOBID=$(shell curl 'https://ci.appveyor.com/api/projects/jgm/pandoc' | jq -r '.build.jobs[1].jobId') && \ + wget "https://ci.appveyor.com/api/buildjobs/$$JOBID/artifacts/windows%2F$@" -O $@ man/pandoc.1: MANUAL.txt man/pandoc.1.template pandoc $< -f markdown-smart -t man -s --template man/pandoc.1.template \ @@ -22,93 +22,150 @@ groups](https://img.shields.io/badge/pandoc-discuss-red.svg?style=social)](https ## The universal markup converter -<div id="description"> - -Pandoc is a [Haskell](https://www.haskell.org) library for converting -from one markup format to another, and a command-line tool that uses -this library. - -Pandoc can read -[Markdown](http://daringfireball.net/projects/markdown/), -[CommonMark](http://commonmark.org), [PHP Markdown -Extra](https://michelf.ca/projects/php-markdown/extra/), -[GitHub-Flavored -Markdown](https://help.github.com/articles/github-flavored-markdown/), -[MultiMarkdown](http://fletcherpenney.net/multimarkdown/), and (subsets -of) [Textile](http://redcloth.org/textile), -[reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html), -[HTML](http://www.w3.org/html/), [LaTeX](http://latex-project.org), -[MediaWiki markup](https://www.mediawiki.org/wiki/Help:Formatting), -[TWiki markup](http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules), -[TikiWiki -markup](https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax), -[Creole 1.0](http://www.wikicreole.org/wiki/Creole1.0), [Haddock -markup](https://www.haskell.org/haddock/doc/html/ch03s08.html), -[OPML](http://dev.opml.org/spec2.html), [Emacs Org -mode](http://orgmode.org), [DocBook](http://docbook.org), -[JATS](https://jats.nlm.nih.gov), -[Muse](https://amusewiki.org/library/manual), -[txt2tags](http://txt2tags.org), [Vimwiki](https://vimwiki.github.io), -[EPUB](http://idpf.org/epub), -[ODT](http://en.wikipedia.org/wiki/OpenDocument), and [Word -docx](https://en.wikipedia.org/wiki/Office_Open_XML). - -Pandoc can write plain text, -[Markdown](http://daringfireball.net/projects/markdown/), -[CommonMark](http://commonmark.org), [PHP Markdown -Extra](https://michelf.ca/projects/php-markdown/extra/), -[GitHub-Flavored -Markdown](https://help.github.com/articles/github-flavored-markdown/), -[MultiMarkdown](http://fletcherpenney.net/multimarkdown/), -[reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html), -[XHTML](http://www.w3.org/TR/xhtml1/), -[HTML5](http://www.w3.org/TR/html5/), [LaTeX](http://latex-project.org) -(including [`beamer`](https://ctan.org/pkg/beamer) slide shows), -[ConTeXt](http://www.contextgarden.net/), -[RTF](http://en.wikipedia.org/wiki/Rich_Text_Format), -[OPML](http://dev.opml.org/spec2.html), [DocBook](http://docbook.org), -[JATS](https://jats.nlm.nih.gov), -[OpenDocument](http://opendocument.xml.org), -[ODT](http://en.wikipedia.org/wiki/OpenDocument), [Word -docx](https://en.wikipedia.org/wiki/Office_Open_XML), [GNU -Texinfo](http://www.gnu.org/software/texinfo/), [MediaWiki -markup](https://www.mediawiki.org/wiki/Help:Formatting), [DokuWiki -markup](https://www.dokuwiki.org/dokuwiki), [ZimWiki -markup](http://zim-wiki.org/manual/Help/Wiki_Syntax.html), [Haddock -markup](https://www.haskell.org/haddock/doc/html/ch03s08.html), -[EPUB](http://idpf.org/epub) (v2 or v3), -[FictionBook2](http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1), -[Textile](http://redcloth.org/textile), [groff -man](http://man7.org/linux/man-pages/man7/groff_man.7.html), [groff -ms](http://man7.org/linux/man-pages/man7/groff_ms.7.html), [Emacs Org -mode](http://orgmode.org), -[AsciiDoc](http://www.methods.co.nz/asciidoc/), [InDesign -ICML](http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf), -[TEI Simple](https://github.com/TEIC/TEI-Simple), -[Muse](https://amusewiki.org/library/manual), -[PowerPoint](https://en.wikipedia.org/wiki/Microsoft_PowerPoint) slide -shows and [Slidy](http://www.w3.org/Talks/Tools/Slidy/), -[Slideous](http://goessner.net/articles/slideous/), -[DZSlides](http://paulrouget.com/dzslides/), -[reveal.js](http://lab.hakim.se/reveal-js/) or -[S5](http://meyerweb.com/eric/tools/s5/) HTML slide shows. It can also -produce [PDF](https://www.adobe.com/pdf/) output on systems where LaTeX, -ConTeXt, `pdfroff`, `wkhtmltopdf`, `prince`, or `weasyprint` is -installed. +Pandoc is a \[Haskell\] library for converting from one markup format to +another, and a command-line tool that uses this library. It can convert +*from* + +<div id="input-formats"> + + - `commonmark` ([CommonMark](http://commonmark.org) Markdown) + - `creole` ([Creole 1.0](http://www.wikicreole.org/wiki/Creole1.0)) + - `docbook` ([DocBook](http://docbook.org)) + - `docx` ([Word docx](https://en.wikipedia.org/wiki/Office_Open_XML)) + - `epub` ([EPUB](http://idpf.org/epub)) + - `gfm` ([GitHub-Flavored + Markdown](https://help.github.com/articles/github-flavored-markdown/)), + or `markdown_github`, which provides deprecated and less accurate + support for Github-Flavored Markdown; please use `gfm` instead, + unless you need to use extensions other than `smart`. + - `haddock` ([Haddock + markup](https://www.haskell.org/haddock/doc/html/ch03s08.html)) + - `html` ([HTML](http://www.w3.org/html/)) + - `jats` ([JATS](https://jats.nlm.nih.gov) XML) + - `json` (JSON version of native AST) + - `latex` ([LaTeX](http://latex-project.org)) + - `markdown` ([Pandoc’s Markdown](#pandocs-markdown)) + - `markdown_mmd` + ([MultiMarkdown](http://fletcherpenney.net/multimarkdown/)) + - `markdown_phpextra` ([PHP Markdown + Extra](https://michelf.ca/projects/php-markdown/extra/)) + - `markdown_strict` (original unextended + [Markdown](http://daringfireball.net/projects/markdown/)) + - `mediawiki` ([MediaWiki + markup](https://www.mediawiki.org/wiki/Help:Formatting)) + - `muse` ([Muse](https://amusewiki.org/library/manual)) + - `native` (native Haskell) + - `odt` ([ODT](http://en.wikipedia.org/wiki/OpenDocument)) + - `opml` ([OPML](http://dev.opml.org/spec2.html)) + - `org` ([Emacs Org mode](http://orgmode.org)) + - `rst` + ([reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html)) + - `t2t` ([txt2tags](http://txt2tags.org)) + - `textile` ([Textile](http://redcloth.org/textile)) + - `tikiwiki` ([TikiWiki + markup](https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax)) + - `twiki` ([TWiki + markup](http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules)) + - `vimwiki` ([Vimwiki](https://vimwiki.github.io)) + +</div> + +It can convert *to* + +<div id="output-formats"> + + - `asciidoc` ([AsciiDoc](http://www.methods.co.nz/asciidoc/)) + - `beamer` ([LaTeX beamer](https://ctan.org/pkg/beamer) slide show) + - `commonmark` ([CommonMark](http://commonmark.org) Markdown) + - `context` ([ConTeXt](http://www.contextgarden.net/)) + - `docbook` or `docbook4` ([DocBook](http://docbook.org) 4) + - `docbook5` (DocBook 5) + - `docx` ([Word docx](https://en.wikipedia.org/wiki/Office_Open_XML)) + - `dokuwiki` ([DokuWiki markup](https://www.dokuwiki.org/dokuwiki)) + - `epub` or `epub3` ([EPUB](http://idpf.org/epub) v3 book) + - `epub2` (EPUB v2) + - `fb2` + ([FictionBook2](http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1) + e-book) + - `gfm` ([GitHub-Flavored + Markdown](https://help.github.com/articles/github-flavored-markdown/)), + or `markdown_github`, which provides deprecated and less accurate + support for Github-Flavored Markdown; please use `gfm` instead, + unless you use extensions that do not work with `gfm`. + - `haddock` ([Haddock + markup](https://www.haskell.org/haddock/doc/html/ch03s08.html)) + - `html` or `html5` ([HTML](http://www.w3.org/html/), i.e. + [HTML5](http://www.w3.org/TR/html5/)/XHTML [polyglot + markup](https://www.w3.org/TR/html-polyglot/)) + - `html4` ([XHTML](http://www.w3.org/TR/xhtml1/) 1.0 Transitional) + - `icml` ([InDesign + ICML](http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf)) + - `jats` ([JATS](https://jats.nlm.nih.gov) XML) + - `json` (JSON version of native AST) + - `latex` ([LaTeX](http://latex-project.org)) + - `man` ([groff + man](http://man7.org/linux/man-pages/man7/groff_man.7.html)) + - `markdown` ([Pandoc’s Markdown](#pandocs-markdown)) + - `markdown_mmd` + ([MultiMarkdown](http://fletcherpenney.net/multimarkdown/)) + - `markdown_phpextra` ([PHP Markdown + Extra](https://michelf.ca/projects/php-markdown/extra/)) + - `markdown_strict` (original unextended + [Markdown](http://daringfireball.net/projects/markdown/)) + - `mediawiki` ([MediaWiki + markup](https://www.mediawiki.org/wiki/Help:Formatting)) + - `ms` ([groff + ms](http://man7.org/linux/man-pages/man7/groff_ms.7.html)) + - `muse` ([Muse](https://amusewiki.org/library/manual)), + - `native` (native Haskell), + - `odt` ([OpenOffice text + document](http://en.wikipedia.org/wiki/OpenDocument)) + - `opml` ([OPML](http://dev.opml.org/spec2.html)) + - `opendocument` ([OpenDocument](http://opendocument.xml.org)) + - `org` ([Emacs Org mode](http://orgmode.org)) + - `plain` (plain text), + - `pptx` + ([PowerPoint](https://en.wikipedia.org/wiki/Microsoft_PowerPoint) + slide show) + - `rst` + ([reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html)) + - `rtf` ([Rich Text + Format](http://en.wikipedia.org/wiki/Rich_Text_Format)) + - `texinfo` ([GNU Texinfo](http://www.gnu.org/software/texinfo/)) + - `textile` ([Textile](http://redcloth.org/textile)) + - `slideous` ([Slideous](http://goessner.net/articles/slideous/) HTML + and JavaScript slide show) + - `slidy` ([Slidy](http://www.w3.org/Talks/Tools/Slidy/) HTML and + JavaScript slide show) + - `dzslides` ([DZSlides](http://paulrouget.com/dzslides/) HTML5 + + JavaScript slide show), + - `revealjs` ([reveal.js](http://lab.hakim.se/reveal-js/) HTML5 + + JavaScript slide show) + - `s5` ([S5](http://meyerweb.com/eric/tools/s5/) HTML and JavaScript + slide show) + - `tei` ([TEI Simple](https://github.com/TEIC/TEI-Simple)) + - `zimwiki` ([ZimWiki + markup](http://zim-wiki.org/manual/Help/Wiki_Syntax.html)) + - the path of a custom lua writer, see [Custom + writers](#custom-writers) below + +</div> + +Pandoc can also produce PDF output via LaTeX, Groff ms, or HTML. Pandoc’s enhanced version of Markdown includes syntax for tables, -definition lists, metadata blocks, `Div` blocks, footnotes and -citations, embedded LaTeX (including math), Markdown inside HTML block -elements, and much more. These enhancements, described further under -Pandoc’s Markdown, can be disabled using the `markdown_strict` format. +definition lists, metadata blocks, footnotes, citations, math, and much +more. See the User’s Manual below under [Pandoc’s +Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown). Pandoc has a modular design: it consists of a set of readers, which parse text in a given format and produce a native representation of the -document (like an *abstract syntax tree* or AST), and a set of writers, -which convert this native representation into a target format. Thus, -adding an input or output format requires only adding a reader or -writer. Users can also run custom [pandoc -filters](http://pandoc.org/filters.html) to modify the intermediate AST. +document (an *abstract syntax tree* or AST), and a set of writers, which +convert this native representation into a target format. Thus, adding an +input or output format requires only adding a reader or writer. Users +can also run custom pandoc filters to modify the intermediate AST (see +the documentation for [filters](https://pandoc.org/filters.html) and +[lua filters](https://pandoc.org/lua-filters.html)). Because pandoc’s intermediate representation of a document is less expressive than many of the formats it converts between, one should not @@ -120,8 +177,6 @@ While conversions from pandoc’s Markdown to all formats aspire to be perfect, conversions from formats more expressive than pandoc’s Markdown can be expected to be lossy. -</div> - ## Installing Here’s [how to install pandoc](INSTALL.md). diff --git a/README.template b/README.template index cf664647a..54cb3b515 100644 --- a/README.template +++ b/README.template @@ -19,9 +19,44 @@ Pandoc The universal markup converter ------------------------------ -::: description +Pandoc is a [Haskell] library for converting from one markup format to +another, and a command-line tool that uses this library. It can convert *from* + +::: {#input-formats} ::: +It can convert *to* + +::: {#output-formats} +::: + +Pandoc can also produce PDF output via LaTeX, Groff ms, or HTML. + +Pandoc's enhanced version of Markdown includes syntax for tables, +definition lists, metadata blocks, footnotes, citations, math, +and much more. See the User's Manual below under +[Pandoc's Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown). + +Pandoc has a modular design: it consists of a set of readers, which parse +text in a given format and produce a native representation of the document +(an _abstract syntax tree_ or AST), and a set of writers, which convert +this native representation into a target format. Thus, adding an input +or output format requires only adding a reader or writer. Users can also +run custom pandoc filters to modify the intermediate AST (see +the documentation for [filters](https://pandoc.org/filters.html) +and [lua filters](https://pandoc.org/lua-filters.html)). + +Because pandoc's intermediate representation of a document is less +expressive than many of the formats it converts between, one should +not expect perfect conversions between every format and every other. +Pandoc attempts to preserve the structural elements of a document, but +not formatting details such as margin size. And some document elements, +such as complex tables, may not fit into pandoc's simple document +model. While conversions from pandoc's Markdown to all formats aspire +to be perfect, conversions from formats more expressive than pandoc's +Markdown can be expected to be lossy. + + Installing ---------- diff --git a/appveyor.yml b/appveyor.yml index 172c62b3f..f0d4975f9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,10 +11,10 @@ environment: STACK_ROOT: "c:\\sr32" STACK: "%STACK_ROOT%\\stack.exe" STACK_FLAGS: "--flag=hslua:lua_32bits" -# - STACK_VERSION: "windows-x86_64" -# STACK_ROOT: "c:\\sr64" -# STACK: "%STACK_ROOT%\\stack.exe" -# STACK_FLAGS: "" + - STACK_VERSION: "windows-x86_64" + STACK_ROOT: "c:\\sr64" + STACK: "%STACK_ROOT%\\stack.exe" + STACK_FLAGS: "" skip_commits: files: @@ -1,3 +1,240 @@ +pandoc (2.1.4) + + * Markdown reader: + + + Allow empty key-value attributes, like `title=""` (#2944). + + Handle table w/o following blank line in fenced div (#4560). + + Remove "fallback" for `doubleQuote` parser. Previously the + parser tried to be efficient -- if no end double quote was found, + it would just return the contents. But this could backfire in a + case `**this should "be bold**`, since the fallback would return + the content `"be bold**` and the closing boldface delimiter + would never be encountered. + + Improve computation of the relative width of the last column in a + multiline table, so we can round-trip tables without constantly + shrinking the last column. + + * EPUB reader: + + + Fix images with space in file path (#4344). + + * LaTeX reader: + + + Properly resolve section numbers with `\ref` and chapters (#4529). + + Parse sloppypar environment (#4517, Marc Schreiber). + + * Textile reader: + + + Fixed tables with no body rows (#4513). + Previously these raised an exception. + + * Mediawiki reader: + + + Improve table parsing (#4508). This fixes detection of table + attributes and also handles `!` characters in cells. + + * DocBook reader: + + + Properly handle title in `section` element (#4526). + Previously we just got `section_title` for `section` (though `sect1`, + `sect2`, etc. were handled properly). + + * Docx reader: + + + Combine adjacent CodeBlocks with the same attributes into + a single CodeBlock. This prevents a multiline codeblock in + Word from being read as different paragraphs. + + * RST reader: + + + Allow < 3 spaces indent under directives (#4579). + + * Muse reader (Alexander Krotov): + + + Add support for Text:Amuse multiline headings. + + Add `<math>` tag support. + + Add support for `<biblio>` and `<play>` tags. + + Allow links to have empty descriptions. + + Require block `<literal>` tags to be on separate lines. + + Allow `-` in anchors. + + Allow verse to be indented. + + Internal improvements. + + * Muse writer (Alexander Krotov): + + + Escape `>` only at the beginning of a line. + + Escape `]` in image title. + + Escape `]` brackets in URLs as `%5D`. + + Only escape brackets when necessary. + + Escape ordered list markers. + + Do not escape list markers unless preceded by space. + + Escape strings starting with space. + + Escape semicolons and markers after line break. + + Escape `;` to avoid accidental comments. + + Don't break headers, line blocks and tables with line breaks. + + Correctly output empty headings. + + Escape horizontal rule only if at the beginning of the line. + + Escape definition list terms starting with list markers. + + Place header IDs before header. + + Improve span writing. + + Do not join Spans in normalization. + + Don't align ordered list items. + + Remove key-value pairs from attributes before normalization. + + Enable `--wrap=preserve` for all tests by default. + + Reduced `<verbatim>` tags in output. + + Internal changes. + + * RST writer: + + + Use more consistent indentation (#4563). Previously we + used an odd mix of 3- and 4-space indentation. Now we use 3-space + indentation, except for ordered lists, where indentation must + depend on the width of the list marker. + + * EPUB writer: + + + Ensure that `pagetitle` is always set, even when structured titles + are used. This prevents spurious warnings about empty title + elements (#4486). + + * FB2 writer (Alexander Krotov): + + + Output links inline instead of producing notes. Previously all links + were turned into footnotes with unclickable URLs inside. + + Allow emphasis and notes in titles. + + Don't intersperse paragraph with empty lines. + + Convert metadata value `abstract` to book annotation. + + * Powerpoint writer (Jesse Rosenthal): + + + Handle Quoted Inlines (#4532). + + Simplify code with `ParseXml`. + + Allow fallback options when looking for placeholder type. + + Check reference-doc for all layouts. + + Simplify speaker notes logic. + + Change notes state to a simpler per-slide value. + + Remove `Maybe` from `SpeakerNotes` in `Slide`. `mempty` + means no speaker notes. + + Add tests for improved speaker notes. + + Handle speaker notes earlier in the conversion process. + + Keep notes with related blocks (#4477). Some blocks automatically + split slides (imgs, tables, `column` divs). We assume that any + speaker notes immediately following these are connected to these + elements, and keep them with the related blocks, splitting after them. + + * Markdown writer: + + + Include a blank line at the end of the row in a single-row multiline + table, to prevent it from being interpreted as a simple table (#4578). + + * CommonMark writer: + + + Correctly ignore LaTeX raw blocks when `raw_tex` is not + enabled (#4527, quasicomputational). + + * EPUB writer: + + + Add `epub:type="footnotes"` to notes section in EPUB3 (#4489). + + * LaTeX writer: + + + In beamer, don't use format specifier for default ordered lists + (#4556). This gives better results for styles that put ordered list + markers in boxes or circles. + + * Ms writer: + + + Use `\f[R]` rather than `\f[]` to reset font (#4552). + + Use `\f[BI]` and `\f[CB]` in headers, instead of `\f[I]` and `\f[C]`, + since the header font is automatically bold (#4552). + + Use `\f[CB]` rather than `\f[BC]` for monospace bold (#4552). + + Create pdf anchor for a Div with an identifier (#4515). + + Escape `/` character in anchor ids (#4515). + + Improve escaping for anchor ids: we now use _uNNN_ instead of uNNN + to avoid ambiguity. + + * Man writer: + + + Don't escape U+2019 as `'` (#4550). + + * Text.Pandoc.Class: + + + `writeMedia`: unescape URI-escaping in file path. This avoids + writing things like `file%20one.png` to the file system. + + * Text.Pandoc.Parsing: + + + Fix `romanNumeral` parser (#4480). We previously accepted 'DDC' + as 1100. + + `uri`: don't treat `*` characters at end as part of URI (#4561). + + * Text.Pandoc.MIME: + + + Use the alias `application/eps` for EPS (#2067). + This will ensure that we retain the eps extension after reading the + image into a mediabag and writing it again. + + * Text.Pandoc.PDF: + + + Use `withTempDir` in `html2pdf`. + + With `xelatex`, don't compress images til the last run (#4484). + This saves time for image-heavy documents. + + Don't try to convert EPS files (#2067). `pdflatex converts them + itself, and JuicyPixels can't do it. + + For `pdflatex`, use a temp directory in the working directory. + Otherwise we can have problems with the EPS conversion pdflatex + tries to do, which can't operate on a file above the working + directory without `--shell-escape`. + + * Changes to tests to accommodate changes in pandoc-types. + In <https://github.com/jgm/pandoc-types/pull/36> we changed + the table builder to pad cells. This commit changes tests + (and two readers) to accord with this behavior. + + * Set default extensions for `beamer` same as `latex`. + + * LaTeX template: + + + Add `beameroption` variable (#4359, Étienne Bersac). + + Use `pgfpages` package; this is needed for notes on second + screen in beamer (Étienne Bersac). + + * Removed pragmas for unused extensions (#4506, Anabra). + + * Fix bash completion for `--print-default-data-file` (#4549). + Previously this looked in the filesystem, even if pandoc + was compiled with `embed_data_files` (and sometimes it looked + in a nonexistent build directory). Now the bash completion + script just includes a hard-coded list of data file names. + + * MANUAL: + + + Clarify template vs metadata variables (#4501, Mauro Bieg). + + Fix raw content example (#4479, Mauro Bieg). + + Specify that you use html for raw output in epub. + + Add examples for raw docx blocks (#4472, Tristan Stenner). + The documentation states that the target format name should match + the output format, which isn't the case for `docx`/`openxml` and + some others. + + Don't say that `empty_paragraphs` affects markdown output (#4540). + + Consolidate input/output format documentation (#4577, Mauro Bieg). + + * New README template. Take in/out formats from manual. + + * Fix example in lua-filters docs (#4459, HeirOfNorton). + + * Use the `-threaded` GHC flag when building benchmarks (#4587, + Francesco Occhipinti). + + * Bump temporary upper bound to 1.4. + + * Use pandoc-citeproc 0.14.3. + + * Removed old lib directory. This was used for something long ago, + but plays no role now. + + * Create 64- and 32-bit versions of Windows binary packages. + pandoc (2.1.3) * Docx reader (Jesse Rosenthal): @@ -18,11 +255,14 @@ pandoc (2.1.3) * Muse reader (Alexander Krotov): - + Various internal improvements. + Require closing tag to have the same indentation as opening. + Do not reparse blocks inside unclosed block tag (#4425). + Parse `<class>` tag (supported by Emacs Muse). + Do not produce empty Str element for unindented verse lines. + + Don't allow footnote references inside links. + + Allow URL to be empty. + + Require that comment semicolons are in the first column (#4551). + + Various internal improvements. * LaTeX reader: diff --git a/data/LaTeXMathML.js b/data/LaTeXMathML.js deleted file mode 100644 index 4957624de..000000000 --- a/data/LaTeXMathML.js +++ /dev/null @@ -1,198 +0,0 @@ -/* -LaTeXMathML.js from http://math.etsu.edu/LaTeXMathML/ -Adapted by Jeff Knisely and Douglas Woodall from ASCIIMathML.js v. 1.4.7, -(c) 2005 Peter Jipsen http://www.chapman.edu/~jipsen. -Released under the GNU General Public License version 2 or later. -See the GNU General Public License (at http://www.gnu.org/copyleft/gpl.html) -for more details. -*/ -var checkForMathML=true;var notifyIfNoMathML=true;var alertIfNoMathML=false;var mathcolor="";var mathfontfamily="";var showasciiformulaonhover=true;var isIE=document.createElementNS==null;if(document.getElementById==null) -alert("This webpage requires a recent browser such as \nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer") -function AMcreateElementXHTML(t){if(isIE)return document.createElement(t);else return document.createElementNS("http://www.w3.org/1999/xhtml",t);} -function AMnoMathMLNote(){var nd=AMcreateElementXHTML("h3");nd.setAttribute("align","center") -nd.appendChild(AMcreateElementXHTML("p"));nd.appendChild(document.createTextNode("To view the "));var an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("LaTeXMathML"));an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html");nd.appendChild(an);nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+"));an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("MathPlayer"));an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");nd.appendChild(an);nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));nd.appendChild(AMcreateElementXHTML("p"));return nd;} -function AMisMathMLavailable(){if(navigator.appName.slice(0,8)=="Netscape") -if(navigator.appVersion.slice(0,1)>="5")return null;else return AMnoMathMLNote();else if(navigator.appName.slice(0,9)=="Microsoft") -try{var ActiveX=new ActiveXObject("MathPlayer.Factory.1");return null;}catch(e){return AMnoMathMLNote();} -else return AMnoMathMLNote();} -var AMcal=[0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46];var AMfrk=[0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128];var AMbbb=[0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124];var CONST=0,UNARY=1,BINARY=2,INFIX=3,LEFTBRACKET=4,RIGHTBRACKET=5,SPACE=6,UNDEROVER=7,DEFINITION=8,TEXT=9,BIG=10,LONG=11,STRETCHY=12,MATRIX=13;var AMsqrt={input:"\\sqrt",tag:"msqrt",output:"sqrt",ttype:UNARY},AMroot={input:"\\root",tag:"mroot",output:"root",ttype:BINARY},AMfrac={input:"\\frac",tag:"mfrac",output:"/",ttype:BINARY},AMover={input:"\\stackrel",tag:"mover",output:"stackrel",ttype:BINARY},AMatop={input:"\\atop",tag:"mfrac",output:"",ttype:INFIX},AMchoose={input:"\\choose",tag:"mfrac",output:"",ttype:INFIX},AMsub={input:"_",tag:"msub",output:"_",ttype:INFIX},AMsup={input:"^",tag:"msup",output:"^",ttype:INFIX},AMtext={input:"\\mathrm",tag:"mtext",output:"text",ttype:TEXT},AMmbox={input:"\\mbox",tag:"mtext",output:"mbox",ttype:TEXT};var AMsymbols=[{input:"\\alpha",tag:"mi",output:"\u03B1",ttype:CONST},{input:"\\beta",tag:"mi",output:"\u03B2",ttype:CONST},{input:"\\gamma",tag:"mi",output:"\u03B3",ttype:CONST},{input:"\\delta",tag:"mi",output:"\u03B4",ttype:CONST},{input:"\\epsilon",tag:"mi",output:"\u03B5",ttype:CONST},{input:"\\varepsilon",tag:"mi",output:"\u025B",ttype:CONST},{input:"\\zeta",tag:"mi",output:"\u03B6",ttype:CONST},{input:"\\eta",tag:"mi",output:"\u03B7",ttype:CONST},{input:"\\theta",tag:"mi",output:"\u03B8",ttype:CONST},{input:"\\vartheta",tag:"mi",output:"\u03D1",ttype:CONST},{input:"\\iota",tag:"mi",output:"\u03B9",ttype:CONST},{input:"\\kappa",tag:"mi",output:"\u03BA",ttype:CONST},{input:"\\lambda",tag:"mi",output:"\u03BB",ttype:CONST},{input:"\\mu",tag:"mi",output:"\u03BC",ttype:CONST},{input:"\\nu",tag:"mi",output:"\u03BD",ttype:CONST},{input:"\\xi",tag:"mi",output:"\u03BE",ttype:CONST},{input:"\\pi",tag:"mi",output:"\u03C0",ttype:CONST},{input:"\\varpi",tag:"mi",output:"\u03D6",ttype:CONST},{input:"\\rho",tag:"mi",output:"\u03C1",ttype:CONST},{input:"\\varrho",tag:"mi",output:"\u03F1",ttype:CONST},{input:"\\varsigma",tag:"mi",output:"\u03C2",ttype:CONST},{input:"\\sigma",tag:"mi",output:"\u03C3",ttype:CONST},{input:"\\tau",tag:"mi",output:"\u03C4",ttype:CONST},{input:"\\upsilon",tag:"mi",output:"\u03C5",ttype:CONST},{input:"\\phi",tag:"mi",output:"\u03C6",ttype:CONST},{input:"\\varphi",tag:"mi",output:"\u03D5",ttype:CONST},{input:"\\chi",tag:"mi",output:"\u03C7",ttype:CONST},{input:"\\psi",tag:"mi",output:"\u03C8",ttype:CONST},{input:"\\omega",tag:"mi",output:"\u03C9",ttype:CONST},{input:"\\Gamma",tag:"mo",output:"\u0393",ttype:CONST},{input:"\\Delta",tag:"mo",output:"\u0394",ttype:CONST},{input:"\\Theta",tag:"mo",output:"\u0398",ttype:CONST},{input:"\\Lambda",tag:"mo",output:"\u039B",ttype:CONST},{input:"\\Xi",tag:"mo",output:"\u039E",ttype:CONST},{input:"\\Pi",tag:"mo",output:"\u03A0",ttype:CONST},{input:"\\Sigma",tag:"mo",output:"\u03A3",ttype:CONST},{input:"\\Upsilon",tag:"mo",output:"\u03A5",ttype:CONST},{input:"\\Phi",tag:"mo",output:"\u03A6",ttype:CONST},{input:"\\Psi",tag:"mo",output:"\u03A8",ttype:CONST},{input:"\\Omega",tag:"mo",output:"\u03A9",ttype:CONST},{input:"\\frac12",tag:"mo",output:"\u00BD",ttype:CONST},{input:"\\frac14",tag:"mo",output:"\u00BC",ttype:CONST},{input:"\\frac34",tag:"mo",output:"\u00BE",ttype:CONST},{input:"\\frac13",tag:"mo",output:"\u2153",ttype:CONST},{input:"\\frac23",tag:"mo",output:"\u2154",ttype:CONST},{input:"\\frac15",tag:"mo",output:"\u2155",ttype:CONST},{input:"\\frac25",tag:"mo",output:"\u2156",ttype:CONST},{input:"\\frac35",tag:"mo",output:"\u2157",ttype:CONST},{input:"\\frac45",tag:"mo",output:"\u2158",ttype:CONST},{input:"\\frac16",tag:"mo",output:"\u2159",ttype:CONST},{input:"\\frac56",tag:"mo",output:"\u215A",ttype:CONST},{input:"\\frac18",tag:"mo",output:"\u215B",ttype:CONST},{input:"\\frac38",tag:"mo",output:"\u215C",ttype:CONST},{input:"\\frac58",tag:"mo",output:"\u215D",ttype:CONST},{input:"\\frac78",tag:"mo",output:"\u215E",ttype:CONST},{input:"\\pm",tag:"mo",output:"\u00B1",ttype:CONST},{input:"\\mp",tag:"mo",output:"\u2213",ttype:CONST},{input:"\\triangleleft",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\triangleright",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\cdot",tag:"mo",output:"\u22C5",ttype:CONST},{input:"\\star",tag:"mo",output:"\u22C6",ttype:CONST},{input:"\\ast",tag:"mo",output:"\u002A",ttype:CONST},{input:"\\times",tag:"mo",output:"\u00D7",ttype:CONST},{input:"\\div",tag:"mo",output:"\u00F7",ttype:CONST},{input:"\\circ",tag:"mo",output:"\u2218",ttype:CONST},{input:"\\bullet",tag:"mo",output:"\u2022",ttype:CONST},{input:"\\oplus",tag:"mo",output:"\u2295",ttype:CONST},{input:"\\ominus",tag:"mo",output:"\u2296",ttype:CONST},{input:"\\otimes",tag:"mo",output:"\u2297",ttype:CONST},{input:"\\bigcirc",tag:"mo",output:"\u25CB",ttype:CONST},{input:"\\oslash",tag:"mo",output:"\u2298",ttype:CONST},{input:"\\odot",tag:"mo",output:"\u2299",ttype:CONST},{input:"\\land",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\wedge",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\lor",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\vee",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\cap",tag:"mo",output:"\u2229",ttype:CONST},{input:"\\cup",tag:"mo",output:"\u222A",ttype:CONST},{input:"\\sqcap",tag:"mo",output:"\u2293",ttype:CONST},{input:"\\sqcup",tag:"mo",output:"\u2294",ttype:CONST},{input:"\\uplus",tag:"mo",output:"\u228E",ttype:CONST},{input:"\\amalg",tag:"mo",output:"\u2210",ttype:CONST},{input:"\\bigtriangleup",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\bigtriangledown",tag:"mo",output:"\u25BD",ttype:CONST},{input:"\\dag",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\dagger",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\ddag",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\ddagger",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\lhd",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\rhd",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\unlhd",tag:"mo",output:"\u22B4",ttype:CONST},{input:"\\unrhd",tag:"mo",output:"\u22B5",ttype:CONST},{input:"\\sum",tag:"mo",output:"\u2211",ttype:UNDEROVER},{input:"\\prod",tag:"mo",output:"\u220F",ttype:UNDEROVER},{input:"\\bigcap",tag:"mo",output:"\u22C2",ttype:UNDEROVER},{input:"\\bigcup",tag:"mo",output:"\u22C3",ttype:UNDEROVER},{input:"\\bigwedge",tag:"mo",output:"\u22C0",ttype:UNDEROVER},{input:"\\bigvee",tag:"mo",output:"\u22C1",ttype:UNDEROVER},{input:"\\bigsqcap",tag:"mo",output:"\u2A05",ttype:UNDEROVER},{input:"\\bigsqcup",tag:"mo",output:"\u2A06",ttype:UNDEROVER},{input:"\\coprod",tag:"mo",output:"\u2210",ttype:UNDEROVER},{input:"\\bigoplus",tag:"mo",output:"\u2A01",ttype:UNDEROVER},{input:"\\bigotimes",tag:"mo",output:"\u2A02",ttype:UNDEROVER},{input:"\\bigodot",tag:"mo",output:"\u2A00",ttype:UNDEROVER},{input:"\\biguplus",tag:"mo",output:"\u2A04",ttype:UNDEROVER},{input:"\\int",tag:"mo",output:"\u222B",ttype:CONST},{input:"\\oint",tag:"mo",output:"\u222E",ttype:CONST},{input:":=",tag:"mo",output:":=",ttype:CONST},{input:"\\lt",tag:"mo",output:"<",ttype:CONST},{input:"\\gt",tag:"mo",output:">",ttype:CONST},{input:"\\ne",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\neq",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\le",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leq",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leqslant",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\ge",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geq",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geqslant",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\equiv",tag:"mo",output:"\u2261",ttype:CONST},{input:"\\ll",tag:"mo",output:"\u226A",ttype:CONST},{input:"\\gg",tag:"mo",output:"\u226B",ttype:CONST},{input:"\\doteq",tag:"mo",output:"\u2250",ttype:CONST},{input:"\\prec",tag:"mo",output:"\u227A",ttype:CONST},{input:"\\succ",tag:"mo",output:"\u227B",ttype:CONST},{input:"\\preceq",tag:"mo",output:"\u227C",ttype:CONST},{input:"\\succeq",tag:"mo",output:"\u227D",ttype:CONST},{input:"\\subset",tag:"mo",output:"\u2282",ttype:CONST},{input:"\\supset",tag:"mo",output:"\u2283",ttype:CONST},{input:"\\subseteq",tag:"mo",output:"\u2286",ttype:CONST},{input:"\\supseteq",tag:"mo",output:"\u2287",ttype:CONST},{input:"\\sqsubset",tag:"mo",output:"\u228F",ttype:CONST},{input:"\\sqsupset",tag:"mo",output:"\u2290",ttype:CONST},{input:"\\sqsubseteq",tag:"mo",output:"\u2291",ttype:CONST},{input:"\\sqsupseteq",tag:"mo",output:"\u2292",ttype:CONST},{input:"\\sim",tag:"mo",output:"\u223C",ttype:CONST},{input:"\\simeq",tag:"mo",output:"\u2243",ttype:CONST},{input:"\\approx",tag:"mo",output:"\u2248",ttype:CONST},{input:"\\cong",tag:"mo",output:"\u2245",ttype:CONST},{input:"\\Join",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\bowtie",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\in",tag:"mo",output:"\u2208",ttype:CONST},{input:"\\ni",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\owns",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\propto",tag:"mo",output:"\u221D",ttype:CONST},{input:"\\vdash",tag:"mo",output:"\u22A2",ttype:CONST},{input:"\\dashv",tag:"mo",output:"\u22A3",ttype:CONST},{input:"\\models",tag:"mo",output:"\u22A8",ttype:CONST},{input:"\\perp",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\smile",tag:"mo",output:"\u2323",ttype:CONST},{input:"\\frown",tag:"mo",output:"\u2322",ttype:CONST},{input:"\\asymp",tag:"mo",output:"\u224D",ttype:CONST},{input:"\\notin",tag:"mo",output:"\u2209",ttype:CONST},{input:"\\begin{eqnarray}",output:"X",ttype:MATRIX,invisible:true},{input:"\\begin{array}",output:"X",ttype:MATRIX,invisible:true},{input:"\\\\",output:"}&{",ttype:DEFINITION},{input:"\\end{eqnarray}",output:"}}",ttype:DEFINITION},{input:"\\end{array}",output:"}}",ttype:DEFINITION},{input:"\\big",tag:"mo",output:"X",atval:"1.2",ieval:"2.2",ttype:BIG},{input:"\\Big",tag:"mo",output:"X",atval:"1.6",ieval:"2.6",ttype:BIG},{input:"\\bigg",tag:"mo",output:"X",atval:"2.2",ieval:"3.2",ttype:BIG},{input:"\\Bigg",tag:"mo",output:"X",atval:"2.9",ieval:"3.9",ttype:BIG},{input:"\\left",tag:"mo",output:"X",ttype:LEFTBRACKET},{input:"\\right",tag:"mo",output:"X",ttype:RIGHTBRACKET},{input:"{",output:"{",ttype:LEFTBRACKET,invisible:true},{input:"}",output:"}",ttype:RIGHTBRACKET,invisible:true},{input:"(",tag:"mo",output:"(",atval:"1",ttype:STRETCHY},{input:"[",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\lbrack",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\{",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\lbrace",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\langle",tag:"mo",output:"\u2329",atval:"1",ttype:STRETCHY},{input:"\\lfloor",tag:"mo",output:"\u230A",atval:"1",ttype:STRETCHY},{input:"\\lceil",tag:"mo",output:"\u2308",atval:"1",ttype:STRETCHY},{input:")",tag:"mo",output:")",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"]",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrack",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\}",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrace",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rangle",tag:"mo",output:"\u232A",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rfloor",tag:"mo",output:"\u230B",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rceil",tag:"mo",output:"\u2309",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"|",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\|",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\vert",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\Vert",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\mid",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\parallel",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"/",tag:"mo",output:"/",atval:"1.01",ttype:STRETCHY},{input:"\\backslash",tag:"mo",output:"\u2216",atval:"1",ttype:STRETCHY},{input:"\\setminus",tag:"mo",output:"\\",ttype:CONST},{input:"\\!",tag:"mspace",atname:"width",atval:"-0.167em",ttype:SPACE},{input:"\\,",tag:"mspace",atname:"width",atval:"0.167em",ttype:SPACE},{input:"\\>",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\:",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\;",tag:"mspace",atname:"width",atval:"0.278em",ttype:SPACE},{input:"~",tag:"mspace",atname:"width",atval:"0.333em",ttype:SPACE},{input:"\\quad",tag:"mspace",atname:"width",atval:"1em",ttype:SPACE},{input:"\\qquad",tag:"mspace",atname:"width",atval:"2em",ttype:SPACE},{input:"\\prime",tag:"mo",output:"\u2032",ttype:CONST},{input:"'",tag:"mo",output:"\u02B9",ttype:CONST},{input:"''",tag:"mo",output:"\u02BA",ttype:CONST},{input:"'''",tag:"mo",output:"\u2034",ttype:CONST},{input:"''''",tag:"mo",output:"\u2057",ttype:CONST},{input:"\\ldots",tag:"mo",output:"\u2026",ttype:CONST},{input:"\\cdots",tag:"mo",output:"\u22EF",ttype:CONST},{input:"\\vdots",tag:"mo",output:"\u22EE",ttype:CONST},{input:"\\ddots",tag:"mo",output:"\u22F1",ttype:CONST},{input:"\\forall",tag:"mo",output:"\u2200",ttype:CONST},{input:"\\exists",tag:"mo",output:"\u2203",ttype:CONST},{input:"\\Re",tag:"mo",output:"\u211C",ttype:CONST},{input:"\\Im",tag:"mo",output:"\u2111",ttype:CONST},{input:"\\aleph",tag:"mo",output:"\u2135",ttype:CONST},{input:"\\hbar",tag:"mo",output:"\u210F",ttype:CONST},{input:"\\ell",tag:"mo",output:"\u2113",ttype:CONST},{input:"\\wp",tag:"mo",output:"\u2118",ttype:CONST},{input:"\\emptyset",tag:"mo",output:"\u2205",ttype:CONST},{input:"\\infty",tag:"mo",output:"\u221E",ttype:CONST},{input:"\\surd",tag:"mo",output:"\\sqrt{}",ttype:DEFINITION},{input:"\\partial",tag:"mo",output:"\u2202",ttype:CONST},{input:"\\nabla",tag:"mo",output:"\u2207",ttype:CONST},{input:"\\triangle",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\therefore",tag:"mo",output:"\u2234",ttype:CONST},{input:"\\angle",tag:"mo",output:"\u2220",ttype:CONST},{input:"\\diamond",tag:"mo",output:"\u22C4",ttype:CONST},{input:"\\Diamond",tag:"mo",output:"\u25C7",ttype:CONST},{input:"\\neg",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\lnot",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\bot",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\top",tag:"mo",output:"\u22A4",ttype:CONST},{input:"\\square",tag:"mo",output:"\u25AB",ttype:CONST},{input:"\\Box",tag:"mo",output:"\u25A1",ttype:CONST},{input:"\\wr",tag:"mo",output:"\u2240",ttype:CONST},{input:"\\arccos",tag:"mi",output:"arccos",ttype:UNARY,func:true},{input:"\\arcsin",tag:"mi",output:"arcsin",ttype:UNARY,func:true},{input:"\\arctan",tag:"mi",output:"arctan",ttype:UNARY,func:true},{input:"\\arg",tag:"mi",output:"arg",ttype:UNARY,func:true},{input:"\\cos",tag:"mi",output:"cos",ttype:UNARY,func:true},{input:"\\cosh",tag:"mi",output:"cosh",ttype:UNARY,func:true},{input:"\\cot",tag:"mi",output:"cot",ttype:UNARY,func:true},{input:"\\coth",tag:"mi",output:"coth",ttype:UNARY,func:true},{input:"\\csc",tag:"mi",output:"csc",ttype:UNARY,func:true},{input:"\\deg",tag:"mi",output:"deg",ttype:UNARY,func:true},{input:"\\det",tag:"mi",output:"det",ttype:UNARY,func:true},{input:"\\dim",tag:"mi",output:"dim",ttype:UNARY,func:true},{input:"\\exp",tag:"mi",output:"exp",ttype:UNARY,func:true},{input:"\\gcd",tag:"mi",output:"gcd",ttype:UNARY,func:true},{input:"\\hom",tag:"mi",output:"hom",ttype:UNARY,func:true},{input:"\\inf",tag:"mo",output:"inf",ttype:UNDEROVER},{input:"\\ker",tag:"mi",output:"ker",ttype:UNARY,func:true},{input:"\\lg",tag:"mi",output:"lg",ttype:UNARY,func:true},{input:"\\lim",tag:"mo",output:"lim",ttype:UNDEROVER},{input:"\\liminf",tag:"mo",output:"liminf",ttype:UNDEROVER},{input:"\\limsup",tag:"mo",output:"limsup",ttype:UNDEROVER},{input:"\\ln",tag:"mi",output:"ln",ttype:UNARY,func:true},{input:"\\log",tag:"mi",output:"log",ttype:UNARY,func:true},{input:"\\max",tag:"mo",output:"max",ttype:UNDEROVER},{input:"\\min",tag:"mo",output:"min",ttype:UNDEROVER},{input:"\\Pr",tag:"mi",output:"Pr",ttype:UNARY,func:true},{input:"\\sec",tag:"mi",output:"sec",ttype:UNARY,func:true},{input:"\\sin",tag:"mi",output:"sin",ttype:UNARY,func:true},{input:"\\sinh",tag:"mi",output:"sinh",ttype:UNARY,func:true},{input:"\\sup",tag:"mo",output:"sup",ttype:UNDEROVER},{input:"\\tan",tag:"mi",output:"tan",ttype:UNARY,func:true},{input:"\\tanh",tag:"mi",output:"tanh",ttype:UNARY,func:true},{input:"\\gets",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\leftarrow",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\to",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\rightarrow",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\leftrightarrow",tag:"mo",output:"\u2194",ttype:CONST},{input:"\\uparrow",tag:"mo",output:"\u2191",ttype:CONST},{input:"\\downarrow",tag:"mo",output:"\u2193",ttype:CONST},{input:"\\updownarrow",tag:"mo",output:"\u2195",ttype:CONST},{input:"\\Leftarrow",tag:"mo",output:"\u21D0",ttype:CONST},{input:"\\Rightarrow",tag:"mo",output:"\u21D2",ttype:CONST},{input:"\\Leftrightarrow",tag:"mo",output:"\u21D4",ttype:CONST},{input:"\\iff",tag:"mo",output:"~\\Longleftrightarrow~",ttype:DEFINITION},{input:"\\Uparrow",tag:"mo",output:"\u21D1",ttype:CONST},{input:"\\Downarrow",tag:"mo",output:"\u21D3",ttype:CONST},{input:"\\Updownarrow",tag:"mo",output:"\u21D5",ttype:CONST},{input:"\\mapsto",tag:"mo",output:"\u21A6",ttype:CONST},{input:"\\longleftarrow",tag:"mo",output:"\u2190",ttype:LONG},{input:"\\longrightarrow",tag:"mo",output:"\u2192",ttype:LONG},{input:"\\longleftrightarrow",tag:"mo",output:"\u2194",ttype:LONG},{input:"\\Longleftarrow",tag:"mo",output:"\u21D0",ttype:LONG},{input:"\\Longrightarrow",tag:"mo",output:"\u21D2",ttype:LONG},{input:"\\Longleftrightarrow",tag:"mo",output:"\u21D4",ttype:LONG},{input:"\\longmapsto",tag:"mo",output:"\u21A6",ttype:CONST},AMsqrt,AMroot,AMfrac,AMover,AMsub,AMsup,AMtext,AMmbox,AMatop,AMchoose,{input:"\\acute",tag:"mover",output:"\u00B4",ttype:UNARY,acc:true},{input:"\\grave",tag:"mover",output:"\u0060",ttype:UNARY,acc:true},{input:"\\breve",tag:"mover",output:"\u02D8",ttype:UNARY,acc:true},{input:"\\check",tag:"mover",output:"\u02C7",ttype:UNARY,acc:true},{input:"\\dot",tag:"mover",output:".",ttype:UNARY,acc:true},{input:"\\ddot",tag:"mover",output:"..",ttype:UNARY,acc:true},{input:"\\mathring",tag:"mover",output:"\u00B0",ttype:UNARY,acc:true},{input:"\\vec",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overrightarrow",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overleftarrow",tag:"mover",output:"\u20D6",ttype:UNARY,acc:true},{input:"\\hat",tag:"mover",output:"\u005E",ttype:UNARY,acc:true},{input:"\\widehat",tag:"mover",output:"\u0302",ttype:UNARY,acc:true},{input:"\\tilde",tag:"mover",output:"~",ttype:UNARY,acc:true},{input:"\\widetilde",tag:"mover",output:"\u02DC",ttype:UNARY,acc:true},{input:"\\bar",tag:"mover",output:"\u203E",ttype:UNARY,acc:true},{input:"\\overbrace",tag:"mover",output:"\uFE37",ttype:UNARY,acc:true},{input:"\\overbracket",tag:"mover",output:"\u23B4",ttype:UNARY,acc:true},{input:"\\overline",tag:"mover",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\underbrace",tag:"munder",output:"\uFE38",ttype:UNARY,acc:true},{input:"\\underbracket",tag:"munder",output:"\u23B5",ttype:UNARY,acc:true},{input:"\\underline",tag:"munder",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true",ttype:UNARY},{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false",ttype:UNARY},{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1",ttype:UNARY},{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2",ttype:UNARY},{input:"\\textrm",tag:"mstyle",output:"\\mathrm",ttype:DEFINITION},{input:"\\mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\textbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\mathit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\textit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\texttt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",ttype:UNARY},{input:"\\mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",ttype:UNARY,codes:AMbbb},{input:"\\mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",ttype:UNARY,codes:AMcal},{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",ttype:UNARY,codes:AMfrk},{input:"\\textcolor",tag:"mstyle",atname:"mathvariant",atval:"mathcolor",ttype:BINARY},{input:"\\colorbox",tag:"mstyle",atname:"mathvariant",atval:"background",ttype:BINARY}];function compareNames(s1,s2){if(s1.input>s2.input)return 1 -else return-1;} -var AMnames=[];function AMinitSymbols(){AMsymbols.sort(compareNames);for(i=0;i<AMsymbols.length;i++)AMnames[i]=AMsymbols[i].input;} -var AMmathml="http://www.w3.org/1998/Math/MathML";function AMcreateElementMathML(t){if(isIE)return document.createElement("m:"+t);else return document.createElementNS(AMmathml,t);} -function AMcreateMmlNode(t,frag){if(isIE)var node=document.createElement("m:"+t);else var node=document.createElementNS(AMmathml,t);node.appendChild(frag);return node;} -function newcommand(oldstr,newstr){AMsymbols=AMsymbols.concat([{input:oldstr,tag:"mo",output:newstr,ttype:DEFINITION}]);} -function AMremoveCharsAndBlanks(str,n){var st;st=str.slice(n);for(var i=0;i<st.length&&st.charCodeAt(i)<=32;i=i+1);return st.slice(i);} -function AMposition(arr,str,n){if(n==0){var h,m;n=-1;h=arr.length;while(n+1<h){m=(n+h)>>1;if(arr[m]<str)n=m;else h=m;} -return h;}else -for(var i=n;i<arr.length&&arr[i]<str;i++);return i;} -function AMgetSymbol(str){var k=0;var j=0;var mk;var st;var tagst;var match="";var more=true;for(var i=1;i<=str.length&&more;i++){st=str.slice(0,i);j=k;k=AMposition(AMnames,st,j);if(k<AMnames.length&&str.slice(0,AMnames[k].length)==AMnames[k]){match=AMnames[k];mk=k;i=match.length;} -more=k<AMnames.length&&str.slice(0,AMnames[k].length)>=AMnames[k];} -AMpreviousSymbol=AMcurrentSymbol;if(match!=""){AMcurrentSymbol=AMsymbols[mk].ttype;return AMsymbols[mk];} -AMcurrentSymbol=CONST;k=1;st=str.slice(0,1);if("0"<=st&&st<="9")tagst="mn";else tagst=(("A">st||st>"Z")&&("a">st||st>"z")?"mo":"mi");return{input:st,tag:tagst,output:st,ttype:CONST};} -var AMpreviousSymbol,AMcurrentSymbol;function AMparseSexpr(str){var symbol,node,result,result2,i,st,newFrag=document.createDocumentFragment();str=AMremoveCharsAndBlanks(str,0);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET) -return[null,str,null];if(symbol.ttype==DEFINITION){str=symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET) -return[null,str,null];} -str=AMremoveCharsAndBlanks(str,symbol.input.length);switch(symbol.ttype){case SPACE:node=AMcreateElementMathML(symbol.tag);node.setAttribute(symbol.atname,symbol.atval);return[node,str,symbol.tag];case UNDEROVER:if(isIE){if(symbol.input.substr(0,4)=="\\big"){str="\\"+symbol.input.substr(4)+str;symbol=AMgetSymbol(str);symbol.ttype=UNDEROVER;str=AMremoveCharsAndBlanks(str,symbol.input.length);}} -return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];case CONST:var output=symbol.output;if(isIE){if(symbol.input=="'") -output="\u2032";else if(symbol.input=="''") -output="\u2033";else if(symbol.input=="'''") -output="\u2033\u2032";else if(symbol.input=="''''") -output="\u2033\u2033";else if(symbol.input=="\\square") -output="\u25A1";else if(symbol.input.substr(0,5)=="\\frac"){var denom=symbol.input.substr(6,1);if(denom=="5"||denom=="6"){str=symbol.input.replace(/\\frac/,"\\frac ")+str;return[node,str,symbol.tag];}}} -node=AMcreateMmlNode(symbol.tag,document.createTextNode(output));return[node,str,symbol.tag];case LONG:node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));node.setAttribute("minsize","1.5");node.setAttribute("maxsize","1.5");node=AMcreateMmlNode("mover",node);node.appendChild(AMcreateElementMathML("mspace"));return[node,str,symbol.tag];case STRETCHY:if(isIE&&symbol.input=="\\backslash") -symbol.output="\\";node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(symbol.input=="|"||symbol.input=="\\vert"||symbol.input=="\\|"||symbol.input=="\\Vert"){node.setAttribute("lspace","0em");node.setAttribute("rspace","0em");} -node.setAttribute("maxsize",symbol.atval);if(symbol.rtag!=null) -return[node,str,symbol.rtag];else -return[node,str,symbol.tag];case BIG:var atval=symbol.atval;if(isIE) -atval=symbol.ieval;symbol=AMgetSymbol(str);if(symbol==null) -return[null,str,null];str=AMremoveCharsAndBlanks(str,symbol.input.length);node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height",atval+"ex");node=AMcreateMmlNode("mrow",node);node.appendChild(space);}else{node.setAttribute("minsize",atval);node.setAttribute("maxsize",atval);} -return[node,str,symbol.tag];case LEFTBRACKET:if(symbol.input=="\\left"){symbol=AMgetSymbol(str);if(symbol!=null){if(symbol.input==".") -symbol.invisible=true;str=AMremoveCharsAndBlanks(str,symbol.input.length);}} -result=AMparseExpr(str,true,false);if(symbol==null||(typeof symbol.invisible=="boolean"&&symbol.invisible)) -node=AMcreateMmlNode("mrow",result[0]);else{node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));node=AMcreateMmlNode("mrow",node);node.appendChild(result[0]);} -return[node,result[1],result[2]];case MATRIX:if(symbol.input=="\\begin{array}"){var mask="";symbol=AMgetSymbol(str);str=AMremoveCharsAndBlanks(str,0);if(symbol==null) -mask="l";else{str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="{") -mask="l";else do{symbol=AMgetSymbol(str);if(symbol!=null){str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="}") -mask=mask+symbol.input;}}while(symbol!=null&&symbol.input!=""&&symbol.input!="}");} -result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);mask=mask.replace(/l/g,"left ");mask=mask.replace(/r/g,"right ");mask=mask.replace(/c/g,"center ");node.setAttribute("columnalign",mask);node.setAttribute("displaystyle","false");if(isIE) -return[node,result[1],null];var lspace=AMcreateElementMathML("mspace");lspace.setAttribute("width","0.167em");var rspace=AMcreateElementMathML("mspace");rspace.setAttribute("width","0.167em");var node1=AMcreateMmlNode("mrow",lspace);node1.appendChild(node);node1.appendChild(rspace);return[node1,result[1],null];}else{result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);if(isIE) -node.setAttribute("columnspacing","0.25em");else -node.setAttribute("columnspacing","0.167em");node.setAttribute("columnalign","right center left");node.setAttribute("displaystyle","true");node=AMcreateMmlNode("mrow",node);return[node,result[1],null];} -case TEXT:if(str.charAt(0)=="{")i=str.indexOf("}");else i=0;if(i==-1) -i=str.length;st=str.slice(1,i);if(st.charAt(0)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);} -newFrag.appendChild(AMcreateMmlNode(symbol.tag,document.createTextNode(st)));if(st.charAt(st.length-1)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);} -str=AMremoveCharsAndBlanks(str,i+1);return[AMcreateMmlNode("mrow",newFrag),str,null];case UNARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str];if(typeof symbol.func=="boolean"&&symbol.func){st=str.charAt(0);if(st=="^"||st=="_"||st==","){return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}else{node=AMcreateMmlNode("mrow",AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node.appendChild(space);} -node.appendChild(result[0]);return[node,result[1],symbol.tag];}} -if(symbol.input=="\\sqrt"){if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height","1.2ex");space.setAttribute("width","0em");node=AMcreateMmlNode(symbol.tag,result[0]) -node.appendChild(space);return[node,result[1],symbol.tag];}else -return[AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];}else if(typeof symbol.acc=="boolean"&&symbol.acc){node=AMcreateMmlNode(symbol.tag,result[0]);var output=symbol.output;if(isIE){if(symbol.input=="\\hat") -output="\u0302";else if(symbol.input=="\\widehat") -output="\u005E";else if(symbol.input=="\\bar") -output="\u00AF";else if(symbol.input=="\\grave") -output="\u0300";else if(symbol.input=="\\tilde") -output="\u0303";} -var node1=AMcreateMmlNode("mo",document.createTextNode(output));if(symbol.input=="\\vec"||symbol.input=="\\check") -node1.setAttribute("maxsize","1.2");if(isIE&&symbol.input=="\\bar") -node1.setAttribute("maxsize","0.5");if(symbol.input=="\\underbrace"||symbol.input=="\\underline") -node1.setAttribute("accentunder","true");else -node1.setAttribute("accent","true");node.appendChild(node1);if(symbol.input=="\\overbrace"||symbol.input=="\\underbrace") -node.ttype=UNDEROVER;return[node,result[1],symbol.tag];}else{if(!isIE&&typeof symbol.codes!="undefined"){for(i=0;i<result[0].childNodes.length;i++) -if(result[0].childNodes[i].nodeName=="mi"||result[0].nodeName=="mi"){st=(result[0].nodeName=="mi"?result[0].firstChild.nodeValue:result[0].childNodes[i].firstChild.nodeValue);var newst=[];for(var j=0;j<st.length;j++) -if(st.charCodeAt(j)>64&&st.charCodeAt(j)<91)newst=newst+ -String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);else newst=newst+st.charAt(j);if(result[0].nodeName=="mi") -result[0]=AMcreateElementMathML("mo").appendChild(document.createTextNode(newst));else result[0].replaceChild(AMcreateElementMathML("mo").appendChild(document.createTextNode(newst)),result[0].childNodes[i]);}} -node=AMcreateMmlNode(symbol.tag,result[0]);node.setAttribute(symbol.atname,symbol.atval);if(symbol.input=="\\scriptstyle"||symbol.input=="\\scriptscriptstyle") -node.setAttribute("displaystyle","false");return[node,result[1],symbol.tag];} -case BINARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];result2=AMparseSexpr(result[1]);if(result2[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];if(symbol.input=="\\textcolor"||symbol.input=="\\colorbox"){var tclr=str.match(/\{\s*([#\w]+)\s*\}/);str=str.replace(/\{\s*[#\w]+\s*\}/,"");if(tclr!=null){if(IsColorName.test(tclr[1].toLowerCase())){tclr=LaTeXColor[tclr[1].toLowerCase()];}else{tclr=tclr[1];} -node=AMcreateElementMathML("mstyle");node.setAttribute(symbol.atval,tclr);node.appendChild(result2[0]);return[node,result2[1],symbol.tag];}} -if(symbol.input=="\\root"||symbol.input=="\\stackrel")newFrag.appendChild(result2[0]);newFrag.appendChild(result[0]);if(symbol.input=="\\frac")newFrag.appendChild(result2[0]);return[AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];case INFIX:str=AMremoveCharsAndBlanks(str,symbol.input.length);return[AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str,symbol.tag];default:return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}} -function AMparseIexpr(str){var symbol,sym1,sym2,node,result,tag,underover;str=AMremoveCharsAndBlanks(str,0);sym1=AMgetSymbol(str);result=AMparseSexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(symbol.ttype==INFIX){str=AMremoveCharsAndBlanks(str,symbol.input.length);result=AMparseSexpr(str);if(result[0]==null) -result[0]=AMcreateMmlNode("mo",document.createTextNode("\u25A1"));str=result[1];tag=result[2];if(symbol.input=="_"||symbol.input=="^"){sym2=AMgetSymbol(str);tag=null;underover=((sym1.ttype==UNDEROVER)||(node.ttype==UNDEROVER));if(symbol.input=="_"&&sym2.input=="^"){str=AMremoveCharsAndBlanks(str,sym2.input.length);var res2=AMparseSexpr(str);str=res2[1];tag=res2[2];node=AMcreateMmlNode((underover?"munderover":"msubsup"),node);node.appendChild(result[0]);node.appendChild(res2[0]);}else if(symbol.input=="_"){node=AMcreateMmlNode((underover?"munder":"msub"),node);node.appendChild(result[0]);}else{node=AMcreateMmlNode((underover?"mover":"msup"),node);node.appendChild(result[0]);} -node=AMcreateMmlNode("mrow",node);}else{node=AMcreateMmlNode(symbol.tag,node);if(symbol.input=="\\atop"||symbol.input=="\\choose") -node.setAttribute("linethickness","0ex");node.appendChild(result[0]);if(symbol.input=="\\choose") -node=AMcreateMmlNode("mfenced",node);}} -return[node,str,tag];} -function AMparseExpr(str,rightbracket,matrix){var symbol,node,result,i,tag,newFrag=document.createDocumentFragment();do{str=AMremoveCharsAndBlanks(str,0);result=AMparseIexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(node!=undefined){if((tag=="mn"||tag=="mi")&&symbol!=null&&typeof symbol.func=="boolean"&&symbol.func){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node=AMcreateMmlNode("mrow",node);node.appendChild(space);} -newFrag.appendChild(node);}}while((symbol.ttype!=RIGHTBRACKET)&&symbol!=null&&symbol.output!="");tag=null;if(symbol.ttype==RIGHTBRACKET){if(symbol.input=="\\right"){str=AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol!=null&&symbol.input==".") -symbol.invisible=true;if(symbol!=null) -tag=symbol.rtag;} -if(symbol!=null) -str=AMremoveCharsAndBlanks(str,symbol.input.length);var len=newFrag.childNodes.length;if(matrix&&len>0&&newFrag.childNodes[len-1].nodeName=="mrow"&&len>1&&newFrag.childNodes[len-2].nodeName=="mo"&&newFrag.childNodes[len-2].firstChild.nodeValue=="&"){var pos=[];var m=newFrag.childNodes.length;for(i=0;matrix&&i<m;i=i+2){pos[i]=[];node=newFrag.childNodes[i];for(var j=0;j<node.childNodes.length;j++) -if(node.childNodes[j].firstChild.nodeValue=="&") -pos[i][pos[i].length]=j;} -var row,frag,n,k,table=document.createDocumentFragment();for(i=0;i<m;i=i+2){row=document.createDocumentFragment();frag=document.createDocumentFragment();node=newFrag.firstChild;n=node.childNodes.length;k=0;for(j=0;j<n;j++){if(typeof pos[i][k]!="undefined"&&j==pos[i][k]){node.removeChild(node.firstChild);row.appendChild(AMcreateMmlNode("mtd",frag));k++;}else frag.appendChild(node.firstChild);} -row.appendChild(AMcreateMmlNode("mtd",frag));if(newFrag.childNodes.length>2){newFrag.removeChild(newFrag.firstChild);newFrag.removeChild(newFrag.firstChild);} -table.appendChild(AMcreateMmlNode("mtr",row));} -return[table,str];} -if(typeof symbol.invisible!="boolean"||!symbol.invisible){node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));newFrag.appendChild(node);}} -return[newFrag,str,tag];} -function AMparseMath(str){var result,node=AMcreateElementMathML("mstyle");var cclr=str.match(/\\color\s*\{\s*([#\w]+)\s*\}/);str=str.replace(/\\color\s*\{\s*[#\w]+\s*\}/g,"");if(cclr!=null){if(IsColorName.test(cclr[1].toLowerCase())){cclr=LaTeXColor[cclr[1].toLowerCase()];}else{cclr=cclr[1];} -node.setAttribute("mathcolor",cclr);}else{if(mathcolor!="")node.setAttribute("mathcolor",mathcolor);};if(mathfontfamily!="")node.setAttribute("fontfamily",mathfontfamily);node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);node=AMcreateMmlNode("math",node);if(showasciiformulaonhover) -node.setAttribute("title",str.replace(/\s+/g," "));if(false){var fnode=AMcreateElementXHTML("font");fnode.setAttribute("face",mathfontfamily);fnode.appendChild(node);return fnode;} -return node;} -function AMstrarr2docFrag(arr,linebreaks){var newFrag=document.createDocumentFragment();var expr=false;for(var i=0;i<arr.length;i++){if(expr)newFrag.appendChild(AMparseMath(arr[i]));else{var arri=(linebreaks?arr[i].split("\n\n"):[arr[i]]);newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[0])));for(var j=1;j<arri.length;j++){newFrag.appendChild(AMcreateElementXHTML("p"));newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[j])));}} -expr=!expr;} -return newFrag;} -function AMprocessNodeR(n,linebreaks){var mtch,str,arr,frg,i;if(n.childNodes.length==0){if((n.nodeType!=8||linebreaks)&&n.parentNode.nodeName!="form"&&n.parentNode.nodeName!="FORM"&&n.parentNode.nodeName!="textarea"&&n.parentNode.nodeName!="TEXTAREA"&&n.parentNode.nodeName!="pre"&&n.parentNode.nodeName!="PRE"){str=n.nodeValue;if(!(str==null)){str=str.replace(/\r\n\r\n/g,"\n\n");str=str.replace(/\x20+/g," ");str=str.replace(/\s*\r\n/g," ");mtch=(str.indexOf("\$")==-1?false:true);str=str.replace(/([^\\])\$/g,"$1 \$");str=str.replace(/^\$/," \$");arr=str.split(" \$");for(i=0;i<arr.length;i++) -arr[i]=arr[i].replace(/\\\$/g,"\$");if(arr.length>1||mtch){if(checkForMathML){checkForMathML=false;var nd=AMisMathMLavailable();AMnoMathML=nd!=null;if(AMnoMathML&¬ifyIfNoMathML) -if(alertIfNoMathML) -alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\nor Firefox/Mozilla/Netscape");else AMbody.insertBefore(nd,AMbody.childNodes[0]);} -if(!AMnoMathML){frg=AMstrarr2docFrag(arr,n.nodeType==8);var len=frg.childNodes.length;n.parentNode.replaceChild(frg,n);return len-1;}else return 0;}}}else return 0;}else if(n.nodeName!="math"){for(i=0;i<n.childNodes.length;i++) -i+=AMprocessNodeR(n.childNodes[i],linebreaks);} -return 0;} -function AMprocessNode(n,linebreaks,spanclassAM){var frag,st;if(spanclassAM!=null){frag=document.getElementsByTagName("span") -for(var i=0;i<frag.length;i++) -if(frag[i].className=="AM") -AMprocessNodeR(frag[i],linebreaks);}else{try{st=n.innerHTML;}catch(err){} -if(st==null||st.indexOf("\$")!=-1) -AMprocessNodeR(n,linebreaks);} -if(isIE){frag=document.getElementsByTagName('math');for(var i=0;i<frag.length;i++)frag[i].update()}} -var inAppendix=false;var sectionCntr=0;var IEcommentWarning=true;var biblist=[];var bibcntr=0;var LaTeXCounter=[];LaTeXCounter["definition"]=0;LaTeXCounter["proposition"]=0;LaTeXCounter["lemma"]=0;LaTeXCounter["theorem"]=0;LaTeXCounter["corollary"]=0;LaTeXCounter["example"]=0;LaTeXCounter["exercise"]=0;LaTeXCounter["subsection"]=0;LaTeXCounter["subsubsection"]=0;LaTeXCounter["figure"]=0;LaTeXCounter["equation"]=0;LaTeXCounter["table"]=0;var LaTeXColor=[];LaTeXColor["greenyellow"]="#D9FF4F";LaTeXColor["yellow"]="#FFFF00";LaTeXColor["goldenrod"]="#FFE529";LaTeXColor["dandelion"]="#FFB529";LaTeXColor["apricot"]="#FFAD7A";LaTeXColor["peach"]="#FF804D";LaTeXColor["melon"]="#FF8A80";LaTeXColor["yelloworange"]="#FF9400";LaTeXColor["orange"]="#FF6321";LaTeXColor["burntorange"]="#FF7D00";LaTeXColor["bittersweet"]="#C20300";LaTeXColor["redorange"]="#FF3B21";LaTeXColor["mahogany"]="#A60000";LaTeXColor["maroon"]="#AD0000";LaTeXColor["brickred"]="#B80000";LaTeXColor["red"]="#FF0000";LaTeXColor["orangered"]="#FF0080";LaTeXColor["rubinered"]="#FF00DE";LaTeXColor["wildstrawberry"]="#FF0A9C";LaTeXColor["salmon"]="#FF789E";LaTeXColor["carnationpink"]="#FF5EFF";LaTeXColor["magenta"]="#FF00FF";LaTeXColor["violetred"]="#FF30FF";LaTeXColor["rhodamine"]="#FF2EFF";LaTeXColor["mulberry"]="#A314FA";LaTeXColor["redviolet"]="#9600A8";LaTeXColor["fuchsia"]="#7303EB";LaTeXColor["lavender"]="#FF85FF";LaTeXColor["thistle"]="#E069FF";LaTeXColor["orchid"]="#AD5CFF";LaTeXColor["darkorchid"]="#9933CC";LaTeXColor["purple"]="#8C24FF";LaTeXColor["plum"]="#8000FF";LaTeXColor["violet"]="#361FFF";LaTeXColor["royalpurple"]="#401AFF";LaTeXColor["blueviolet"]="#1A0DF5";LaTeXColor["periwinkle"]="#6E73FF";LaTeXColor["cadetblue"]="#616EC4";LaTeXColor["cornflowerblue"]="#59DEFF";LaTeXColor["midnightblue"]="#007091";LaTeXColor["navyblue"]="#0F75FF";LaTeXColor["royalblue"]="#0080FF";LaTeXColor["blue"]="#0000FF";LaTeXColor["cerulean"]="#0FE3FF";LaTeXColor["cyan"]="#00FFFF";LaTeXColor["processblue"]="#0AFFFF";LaTeXColor["skyblue"]="#61FFE0";LaTeXColor["turquoise"]="#26FFCC";LaTeXColor["tealblue"]="#1FFAA3";LaTeXColor["aquamarine"]="#2EFFB2";LaTeXColor["bluegreen"]="#26FFAB";LaTeXColor["emerald"]="#00FF80";LaTeXColor["junglegreen"]="#03FF7A";LaTeXColor["seagreen"]="#4FFF80";LaTeXColor["green"]="#00FF00";LaTeXColor["forestgreen"]="#00E000";LaTeXColor["pinegreen"]="#00BF29";LaTeXColor["limegreen"]="#80FF00";LaTeXColor["yellowgreen"]="#8FFF42";LaTeXColor["springgreen"]="#BDFF3D";LaTeXColor["olivegreen"]="#009900";LaTeXColor["rawsienna"]="#8C0000";LaTeXColor["sepia"]="#4D0000";LaTeXColor["brown"]="#660000";LaTeXColor["tan"]="#DB9470";LaTeXColor["gray"]="#808080";LaTeXColor["grey"]="#808080";LaTeXColor["black"]="#000000";LaTeXColor["white"]="#FFFFFF";var IsColorName=/^(?:greenyellow|yellow|goldenrod|dandelion|apricot|peach|melon|yelloworange|orange|burntorange|bittersweet|redorange|mahogany|maroon|brickred|red|orangered|rubinered|wildstrawberry|salmon|carnationpink|magenta|violetred|rhodamine|mulberry|redviolet|fuchsia|lavender|thistle|orchid|darkorchid|purple|plum|violet|royalpurple|blueviolet|periwinkle|cadetblue|cornflowerblue|midnightblue|navyblue|royalblue|blue|cerulean|cyan|processblue|skyblue|turquoise|tealblue|aquamarine|bluegreen|emerald|junglegreen|seagreen|green|forestgreen|pinegreen|limegreen|yellowgreen|springgreen|olivegreen|rawsienna|sepia|brown|tan|gray|grey|black|white)$/;var IsCounter=/^(?:definition|proposition|lemma|theorem|corollary|example|exercise|subsection|subsubsection|figure|equation|table)$/;var IsLaTeXElement=/^(?:displayequation|title|author|address|date|abstract|keyword|section|subsection|subsubsection|ref|cite|thebibliography|definition|proposition|lemma|theorem|corollary|example|exercise|itemize|enumerate|enddefinition|endproposition|endlemma|endtheorem|endcorollary|endexample|endexercise|enditemize|endenumerate|LaTeXMathMLlabel|LaTeXMathML|smallskip|medskip|bigskip|quote|quotation|endquote|endquotation|center|endcenter|description|enddescription|inlinemath)$/;var IsTextOnlyArea=/^(?:form|textarea|pre)$/i;var tableid=0;function makeNumberString(cntr){if(sectionCntr>0){if(inAppendix){return"A"+sectionCntr+"."+cntr;}else{return sectionCntr+"."+cntr;}}else{return""+cntr;}};function LaTeXpreProcess(thebody){var TheBody=thebody;if(TheBody.hasChildNodes()){if(!(IsLaTeXElement.test(TheBody.className))) -{for(var i=0;i<TheBody.childNodes.length;i++){LaTeXpreProcess(TheBody.childNodes[i])}}} -else{if(TheBody.nodeType==3&&!(IsTextOnlyArea.test(TheBody.parentNode.nodeName))) -{var str=TheBody.nodeValue;if(!(str==null)){str=str.replace(/\\%/g,"<per>");str=str.replace(/%[^\n]*(?=\n)/g,"");str=str.replace(/%[^\r]*(?=\r)/g,"");str=str.replace(/%[^\n]*$/,"") -if(isIE&&str.match(/%/g)!=null&&IEcommentWarning){alert("Comments may not have parsed properly. Try putting in <pre class='LaTeX><div>..</div></pre> structure.");IEcommentWarning=false;} -str=str.replace(/<per>/g,"%");if(str.match(/XXX[\s\S]*/)!=null){var tmp=str.match(/XXX[\s\S]*/)[0];var tmpstr=tmp.charCodeAt(7)+"::"+tmp.charCodeAt(8)+"::"+tmp.charCodeAt(9)+"::"+tmp.charCodeAt(10)+"::"+tmp.charCodeAt(11)+"::"+tmp.charCodeAt(12)+"::"+tmp.charCodeAt(13);alert(tmpstr);} -str=str.replace(/([^\\])\\(\s)/g,"$1\u00A0$2");str=str.replace(/\\quad/g,"\u2001");str=str.replace(/\\qquad/g,"\u2001\u2001");str=str.replace(/\\enspace/g,"\u2002");str=str.replace(/\\;/g,"\u2004");str=str.replace(/\\:/g,"\u2005");str=str.replace(/\\,/g,"\u2006");str=str.replace(/\\thinspace/g,"\u200A");str=str.replace(/([^\\])~/g,"$1\u00A0");str=str.replace(/\\~/g,"~");str=str.replace(/\\\[/g," <DEQ> $\\displaystyle{");str=str.replace(/\\\]/g,"}$ <DEQ> ");str=str.replace(/\$\$/g,"${$<DEQ>$}$");str=str.replace(/\\begin\s*\{\s*array\s*\}/g,"\\begin{array}");str=str.replace(/\\end\s*\{\s*array\s*\}/g,"\\end{array}");str=str.replace(/\\begin\s*\{\s*eqnarray\s*\}/g," <DEQ>eqno$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*eqnarray\*\s*\}/g," <DEQ>$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\*\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*displaymath\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*displaymath\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\*\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\*\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\}/g," <DEQ>eqno$\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\}/g,"}$ <DEQ> ");str=str.split("<DEQ>");var newFrag=document.createDocumentFragment();for(var i=0;i<str.length;i++){if(i%2){var DEQtable=document.createElement("table");DEQtable.className='displayequation';var DEQtbody=document.createElement("tbody");var DEQtr=document.createElement("tr");var DEQtdeq=document.createElement("td");DEQtdeq.className='eq';str[i]=str[i].replace(/\$\}\$/g,"$\\displaystyle{");str[i]=str[i].replace(/\$\{\$/g,"}");var lbl=str[i].match(/\\label\s*\{\s*(\w+)\s*\}/);var ISeqno=str[i].match(/^eqno/);str[i]=str[i].replace(/^eqno/," ");str[i]=str[i].replace(/\\label\s*\{\s*\w+\s*\}/," ");DEQtdeq.appendChild(document.createTextNode(str[i]));DEQtr.appendChild(DEQtdeq);str[i]=str[i].replace(/\\nonumber/g,"");if(ISeqno!=null||lbl!=null){var DEQtdno=document.createElement("td");DEQtdno.className='eqno';LaTeXCounter["equation"]++;var eqnoString=makeNumberString(LaTeXCounter["equation"]);var DEQanchor=document.createElement("a");if(lbl!=null){DEQanchor.id=lbl[1]};DEQanchor.className="eqno";var anchorSpan=document.createElement("span");anchorSpan.className="eqno";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(eqnoString));DEQanchor.appendChild(anchorSpan);DEQtdno.appendChild(DEQanchor);var DEQspan=document.createElement("span");DEQspan.className="eqno";DEQspan.appendChild(document.createTextNode("("+eqnoString+")"));DEQtdno.appendChild(DEQspan);DEQtr.appendChild(DEQtdno);} -DEQtbody.appendChild(DEQtr);DEQtable.appendChild(DEQtbody);newFrag.appendChild(DEQtable);} -else{str[i]=str[i].replace(/\$\}\$/g,"");str[i]=str[i].replace(/\$\{\$/g,"");str[i]=str[i].replace(/\\maketitle/g,"");str[i]=str[i].replace(/\\begin\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\end\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\documentclass[^\}]*?\}/g,"");str[i]=str[i].replace(/\\usepackage[^\}]*?\}/g,"");str[i]=str[i].replace(/\\noindent/g,"");str[i]=str[i].replace(/\\notag/g,"");str[i]=str[i].replace(/\\ref\s*\{\s*(\w+)\}/g," \\[ref\\]$1\\[ ");str[i]=str[i].replace(/\\url\s*\{\s*([^\}\n]+)\}/g," \\[url\\]$1\\[ ");str[i]=str[i].replace(/\\href\s*\{\s*([^\}]+)\}\s*\{\s*([^\}]+)\}/g," \\[href\\]$1\\]$2\\[ ");str[i]=str[i].replace(/\\cite\s*\{\s*(\w+)\}/g," \\[cite\\]$1\\[ ");str[i]=str[i].replace(/\\qed/g,"\u220E");str[i]=str[i].replace(/\\endproof/g,"\u220E");str[i]=str[i].replace(/\\proof/g,"\\textbf{Proof: }");str[i]=str[i].replace(/\\n(?=\s)/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\newline/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\linebreak/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\smallskip/g," \\[logicalbreak\\]smallskip\\[ ");str[i]=str[i].replace(/\\medskip/g," \\[logicalbreak\\]medskip\\[ ");str[i]=str[i].replace(/\\bigskip/g," \\[logicalbreak\\]bigskip\\[ ");str[i]=str[i].replace(/[\n\r]+[ \f\n\r\t\v\u2028\u2029]*[\n\r]+/g," \\[logicalbreak\\]LaTeXMathML\\[ ");if(isIE){str[i]=str[i].replace(/\r/g," ");} -str[i]=str[i].replace(/\\bibitem\s*([^\{]*\{\s*\w*\s*\})/g," \\[bibitem\\]$1\\[ ");str[i]=str[i].replace(/\\bibitem\s*/g," \\[bibitem\\] \\[ ");str[i]=str[i].replace(/\\item\s*\[\s*(\w+)\s*\]/g," \\[alistitem\\]$1\\[ ");str[i]=str[i].replace(/\\item\s*/g," \\[alistitem\\] \\[ ");str[i]=str[i].replace(/\\appendix/g," \\[appendix\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*figure\s*\}([\s\S]+?)\\end\s*\{\s*figure\s*\}/g," \\[figure\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*table\s*\}([\s\S]+?)\\end\s*\{\s*table\s*\}/g," \\[table\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*theorem\s*\}/g," \\[theorem\\]Theorem \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*theorem\s*\}/g," \\[endtheorem\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*definition\s*\}/g," \\[definition\\]Definition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*definition\s*\}/g," \\[enddefinition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*lemma\s*\}/g," \\[lemma\\]Lemma \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*lemma\s*\}/g," \\[endlemma\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*corollary\s*\}/g," \\[corollary\\]Corollary \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*corollary\s*\}/g," \\[endcorollary\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proposition\s*\}/g," \\[proposition\\]Proposition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*proposition\s*\}/g," \\[endproposition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*example\s*\}/g," \\[example\\]Example \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*example\s*\}/g," \\[endexample\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*exercise\s*\}/g," \\[exercise\\]Exercise \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*exercise\s*\}/g," \\[endexercise\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}\s*\{\s*\w+\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*thebibliography\s*\}/g," \\[endthebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proof\s*\}/g," \\[proof\\]Proof: \\[ ");if(isIE){str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g,"\u220E \\[endproof\\] \\[ ");}else{str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g," \\[endproof\\] \\[ ");} -str[i]=str[i].replace(/\\title\s*\{\s*([^\}]+)\}/g," \\[title\\] \\[$1 \\[endtitle\\] \\[ ");str[i]=str[i].replace(/\\author\s*\{\s*([^\}]+)\}/g," \\[author\\] \\[$1 \\[endauthor\\] \\[ ");str[i]=str[i].replace(/\\address\s*\{\s*([^\}]+)\}/g," \\[address\\] \\[$1 \\[endaddress\\] \\[ ");str[i]=str[i].replace(/\\date\s*\{\s*([^\}]+)\}/g," \\[date\\] \\[$1 \\[enddate\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*keyword\s*\}/g," \\[keyword\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*keyword\s*\}/g," \\[endkeyword\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*abstract\s*\}/g," \\[abstract\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*abstract\s*\}/g," \\[endabstract\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[$1\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[end$1\\] \\[ ");var sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\section\s*\{/," \\[section\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);} -sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsection\s*\{/," \\[subsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);} -sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsubsection\s*\{/," \\[subsubsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);} -var CatToNextEven="";var strtmp=str[i].split("\\[");for(var j=0;j<strtmp.length;j++){if(j%2){var strtmparray=strtmp[j].split("\\]");switch(strtmparray[0]){case"section":var nodeTmp=document.createElement("H2");nodeTmp.className='section';sectionCntr++;for(var div in LaTeXCounter){LaTeXCounter[div]=0};var nodeAnchor=document.createElement("a");if(inAppendix){nodeAnchor.className='appendixsection';}else{nodeAnchor.className='section';} -var nodeNumString=makeNumberString("");var anchorSpan=document.createElement("span");anchorSpan.className="section";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='section';nodeSpan.appendChild(document.createTextNode(nodeNumString+" "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsection":var nodeTmp=document.createElement("H3");nodeTmp.className='subsection';LaTeXCounter["subsection"]++;LaTeXCounter["subsubsection"]=0;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsubsection":var nodeTmp=document.createElement("H4");nodeTmp.className='subsubsection';LaTeXCounter["subsubsection"]++;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsubsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]+"."+LaTeXCounter["subsubsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsubsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsubsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"href":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"url":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"figure":var nodeTmp=document.createElement("table");nodeTmp.className='figure';var FIGtbody=document.createElement("tbody");var FIGlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var FIGcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;FIGcap=tmp.substring(capstart,pos);break}}} -var FIGtr2=document.createElement("tr");var FIGtd2=document.createElement("td");FIGtd2.className="caption";var FIGanchor=document.createElement("a");FIGanchor.className="figure";if(FIGlbl!=null){FIGanchor.id=FIGlbl[1];} -LaTeXCounter["figure"]++;var fignmbr=makeNumberString(LaTeXCounter["figure"]);var anchorSpan=document.createElement("span");anchorSpan.className="figure";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(fignmbr));FIGanchor.appendChild(anchorSpan);FIGtd2.appendChild(FIGanchor);var FIGspan=document.createElement("span");FIGspan.className="figure";FIGspan.appendChild(document.createTextNode("Figure "+fignmbr+". "));FIGtd2.appendChild(FIGspan);FIGtd2.appendChild(document.createTextNode(""+FIGcap));FIGtr2.appendChild(FIGtd2);FIGtbody.appendChild(FIGtr2);var IsSpecial=false;var FIGinfo=strtmparray[1].match(/\\includegraphics\s*\{([^\}]+)\}/);if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\includegraphics\s*\[[^\]]*\]\s*\{\s*([^\}]+)\s*\}/);} -if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\special\s*\{\s*([^\}]+)\}/);IsSpecial=true};if(FIGinfo!=null){var FIGtr1=document.createElement("tr");var FIGtd1=document.createElement("td");FIGtd1.className="image";var FIGimg=document.createElement("img");var FIGsrc=FIGinfo[1];FIGimg.src=FIGsrc;FIGimg.alt="Figure "+FIGsrc+" did not load";FIGimg.title="Figure "+fignmbr+". "+FIGcap;FIGimg.id="figure"+fignmbr;FIGtd1.appendChild(FIGimg);FIGtr1.appendChild(FIGtd1);FIGtbody.appendChild(FIGtr1);} -nodeTmp.appendChild(FIGtbody);newFrag.appendChild(nodeTmp);break;case"table":var nodeTmp=document.createElement("table");if(strtmparray[1].search(/\\centering/)>=0){nodeTmp.className='LaTeXtable centered';nodeTmp.align="center";}else{nodeTmp.className='LaTeXtable';};tableid++;nodeTmp.id="LaTeXtable"+tableid;var TABlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var TABcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;TABcap=tmp.substring(capstart,pos);break}}} -if(TABcap!=""){var TABtbody=document.createElement("tbody");var TABcaption=document.createElement("caption");TABcaption.className="LaTeXtable centered";var TABanchor=document.createElement("a");TABanchor.className="LaTeXtable";if(TABlbl!=null){TABanchor.id=TABlbl[1];} -LaTeXCounter["table"]++;var tabnmbr=makeNumberString(LaTeXCounter["table"]);var anchorSpan=document.createElement("span");anchorSpan.className="LaTeXtable";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(tabnmbr));TABanchor.appendChild(anchorSpan);TABcaption.appendChild(TABanchor);var TABspan=document.createElement("span");TABspan.className="LaTeXtable";TABspan.appendChild(document.createTextNode("Table "+tabnmbr+". "));TABcaption.appendChild(TABspan);TABcaption.appendChild(document.createTextNode(""+TABcap));nodeTmp.appendChild(TABcaption);} -var TABinfo=strtmparray[1].match(/\\begin\s*\{\s*tabular\s*\}([\s\S]+)\\end\s*\{\s*tabular\s*\}/);if(TABinfo!=null){var TABtbody=document.createElement('tbody');var TABrow=null;var TABcell=null;var row=0;var col=0;var TABalign=TABinfo[1].match(/^\s*\{([^\}]+)\}/);TABinfo=TABinfo[1].replace(/^\s*\{[^\}]+\}/,"");TABinfo=TABinfo.replace(/\\hline/g,"");TABalign[1]=TABalign[1].replace(/\|/g,"");TABalign[1]=TABalign[1].replace(/\s/g,"");TABinfo=TABinfo.split("\\\\");for(row=0;row<TABinfo.length;row++){TABrow=document.createElement("tr");TABinfo[row]=TABinfo[row].split("&");for(col=0;col<TABinfo[row].length;col++){TABcell=document.createElement("td");switch(TABalign[1].charAt(col)){case"l":TABcell.align="left";break;case"c":TABcell.align="center";break;case"r":TABcell.align="right";break;default:TABcell.align="left";};TABcell.appendChild(document.createTextNode(TABinfo[row][col]));TABrow.appendChild(TABcell);} -TABtbody.appendChild(TABrow);} -nodeTmp.appendChild(TABtbody);} -newFrag.appendChild(nodeTmp);break;case"logicalbreak":var nodeTmp=document.createElement("p");nodeTmp.className=strtmparray[1];nodeTmp.appendChild(document.createTextNode("\u00A0"));newFrag.appendChild(nodeTmp);break;case"appendix":inAppendix=true;sectionCntr=0;break;case"alistitem":var EndDiv=document.createElement("div");EndDiv.className="endlistitem";newFrag.appendChild(EndDiv);var BegDiv=document.createElement("div");BegDiv.className="listitem";if(strtmparray[1]!=" "){var BegSpan=document.createElement("span");BegSpan.className="listitemmarker";var boldBegSpan=document.createElement("b");boldBegSpan.appendChild(document.createTextNode(strtmparray[1]+" "));BegSpan.appendChild(boldBegSpan);BegDiv.appendChild(BegSpan);} -newFrag.appendChild(BegDiv);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"bibitem":newFrag.appendChild(document.createElement("br"));var nodeTmp=document.createElement("a");nodeTmp.className='bibitem';var nodeSpan=document.createElement("span");nodeSpan.className='bibitem';bibcntr++;var lbl=strtmparray[1].match(/\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\s*\{\s*\w+\s*\}/g,"");strtmparray[1]=strtmparray[1].replace(/^\s*\[/,"");strtmparray[1]=strtmparray[1].replace(/\s*\]$/,"");strtmparray[1]=strtmparray[1].replace(/^\s+|\s+$/g,"");if(lbl==null){biblist[bibcntr]="bibitem"+bibcntr}else{biblist[bibcntr]=lbl[1];};nodeTmp.name=biblist[bibcntr];nodeTmp.id=biblist[bibcntr];if(strtmparray[1]!=""){nodeSpan.appendChild(document.createTextNode(strtmparray[1]));}else{nodeSpan.appendChild(document.createTextNode("["+bibcntr+"]"));} -nodeTmp.appendChild(nodeSpan);newFrag.appendChild(nodeTmp);break;case"cite":var nodeTmp=document.createElement("a");nodeTmp.className='cite';nodeTmp.name='cite';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;case"ref":var nodeTmp=document.createElement("a");nodeTmp.className='ref';nodeTmp.name='ref';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("div");nodeTmp.className=strtmparray[0];if(IsCounter.test(strtmparray[0])){LaTeXCounter[strtmparray[0]]++;var nodeAnchor=document.createElement("a");nodeAnchor.className=strtmparray[0];var divnum=makeNumberString(LaTeXCounter[strtmparray[0]]);var anchorSpan=document.createElement("span");anchorSpan.className=strtmparray[0];anchorSpan.appendChild(document.createTextNode(divnum));anchorSpan.style.display="none";nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]+" "+divnum+". "));nodeTmp.appendChild(nodeSpan);} -if(isIE){if(strtmparray[0]==("thebibliography"||"abstract"||"keyword"||"proof")){var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]));nodeTmp.appendChild(nodeSpan);}} -if(strtmparray[0]=="endenumerate"||strtmparray[0]=="enditemize"||strtmparray[0]=="enddescription"){var endDiv=document.createElement("div");endDiv.className="endlistitem";newFrag.appendChild(endDiv);} -newFrag.appendChild(nodeTmp);if(strtmparray[0]=="enumerate"||strtmparray[0]=="itemize"||strtmparray[0]=="description"){var endDiv=document.createElement("div");endDiv.className="listitem";newFrag.appendChild(endDiv);}}}else{strtmp[j]=strtmp[j].replace(/\\\$/g,"<per>");strtmp[j]=strtmp[j].replace(/\$([^\$]+)\$/g," \\[$1\\[ ");strtmp[j]=strtmp[j].replace(/<per>/g,"\\$");strtmp[j]=strtmp[j].replace(/\\begin\s*\{\s*math\s*\}([\s\S]+?)\\end\s*\{\s*math\s*\}/g," \\[$1\\[ ");var strtmptmp=strtmp[j].split("\\[");for(var jjj=0;jjj<strtmptmp.length;jjj++){if(jjj%2){var nodeTmp=document.createElement("span");nodeTmp.className='inlinemath';nodeTmp.appendChild(document.createTextNode("$"+strtmptmp[jjj]+"$"));newFrag.appendChild(nodeTmp);}else{var TagIndex=strtmptmp[jjj].search(/\\\w+/);var tmpIndex=TagIndex;while(tmpIndex>-1){if(/^\\textcolor/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\textcolor\s*\{\s*(\w+)\s*\}\s*/," \\[textcolor\\]$1\\]|");}else{if(/^\\colorbox/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\colorbox\s*\{\s*(\w+)\s*\}\s*/," \\[colorbox\\]$1\\]|");}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).replace(/\\\s*(\w+)\s*/," \\[$1\\]|");}} -TagIndex+=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\|/);TagIndex++;strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\]\|/,"\\] ");if(strtmptmp[jjj].charAt(TagIndex)=="{"){strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);var delimcnt=1;for(var kk=TagIndex;kk<strtmptmp[jjj].length;kk++){if(strtmptmp[jjj].charAt(kk)=="{"){delimcnt++};if(strtmptmp[jjj].charAt(kk)=="}"){delimcnt--};if(delimcnt==0){break;}} -strtmptmp[jjj]=strtmptmp[jjj].substring(0,kk)+"\\[ "+strtmptmp[jjj].substring(kk+1,strtmptmp[jjj].length);TagIndex=kk+3;}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+"\\[ "+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);TagIndex=TagIndex+3;} -if(TagIndex<strtmptmp[jjj].length){tmpIndex=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\\\w+/);} -else{tmpIndex=-1};TagIndex+=tmpIndex;} -strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\\s*\\\\/g,"\\\\");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\/g," \\[br\\] \\[ ");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\label\s*\{\s*(\w+)\s*\}/g," \\[a\\]$1\\[ ");var strlbls=strtmptmp[jjj].split("\\[");for(var jj=0;jj<strlbls.length;jj++){if(jj%2){var strtmparray=strlbls[jj].split("\\]");switch(strtmparray[0]){case"textcolor":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.color=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.color=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"colorbox":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.background=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.background=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"a":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathMLlabel';nodeTmp.id=strtmparray[1];nodeTmp.style.display="none";newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("span");nodeTmp.className=strtmparray[0];nodeTmp.appendChild(document.createTextNode(strtmparray[1])) -newFrag.appendChild(nodeTmp);}}else{newFrag.appendChild(document.createTextNode(strlbls[jj]));}}}}}}}};TheBody.parentNode.replaceChild(newFrag,TheBody);}}} -return TheBody;} -function LaTeXDivsAndRefs(thebody){var TheBody=thebody;var EndDivClass=null;var AllDivs=TheBody.getElementsByTagName("div");var lbl2id="";var lblnode=null;for(var i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){EndDivClass=EndDivClass[0];var DivClass=EndDivClass.substring(3,EndDivClass.length);var EndDivNode=AllDivs[i];break;}} -while(EndDivClass!=null){var newFrag=document.createDocumentFragment();var RootNode=EndDivNode.parentNode;var ClassCount=1;while(EndDivNode.previousSibling!=null&&ClassCount>0){switch(EndDivNode.previousSibling.className){case EndDivClass:ClassCount++;newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);break;case DivClass:if(EndDivNode.previousSibling.nodeName=="DIV"){ClassCount--;if(lbl2id!=""){EndDivNode.previousSibling.id=lbl2id;lbl2id=""} -if(ClassCount==0){RootNode=EndDivNode.previousSibling;}else{newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}};break;case'LaTeXMathMLlabel':lbl2id=EndDivNode.previousSibling.id;EndDivNode.parentNode.removeChild(EndDivNode.previousSibling);break;default:newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}} -RootNode.appendChild(newFrag);EndDivNode.parentNode.removeChild(EndDivNode);AllDivs=TheBody.getElementsByTagName("DIV");for(i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){ClassCount=0;EndDivClass=EndDivClass[0];DivClass=EndDivClass.substring(3,EndDivClass.length);EndDivNode=AllDivs[i];RootNode=EndDivNode.parentNode;break;}}} -var AllDivs=TheBody.getElementsByTagName("div");var DIV2LI=null;for(var i=0;i<AllDivs.length;i++){if(AllDivs[i].className=="itemize"||AllDivs[i].className=="enumerate"||AllDivs[i].className=="description"){if(AllDivs[i].className=="itemize"){RootNode=document.createElement("UL");}else{RootNode=document.createElement("OL");} -RootNode.className='LaTeXMathML';if(AllDivs[i].hasChildNodes()){AllDivs[i].removeChild(AllDivs[i].firstChild)};while(AllDivs[i].hasChildNodes()){if(AllDivs[i].firstChild.hasChildNodes()){DIV2LI=document.createElement("LI");while(AllDivs[i].firstChild.hasChildNodes()){DIV2LI.appendChild(AllDivs[i].firstChild.firstChild);} -if(DIV2LI.firstChild.className=="listitemmarker"){DIV2LI.style.listStyleType="none";} -RootNode.appendChild(DIV2LI)} -AllDivs[i].removeChild(AllDivs[i].firstChild);} -AllDivs[i].appendChild(RootNode);}} -var AllAnchors=TheBody.getElementsByTagName("a");for(var i=0;i<AllAnchors.length;i++){if(AllAnchors[i].className=="ref"||AllAnchors[i].className=="cite"){var label=AllAnchors[i].href.match(/\#(\w+)/);if(label!=null){var labelNode=document.getElementById(label[1]);if(labelNode!=null){var TheSpans=labelNode.getElementsByTagName("SPAN");if(TheSpans!=null){var refNode=TheSpans[0].cloneNode(true);refNode.style.display="inline" -refNode.className=AllAnchors[i].className;AllAnchors[i].appendChild(refNode);}}}}} -return TheBody;} -var AMbody;var AMnoMathML=false,AMtranslated=false;function translate(spanclassAM){if(!AMtranslated){AMtranslated=true;AMinitSymbols();var LaTeXContainers=[];var AllContainers=document.getElementsByTagName('*');var ExtendName="";for(var k=0,l=0;k<AllContainers.length;k++){ExtendName=" "+AllContainers[k].className+" ";if(ExtendName.match(/\sLaTeX\s/)!=null){LaTeXContainers[l]=AllContainers[k];l++;}};if(LaTeXContainers.length>0){for(var m=0;m<LaTeXContainers.length;m++){AMbody=LaTeXContainers[m];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");} -if(AMbody.tagName=="PRE"){var PreChilds=document.createDocumentFragment();var DivChilds=document.createElement("DIV");while(AMbody.hasChildNodes()){DivChilds.appendChild(AMbody.firstChild);} -PreChilds.appendChild(DivChilds);AMbody.parentNode.replaceChild(PreChilds,AMbody);AMbody=DivChilds;} -AMprocessNode(AMbody,false,spanclassAM);}}else{AMbody=document.getElementsByTagName("body")[0];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");} -AMprocessNode(AMbody,false,spanclassAM);}}} -if(isIE){document.write("<object id=\"mathplayer\" classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");} -function generic() -{translate();};if(typeof window.addEventListener!='undefined') -{window.addEventListener('load',generic,false);} -else if(typeof document.addEventListener!='undefined') -{document.addEventListener('load',generic,false);} -else if(typeof window.attachEvent!='undefined') -{window.attachEvent('onload',generic);} -else -{if(typeof window.onload=='function') -{var existing=onload;window.onload=function() -{existing();generic();};} -else -{window.onload=generic;}} diff --git a/data/bash_completion.tpl b/data/bash_completion.tpl index c9145c06c..60140a1e4 100644 --- a/data/bash_completion.tpl +++ b/data/bash_completion.tpl @@ -4,7 +4,7 @@ _pandoc() { - local cur prev opts lastc informats outformats datadir + local cur prev opts lastc informats outformats datafiles COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" @@ -14,7 +14,7 @@ _pandoc() informats="%s" outformats="%s" highlight_styles="%s" - datadir="%s" + datafiles="%s" case "${prev}" in --from|-f|--read|-r) @@ -34,7 +34,7 @@ _pandoc() return 0 ;; --print-default-data-file) - COMPREPLY=( $(compgen -W "reference.odt reference.docx $(find ${datadir} | sed -e 's/.*\/data\///')" -- ${cur}) ) + COMPREPLY=( $(compgen -W "${datafiles}" -- ${cur}) ) return 0 ;; --wrap) diff --git a/data/pptx/docProps/thumbnail.jpeg b/data/pptx/docProps/thumbnail.jpeg Binary files differdeleted file mode 100644 index 07aa48f19..000000000 --- a/data/pptx/docProps/thumbnail.jpeg +++ /dev/null diff --git a/data/templates/default.latex b/data/templates/default.latex index 7f2d72340..31093374f 100644 --- a/data/templates/default.latex +++ b/data/templates/default.latex @@ -7,6 +7,11 @@ $endif$$if(dir)$$if(latex-dir-rtl)$ $endif$$endif$% \documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(papersize)$$papersize$paper,$endif$$if(beamer)$ignorenonframetext,$if(handout)$handout,$endif$$if(aspectratio)$aspectratio=$aspectratio$,$endif$$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$} $if(beamer)$ +$if(background-image)$ +\usebackgroundtemplate{% +\includegraphics[width=\paperwidth]{$background-image$}% +} +$endif$ \usepackage{pgfpages} \setbeamertemplate{caption}[numbered] \setbeamertemplate{caption label separator}{: } diff --git a/data/templates/default.ms b/data/templates/default.ms index f4204338a..02bbc626a 100644 --- a/data/templates/default.ms +++ b/data/templates/default.ms @@ -90,7 +90,10 @@ $for(author)$ $author$ $endfor$ $if(date)$ -.ND "$date$" +.AU +.sp 0.5 +.ft R +$date$ $endif$ $if(abstract)$ .AB diff --git a/data/templates/default.revealjs b/data/templates/default.revealjs index 65ab09049..6f847e23a 100644 --- a/data/templates/default.revealjs +++ b/data/templates/default.revealjs @@ -197,6 +197,11 @@ $endif$ $if(parallaxBackgroundImage)$ // Parallax background image parallaxBackgroundImage: '$parallaxBackgroundImage$', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'" +$else$ +$if(background-image)$ + // Parallax background image + parallaxBackgroundImage: '$background-image$', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'" +$endif$ $endif$ $if(parallaxBackgroundSize)$ // Parallax background size diff --git a/linux/Dockerfile b/linux/Dockerfile index 40d37d13d..8a43e59f7 100644 --- a/linux/Dockerfile +++ b/linux/Dockerfile @@ -1,18 +1,25 @@ # USE ALPINE LINUX -FROM alpine:edge +FROM alpine +RUN apk update +# INSTALL BASIC DEV TOOLS, GHC, GMP & ZLIB RUN echo "https://s3-us-west-2.amazonaws.com/alpine-ghc/8.0" >> /etc/apk/repositories ADD https://raw.githubusercontent.com/mitchty/alpine-ghc/master/mitch.tishmack%40gmail.com-55881c97.rsa.pub \ /etc/apk/keys/mitch.tishmack@gmail.com-55881c97.rsa.pub RUN apk update -RUN apk add alpine-sdk git ca-certificates ghc cabal stack zlib-dev \ - dpkg fakeroot sed gawk grep bash linux-headers -RUN stack update +RUN apk add alpine-sdk git ca-certificates ghc gmp-dev zlib-dev bash dpkg fakeroot +# GRAB A RECENT BINARY OF STACK +RUN curl -L https://www.stackage.org/stack/linux-x86_64-static | tar xz --wildcards --strip-components=1 -C /usr/local/bin '*/stack' +# COMPRESS WITH UPX +ADD https://github.com/lalyos/docker-upx/releases/download/v3.91/upx /usr/local/bin/upx +RUN chmod 755 /usr/local/bin/upx +RUN ulimit -n 4096 RUN stack config set system-ghc --global true +RUN stack --resolver lts-9 setup --install-cabal 2.0.1.1 #RUN mkdir -p /etc/stack #RUN echo "build: { split-objs: true }" > /etc/stack/config.yaml RUN mkdir -p /usr/src/ WORKDIR /usr/src/ -RUN git clone https://github.com/jgm/pandoc +RUN git clone https://github.com/jgm/pandoc WORKDIR /usr/src/pandoc RUN stack install --stack-yaml stack.lts9.yaml \ --only-dependencies \ diff --git a/man/pandoc.1 b/man/pandoc.1 index d0ad08626..5f1acb411 100644 --- a/man/pandoc.1 +++ b/man/pandoc.1 @@ -1,5 +1,5 @@ .\"t -.TH PANDOC 1 "March 17, 2018" "pandoc 2.1.3" +.TH PANDOC 1 "March 17, 2018" "pandoc 2.1.4" .SH NAME pandoc - general markup converter .SH SYNOPSIS @@ -10,34 +10,21 @@ pandoc - general markup converter Pandoc is a Haskell library for converting from one markup format to another, and a command\-line tool that uses this library. .PP -Pandoc can read Markdown, CommonMark, PHP Markdown Extra, -GitHub\-Flavored Markdown, MultiMarkdown, and (subsets of) Textile, -reStructuredText, HTML, LaTeX, MediaWiki markup, TWiki markup, TikiWiki -markup, Creole 1.0, Haddock markup, OPML, Emacs Org mode, DocBook, JATS, -Muse, txt2tags, Vimwiki, EPUB, ODT, and Word docx. -.PP -Pandoc can write plain text, Markdown, CommonMark, PHP Markdown Extra, -GitHub\-Flavored Markdown, MultiMarkdown, reStructuredText, XHTML, -HTML5, LaTeX (including \f[C]beamer\f[] slide shows), ConTeXt, RTF, -OPML, DocBook, JATS, OpenDocument, ODT, Word docx, GNU Texinfo, -MediaWiki markup, DokuWiki markup, ZimWiki markup, Haddock markup, EPUB -(v2 or v3), FictionBook2, Textile, groff man, groff ms, Emacs Org mode, -AsciiDoc, InDesign ICML, TEI Simple, Muse, PowerPoint slide shows and -Slidy, Slideous, DZSlides, reveal.js or S5 HTML slide shows. -It can also produce PDF output on systems where LaTeX, ConTeXt, -\f[C]pdfroff\f[], \f[C]wkhtmltopdf\f[], \f[C]prince\f[], or -\f[C]weasyprint\f[] is installed. +Pandoc can convert between numerous markup and word processing formats, +including, but not limited to, various flavors of Markdown, HTML, LaTeX +and Word docx. +For the full lists of input and output formats, see the +\f[C]\-\-from\f[] and \f[C]\-\-to\f[] options below. +Pandoc can also produce PDF output: see creating a PDF, below. .PP Pandoc\[aq]s enhanced version of Markdown includes syntax for tables, -definition lists, metadata blocks, \f[C]Div\f[] blocks, footnotes and -citations, embedded LaTeX (including math), Markdown inside HTML block -elements, and much more. -These enhancements, described further under Pandoc\[aq]s Markdown, can -be disabled using the \f[C]markdown_strict\f[] format. +definition lists, metadata blocks, footnotes, citations, math, and much +more. +See below under Pandoc\[aq]s Markdown. .PP Pandoc has a modular design: it consists of a set of readers, which parse text in a given format and produce a native representation of the -document (like an \f[I]abstract syntax tree\f[] or AST), and a set of +document (an \f[I]abstract syntax tree\f[] or AST), and a set of writers, which convert this native representation into a target format. Thus, adding an input or output format requires only adding a reader or writer. @@ -229,69 +216,182 @@ pandoc\ \-f\ html\ \-t\ markdown\ \-\-request\-header\ User\-Agent:"Mozilla/5.0" .TP .B \f[C]\-f\f[] \f[I]FORMAT\f[], \f[C]\-r\f[] \f[I]FORMAT\f[], \f[C]\-\-from=\f[]\f[I]FORMAT\f[], \f[C]\-\-read=\f[]\f[I]FORMAT\f[] Specify input format. -\f[I]FORMAT\f[] can be \f[C]native\f[] (native Haskell), \f[C]json\f[] -(JSON version of native AST), \f[C]markdown\f[] (pandoc\[aq]s extended -Markdown), \f[C]markdown_strict\f[] (original unextended Markdown), -\f[C]markdown_phpextra\f[] (PHP Markdown Extra), \f[C]markdown_mmd\f[] -(MultiMarkdown), \f[C]gfm\f[] (GitHub\-Flavored Markdown), -\f[C]commonmark\f[] (CommonMark Markdown), \f[C]textile\f[] (Textile), -\f[C]rst\f[] (reStructuredText), \f[C]html\f[] (HTML), \f[C]docbook\f[] -(DocBook), \f[C]t2t\f[] (txt2tags), \f[C]docx\f[] (docx), \f[C]odt\f[] -(ODT), \f[C]epub\f[] (EPUB), \f[C]opml\f[] (OPML), \f[C]org\f[] (Emacs -Org mode), \f[C]mediawiki\f[] (MediaWiki markup), \f[C]twiki\f[] (TWiki -markup), \f[C]tikiwiki\f[] (TikiWiki markup), \f[C]creole\f[] (Creole -1.0), \f[C]haddock\f[] (Haddock markup), or \f[C]latex\f[] (LaTeX). -(\f[C]markdown_github\f[] provides deprecated and less accurate support -for Github\-Flavored Markdown; please use \f[C]gfm\f[] instead, unless -you need to use extensions other than \f[C]smart\f[].) Extensions can be -individually enabled or disabled by appending \f[C]+EXTENSION\f[] or -\f[C]\-EXTENSION\f[] to the format name. +\f[I]FORMAT\f[] can be: +.RS +.IP \[bu] 2 +\f[C]commonmark\f[] (CommonMark Markdown) +.IP \[bu] 2 +\f[C]creole\f[] (Creole 1.0) +.IP \[bu] 2 +\f[C]docbook\f[] (DocBook) +.IP \[bu] 2 +\f[C]docx\f[] (Word docx) +.IP \[bu] 2 +\f[C]epub\f[] (EPUB) +.IP \[bu] 2 +\f[C]gfm\f[] (GitHub\-Flavored Markdown), or \f[C]markdown_github\f[], +which provides deprecated and less accurate support for Github\-Flavored +Markdown; please use \f[C]gfm\f[] instead, unless you need to use +extensions other than \f[C]smart\f[]. +.IP \[bu] 2 +\f[C]haddock\f[] (Haddock markup) +.IP \[bu] 2 +\f[C]html\f[] (HTML) +.IP \[bu] 2 +\f[C]jats\f[] (JATS XML) +.IP \[bu] 2 +\f[C]json\f[] (JSON version of native AST) +.IP \[bu] 2 +\f[C]latex\f[] (LaTeX) +.IP \[bu] 2 +\f[C]markdown\f[] (Pandoc\[aq]s Markdown) +.IP \[bu] 2 +\f[C]markdown_mmd\f[] (MultiMarkdown) +.IP \[bu] 2 +\f[C]markdown_phpextra\f[] (PHP Markdown Extra) +.IP \[bu] 2 +\f[C]markdown_strict\f[] (original unextended Markdown) +.IP \[bu] 2 +\f[C]mediawiki\f[] (MediaWiki markup) +.IP \[bu] 2 +\f[C]muse\f[] (Muse) +.IP \[bu] 2 +\f[C]native\f[] (native Haskell) +.IP \[bu] 2 +\f[C]odt\f[] (ODT) +.IP \[bu] 2 +\f[C]opml\f[] (OPML) +.IP \[bu] 2 +\f[C]org\f[] (Emacs Org mode) +.IP \[bu] 2 +\f[C]rst\f[] (reStructuredText) +.IP \[bu] 2 +\f[C]t2t\f[] (txt2tags) +.IP \[bu] 2 +\f[C]textile\f[] (Textile) +.IP \[bu] 2 +\f[C]tikiwiki\f[] (TikiWiki markup) +.IP \[bu] 2 +\f[C]twiki\f[] (TWiki markup) +.IP \[bu] 2 +\f[C]vimwiki\f[] (Vimwiki) +.PP +Extensions can be individually enabled or disabled by appending +\f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format name. See Extensions below, for a list of extensions and their names. See \f[C]\-\-list\-input\-formats\f[] and \f[C]\-\-list\-extensions\f[], below. -.RS .RE .TP .B \f[C]\-t\f[] \f[I]FORMAT\f[], \f[C]\-w\f[] \f[I]FORMAT\f[], \f[C]\-\-to=\f[]\f[I]FORMAT\f[], \f[C]\-\-write=\f[]\f[I]FORMAT\f[] Specify output format. -\f[I]FORMAT\f[] can be \f[C]native\f[] (native Haskell), \f[C]json\f[] -(JSON version of native AST), \f[C]plain\f[] (plain text), -\f[C]markdown\f[] (pandoc\[aq]s extended Markdown), -\f[C]markdown_strict\f[] (original unextended Markdown), -\f[C]markdown_phpextra\f[] (PHP Markdown Extra), \f[C]markdown_mmd\f[] -(MultiMarkdown), \f[C]gfm\f[] (GitHub\-Flavored Markdown), -\f[C]commonmark\f[] (CommonMark Markdown), \f[C]rst\f[] -(reStructuredText), \f[C]html4\f[] (XHTML 1.0 Transitional), -\f[C]html\f[] or \f[C]html5\f[] (HTML5/XHTML polyglot markup), -\f[C]latex\f[] (LaTeX), \f[C]beamer\f[] (LaTeX beamer slide show), -\f[C]context\f[] (ConTeXt), \f[C]man\f[] (groff man), \f[C]mediawiki\f[] -(MediaWiki markup), \f[C]dokuwiki\f[] (DokuWiki markup), -\f[C]zimwiki\f[] (ZimWiki markup), \f[C]textile\f[] (Textile), -\f[C]org\f[] (Emacs Org mode), \f[C]texinfo\f[] (GNU Texinfo), -\f[C]opml\f[] (OPML), \f[C]docbook\f[] or \f[C]docbook4\f[] (DocBook 4), -\f[C]docbook5\f[] (DocBook 5), \f[C]jats\f[] (JATS XML), -\f[C]opendocument\f[] (OpenDocument), \f[C]odt\f[] (OpenOffice text -document), \f[C]docx\f[] (Word docx), \f[C]haddock\f[] (Haddock markup), -\f[C]rtf\f[] (rich text format), \f[C]epub2\f[] (EPUB v2 book), -\f[C]epub\f[] or \f[C]epub3\f[] (EPUB v3), \f[C]fb2\f[] (FictionBook2 -e\-book), \f[C]asciidoc\f[] (AsciiDoc), \f[C]icml\f[] (InDesign ICML), -\f[C]tei\f[] (TEI Simple), \f[C]slidy\f[] (Slidy HTML and JavaScript -slide show), \f[C]slideous\f[] (Slideous HTML and JavaScript slide -show), \f[C]dzslides\f[] (DZSlides HTML5 + JavaScript slide show), -\f[C]revealjs\f[] (reveal.js HTML5 + JavaScript slide show), \f[C]s5\f[] -(S5 HTML and JavaScript slide show), \f[C]pptx\f[] (PowerPoint slide -show) or the path of a custom lua writer (see Custom writers, below). -(\f[C]markdown_github\f[] provides deprecated and less accurate support -for Github\-Flavored Markdown; please use \f[C]gfm\f[] instead, unless -you use extensions that do not work with \f[C]gfm\f[].) Note that -\f[C]odt\f[], \f[C]docx\f[], and \f[C]epub\f[] output will not be -directed to \f[I]stdout\f[] unless forced with \f[C]\-o\ \-\f[]. +\f[I]FORMAT\f[] can be: +.RS +.IP \[bu] 2 +\f[C]asciidoc\f[] (AsciiDoc) +.IP \[bu] 2 +\f[C]beamer\f[] (LaTeX beamer slide show) +.IP \[bu] 2 +\f[C]commonmark\f[] (CommonMark Markdown) +.IP \[bu] 2 +\f[C]context\f[] (ConTeXt) +.IP \[bu] 2 +\f[C]docbook\f[] or \f[C]docbook4\f[] (DocBook 4) +.IP \[bu] 2 +\f[C]docbook5\f[] (DocBook 5) +.IP \[bu] 2 +\f[C]docx\f[] (Word docx) +.IP \[bu] 2 +\f[C]dokuwiki\f[] (DokuWiki markup) +.IP \[bu] 2 +\f[C]epub\f[] or \f[C]epub3\f[] (EPUB v3 book) +.IP \[bu] 2 +\f[C]epub2\f[] (EPUB v2) +.IP \[bu] 2 +\f[C]fb2\f[] (FictionBook2 e\-book) +.IP \[bu] 2 +\f[C]gfm\f[] (GitHub\-Flavored Markdown), or \f[C]markdown_github\f[], +which provides deprecated and less accurate support for Github\-Flavored +Markdown; please use \f[C]gfm\f[] instead, unless you use extensions +that do not work with \f[C]gfm\f[]. +.IP \[bu] 2 +\f[C]haddock\f[] (Haddock markup) +.IP \[bu] 2 +\f[C]html\f[] or \f[C]html5\f[] (HTML, i.e. +HTML5/XHTML polyglot markup) +.IP \[bu] 2 +\f[C]html4\f[] (XHTML 1.0 Transitional) +.IP \[bu] 2 +\f[C]icml\f[] (InDesign ICML) +.IP \[bu] 2 +\f[C]jats\f[] (JATS XML) +.IP \[bu] 2 +\f[C]json\f[] (JSON version of native AST) +.IP \[bu] 2 +\f[C]latex\f[] (LaTeX) +.IP \[bu] 2 +\f[C]man\f[] (groff man) +.IP \[bu] 2 +\f[C]markdown\f[] (Pandoc\[aq]s Markdown) +.IP \[bu] 2 +\f[C]markdown_mmd\f[] (MultiMarkdown) +.IP \[bu] 2 +\f[C]markdown_phpextra\f[] (PHP Markdown Extra) +.IP \[bu] 2 +\f[C]markdown_strict\f[] (original unextended Markdown) +.IP \[bu] 2 +\f[C]mediawiki\f[] (MediaWiki markup) +.IP \[bu] 2 +\f[C]ms\f[] (groff ms) +.IP \[bu] 2 +\f[C]muse\f[] (Muse), +.IP \[bu] 2 +\f[C]native\f[] (native Haskell), +.IP \[bu] 2 +\f[C]odt\f[] (OpenOffice text document) +.IP \[bu] 2 +\f[C]opml\f[] (OPML) +.IP \[bu] 2 +\f[C]opendocument\f[] (OpenDocument) +.IP \[bu] 2 +\f[C]org\f[] (Emacs Org mode) +.IP \[bu] 2 +\f[C]plain\f[] (plain text), +.IP \[bu] 2 +\f[C]pptx\f[] (PowerPoint slide show) +.IP \[bu] 2 +\f[C]rst\f[] (reStructuredText) +.IP \[bu] 2 +\f[C]rtf\f[] (Rich Text Format) +.IP \[bu] 2 +\f[C]texinfo\f[] (GNU Texinfo) +.IP \[bu] 2 +\f[C]textile\f[] (Textile) +.IP \[bu] 2 +\f[C]slideous\f[] (Slideous HTML and JavaScript slide show) +.IP \[bu] 2 +\f[C]slidy\f[] (Slidy HTML and JavaScript slide show) +.IP \[bu] 2 +\f[C]dzslides\f[] (DZSlides HTML5 + JavaScript slide show), +.IP \[bu] 2 +\f[C]revealjs\f[] (reveal.js HTML5 + JavaScript slide show) +.IP \[bu] 2 +\f[C]s5\f[] (S5 HTML and JavaScript slide show) +.IP \[bu] 2 +\f[C]tei\f[] (TEI Simple) +.IP \[bu] 2 +\f[C]zimwiki\f[] (ZimWiki markup) +.IP \[bu] 2 +the path of a custom lua writer, see Custom writers below +.PP +Note that \f[C]odt\f[], \f[C]docx\f[], and \f[C]epub\f[] output will not +be directed to \f[I]stdout\f[] unless forced with \f[C]\-o\ \-\f[]. +.PP Extensions can be individually enabled or disabled by appending \f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format name. See Extensions below, for a list of extensions and their names. See \f[C]\-\-list\-output\-formats\f[] and \f[C]\-\-list\-extensions\f[], below. -.RS .RE .TP .B \f[C]\-o\f[] \f[I]FILE\f[], \f[C]\-\-output=\f[]\f[I]FILE\f[] @@ -537,14 +637,16 @@ return\ {{Str\ =\ expand_hello_world}} .B \f[C]\-M\f[] \f[I]KEY\f[][\f[C]=\f[]\f[I]VAL\f[]], \f[C]\-\-metadata=\f[]\f[I]KEY\f[][\f[C]:\f[]\f[I]VAL\f[]] Set the metadata field \f[I]KEY\f[] to the value \f[I]VAL\f[]. A value specified on the command line overrides a value specified in the -document. +document using [YAML metadata +blocks][Extension:\f[C]yaml_metadata_block\f[]]. Values will be parsed as YAML boolean or string values. If no value is specified, the value will be treated as Boolean true. Like \f[C]\-\-variable\f[], \f[C]\-\-metadata\f[] causes template variables to be set. But unlike \f[C]\-\-variable\f[], \f[C]\-\-metadata\f[] affects the metadata of the underlying document (which is accessible from filters -and may be printed in some output formats). +and may be printed in some output formats) and metadata values will be +escaped when inserted into the template. .RS .RE .TP @@ -1419,23 +1521,25 @@ template. For \f[C]pdf\f[] output, customize the \f[C]default.latex\f[] template (or the \f[C]default.context\f[] template, if you use \f[C]\-t\ context\f[], or the \f[C]default.ms\f[] template, if you use -\f[C]\-t\ ms\f[], or the \f[C]default.html5\f[] template, if you use -\f[C]\-t\ html5\f[]). +\f[C]\-t\ ms\f[], or the \f[C]default.html\f[] template, if you use +\f[C]\-t\ html\f[]). .IP \[bu] 2 \f[C]docx\f[] has no template (however, you can use \f[C]\-\-reference\-doc\f[] to customize the output). .PP Templates contain \f[I]variables\f[], which allow for the inclusion of arbitrary information at any point in the file. -Variables may be set within the document using YAML metadata blocks. -They may also be set at the command line using the -\f[C]\-V/\-\-variable\f[] option: variables set in this way override -metadata fields with the same name. +They may be set at the command line using the \f[C]\-V/\-\-variable\f[] +option. +If a variable is not set, pandoc will look for the key in the +document\[aq]s metadata \[en] which can be set using either [YAML +metadata blocks][Extension:\f[C]yaml_metadata_block\f[]] or with the +\f[C]\-\-metadata\f[] option. .SS Variables set by pandoc .PP Some variables are set automatically by pandoc. -These vary somewhat depending on the output format, but include metadata -fields as well as the following: +These vary somewhat depending on the output format, but include the +following: .TP .B \f[C]sourcefile\f[], \f[C]outputfile\f[] source and destination filenames, as given on the command line. @@ -1678,6 +1782,11 @@ option for document class, e.g. .RS .RE .TP +.B \f[C]beameroption\f[] +In beamer, add extra beamer option with \f[C]\\setbeameroption{}\f[] +.RS +.RE +.TP .B \f[C]geometry\f[] option for \f[C]geometry\f[] package, e.g. \f[C]margin=1in\f[]; may be repeated for multiple options @@ -2359,7 +2468,7 @@ pandoc\ \-f\ markdown+lhs\ \-t\ html+lhs writes HTML with the Haskell code in bird tracks, so it can be copied and pasted as literate Haskell source. .PP -Note that GHC expects the bird tracks in the first column, so indentend +Note that GHC expects the bird tracks in the first column, so indented literate code blocks (e.g. inside an itemized environment) will not be picked up by the Haskell compiler. @@ -2377,8 +2486,7 @@ This extension can be enabled/disabled for the following formats: .RE .TP .B output formats -\f[C]markdown\f[], \f[C]docx\f[], \f[C]odt\f[], \f[C]opendocument\f[], -\f[C]html\f[] +\f[C]docx\f[], \f[C]odt\f[], \f[C]opendocument\f[], \f[C]html\f[] .RS .RE .SS Extension: \f[C]styles\f[] @@ -3772,7 +3880,8 @@ For example: .nf \f[C] header\-includes: -\-\ ```{=latex} +\-\ | +\ \ ```{=latex} \ \ \\let\\oldsection\\section \ \ \\renewcommand{\\section}[1]{\\clearpage\\oldsection{#1}} \ \ ``` @@ -4194,9 +4303,29 @@ This\ is\ `<a>html</a>`{=html} \f[] .fi .PP +This can be useful to insert raw xml into \f[C]docx\f[] documents, e.g. +a pagebreak: +.IP +.nf +\f[C] +```{=openxml} +<w:p> +\ \ <w:r> +\ \ \ \ <w:br\ w:type="page"/> +\ \ </w:r> +</w:p> +``` +\f[] +.fi +.PP The format name should match the target format name (see \f[C]\-t/\-\-to\f[], above, for a list, or use \f[C]pandoc\ \-\-list\-output\-formats\f[]). +Use \f[C]openxml\f[] for \f[C]docx\f[] output, \f[C]opendocument\f[] for +\f[C]odt\f[] output, \f[C]html5\f[] for \f[C]epub3\f[] output, +\f[C]html4\f[] for \f[C]epub2\f[] output, and \f[C]latex\f[], +\f[C]beamer\f[], \f[C]ms\f[], or \f[C]html5\f[] for \f[C]pdf\f[] output +(depending on what you use for \f[C]\-\-pdf\-engine\f[]). .PP This extension presupposes that the relevant kind of inline code or fenced code block is enabled. diff --git a/pandoc.cabal b/pandoc.cabal index 512062c46..24fba87f7 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -1,5 +1,5 @@ name: pandoc -version: 2.1.3 +version: 2.2 cabal-version: >= 1.10 build-type: Custom license: GPL-2 @@ -102,7 +102,6 @@ data-files: data/odt/META-INF/manifest.xml -- source files for reference.pptx data/pptx/_rels/.rels - data/pptx/docProps/thumbnail.jpeg data/pptx/docProps/app.xml data/pptx/docProps/core.xml data/pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels @@ -149,8 +148,6 @@ data-files: data/pptx/[Content_Types].xml -- stylesheet for EPUB writer data/epub.css - -- data for LaTeXMathML writer - data/LaTeXMathML.js -- data for dzslides writer data/dzslides/template.html -- default abbreviations file @@ -371,7 +368,7 @@ library zlib >= 0.5 && < 0.7, skylighting >= 0.5.1 && < 0.8, data-default >= 0.4 && < 0.8, - temporary >= 1.1 && < 1.3, + temporary >= 1.1 && < 1.4, blaze-html >= 0.9 && < 0.10, blaze-markup >= 0.8 && < 0.9, yaml >= 0.8.8.2 && < 0.9, @@ -599,7 +596,7 @@ benchmark weigh-pandoc hs-source-dirs: prelude other-modules: Prelude build-depends: base-compat >= 0.9 - ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind + ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded default-language: Haskell2010 other-extensions: NoImplicitPrelude @@ -618,7 +615,7 @@ test-suite test-pandoc filepath >= 1.1 && < 1.5, hslua >= 0.9.5 && < 0.9.6, process >= 1.2.3 && < 1.7, - temporary >= 1.1 && < 1.3, + temporary >= 1.1 && < 1.4, Diff >= 0.2 && < 0.4, tasty >= 0.11 && < 1.1, tasty-hunit >= 0.9 && < 0.11, @@ -702,6 +699,6 @@ benchmark benchmark-pandoc hs-source-dirs: prelude other-modules: Prelude build-depends: base-compat >= 0.9 - ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind + ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded default-language: Haskell2010 other-extensions: NoImplicitPrelude diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index 76d1d79c0..99277d434 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -52,7 +52,7 @@ import Data.Aeson (defaultOptions) import Data.Aeson.TH (deriveJSON) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as B -import Data.Char (toLower, toUpper) +import Data.Char (toLower, toUpper, isAscii, ord) import Data.List (find, intercalate, isPrefixOf, isSuffixOf, sort) import qualified Data.Map as M import Data.Maybe (fromMaybe, isJust, isNothing) @@ -66,7 +66,12 @@ import Data.Yaml (decode) import qualified Data.Yaml as Yaml import GHC.Generics import Network.URI (URI (..), parseURI) +#ifdef EMBED_DATA_FILES +import Text.Pandoc.Data (dataFiles) +#else +import System.Directory (getDirectoryContents) import Paths_pandoc (getDataDir) +#endif import Data.Aeson.Encode.Pretty (encodePretty', Config(..), keyOrder, defConfig, Indent(..), NumberFormat(..)) import Skylighting (Style, Syntax (..), defaultSyntaxMap, parseTheme, @@ -352,12 +357,6 @@ convertWithOpts opts = do maybe return (addStringAsVariable "epub-cover-image") (optEpubCoverImage opts) >>= - (\vars -> case optHTMLMathMethod opts of - LaTeXMathML Nothing -> do - s <- UTF8.toString <$> readDataFile "LaTeXMathML.js" - return $ ("mathml-script", s) : vars - _ -> return vars) - >>= (\vars -> if format == "dzslides" then do dztempl <- UTF8.toString <$> readDataFile @@ -514,16 +513,19 @@ convertWithOpts opts = do let htmlFormat = format `elem` ["html","html4","html5","s5","slidy", "slideous","dzslides","revealjs"] - handleEntities = if (htmlFormat || - format == "docbook4" || - format == "docbook5" || - format == "docbook") && optAscii opts - then toEntities - else id + escape + | optAscii opts + , htmlFormat || format == "docbook4" || + format == "docbook5" || format == "docbook" || + format == "jats" || format == "opml" || + format == "icml" = toEntities + | optAscii opts + , format == "ms" || format == "man" = groffEscape + | otherwise = id addNl = if standalone then id else (<> T.singleton '\n') - output <- (addNl . handleEntities) <$> f writerOptions doc + output <- (addNl . escape) <$> f writerOptions doc writerFn eol outputFile =<< if optSelfContained opts && htmlFormat -- TODO not maximally efficient; change type @@ -531,6 +533,12 @@ convertWithOpts opts = do then T.pack <$> makeSelfContained (T.unpack output) else return output +groffEscape :: Text -> Text +groffEscape = T.concatMap toUchar + where toUchar c + | isAscii c = T.singleton c + | otherwise = T.pack $ printf "\\[u%04X]" (ord c) + type Transform = Pandoc -> Pandoc isTextFormat :: String -> Bool @@ -1396,40 +1404,6 @@ options = "URL") "" -- Use KaTeX for HTML Math - , Option "m" ["latexmathml", "asciimathml"] - (OptArg - (\arg opt -> do - deprecatedOption "--latexmathml, --asciimathml, -m" "" - return opt { optHTMLMathMethod = LaTeXMathML arg }) - "URL") - "" -- "Use LaTeXMathML script in html output" - - , Option "" ["mimetex"] - (OptArg - (\arg opt -> do - deprecatedOption "--mimetex" "" - let url' = case arg of - Just u -> u ++ "?" - Nothing -> "/cgi-bin/mimetex.cgi?" - return opt { optHTMLMathMethod = WebTeX url' }) - "URL") - "" -- "Use mimetex for HTML math" - - , Option "" ["jsmath"] - (OptArg - (\arg opt -> do - deprecatedOption "--jsmath" "" - return opt { optHTMLMathMethod = JsMath arg}) - "URL") - "" -- "Use jsMath for HTML math" - - , Option "" ["gladtex"] - (NoArg - (\opt -> do - deprecatedOption "--gladtex" "" - return opt { optHTMLMathMethod = GladTeX })) - "" -- "Use gladtex for HTML math" - , Option "" ["abbreviations"] (ReqArg (\arg opt -> return opt { optAbbreviations = Just arg }) @@ -1475,7 +1449,7 @@ options = , Option "" ["bash-completion"] (NoArg (\_ -> do - ddir <- getDataDir + datafiles <- getDataFileNames tpl <- runIOorExplode $ UTF8.toString <$> readDefaultDataFile "bash_completion.tpl" @@ -1487,7 +1461,7 @@ options = (unwords readersNames) (unwords writersNames) (unwords $ map fst highlightingStyles) - ddir + (unwords datafiles) exitSuccess )) "" -- "Print bash completion script" @@ -1561,6 +1535,16 @@ options = ] +getDataFileNames :: IO [FilePath] +getDataFileNames = do +#ifdef EMBED_DATA_FILES + let allDataFiles = map fst dataFiles +#else + allDataFiles <- filter (\x -> x /= "." && x /= "..") <$> + (getDataDir >>= getDirectoryContents) +#endif + return $ "reference.docx" : "reference.odt" : "reference.pptx" : allDataFiles + -- Returns usage message usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]") diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index c78822ee9..3529054e6 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -855,7 +855,7 @@ writeMedia :: FilePath -> MediaBag -> FilePath -> PandocIO () writeMedia dir mediabag subpath = do -- we join and split to convert a/b/c to a\b\c on Windows; -- in zip containers all paths use / - let fullpath = dir </> normalise subpath + let fullpath = dir </> unEscapeString (normalise subpath) let mbcontents = lookupMedia subpath mediabag case mbcontents of Nothing -> throwError $ PandocResourceNotFound subpath diff --git a/src/Text/Pandoc/MIME.hs b/src/Text/Pandoc/MIME.hs index 2f37c1b83..cb7debb2e 100644 --- a/src/Text/Pandoc/MIME.hs +++ b/src/Text/Pandoc/MIME.hs @@ -174,7 +174,7 @@ mimeTypesList = -- List borrowed from happstack-server. ,("eml","message/rfc822") ,("ent","chemical/x-ncbi-asn1-ascii") ,("eot","application/vnd.ms-fontobject") - ,("eps","application/postscript") + ,("eps","application/eps") ,("etx","text/x-setext") ,("exe","application/x-msdos-program") ,("ez","application/andrew-inset") diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index a542954ad..4797a3094 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -106,9 +106,6 @@ defaultAbbrevs = Set.fromList data EPUBVersion = EPUB2 | EPUB3 deriving (Eq, Show, Read, Data, Typeable, Generic) data HTMLMathMethod = PlainMath - | LaTeXMathML (Maybe String) -- url of LaTeXMathML.js - | JsMath (Maybe String) -- url of jsMath load script - | GladTeX | WebTeX String -- url of TeX->image script. | MathML | MathJax String -- url of MathJax.js diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index d73126f44..c73ab2dd9 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -51,7 +51,7 @@ import System.Environment import System.Exit (ExitCode (..)) import System.FilePath import System.IO (stdout) -import System.IO.Temp (withTempDirectory, withTempFile) +import System.IO.Temp (withTempDirectory) #if MIN_VERSION_base(4,8,3) import System.IO.Error (IOError, isDoesNotExistError) #else @@ -130,9 +130,11 @@ makePDF "pdfroff" pdfargs writer opts doc = do verbosity <- getVerbosity liftIO $ ms2pdf verbosity args source makePDF program pdfargs writer opts doc = do - let withTemp = if takeBaseName program == "context" - then withTempDirectory "." - else withTempDir + -- With context and latex, we create a temp directory within + -- the working directory, since pdflatex sometimes tries to + -- use tools like epstopdf.pl, which are restricted if run + -- on files outside the working directory. + let withTemp = withTempDirectory "." commonState <- getCommonState verbosity <- getVerbosity liftIO $ withTemp "tex2pdf." $ \tmpdir -> do @@ -173,6 +175,8 @@ convertImage tmpdir fname = Just "image/png" -> doNothing Just "image/jpeg" -> doNothing Just "application/pdf" -> doNothing + -- Note: eps is converted by pdflatex using epstopdf.pl + Just "application/eps" -> doNothing Just "image/svg+xml" -> E.catch (do (exit, _) <- pipeProcess Nothing "rsvg-convert" ["-f","pdf","-a","-o",pdfOut,fname] BL.empty @@ -368,43 +372,44 @@ html2pdf verbosity program args htmlSource = do baseTag = TagOpen "base" [("href", T.pack cwd <> T.singleton pathSeparator)] : [TagText "\n"] source = renderTags $ hd ++ baseTag ++ tl - pdfFile <- withTempFile "." "html2pdf.pdf" $ \fp _ -> return fp - let pdfFileArgName = ["-o" | program == "prince"] - let programArgs = args ++ ["-"] ++ pdfFileArgName ++ [pdfFile] - env' <- getEnvironment - when (verbosity >= INFO) $ do - putStrLn "[makePDF] Command line:" - putStrLn $ program ++ " " ++ unwords (map show programArgs) - putStr "\n" - putStrLn "[makePDF] Environment:" - mapM_ print env' - putStr "\n" - putStrLn "[makePDF] Contents of intermediate HTML:" - TextIO.putStr source - putStr "\n" - (exit, out) <- E.catch - (pipeProcess (Just env') program programArgs $ BL.fromStrict $ UTF8.fromText source) - (\(e :: IOError) -> if isDoesNotExistError e - then E.throwIO $ - PandocPDFProgramNotFoundError program - else E.throwIO e) - when (verbosity >= INFO) $ do - BL.hPutStr stdout out - putStr "\n" - pdfExists <- doesFileExist pdfFile - mbPdf <- if pdfExists - -- We read PDF as a strict bytestring to make sure that the - -- temp directory is removed on Windows. - -- See https://github.com/jgm/pandoc/issues/1192. - then do - res <- (Just . BL.fromChunks . (:[])) `fmap` BS.readFile pdfFile - removeFile pdfFile - return res - else return Nothing - return $ case (exit, mbPdf) of - (ExitFailure _, _) -> Left out - (ExitSuccess, Nothing) -> Left "" - (ExitSuccess, Just pdf) -> Right pdf + withTempDir "html2pdf.pdf" $ \tmpdir -> do + let pdfFile = tmpdir </> "out.pdf" + let pdfFileArgName = ["-o" | program == "prince"] + let programArgs = args ++ ["-"] ++ pdfFileArgName ++ [pdfFile] + env' <- getEnvironment + when (verbosity >= INFO) $ do + putStrLn "[makePDF] Command line:" + putStrLn $ program ++ " " ++ unwords (map show programArgs) + putStr "\n" + putStrLn "[makePDF] Environment:" + mapM_ print env' + putStr "\n" + putStrLn "[makePDF] Contents of intermediate HTML:" + TextIO.putStr source + putStr "\n" + (exit, out) <- E.catch + (pipeProcess (Just env') program programArgs $ BL.fromStrict $ UTF8.fromText source) + (\(e :: IOError) -> if isDoesNotExistError e + then E.throwIO $ + PandocPDFProgramNotFoundError program + else E.throwIO e) + when (verbosity >= INFO) $ do + BL.hPutStr stdout out + putStr "\n" + pdfExists <- doesFileExist pdfFile + mbPdf <- if pdfExists + -- We read PDF as a strict bytestring to make sure that the + -- temp directory is removed on Windows. + -- See https://github.com/jgm/pandoc/issues/1192. + then do + res <- (Just . BL.fromChunks . (:[])) `fmap` BS.readFile pdfFile + removeFile pdfFile + return res + else return Nothing + return $ case (exit, mbPdf) of + (ExitFailure _, _) -> Left out + (ExitSuccess, Nothing) -> Left "" + (ExitSuccess, Just pdf) -> Right pdf context2pdf :: Verbosity -- ^ Verbosity level -> FilePath -- ^ temp directory for output diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index d812f5ee5..fa6baf1c7 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -135,7 +135,7 @@ module Text.Pandoc.Parsing ( takeWhileP, extractIdClass, insertIncludedFile, insertIncludedFileF, - -- * Re-exports from Text.Pandoc.Parsec + -- * Re-exports from Text.Parsec Stream, runParser, runParserT, @@ -593,7 +593,7 @@ uri = try $ do -- http://en.wikipedia.org/wiki/State_of_emergency_(disambiguation) -- as a URL, while NOT picking up the closing paren in -- (http://wikipedia.org). So we include balanced parens in the URL. - let isWordChar c = isAlphaNum c || c `elem` "#$%*+/@\\_-&=" + let isWordChar c = isAlphaNum c || c `elem` "#$%+/@\\_-&=" let wordChar = satisfy isWordChar let percentEscaped = try $ char '%' >> skipMany1 (satisfy isHexDigit) let entity = () <$ characterReference diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 6bc4584c2..3d48c7ee8 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -1,4 +1,33 @@ {-# LANGUAGE NoImplicitPrelude #-} +{- +Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-} + +{- | + Module : Text.Pandoc.Readers.DocBook + Copyright : Copyright (C) 2006-2018 John MacFarlane + License : GNU GPL, version 2 or above + + Maintainer : John MacFarlane <jgm@berkeley.edu> + Stability : alpha + Portability : portable + +Conversion of DocBook XML to 'Pandoc' document. +-} module Text.Pandoc.Readers.DocBook ( readDocBook ) where import Prelude import Control.Monad.State.Strict @@ -236,7 +265,7 @@ List of all DocBook tags, with [x] indicating implemented, [ ] manvolnum - A reference volume number [x] markup - A string of formatting markup in text that is to be represented literally -[ ] mathphrase - A mathematical phrase, an expression that can be represented +[x] mathphrase - A mathematical phrase, an expression that can be represented with ordinary text and a small amount of markup [ ] medialabel - A name that identifies the physical medium on which some information resides @@ -698,6 +727,8 @@ parseBlock (Elem e) = "bibliodiv" -> sect 1 "biblioentry" -> parseMixed para (elContent e) "bibliomixed" -> parseMixed para (elContent e) + "equation" -> para <$> equation e displayMath + "informalequation" -> para <$> equation e displayMath "glosssee" -> para . (\ils -> text "See " <> ils <> str ".") <$> getInlines e "glossseealso" -> para . (\ils -> text "See also " <> ils <> str ".") @@ -924,9 +955,9 @@ parseInline (CRef ref) = return $ maybe (text $ map toUpper ref) text $ lookupEntity ref parseInline (Elem e) = case qName (elName e) of - "equation" -> equation displayMath - "informalequation" -> equation displayMath - "inlineequation" -> equation math + "equation" -> equation e displayMath + "informalequation" -> equation e displayMath + "inlineequation" -> equation e math "subscript" -> subscript <$> innerInlines "superscript" -> superscript <$> innerInlines "inlinemediaobject" -> getMediaobject e @@ -1005,13 +1036,6 @@ parseInline (Elem e) = _ -> innerInlines where innerInlines = (trimInlines . mconcat) <$> mapM parseInline (elContent e) - equation constructor = return $ mconcat $ - map (constructor . writeTeX) - $ rights - $ map (readMathML . showElement . everywhere (mkT removePrefix)) - $ filterChildren (\x -> qName (elName x) == "math" && - qPrefix (elName x) == Just "mml") e - removePrefix elname = elname { qPrefix = Nothing } codeWithLang = do let classes' = case attrValue "language" e of "" -> [] @@ -1049,6 +1073,7 @@ parseInline (Elem e) = | not (null xrefLabel) = xrefLabel | otherwise = case qName (elName el) of "chapter" -> descendantContent "title" el + "section" -> descendantContent "title" el "sect1" -> descendantContent "title" el "sect2" -> descendantContent "title" el "sect3" -> descendantContent "title" el @@ -1061,3 +1086,45 @@ parseInline (Elem e) = xrefLabel = attrValue "xreflabel" el descendantContent name = maybe "???" strContent . filterElementName (\n -> qName n == name) + +-- | Extract a math equation from an element +-- +-- asciidoc can generate Latex math in CDATA sections. +-- +-- Note that if some MathML can't be parsed it is silently ignored! +equation + :: Monad m + => Element + -- ^ The element from which to extract a mathematical equation + -> (String -> Inlines) + -- ^ A constructor for some Inlines, taking the TeX code as input + -> m Inlines +equation e constructor = + return $ mconcat $ map constructor $ mathMLEquations ++ latexEquations + where + mathMLEquations :: [String] + mathMLEquations = map writeTeX $ rights $ readMath + (\x -> qName (elName x) == "math" && qPrefix (elName x) == Just "mml") + (readMathML . showElement) + + latexEquations :: [String] + latexEquations = readMath (\x -> qName (elName x) == "mathphrase") + (concat . fmap showVerbatimCData . elContent) + + readMath :: (Element -> Bool) -> (Element -> b) -> [b] + readMath childPredicate fromElement = + ( map (fromElement . everywhere (mkT removePrefix)) + $ filterChildren childPredicate e + ) + +-- | Get the actual text stored in a verbatim CData block. 'showContent' +-- returns the text still surrounded by the [[CDATA]] tags. +-- +-- Returns 'showContent' if this is not a verbatim CData +showVerbatimCData :: Content -> String +showVerbatimCData (Text (CData CDataVerbatim d _)) = d +showVerbatimCData c = showContent c + +-- | Set the prefix of a name to 'Nothing' +removePrefix :: QName -> QName +removePrefix elname = elname { qPrefix = Nothing } diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs index 00603603a..ca9f8c8dd 100644 --- a/src/Text/Pandoc/Readers/Docx.hs +++ b/src/Text/Pandoc/Readers/Docx.hs @@ -688,6 +688,10 @@ bodyPartToBlocks (Tbl cap _ look parts@(r:rs)) = do rowLength :: Row -> Int rowLength (Row c) = length c + -- pad cells. New Text.Pandoc.Builder will do that for us, + -- so this is for compatibility while we switch over. + let cells' = map (\row -> take width (row ++ repeat mempty)) cells + hdrCells <- case hdr of Just r' -> rowToBlocksList r' Nothing -> return $ replicate width mempty @@ -700,7 +704,7 @@ bodyPartToBlocks (Tbl cap _ look parts@(r:rs)) = do let alignments = replicate width AlignDefault widths = replicate width 0 :: [Double] - return $ table caption (zip alignments widths) hdrCells cells + return $ table caption (zip alignments widths) hdrCells cells' bodyPartToBlocks (OMathPara e) = return $ para $ displayMath (writeTeX e) diff --git a/src/Text/Pandoc/Readers/Docx/Combine.hs b/src/Text/Pandoc/Readers/Docx/Combine.hs index dfd2b5666..108c4bbe5 100644 --- a/src/Text/Pandoc/Readers/Docx/Combine.hs +++ b/src/Text/Pandoc/Readers/Docx/Combine.hs @@ -135,6 +135,10 @@ combineBlocks bs cs | bs' :> BlockQuote bs'' <- viewr (unMany bs) , BlockQuote cs'' :< cs' <- viewl (unMany cs) = Many $ (bs' |> BlockQuote (bs'' <> cs'')) >< cs' + | bs' :> CodeBlock attr codeStr <- viewr (unMany bs) + , CodeBlock attr' codeStr' :< cs' <- viewl (unMany cs) + , attr == attr' = + Many $ (bs' |> CodeBlock attr (codeStr <> "\n" <> codeStr')) >< cs' combineBlocks bs cs = bs <> cs instance (Monoid a, Eq a) => Eq (Modifier a) where diff --git a/src/Text/Pandoc/Readers/EPUB.hs b/src/Text/Pandoc/Readers/EPUB.hs index 714468a8a..c26447641 100644 --- a/src/Text/Pandoc/Readers/EPUB.hs +++ b/src/Text/Pandoc/Readers/EPUB.hs @@ -1,7 +1,35 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE ViewPatterns #-} +{- +Copyright (C) 2014-2018 Matthew Pickering +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-} + +{- | + Module : Text.Pandoc.Readers.EPUB + Copyright : Copyright (C) 2014-2018 Matthew Pickering + License : GNU GPL, version 2 or above + + Maintainer : John MacFarlane <jgm@berkeley.edu> + Stability : alpha + Portability : portable + +Conversion of EPUB to 'Pandoc' document. +-} module Text.Pandoc.Readers.EPUB (readEPUB) @@ -93,7 +121,7 @@ fetchImages mimes root arc (query iq -> links) = mapM_ (uncurry3 insertMedia) (mapMaybe getEntry links) where getEntry link = - let abslink = normalise (root </> link) in + let abslink = normalise (unEscapeString (root </> link)) in (link , lookup link mimes, ) . fromEntry <$> findEntryByPath abslink arc @@ -264,7 +292,7 @@ findAttrE :: PandocMonad m => QName -> Element -> m String findAttrE q e = mkE "findAttr" $ findAttr q e findEntryByPathE :: PandocMonad m => FilePath -> Archive -> m Entry -findEntryByPathE (normalise -> path) a = +findEntryByPathE (normalise . unEscapeString -> path) a = mkE ("No entry on path: " ++ path) $ findEntryByPath path a parseXMLDocE :: PandocMonad m => String -> m Element diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs index b221b6fb2..32a1ba5a6 100644 --- a/src/Text/Pandoc/Readers/HTML.hs +++ b/src/Text/Pandoc/Readers/HTML.hs @@ -510,14 +510,16 @@ pTable = try $ do [Plain _] -> True _ -> False let isSimple = all isSinglePlain $ concat (head':rows''') - let cols = length $ if null head' then head rows''' else head' + let cols = if null head' + then maximum (map length rows''') + else length head' -- add empty cells to short rows let addEmpties r = case cols - length r of n | n > 0 -> r <> replicate n mempty | otherwise -> r let rows = map addEmpties rows''' let aligns = case rows'' of - (cs:_) -> map fst cs + (cs:_) -> take cols $ map fst cs ++ repeat AlignDefault _ -> replicate cols AlignDefault let widths = if null widths' then if isSimple diff --git a/src/Text/Pandoc/Readers/JATS.hs b/src/Text/Pandoc/Readers/JATS.hs index 29f23137c..59af76d23 100644 --- a/src/Text/Pandoc/Readers/JATS.hs +++ b/src/Text/Pandoc/Readers/JATS.hs @@ -1,5 +1,35 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TupleSections #-} +{- +Copyright (C) 2017-2018 Hamish Mackenzie + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-} + +{- | + Module : Text.Pandoc.Readers.JATS + Copyright : Copyright (C) 2017-2018 Hamish Mackenzie + License : GNU GPL, version 2 or above + + Maintainer : John MacFarlane <jgm@berkeley.edu> + Stability : alpha + Portability : portable + +Conversion of JATS XML to 'Pandoc' document. +-} + module Text.Pandoc.Readers.JATS ( readJATS ) where import Prelude import Control.Monad.State.Strict diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 52782653e..041b552dc 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -48,7 +48,7 @@ import Control.Applicative (many, optional, (<|>)) import Control.Monad import Control.Monad.Except (throwError) import Control.Monad.Trans (lift) -import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord, toLower) +import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord, toLower, toUpper) import Data.Default import Data.List (intercalate, isPrefixOf) import qualified Data.Map as M @@ -164,6 +164,7 @@ data LaTeXState = LaTeXState{ sOptions :: ReaderOptions , sInTableCell :: Bool , sLastHeaderNum :: HeaderNum , sLabels :: M.Map String [Inline] + , sHasChapters :: Bool , sToggles :: M.Map String Bool } deriving Show @@ -183,6 +184,7 @@ defaultLaTeXState = LaTeXState{ sOptions = def , sInTableCell = False , sLastHeaderNum = HeaderNum [] , sLabels = M.empty + , sHasChapters = False , sToggles = M.empty } @@ -240,21 +242,30 @@ withVerbatimMode parser = do return result rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s) - => LP m a -> ParserT String s m (a, String) -rawLaTeXParser parser = do + => LP m a -> LP m a -> ParserT String s m (a, String) +rawLaTeXParser parser valParser = do inp <- getInput let toks = tokenize "source" $ T.pack inp pstate <- getState - let lstate = def{ sOptions = extractReaderOptions pstate - , sMacros = extractMacros pstate } - let rawparser = (,) <$> withRaw parser <*> getState - res <- lift $ runParserT rawparser lstate "chunk" toks - case res of + let lstate = def{ sOptions = extractReaderOptions pstate } + let lstate' = lstate { sMacros = extractMacros pstate } + let rawparser = (,) <$> withRaw valParser <*> getState + res' <- lift $ runParserT (snd <$> withRaw parser) lstate "chunk" toks + case res' of Left _ -> mzero - Right ((val, raw), st) -> do - updateState (updateMacros (sMacros st <>)) - rawstring <- takeP (T.length (untokenize raw)) - return (val, rawstring) + Right toks' -> do + res <- lift $ runParserT (do doMacros 0 + -- retokenize, applying macros + ts <- many (satisfyTok (const True)) + setInput ts + rawparser) + lstate' "chunk" toks' + case res of + Left _ -> mzero + Right ((val, raw), st) -> do + updateState (updateMacros (sMacros st <>)) + _ <- takeP (T.length (untokenize toks')) + return (val, T.unpack (untokenize raw)) applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s) => String -> ParserT String s m String @@ -275,19 +286,18 @@ rawLaTeXBlock = do lookAhead (try (char '\\' >> letter)) -- we don't want to apply newly defined latex macros to their own -- definitions: - snd <$> rawLaTeXParser macroDef - <|> ((snd <$> rawLaTeXParser (environment <|> blockCommand)) >>= applyMacros) + snd <$> rawLaTeXParser (environment <|> macroDef <|> blockCommand) blocks rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s) => ParserT String s m String rawLaTeXInline = do lookAhead (try (char '\\' >> letter)) - rawLaTeXParser (inlineEnvironment <|> inlineCommand') >>= applyMacros . snd + snd <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') inlines inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines inlineCommand = do lookAhead (try (char '\\' >> letter)) - fst <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') + fst <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') inlines tokenize :: SourceName -> Text -> [Tok] tokenize sourcename = totoks (initialPos sourcename) @@ -1313,6 +1323,12 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("slshape", extractSpaces emph <$> inlines) , ("scshape", extractSpaces smallcaps <$> inlines) , ("bfseries", extractSpaces strong <$> inlines) + , ("MakeUppercase", makeUppercase <$> tok) + , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase + , ("uppercase", makeUppercase <$> tok) + , ("MakeLowercase", makeLowercase <$> tok) + , ("MakeTextLowercase", makeLowercase <$> tok) + , ("lowercase", makeLowercase <$> tok) , ("/", pure mempty) -- italic correction , ("aa", lit "å") , ("AA", lit "Å") @@ -1513,6 +1529,16 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("foreignlanguage", foreignlanguage) ] +makeUppercase :: Inlines -> Inlines +makeUppercase = fromList . walk (alterStr (map toUpper)) . toList + +makeLowercase :: Inlines -> Inlines +makeLowercase = fromList . walk (alterStr (map toLower)) . toList + +alterStr :: (String -> String) -> Inline -> Inline +alterStr f (Str xs) = Str (f xs) +alterStr _ x = x + foreignlanguage :: PandocMonad m => LP m Inlines foreignlanguage = do babelLang <- T.unpack . untokenize <$> braced @@ -1685,6 +1711,9 @@ treatAsBlock = Set.fromList , "clearpage" , "pagebreak" , "titleformat" + , "listoffigures" + , "listoftables" + , "write" ] isInlineCommand :: Text -> Bool @@ -1984,9 +2013,13 @@ section starred (ident, classes, kvs) lvl = do try (spaces >> controlSeq "label" >> spaces >> toksToString <$> braced) let classes' = if starred then "unnumbered" : classes else classes + when (lvl == 0) $ + updateState $ \st -> st{ sHasChapters = True } unless starred $ do hn <- sLastHeaderNum <$> getState - let num = incrementHeaderNum lvl hn + hasChapters <- sHasChapters <$> getState + let lvl' = lvl + if hasChapters then 1 else 0 + let num = incrementHeaderNum lvl' hn updateState $ \st -> st{ sLastHeaderNum = num } updateState $ \st -> st{ sLabels = M.insert lab [Str (renderHeaderNum num)] @@ -2143,19 +2176,6 @@ environments = M.fromList codeBlockWith attr <$> verbEnv "lstlisting") , ("minted", minted) , ("obeylines", obeylines) - , ("displaymath", mathEnvWith para Nothing "displaymath") - , ("equation", mathEnvWith para Nothing "equation") - , ("equation*", mathEnvWith para Nothing "equation*") - , ("gather", mathEnvWith para (Just "gathered") "gather") - , ("gather*", mathEnvWith para (Just "gathered") "gather*") - , ("multline", mathEnvWith para (Just "gathered") "multline") - , ("multline*", mathEnvWith para (Just "gathered") "multline*") - , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray") - , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*") - , ("align", mathEnvWith para (Just "aligned") "align") - , ("align*", mathEnvWith para (Just "aligned") "align*") - , ("alignat", mathEnvWith para (Just "aligned") "alignat") - , ("alignat*", mathEnvWith para (Just "aligned") "alignat*") , ("tikzpicture", rawVerbEnv "tikzpicture") -- etoolbox , ("ifstrequal", ifstrequal) @@ -2166,11 +2186,14 @@ environments = M.fromList ] environment :: PandocMonad m => LP m Blocks -environment = do +environment = try $ do controlSeq "begin" name <- untokenize <$> braced - M.findWithDefault mzero name environments - <|> rawEnv name + M.findWithDefault mzero name environments <|> + if M.member name (inlineEnvironments + :: M.Map Text (LP PandocPure Inlines)) + then mzero + else rawEnv name env :: PandocMonad m => Text -> LP m a -> LP m a env name p = p <* end_ name diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 71e6f8249..156b2b622 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -674,6 +674,8 @@ keyValAttr = try $ do char '=' val <- enclosed (char '"') (char '"') litChar <|> enclosed (char '\'') (char '\'') litChar + <|> ("" <$ try (string "\"\"")) + <|> ("" <$ try (string "''")) <|> many (escapedChar' <|> noneOf " \t\n\r}") return $ \(id',cs,kvs) -> case key of @@ -910,6 +912,17 @@ listContinuation continuationIndent = try $ do blanks <- many blankline return $ concat (x:xs) ++ blanks +-- Variant of blanklines that doesn't require blank lines +-- before a fence or eof. +blanklines' :: PandocMonad m => MarkdownParser m [Char] +blanklines' = blanklines <|> try checkDivCloser + where checkDivCloser = do + guardEnabled Ext_fenced_divs + divLevel <- stateFencedDivLevel <$> getState + guard (divLevel >= 1) + lookAhead divFenceEnd + return "" + notFollowedByDivCloser :: PandocMonad m => MarkdownParser m () notFollowedByDivCloser = guardDisabled Ext_fenced_divs <|> @@ -1251,7 +1264,7 @@ alignType strLst len = -- Parse a table footer - dashed lines followed by blank line. tableFooter :: PandocMonad m => MarkdownParser m String -tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines +tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines' -- Parse a table separator - dashed line. tableSep :: PandocMonad m => MarkdownParser m Char @@ -1262,7 +1275,7 @@ rawTableLine :: PandocMonad m => [Int] -> MarkdownParser m [String] rawTableLine indices = do - notFollowedBy' (blanklines <|> tableFooter) + notFollowedBy' (blanklines' <|> tableFooter) line <- many1Till anyChar newline return $ map trim $ tail $ splitStringByIndices (init indices) line @@ -1300,7 +1313,7 @@ simpleTable headless = do (aligns, _widths, heads', lines') <- tableWith (simpleTableHeader headless) tableLine (return ()) - (if headless then tableFooter else tableFooter <|> blanklines) + (if headless then tableFooter else tableFooter <|> blanklines') -- Simple tables get 0s for relative column widths (i.e., use default) return (aligns, replicate (length aligns) 0, heads', lines') @@ -1328,11 +1341,16 @@ multilineTableHeader headless = try $ do newline let (lengths, lines') = unzip dashes let indices = scanl (+) (length initSp) lines' + -- compensate for the fact that intercolumn spaces are + -- not included in the last index: + let indices' = case reverse indices of + [] -> [] + (x:xs) -> reverse (x+1:xs) rawHeadsList <- if headless then fmap (map (:[]) . tail . - splitStringByIndices (init indices)) $ lookAhead anyLine + splitStringByIndices (init indices')) $ lookAhead anyLine else return $ transpose $ map - (tail . splitStringByIndices (init indices)) + (tail . splitStringByIndices (init indices')) rawContent let aligns = zipWith alignType rawHeadsList lengths let rawHeads = if headless @@ -1340,7 +1358,7 @@ multilineTableHeader headless = try $ do else map (unlines . map trim) rawHeadsList heads <- fmap sequence $ mapM ((parseFromString' (mconcat <$> many plain)).trim) rawHeads - return (heads, aligns, indices) + return (heads, aligns, indices') -- Parse a grid table: starts with row of '-' on top, then header -- (which may be grid), then the rows, @@ -2146,7 +2164,6 @@ singleQuoted = try $ do doubleQuoted :: PandocMonad m => MarkdownParser m (F Inlines) doubleQuoted = try $ do doubleQuoteStart - contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline) - withQuoteContext InDoubleQuote (doubleQuoteEnd >> return - (fmap B.doubleQuoted . trimInlinesF $ contents)) - <|> return (return (B.str "\8220") <> contents) + withQuoteContext InDoubleQuote $ + fmap B.doubleQuoted . trimInlinesF . mconcat <$> + many1Till inline doubleQuoteEnd diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 30475d91e..fe6b3698c 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -36,8 +36,7 @@ TODO: - Org tables - table.el tables - Images with attributes (floating and width) -- Citations and <biblio> -- <play> environment +- <cite> tag -} module Text.Pandoc.Readers.Muse (readMuse) where @@ -85,24 +84,21 @@ data MuseState = MuseState { museMeta :: F Meta -- ^ Document metadata , museLastStrPos :: Maybe SourcePos -- ^ Position after last str parsed , museLogMessages :: [LogMessage] , museNotes :: M.Map String (SourcePos, F Blocks) - , museInLink :: Bool - , museInPara :: Bool + , museInLink :: Bool -- ^ True when parsing a link description to avoid nested links + , museInPara :: Bool -- ^ True when looking for a paragraph terminator } instance Default MuseState where - def = defaultMuseState - -defaultMuseState :: MuseState -defaultMuseState = MuseState { museMeta = return nullMeta - , museOptions = def - , museHeaders = M.empty - , museIdentifierList = Set.empty - , museLastStrPos = Nothing - , museLogMessages = [] - , museNotes = M.empty - , museInLink = False - , museInPara = False - } + def = MuseState { museMeta = return nullMeta + , museOptions = def + , museHeaders = M.empty + , museIdentifierList = Set.empty + , museLastStrPos = Nothing + , museLogMessages = [] + , museNotes = M.empty + , museInLink = False + , museInPara = False + } type MuseParser = ParserT String MuseState @@ -125,10 +121,7 @@ instance HasLogMessages MuseState where addLogMessage m s = s{ museLogMessages = m : museLogMessages s } getLogMessages = reverse . museLogMessages --- --- main parser --- - +-- | Parse Muse document parseMuse :: PandocMonad m => MuseParser m Pandoc parseMuse = do many directive @@ -140,14 +133,56 @@ parseMuse = do reportLogMessages return doc --- --- utility functions --- +-- * Utility functions + +commonPrefix :: String -> String -> String +commonPrefix _ [] = [] +commonPrefix [] _ = [] +commonPrefix (x:xs) (y:ys) + | x == y = x : commonPrefix xs ys + | otherwise = [] + +-- | Trim up to one newline from the beginning of the string. +lchop :: String -> String +lchop s = case s of + '\n':ss -> ss + _ -> s + +-- | Trim up to one newline from the end of the string. +rchop :: String -> String +rchop = reverse . lchop . reverse + +dropSpacePrefix :: [String] -> [String] +dropSpacePrefix lns = + map (drop maxIndent) lns + where flns = filter (not . all (== ' ')) lns + maxIndent = if null flns then maximum (map length lns) else length $ takeWhile (== ' ') $ foldl1 commonPrefix flns + +atStart :: PandocMonad m => MuseParser m a -> MuseParser m a +atStart p = do + pos <- getPosition + st <- getState + guard $ museLastStrPos st /= Just pos + p + +-- * Parsers +-- | Parse end-of-line, which can be either a newline or end-of-file. eol :: Stream s m Char => ParserT s st m () eol = void newline <|> eof -htmlElement :: PandocMonad m => String -> MuseParser m (Attr, String) +someUntil :: (Stream s m t) + => ParserT s u m a + -> ParserT s u m b + -> ParserT s u m ([a], b) +someUntil p end = first <$> ((:) <$> p) <*> manyUntil p end + +-- ** HTML parsers + +-- | Parse HTML tag, returning its attributes and literal contents. +htmlElement :: PandocMonad m + => String -- ^ Tag name + -> MuseParser m (Attr, String) htmlElement tag = try $ do (TagOpen _ attr, _) <- htmlTag (~== TagOpen tag []) content <- manyTill anyChar endtag @@ -155,13 +190,16 @@ htmlElement tag = try $ do where endtag = void $ htmlTag (~== TagClose tag) -htmlBlock :: PandocMonad m => String -> MuseParser m (Attr, String) +htmlBlock :: PandocMonad m + => String -- ^ Tag name + -> MuseParser m (Attr, String) htmlBlock tag = try $ do many spaceChar res <- htmlElement tag manyTill spaceChar eol return res +-- | Convert HTML attributes to Pandoc 'Attr' htmlAttrToPandoc :: [Attribute String] -> Attr htmlAttrToPandoc attrs = (ident, classes, keyvals) where @@ -170,7 +208,8 @@ htmlAttrToPandoc attrs = (ident, classes, keyvals) keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"] parseHtmlContent :: PandocMonad m - => String -> MuseParser m (Attr, F Blocks) + => String -- ^ Tag name + -> MuseParser m (Attr, F Blocks) parseHtmlContent tag = try $ do many spaceChar pos <- getPosition @@ -182,29 +221,7 @@ parseHtmlContent tag = try $ do where endtag = void $ htmlTag (~== TagClose tag) -commonPrefix :: String -> String -> String -commonPrefix _ [] = [] -commonPrefix [] _ = [] -commonPrefix (x:xs) (y:ys) - | x == y = x : commonPrefix xs ys - | otherwise = [] - -atStart :: PandocMonad m => MuseParser m a -> MuseParser m a -atStart p = do - pos <- getPosition - st <- getState - guard $ museLastStrPos st /= Just pos - p - -someUntil :: (Stream s m t) - => ParserT s u m a - -> ParserT s u m b - -> ParserT s u m ([a], b) -someUntil p end = first <$> ((:) <$> p) <*> manyUntil p end - --- --- directive parsers --- +-- ** Directive parsers -- While not documented, Emacs Muse allows "-" in directive name parseDirectiveKey :: PandocMonad m => MuseParser m String @@ -235,9 +252,7 @@ directive = do where translateKey "cover" = "cover-image" translateKey x = x --- --- block parsers --- +-- ** Block parsers parseBlocks :: PandocMonad m => MuseParser m (F Blocks) @@ -248,8 +263,8 @@ parseBlocks = paraStart) where parseEnd = mempty <$ eof - blockStart = (B.<>) <$> (header <|> blockElements <|> emacsNoteBlock) - <*> parseBlocks + blockStart = ((B.<>) <$> (emacsHeading <|> blockElements <|> emacsNoteBlock) + <*> parseBlocks) <|> (uncurry (B.<>) <$> amuseHeadingUntil parseBlocks) listStart = do updateState (\st -> st { museInPara = False }) uncurry (B.<>) <$> (anyListUntil parseBlocks <|> amuseNoteBlockUntil parseBlocks) @@ -322,19 +337,24 @@ blockElements = do , rightTag , quoteTag , divTag + , biblioTag + , playTag , verseTag , lineBlock , table , commentTag ] +-- | Parse a line comment, starting with @;@ in the first column. comment :: PandocMonad m => MuseParser m (F Blocks) comment = try $ do + getPosition >>= \pos -> guard (sourceColumn pos == 1) char ';' optional (spaceChar >> many (noneOf "\n")) eol return mempty +-- | Parse a horizontal rule, consisting of 4 or more @\'-\'@ characters. separator :: PandocMonad m => MuseParser m (F Blocks) separator = try $ do string "----" @@ -343,8 +363,10 @@ separator = try $ do eol return $ return B.horizontalRule -header :: PandocMonad m => MuseParser m (F Blocks) -header = try $ do +-- | Parse a single-line heading. +emacsHeading :: PandocMonad m => MuseParser m (F Blocks) +emacsHeading = try $ do + guardDisabled Ext_amuse anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol) getPosition >>= \pos -> guard (sourceColumn pos == 1) level <- fmap length $ many1 $ char '*' @@ -354,6 +376,24 @@ header = try $ do attr <- registerHeader (anchorId, [], []) (runF content def) return $ B.headerWith attr level <$> content +-- | Parse a multi-line heading. +-- It is a Text::Amuse extension, Emacs Muse does not allow heading to span multiple lines. +amuseHeadingUntil :: PandocMonad m + => MuseParser m a -- ^ Terminator parser + -> MuseParser m (F Blocks, a) +amuseHeadingUntil end = try $ do + guardEnabled Ext_amuse + anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol) + getPosition >>= \pos -> guard (sourceColumn pos == 1) + level <- fmap length $ many1 $ char '*' + guard $ level <= 5 + spaceChar + (content, e) <- paraContentsUntil end + attr <- registerHeader (anchorId, [], []) (runF content def) + return (B.headerWith attr level <$> content, e) + +-- | Parse an example between @{{{@ and @}}}@. +-- It is an Amusewiki extension influenced by Creole wiki, as described in @Text::Amuse@ documentation. example :: PandocMonad m => MuseParser m (F Blocks) example = try $ do string "{{{" @@ -361,27 +401,14 @@ example = try $ do contents <- manyTill anyChar $ try (optional blankline >> string "}}}") return $ return $ B.codeBlock contents --- Trim up to one newline from the beginning of the string. -lchop :: String -> String -lchop s = case s of - '\n':ss -> ss - _ -> s - --- Trim up to one newline from the end of the string. -rchop :: String -> String -rchop = reverse . lchop . reverse - -dropSpacePrefix :: [String] -> [String] -dropSpacePrefix lns = - map (drop maxIndent) lns - where flns = filter (not . all (== ' ')) lns - maxIndent = if null flns then maximum (map length lns) else length $ takeWhile (== ' ') $ foldl1 commonPrefix flns - +-- | Parse an @\<example>@ tag. exampleTag :: PandocMonad m => MuseParser m (F Blocks) exampleTag = try $ do (attr, contents) <- htmlBlock "example" return $ return $ B.codeBlockWith attr $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop contents +-- | Parse a @\<literal>@ tag as a raw block. +-- For 'RawInline' @\<literal>@ parser, see 'inlineLiteralTag'. literalTag :: PandocMonad m => MuseParser m (F Blocks) literalTag = try $ do many spaceChar @@ -396,23 +423,41 @@ literalTag = try $ do format (_, _, kvs) = fromMaybe "html" $ lookup "style" kvs rawBlock (attrs, content) = B.rawBlock (format attrs) $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content --- <center> tag is ignored +-- | Parse @\<center>@ tag. +-- Currently it is ignored as Pandoc cannot represent centered blocks. centerTag :: PandocMonad m => MuseParser m (F Blocks) centerTag = snd <$> parseHtmlContent "center" --- <right> tag is ignored +-- | Parse @\<right>@ tag. +-- Currently it is ignored as Pandoc cannot represent centered blocks. rightTag :: PandocMonad m => MuseParser m (F Blocks) rightTag = snd <$> parseHtmlContent "right" +-- | Parse @\<quote>@ tag. quoteTag :: PandocMonad m => MuseParser m (F Blocks) quoteTag = fmap B.blockQuote . snd <$> parseHtmlContent "quote" --- <div> tag is supported by Emacs Muse, but not Amusewiki 2.025 +-- | Parse @\<div>@ tag. +-- @\<div>@ tag is supported by Emacs Muse, but not Amusewiki 2.025. divTag :: PandocMonad m => MuseParser m (F Blocks) divTag = do (attrs, content) <- parseHtmlContent "div" return $ B.divWith attrs <$> content +-- | Parse @\<biblio>@ tag, the result is the same as @\<div class="biblio">@. +-- @\<biblio>@ tag is supported only in Text::Amuse mode. +biblioTag :: PandocMonad m => MuseParser m (F Blocks) +biblioTag = do + guardEnabled Ext_amuse + fmap (B.divWith ("", ["biblio"], [])) . snd <$> parseHtmlContent "biblio" + +-- | Parse @\<play>@ tag, the result is the same as @\<div class="play">@. +-- @\<play>@ tag is supported only in Text::Amuse mode. +playTag :: PandocMonad m => MuseParser m (F Blocks) +playTag = do + guardEnabled Ext_amuse + fmap (B.divWith ("", ["play"], [])) . snd <$> parseHtmlContent "play" + verseLine :: PandocMonad m => MuseParser m (F Inlines) verseLine = do indent <- (B.str <$> many1 (char ' ' >> pure '\160')) <|> pure mempty @@ -424,25 +469,34 @@ verseLines = do lns <- many verseLine return $ B.lineBlock <$> sequence lns +-- | Parse @\<verse>@ tag. verseTag :: PandocMonad m => MuseParser m (F Blocks) verseTag = do (_, content) <- htmlBlock "verse" parseFromString verseLines (intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content) +-- | Parse @\<comment>@ tag. commentTag :: PandocMonad m => MuseParser m (F Blocks) commentTag = htmlBlock "comment" >> return mempty --- Indented paragraph is either center, right or quote +-- | Parse paragraph contents. +paraContentsUntil :: PandocMonad m + => MuseParser m a -- ^ Terminator parser + -> MuseParser m (F Inlines, a) +paraContentsUntil end = do + updateState (\st -> st { museInPara = True }) + (l, e) <- someUntil inline $ try (manyTill spaceChar eol >> end) + updateState (\st -> st { museInPara = False }) + return (trimInlinesF $ mconcat l, e) + +-- | Parse a paragraph. paraUntil :: PandocMonad m - => MuseParser m a + => MuseParser m a -- ^ Terminator parser -> MuseParser m (F Blocks, a) paraUntil end = do state <- getState guard $ not $ museInPara state - setState $ state{ museInPara = True } - (l, e) <- someUntil inline $ try (manyTill spaceChar eol >> end) - updateState (\st -> st { museInPara = False }) - return (fmap B.para $ trimInlinesF $ mconcat l, e) + first (fmap B.para) <$> paraContentsUntil end noteMarker :: PandocMonad m => MuseParser m String noteMarker = try $ do @@ -461,9 +515,8 @@ amuseNoteBlockUntil end = try $ do updateState (\st -> st { museInPara = False }) (content, e) <- listItemContentsUntil (sourceColumn pos - 1) (fail "x") end oldnotes <- museNotes <$> getState - case M.lookup ref oldnotes of - Just _ -> logMessage $ DuplicateNoteReference ref pos - Nothing -> return () + when (M.member ref oldnotes) + (logMessage $ DuplicateNoteReference ref pos) updateState $ \s -> s{ museNotes = M.insert ref (pos, content) oldnotes } return (mempty, e) @@ -476,9 +529,8 @@ emacsNoteBlock = try $ do ref <- noteMarker <* skipSpaces content <- mconcat <$> blocksTillNote oldnotes <- museNotes <$> getState - case M.lookup ref oldnotes of - Just _ -> logMessage $ DuplicateNoteReference ref pos - Nothing -> return () + when (M.member ref oldnotes) + (logMessage $ DuplicateNoteReference ref pos) updateState $ \s -> s{ museNotes = M.insert ref (pos, content) oldnotes } return mempty where @@ -503,29 +555,28 @@ blanklineVerseLine = try $ do blankline pure mempty +-- | Parse a line block indicated by @\'>\'@ characters. lineBlock :: PandocMonad m => MuseParser m (F Blocks) lineBlock = try $ do + many spaceChar col <- sourceColumn <$> getPosition lns <- (blanklineVerseLine <|> lineVerseLine) `sepBy1'` try (indentWith (col - 1)) return $ B.lineBlock <$> sequence lns --- --- lists --- +-- *** List parsers bulletListItemsUntil :: PandocMonad m - => Int - -> MuseParser m a + => Int -- ^ Indentation + -> MuseParser m a -- ^ Terminator parser -> MuseParser m ([F Blocks], a) bulletListItemsUntil indent end = try $ do char '-' void spaceChar <|> lookAhead eol updateState (\st -> st { museInPara = False }) - (x, e) <- listItemContentsUntil (indent + 2) (Right <$> try (optional blankline >> indentWith indent >> bulletListItemsUntil indent end)) (Left <$> end) - case e of - Left ee -> return ([x], ee) - Right (xs, ee) -> return (x:xs, ee) + (x, (xs, e)) <- listItemContentsUntil (indent + 2) (try (optional blankline >> indentWith indent >> bulletListItemsUntil indent end)) (([],) <$> end) + return (x:xs, e) +-- | Parse a bullet list. bulletListUntil :: PandocMonad m => MuseParser m a -> MuseParser m (F Blocks, a) @@ -569,11 +620,10 @@ orderedListItemsUntil indent style end = pos <- getPosition void spaceChar <|> lookAhead eol updateState (\st -> st { museInPara = False }) - (x, e) <- listItemContentsUntil (sourceColumn pos) (Right <$> try (optional blankline >> indentWith indent >> museOrderedListMarker style >> continuation)) (Left <$> end) - case e of - Left ee -> return ([x], ee) - Right (xs, ee) -> return (x:xs, ee) + (x, (xs, e)) <- listItemContentsUntil (sourceColumn pos) (try (optional blankline >> indentWith indent >> museOrderedListMarker style >> continuation)) (([],) <$> end) + return (x:xs, e) +-- | Parse an ordered list. orderedListUntil :: PandocMonad m => MuseParser m a -> MuseParser m (F Blocks, a) @@ -594,10 +644,8 @@ descriptionsUntil :: PandocMonad m descriptionsUntil indent end = do void spaceChar <|> lookAhead eol updateState (\st -> st { museInPara = False }) - (x, e) <- listItemContentsUntil indent (Right <$> try (optional blankline >> indentWith indent >> manyTill spaceChar (string "::") >> descriptionsUntil indent end)) (Left <$> end) - case e of - Right (xs, ee) -> return (x:xs, ee) - Left ee -> return ([x], ee) + (x, (xs, e)) <- listItemContentsUntil indent (try (optional blankline >> indentWith indent >> manyTill spaceChar (string "::") >> descriptionsUntil indent end)) (([],) <$> end) + return (x:xs, e) definitionListItemsUntil :: PandocMonad m => Int @@ -609,17 +657,13 @@ definitionListItemsUntil indent end = continuation = try $ do pos <- getPosition term <- trimInlinesF . mconcat <$> manyTill (choice inlineList) (try $ string "::") - (x, e) <- descriptionsUntil (sourceColumn pos) ((Right <$> try (optional blankline >> indentWith indent >> continuation)) <|> (Left <$> end)) - let xx = do - term' <- term - x' <- sequence x - return (term', x') - case e of - Left ee -> return ([xx], ee) - Right (xs, ee) -> return (xx:xs, ee) + (x, (xs, e)) <- descriptionsUntil (sourceColumn pos) (try (optional blankline >> indentWith indent >> continuation) <|> (([],) <$> end)) + let xx = (,) <$> term <*> sequence x + return (xx:xs, e) +-- | Parse a definition list. definitionListUntil :: PandocMonad m - => MuseParser m a + => MuseParser m a -- ^ Terminator parser -> MuseParser m (F Blocks, a) definitionListUntil end = try $ do many spaceChar @@ -629,15 +673,14 @@ definitionListUntil end = try $ do first (fmap B.definitionList . sequence) <$> definitionListItemsUntil indent end anyListUntil :: PandocMonad m - => MuseParser m a + => MuseParser m a -- ^ Terminator parser -> MuseParser m (F Blocks, a) anyListUntil end = bulletListUntil end <|> orderedListUntil end <|> definitionListUntil end --- --- tables --- +-- *** Table parsers +-- | Internal Muse table representation. data MuseTable = MuseTable { museTableCaption :: Inlines , museTableHeaders :: [[Blocks]] @@ -645,10 +688,10 @@ data MuseTable = MuseTable , museTableFooters :: [[Blocks]] } -data MuseTableElement = MuseHeaderRow (F [Blocks]) - | MuseBodyRow (F [Blocks]) - | MuseFooterRow (F [Blocks]) - | MuseCaption (F Inlines) +data MuseTableElement = MuseHeaderRow [Blocks] + | MuseBodyRow [Blocks] + | MuseFooterRow [Blocks] + | MuseCaption Inlines museToPandocTable :: MuseTable -> Blocks museToPandocTable (MuseTable caption headers body footers) = @@ -658,69 +701,66 @@ museToPandocTable (MuseTable caption headers body footers) = headRow = if null headers then [] else head headers rows = (if null headers then [] else tail headers) ++ body ++ footers -museAppendElement :: MuseTable - -> MuseTableElement - -> F MuseTable -museAppendElement tbl element = +museAppendElement :: MuseTableElement + -> MuseTable + -> MuseTable +museAppendElement element tbl = case element of - MuseHeaderRow row -> do - row' <- row - return tbl{ museTableHeaders = museTableHeaders tbl ++ [row'] } - MuseBodyRow row -> do - row' <- row - return tbl{ museTableRows = museTableRows tbl ++ [row'] } - MuseFooterRow row-> do - row' <- row - return tbl{ museTableFooters = museTableFooters tbl ++ [row'] } - MuseCaption inlines -> do - inlines' <- inlines - return tbl{ museTableCaption = inlines' } + MuseHeaderRow row -> tbl{ museTableHeaders = row : museTableHeaders tbl } + MuseBodyRow row -> tbl{ museTableRows = row : museTableRows tbl } + MuseFooterRow row -> tbl{ museTableFooters = row : museTableFooters tbl } + MuseCaption inlines -> tbl{ museTableCaption = inlines } tableCell :: PandocMonad m => MuseParser m (F Blocks) tableCell = try $ fmap B.plain . trimInlinesF . mconcat <$> manyTill inline (lookAhead cellEnd) where cellEnd = try $ void (many1 spaceChar >> char '|') <|> eol -tableElements :: PandocMonad m => MuseParser m [MuseTableElement] -tableElements = tableParseElement `sepEndBy1` eol +tableElements :: PandocMonad m => MuseParser m (F [MuseTableElement]) +tableElements = sequence <$> (tableParseElement `sepEndBy1` eol) -elementsToTable :: [MuseTableElement] -> F MuseTable -elementsToTable = foldM museAppendElement emptyTable +elementsToTable :: [MuseTableElement] -> MuseTable +elementsToTable = foldr museAppendElement emptyTable where emptyTable = MuseTable mempty mempty mempty mempty +-- | Parse a table. table :: PandocMonad m => MuseParser m (F Blocks) -table = try $ fmap museToPandocTable <$> (elementsToTable <$> tableElements) +table = try $ fmap (museToPandocTable . elementsToTable) <$> tableElements -tableParseElement :: PandocMonad m => MuseParser m MuseTableElement +tableParseElement :: PandocMonad m => MuseParser m (F MuseTableElement) tableParseElement = tableParseHeader <|> tableParseBody <|> tableParseFooter <|> tableParseCaption -tableParseRow :: PandocMonad m => Int -> MuseParser m (F [Blocks]) +tableParseRow :: PandocMonad m + => Int -- ^ Number of separator characters + -> MuseParser m (F [Blocks]) tableParseRow n = try $ do fields <- tableCell `sepBy2` fieldSep return $ sequence fields where p `sepBy2` sep = (:) <$> p <*> many1 (sep >> p) fieldSep = many1 spaceChar >> count n (char '|') >> (void (many1 spaceChar) <|> void (lookAhead newline)) -tableParseHeader :: PandocMonad m => MuseParser m MuseTableElement -tableParseHeader = MuseHeaderRow <$> tableParseRow 2 +-- | Parse a table header row. +tableParseHeader :: PandocMonad m => MuseParser m (F MuseTableElement) +tableParseHeader = fmap MuseHeaderRow <$> tableParseRow 2 -tableParseBody :: PandocMonad m => MuseParser m MuseTableElement -tableParseBody = MuseBodyRow <$> tableParseRow 1 +-- | Parse a table body row. +tableParseBody :: PandocMonad m => MuseParser m (F MuseTableElement) +tableParseBody = fmap MuseBodyRow <$> tableParseRow 1 -tableParseFooter :: PandocMonad m => MuseParser m MuseTableElement -tableParseFooter = MuseFooterRow <$> tableParseRow 3 +-- | Parse a table footer row. +tableParseFooter :: PandocMonad m => MuseParser m (F MuseTableElement) +tableParseFooter = fmap MuseFooterRow <$> tableParseRow 3 -tableParseCaption :: PandocMonad m => MuseParser m MuseTableElement +-- | Parse table caption. +tableParseCaption :: PandocMonad m => MuseParser m (F MuseTableElement) tableParseCaption = try $ do many spaceChar string "|+" - MuseCaption <$> (trimInlinesF . mconcat <$> many1Till inline (string "+|")) + fmap MuseCaption <$> (trimInlinesF . mconcat <$> many1Till inline (string "+|")) --- --- inline parsers --- +-- ** Inline parsers inlineList :: PandocMonad m => [MuseParser m (F Inlines)] inlineList = [ whitespace @@ -750,17 +790,18 @@ inlineList = [ whitespace inline :: PandocMonad m => MuseParser m (F Inlines) inline = endline <|> choice inlineList <?> "inline" +-- | Parse a soft break. endline :: PandocMonad m => MuseParser m (F Inlines) endline = try $ do newline notFollowedBy blankline - returnF B.softbreak + return $ return B.softbreak parseAnchor :: PandocMonad m => MuseParser m String parseAnchor = try $ do getPosition >>= \pos -> guard (sourceColumn pos == 1) char '#' - (:) <$> letter <*> many (letter <|> digit) + (:) <$> letter <*> many (letter <|> digit <|> char '-') anchor :: PandocMonad m => MuseParser m (F Inlines) anchor = try $ do @@ -768,8 +809,11 @@ anchor = try $ do skipMany spaceChar <|> void newline return $ return $ B.spanWith (anchorId, [], []) mempty +-- | Parse a footnote reference. footnote :: PandocMonad m => MuseParser m (F Inlines) footnote = try $ do + inLink <- museInLink <$> getState + guard $ not inLink ref <- noteMarker return $ do notes <- asksF museNotes @@ -777,7 +821,7 @@ footnote = try $ do Nothing -> return $ B.str $ "[" ++ ref ++ "]" Just (_pos, contents) -> do st <- askF - let contents' = runF contents st { museNotes = M.empty } + let contents' = runF contents st { museNotes = M.delete ref (museNotes st) } return $ B.note contents' whitespace :: PandocMonad m => MuseParser m (F Inlines) @@ -785,6 +829,7 @@ whitespace = try $ do skipMany1 spaceChar return $ return B.space +-- | Parse @\<br>@ tag. br :: PandocMonad m => MuseParser m (F Inlines) br = try $ do string "<br>" @@ -800,42 +845,54 @@ enclosedInlines :: (PandocMonad m, Show a, Show b) enclosedInlines start end = try $ trimInlinesF . mconcat <$> (enclosed (atStart start) end inline <* notFollowedBy (satisfy isLetter)) +-- | Parse an inline tag, such as @\<em>@ and @\<strong>@. inlineTag :: PandocMonad m - => String + => String -- ^ Tag name -> MuseParser m (F Inlines) inlineTag tag = try $ do htmlTag (~== TagOpen tag []) mconcat <$> manyTill inline (void $ htmlTag (~== TagClose tag)) -strongTag :: PandocMonad m => MuseParser m (F Inlines) -strongTag = fmap B.strong <$> inlineTag "strong" - +-- | Parse strong inline markup, indicated by @**@. strong :: PandocMonad m => MuseParser m (F Inlines) strong = fmap B.strong <$> emphasisBetween (string "**") +-- | Parse emphasis inline markup, indicated by @*@. emph :: PandocMonad m => MuseParser m (F Inlines) emph = fmap B.emph <$> emphasisBetween (char '*') +-- | Parse underline inline markup, indicated by @_@. +-- Supported only in Emacs Muse mode, not Text::Amuse. underlined :: PandocMonad m => MuseParser m (F Inlines) underlined = do guardDisabled Ext_amuse -- Supported only by Emacs Muse fmap underlineSpan <$> emphasisBetween (char '_') +-- | Parse @\<strong>@ tag. +strongTag :: PandocMonad m => MuseParser m (F Inlines) +strongTag = fmap B.strong <$> inlineTag "strong" + +-- | Parse @\<em>@ tag. emphTag :: PandocMonad m => MuseParser m (F Inlines) emphTag = fmap B.emph <$> inlineTag "em" +-- | Parse @\<sup>@ tag. superscriptTag :: PandocMonad m => MuseParser m (F Inlines) superscriptTag = fmap B.superscript <$> inlineTag "sup" +-- | Parse @\<sub>@ tag. subscriptTag :: PandocMonad m => MuseParser m (F Inlines) subscriptTag = fmap B.subscript <$> inlineTag "sub" +-- | Parse @\<del>@ tag. strikeoutTag :: PandocMonad m => MuseParser m (F Inlines) strikeoutTag = fmap B.strikeout <$> inlineTag "del" +-- | Parse @\<verbatim>@ tag. verbatimTag :: PandocMonad m => MuseParser m (F Inlines) verbatimTag = return . B.text . snd <$> htmlElement "verbatim" +-- | Parse @\<class>@ tag. classTag :: PandocMonad m => MuseParser m (F Inlines) classTag = do (TagOpen _ attrs, _) <- htmlTag (~== TagOpen "class" []) @@ -843,11 +900,13 @@ classTag = do let classes = maybe [] words $ lookup "name" attrs return $ B.spanWith ("", classes, []) <$> mconcat res +-- | Parse "~~" as nonbreaking space. nbsp :: PandocMonad m => MuseParser m (F Inlines) nbsp = try $ do string "~~" return $ return $ B.str "\160" +-- | Parse code markup, indicated by @\'=\'@ characters. code :: PandocMonad m => MuseParser m (F Inlines) code = try $ do atStart $ char '=' @@ -858,13 +917,16 @@ code = try $ do notFollowedBy $ satisfy isLetter return $ return $ B.code contents +-- | Parse @\<code>@ tag. codeTag :: PandocMonad m => MuseParser m (F Inlines) codeTag = return . uncurry B.codeWith <$> htmlElement "code" --- <math> tag is an Emacs Muse extension enabled by (require 'muse-latex2png) +-- | Parse @\<math>@ tag. +-- @\<math>@ tag is an Emacs Muse extension enabled by @(require 'muse-latex2png)@ mathTag :: PandocMonad m => MuseParser m (F Inlines) mathTag = return . B.math . snd <$> htmlElement "math" +-- | Parse inline @\<literal>@ tag as a raw inline. inlineLiteralTag :: PandocMonad m => MuseParser m (F Inlines) inlineLiteralTag = (return . rawInline) <$> htmlElement "literal" @@ -879,18 +941,19 @@ str = return . B.str <$> many1 alphaNum <* updateLastStrPos symbol :: PandocMonad m => MuseParser m (F Inlines) symbol = return . B.str <$> count 1 nonspaceChar +-- | Parse a link or image. link :: PandocMonad m => MuseParser m (F Inlines) link = try $ do st <- getState guard $ not $ museInLink st setState $ st{ museInLink = True } - (url, title, content) <- linkText + (url, content) <- linkText updateState (\state -> state { museInLink = False }) return $ case stripPrefix "URL:" url of Nothing -> if isImageUrl url - then B.image url title <$> fromMaybe (return mempty) content - else B.link url title <$> fromMaybe (return $ B.str url) content - Just url' -> B.link url' title <$> fromMaybe (return $ B.str url') content + then B.image url "" <$> fromMaybe (return mempty) content + else B.link url "" <$> fromMaybe (return $ B.str url) content + Just url' -> B.link url' "" <$> fromMaybe (return $ B.str url') content where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] isImageUrl = (`elem` imageExtensions) . takeExtension @@ -898,10 +961,10 @@ link = try $ do linkContent :: PandocMonad m => MuseParser m (F Inlines) linkContent = char '[' >> trimInlinesF . mconcat <$> manyTill inline (string "]") -linkText :: PandocMonad m => MuseParser m (String, String, Maybe (F Inlines)) +linkText :: PandocMonad m => MuseParser m (String, Maybe (F Inlines)) linkText = do string "[[" - url <- many1Till anyChar $ char ']' + url <- manyTill anyChar $ char ']' content <- optionMaybe linkContent char ']' - return (url, "", content) + return (url, content) diff --git a/src/Text/Pandoc/Readers/OPML.hs b/src/Text/Pandoc/Readers/OPML.hs index 3f4586295..1a489ab94 100644 --- a/src/Text/Pandoc/Readers/OPML.hs +++ b/src/Text/Pandoc/Readers/OPML.hs @@ -1,4 +1,34 @@ {-# LANGUAGE NoImplicitPrelude #-} +{- +Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-} + +{- | + Module : Text.Pandoc.Readers.OPML + Copyright : Copyright (C) 2013-2018 John MacFarlane + License : GNU GPL, version 2 or above + + Maintainer : John MacFarlane <jgm@berkeley.edu> + Stability : alpha + Portability : portable + +Conversion of OPML to 'Pandoc' document. +-} + module Text.Pandoc.Readers.OPML ( readOPML ) where import Prelude import Control.Monad.State.Strict diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 566f9b959..71a38cf82 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -651,11 +651,15 @@ directive' = do skipMany spaceChar top <- many $ satisfy (/='\n') <|> try (char '\n' <* - notFollowedBy' (rawFieldListItem 3) <* - count 3 (char ' ') <* + notFollowedBy' (rawFieldListItem 1) <* + many1 (char ' ') <* notFollowedBy blankline) newline - fields <- many $ rawFieldListItem 3 + fields <- do + fieldIndent <- length <$> lookAhead (many (char ' ')) + if fieldIndent == 0 + then return [] + else many $ rawFieldListItem fieldIndent body <- option "" $ try $ blanklines >> indentedBlock optional blanklines let body' = body ++ "\n\n" @@ -1086,10 +1090,15 @@ targetURI :: Monad m => ParserT [Char] st m [Char] targetURI = do skipSpaces optional newline - contents <- many1 (try (many spaceChar >> newline >> - many1 spaceChar >> noneOf " \t\n") <|> noneOf "\n") + contents <- trim <$> + many1 (satisfy (/='\n') + <|> try (newline >> many1 spaceChar >> noneOf " \t\n")) blanklines - return $ escapeURI $ trim contents + case reverse contents of + -- strip backticks + '_':'`':xs -> return (dropWhile (=='`') (reverse xs) ++ "_") + '_':_ -> return contents + _ -> return (escapeURI contents) substKey :: PandocMonad m => RSTParser m () substKey = try $ do diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 7fcb50b05..a46011a8f 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -118,6 +118,9 @@ description meta' = do bt <- booktitle meta' let as = authors meta' dd <- docdate meta' + annotation <- case lookupMeta "abstract" meta' of + Just (MetaBlocks bs) -> (list . el "annotation") <$> cMapM blockToXml bs + _ -> pure mempty let lang = case lookupMeta "lang" meta' of Just (MetaInlines [Str s]) -> [el "lang" $ iso639 s] Just (MetaString s) -> [el "lang" $ iso639 s] @@ -132,7 +135,7 @@ description meta' = do Just (MetaString s) -> coverimage s _ -> return [] return $ el "description" - [ el "title-info" (genre : (bt ++ as ++ dd ++ lang)) + [ el "title-info" (genre : (bt ++ annotation ++ as ++ dd ++ lang)) , el "document-info" (el "program-used" "pandoc" : coverpage) ] @@ -311,9 +314,6 @@ isMimeType s = footnoteID :: Int -> String footnoteID i = "n" ++ show i -linkID :: Int -> String -linkID i = "l" ++ show i - -- | Convert a block-level Pandoc's element to FictionBook XML representation. blockToXml :: PandocMonad m => Block -> FBM m [Content] blockToXml (Plain ss) = cMapM toXml ss -- FIXME: can lead to malformed FB2 @@ -452,23 +452,9 @@ toXml (Math _ formula) = insertMath InlineImage formula toXml il@(RawInline _ _) = do report $ InlineNotRendered il return [] -- raw TeX and raw HTML are suppressed -toXml (Link _ text (url,ttl)) = do - fns <- footnotes `liftM` get - let n = 1 + length fns - let ln_id = linkID n - let ln_ref = list . el "sup" . txt $ "[" ++ show n ++ "]" +toXml (Link _ text (url,_)) = do ln_text <- cMapM toXml text - let ln_desc = - let ttl' = dropWhile isSpace ttl - in if null ttl' - then list . el "p" $ el "code" url - else list . el "p" $ [ txt (ttl' ++ ": "), el "code" url ] - modify (\s -> s { footnotes = (n, ln_id, ln_desc) : fns }) - return $ ln_text ++ - [ el "a" - ( [ attr ("l","href") ('#':ln_id) - , uattr "type" "note" ] - , ln_ref) ] + return [ el "a" ( [ attr ("l","href") url ], ln_text) ] toXml img@Image{} = insertImage InlineImage img toXml (Note bs) = do fns <- footnotes `liftM` get diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index d1a366445..762bbd0e5 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -260,10 +260,6 @@ pandocToHtml opts (Pandoc meta blocks) = do notes <- footnoteSection opts (reverse (stNotes st)) let thebody = blocks' >> notes let math = case writerHTMLMathMethod opts of - LaTeXMathML (Just url) -> - H.script ! A.src (toValue url) - ! A.type_ "text/javascript" - $ mempty MathJax url | slideVariant /= RevealJsSlides -> -- mathjax is handled via a special plugin in revealjs @@ -274,10 +270,6 @@ pandocToHtml opts (Pandoc meta blocks) = do preEscapedString "MathJax.Hub.Queue([\"Typeset\",MathJax.Hub]);" _ -> mempty - JsMath (Just url) -> - H.script ! A.src (toValue url) - ! A.type_ "text/javascript" - $ mempty KaTeX url -> do H.script ! A.src (toValue $ url ++ "katex.min.js") $ mempty @@ -1024,19 +1016,6 @@ inlineToHtml opts inline = do let mathClass = toValue $ ("math " :: String) ++ if t == InlineMath then "inline" else "display" case writerHTMLMathMethod opts of - LaTeXMathML _ -> - -- putting LaTeXMathML in container with class "LaTeX" prevents - -- non-math elements on the page from being treated as math by - -- the javascript - return $ H.span ! A.class_ "LaTeX" $ - case t of - InlineMath -> toHtml ("$" ++ str ++ "$") - DisplayMath -> toHtml ("$$" ++ str ++ "$$") - JsMath _ -> do - let m = preEscapedString str - return $ case t of - InlineMath -> H.span ! A.class_ mathClass $ m - DisplayMath -> H.div ! A.class_ mathClass $ m WebTeX url -> do let imtag = if html5 then H5.img else H.img let m = imtag ! A.style "vertical-align:middle" @@ -1047,10 +1026,6 @@ inlineToHtml opts inline = do return $ case t of InlineMath -> m DisplayMath -> brtag >> m >> brtag - GladTeX -> - return $ case t of - InlineMath -> preEscapedString $ "<EQ ENV=\"math\">" ++ str ++ "</EQ>" - DisplayMath -> preEscapedString $ "<EQ ENV=\"displaymath\">" ++ str ++ "</EQ>" MathML -> do let conf = useShortEmptyTags (const False) defaultConfigPP diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index f354bc0a2..d9868b7cd 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -678,6 +678,7 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do let enum = text $ "enum" ++ map toLower (toRomanNumeral oldlevel) let stylecommand | numstyle == DefaultStyle && numdelim == DefaultDelim = empty + | beamer && numstyle == Decimal && numdelim == Period = empty | beamer = brackets (todelim exemplar) | otherwise = "\\def" <> "\\label" <> enum <> braces (todelim $ tostyle enum) diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 3bfa8a012..075858e5e 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -732,7 +732,10 @@ pandocTable opts multiline headless aligns widths rawHeaders rawRows = do then empty else border <> cr <> head' let body = if multiline - then vsep rows' + then vsep rows' $$ + if length rows' < 2 + then blankline -- #4578 + else empty else vcat rows' let bottom = if headless then underline diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs index 600b71c40..16a66c85b 100644 --- a/src/Text/Pandoc/Writers/Ms.hs +++ b/src/Text/Pandoc/Writers/Ms.hs @@ -40,7 +40,7 @@ module Text.Pandoc.Writers.Ms ( writeMs ) where import Prelude import Control.Monad.State.Strict import Data.Char (isLower, isUpper, toUpper, ord) -import Data.List (intercalate, intersperse, sort) +import Data.List (intercalate, intersperse) import qualified Data.Map as Map import Data.Maybe (catMaybes, fromMaybe) import Data.Text (Text) @@ -68,6 +68,7 @@ data WriterState = WriterState { stHasInlineMath :: Bool , stNotes :: [Note] , stSmallCaps :: Bool , stHighlighting :: Bool + , stInHeader :: Bool , stFontFeatures :: Map.Map Char Bool } @@ -77,6 +78,7 @@ defaultWriterState = WriterState{ stHasInlineMath = False , stNotes = [] , stSmallCaps = False , stHighlighting = False + , stInHeader = False , stFontFeatures = Map.fromList [ ('I',False) , ('B',False) @@ -135,7 +137,6 @@ msEscapes = Map.fromList [ ('\160', "\\~") , ('\'', "\\[aq]") , ('`', "\\`") - , ('\8217', "'") , ('"', "\\[dq]") , ('\x2014', "\\[em]") , ('\x2013', "\\[en]") @@ -218,11 +219,16 @@ blockToMs :: PandocMonad m -> Block -- ^ Block element -> MS m Doc blockToMs _ Null = return empty -blockToMs opts (Div _ bs) = do +blockToMs opts (Div (ident,_,_) bs) = do + let anchor = if null ident + then empty + else nowrap $ + text ".pdfhref M " + <> doubleQuotes (text (toAscii ident)) setFirstPara res <- blockListToMs opts bs setFirstPara - return res + return $ anchor $$ res blockToMs opts (Plain inlines) = liftM vcat $ mapM (inlineListToMs' opts) $ splitSentences inlines blockToMs opts (Para [Image attr alt (src,_tit)]) @@ -260,7 +266,9 @@ blockToMs _ HorizontalRule = do return $ text ".HLINE" blockToMs opts (Header level (ident,classes,_) inlines) = do setFirstPara + modify $ \st -> st{ stInHeader = True } contents <- inlineListToMs' opts $ map breakToSpace inlines + modify $ \st -> st{ stInHeader = False } let (heading, secnum) = if writerNumberSections opts && "unnumbered" `notElem` classes then (".NH", "\\*[SN]") @@ -555,8 +563,15 @@ handleNote opts bs = do fontChange :: PandocMonad m => MS m Doc fontChange = do features <- gets stFontFeatures - let filling = sort [c | (c,True) <- Map.toList features] - return $ text $ "\\f[" ++ filling ++ "]" + inHeader <- gets stInHeader + let filling = ['C' | fromMaybe False $ Map.lookup 'C' features] ++ + ['B' | inHeader || + fromMaybe False (Map.lookup 'B' features)] ++ + ['I' | fromMaybe False $ Map.lookup 'I' features] + return $ + if null filling + then text "\\f[R]" + else text $ "\\f[" ++ filling ++ "]" withFontFeature :: PandocMonad m => Char -> MS m Doc -> MS m Doc withFontFeature c action = do @@ -641,7 +656,10 @@ highlightCode opts attr str = modify (\st -> st{ stHighlighting = True }) return h +-- This is used for PDF anchors. toAscii :: String -> String -toAscii = concatMap (\c -> case toAsciiChar c of - Nothing -> 'u':show (ord c) - Just c' -> [c']) +toAscii = concatMap + (\c -> case toAsciiChar c of + Nothing -> '_':'u':show (ord c) ++ "_" + Just '/' -> '_':'u':show (ord c) ++ "_" -- see #4515 + Just c' -> [c']) diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index e9cf6d433..6ed6ed1ca 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -71,8 +71,9 @@ data WriterEnv = , envTopLevel :: Bool , envInsideBlock :: Bool , envInlineStart :: Bool - , envInsideLinkDescription :: Bool -- Escape ] if True + , envInsideLinkDescription :: Bool -- ^ Escape ] if True , envAfterSpace :: Bool + , envOneLine :: Bool -- ^ True if newlines are not allowed } data WriterState = @@ -86,7 +87,7 @@ instance Default WriterState } evalMuse :: PandocMonad m => Muse m a -> WriterEnv -> WriterState -> m a -evalMuse document env st = evalStateT (runReaderT document env) st +evalMuse document env = evalStateT $ runReaderT document env -- | Convert Pandoc to Muse. writeMuse :: PandocMonad m @@ -100,7 +101,8 @@ writeMuse opts document = , envInsideBlock = False , envInlineStart = True , envInsideLinkDescription = False - , envAfterSpace = True + , envAfterSpace = False + , envOneLine = False } -- | Return Muse representation of document. @@ -173,7 +175,7 @@ blockToMuse (Para inlines) = do contents <- inlineListToMuse' inlines return $ contents <> blankline blockToMuse (LineBlock lns) = do - lns' <- mapM inlineListToMuse lns + lns' <- local (\env -> env { envOneLine = True }) $ mapM inlineListToMuse lns return $ nowrap $ vcat (map (text "> " <>) lns') <> blankline blockToMuse (CodeBlock (_,_,_) str) = return $ "<example>" $$ text str $$ "</example>" $$ blankline @@ -221,7 +223,7 @@ blockToMuse (DefinitionList items) = do => ([Inline], [[Block]]) -> Muse m Doc definitionListItemToMuse (label, defs) = do - label' <- inlineListToMuse' label + label' <- local (\env -> env { envOneLine = True, envAfterSpace = True }) $ inlineListToMuse' label contents <- vcat <$> mapM descriptionToMuse defs let ind = offset label' return $ hang ind label' contents @@ -231,8 +233,7 @@ blockToMuse (DefinitionList items) = do descriptionToMuse desc = hang 4 " :: " <$> blockListToMuse desc blockToMuse (Header level (ident,_,_) inlines) = do opts <- asks envOptions - contents <- inlineListToMuse inlines - + contents <- local (\env -> env { envOneLine = True }) $ inlineListToMuse' inlines ids <- gets stIds let autoId = uniqueIdent inlines ids modify $ \st -> st{ stIds = Set.insert autoId ids } @@ -275,7 +276,7 @@ blockToMuse Null = return empty notesToMuse :: PandocMonad m => Notes -> Muse m Doc -notesToMuse notes = vsep <$> (zipWithM noteToMuse [1 ..] notes) +notesToMuse notes = vsep <$> zipWithM noteToMuse [1 ..] notes -- | Return Muse representation of a note. noteToMuse :: PandocMonad m @@ -306,8 +307,7 @@ startsWithMarker _ [] = False -- | Escape special characters for Muse if needed. containsFootnotes :: String -> Bool -containsFootnotes st = - p st +containsFootnotes = p where p ('[':xs) = q xs || p xs p (_:xs) = p xs p "" = False @@ -323,7 +323,7 @@ containsFootnotes st = conditionalEscapeString :: Bool -> String -> String conditionalEscapeString isInsideLinkDescription s = - if any (`elem` ("#*<=>|" :: String)) s || + if any (`elem` ("#*<=|" :: String)) s || "::" `isInfixOf` s || "~~" `isInfixOf` s || "[[" `isInfixOf` s || @@ -395,17 +395,20 @@ urlEscapeBrackets (x:xs) = x:urlEscapeBrackets xs urlEscapeBrackets [] = [] isHorizontalRule :: String -> Bool -isHorizontalRule s = - ((length xs) >= 4) && null ys - where (xs, ys) = span (== '-') s +isHorizontalRule s = length s >= 4 && all (== '-') s + +startsWithSpace :: String -> Bool +startsWithSpace (x:_) = isSpace x +startsWithSpace [] = False fixOrEscape :: Bool -> Inline -> Bool fixOrEscape sp (Str "-") = sp fixOrEscape sp (Str ";") = not sp +fixOrEscape _ (Str ">") = True fixOrEscape sp (Str s) = (sp && (startsWithMarker isDigit s || startsWithMarker isAsciiLower s || startsWithMarker isAsciiUpper s)) - || isHorizontalRule s + || isHorizontalRule s || startsWithSpace s fixOrEscape _ Space = True fixOrEscape _ SoftBreak = True fixOrEscape _ _ = False @@ -433,14 +436,15 @@ renderInlineList (x:xs) = do -- | Normalize and convert list of Pandoc inline elements to Muse. inlineListToMuse'' :: PandocMonad m - => Bool - -> [Inline] - -> Muse m Doc + => Bool + -> [Inline] + -> Muse m Doc inlineListToMuse'' start lst = do lst' <- (normalizeInlineList . fixNotes) <$> preprocessInlineList (map (removeKeyValues . replaceSmallCaps) lst) topLevel <- asks envTopLevel + afterSpace <- asks envAfterSpace local (\env -> env { envInlineStart = start - , envAfterSpace = start && not topLevel + , envAfterSpace = afterSpace || (start && not topLevel) }) $ renderInlineList lst' inlineListToMuse' :: PandocMonad m => [Inline] -> Muse m Doc @@ -487,11 +491,14 @@ inlineToMuse Math{} = fail "Math should be expanded before normalization" inlineToMuse (RawInline (Format f) str) = return $ "<literal style=\"" <> text f <> "\">" <> text str <> "</literal>" -inlineToMuse LineBreak = return $ "<br>" <> cr +inlineToMuse LineBreak = do + oneline <- asks envOneLine + return $ if oneline then "<br>" else "<br>" <> cr inlineToMuse Space = return space inlineToMuse SoftBreak = do + oneline <- asks envOneLine wrapText <- asks $ writerWrapText . envOptions - return $ if wrapText == WrapPreserve then cr else space + return $ if not oneline && wrapText == WrapPreserve then cr else space inlineToMuse (Link _ txt (src, _)) = case txt of [Str x] | escapeURI x == src -> diff --git a/src/Text/Pandoc/Writers/Powerpoint/Output.hs b/src/Text/Pandoc/Writers/Powerpoint/Output.hs index dc5f1c9a9..865ef1efc 100644 --- a/src/Text/Pandoc/Writers/Powerpoint/Output.hs +++ b/src/Text/Pandoc/Writers/Powerpoint/Output.hs @@ -58,7 +58,7 @@ import Text.Pandoc.MIME import qualified Data.ByteString.Lazy as BL import Text.Pandoc.Writers.OOXML import qualified Data.Map as M -import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, isJust, maybeToList, catMaybes) +import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, maybeToList, catMaybes) import Text.Pandoc.ImageSize import Control.Applicative ((<|>)) import System.FilePath.Glob @@ -328,10 +328,8 @@ presHasSpeakerNotes :: Presentation -> Bool presHasSpeakerNotes (Presentation _ slides) = not $ all (mempty ==) $ map slideSpeakerNotes slides curSlideHasSpeakerNotes :: PandocMonad m => P m Bool -curSlideHasSpeakerNotes = do - sldId <- asks envCurSlideId - notesIdMap <- asks envSpeakerNotesIdMap - return $ isJust $ M.lookup sldId notesIdMap +curSlideHasSpeakerNotes = + M.member <$> asks envCurSlideId <*> asks envSpeakerNotesIdMap -------------------------------------------------- diff --git a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs index c49943bcf..e14476b16 100644 --- a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs +++ b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs @@ -376,9 +376,20 @@ inlineToParElems (Note blks) = do modify $ \st -> st { stNoteIds = M.insert curNoteId blks notes } local (\env -> env{envRunProps = (envRunProps env){rLink = Just $ InternalTarget endNotesSlideId}}) $ inlineToParElems $ Superscript [Str $ show curNoteId] -inlineToParElems (Span _ ils) = concatMapM inlineToParElems ils +inlineToParElems (Span _ ils) = inlinesToParElems ils +inlineToParElems (Quoted quoteType ils) = + inlinesToParElems $ [Str open] ++ ils ++ [Str close] + where (open, close) = case quoteType of + SingleQuote -> ("\x2018", "\x2019") + DoubleQuote -> ("\x201C", "\x201D") inlineToParElems (RawInline _ _) = return [] -inlineToParElems _ = return [] +inlineToParElems (Cite _ ils) = inlinesToParElems ils +-- Note: we shouldn't reach this, because images should be handled at +-- the shape level, but should that change in the future, we render +-- the alt text. +inlineToParElems (Image _ alt _) = inlinesToParElems alt + + isListType :: Block -> Bool isListType (OrderedList _ _) = True diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 74fc4dca4..084615357 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -31,7 +31,7 @@ Conversion of 'Pandoc' documents to reStructuredText. reStructuredText: <http://docutils.sourceforge.net/rst.html> -} -module Text.Pandoc.Writers.RST ( writeRST ) where +module Text.Pandoc.Writers.RST ( writeRST, flatten ) where import Prelude import Control.Monad.State.Strict import Data.Char (isSpace, toLower) @@ -263,7 +263,6 @@ blockToRST (Header level (name,classes,_) inlines) = do return $ nowrap $ hang 3 ".. " (rub $$ name' $$ cls) $$ blankline blockToRST (CodeBlock (_,classes,kvs) str) = do opts <- gets stOptions - let tabstop = writerTabStop opts let startnum = maybe "" (\x -> " " <> text x) $ lookup "startFrom" kvs let numberlines = if "numberLines" `elem` classes then " :number-lines:" <> startnum @@ -276,11 +275,10 @@ blockToRST (CodeBlock (_,classes,kvs) str) = do c `notElem` ["sourceCode","literate","numberLines"]] of [] -> "::" (lang:_) -> (".. code:: " <> text lang) $$ numberlines) - $+$ nest tabstop (text str) $$ blankline + $+$ nest 3 (text str) $$ blankline blockToRST (BlockQuote blocks) = do - tabstop <- gets $ writerTabStop . stOptions contents <- blockListToRST blocks - return $ nest tabstop contents <> blankline + return $ nest 3 contents <> blankline blockToRST (Table caption aligns widths headers rows) = do caption' <- inlineListToRST caption let blocksToDoc opts bs = do @@ -338,8 +336,7 @@ definitionListItemToRST :: PandocMonad m => ([Inline], [[Block]]) -> RST m Doc definitionListItemToRST (label, defs) = do label' <- inlineListToRST label contents <- liftM vcat $ mapM blockListToRST defs - tabstop <- gets $ writerTabStop . stOptions - return $ nowrap label' $$ nest tabstop (nestle contents <> cr) + return $ nowrap label' $$ nest 3 (nestle contents <> cr) -- | Format a list of lines as line block. linesToLineBlock :: PandocMonad m => [[Inline]] -> RST m Doc @@ -380,8 +377,10 @@ blockListToRST :: PandocMonad m blockListToRST = blockListToRST' False transformInlines :: [Inline] -> [Inline] -transformInlines = stripLeadingTrailingSpace . insertBS - . filter hasContents . removeSpaceAfterDisplayMath +transformInlines = insertBS . + filter hasContents . + removeSpaceAfterDisplayMath . + concatMap (transformNested . flatten) where -- empty inlines are not valid RST syntax hasContents :: Inline -> Bool hasContents (Str "") = False @@ -415,6 +414,8 @@ transformInlines = stripLeadingTrailingSpace . insertBS x : insertBS (y : zs) insertBS (x:ys) = x : insertBS ys insertBS [] = [] + transformNested :: [Inline] -> [Inline] + transformNested = map (mapNested stripLeadingTrailingSpace) surroundComplex :: Inline -> Inline -> Bool surroundComplex (Str s@(_:_)) (Str s'@(_:_)) = case (last s, head s') of @@ -452,6 +453,74 @@ transformInlines = stripLeadingTrailingSpace . insertBS isComplex (Span _ (x:_)) = isComplex x isComplex _ = False +-- | Flattens nested inlines. Extracts nested inlines and goes through +-- them either collapsing them in the outer inline container or +-- pulling them out of it +flatten :: Inline -> [Inline] +flatten outer = combineAll $ dropInlineParent outer + where combineAll = foldl combine [] + + combine :: [Inline] -> Inline -> [Inline] + combine f i = + case (outer, i) of + -- quotes are not rendered using RST inlines, so we can keep + -- them and they will be readable and parsable + (Quoted _ _, _) -> keep f i + (_, Quoted _ _) -> keep f i + -- parent inlines would prevent links from being correctly + -- parsed, in this case we prioritise the content over the + -- style + (_, Link _ _ _) -> emerge f i + -- always give priority to strong text over emphasis + (Emph _, Strong _) -> emerge f i + -- drop all other nested styles + (_, _) -> collapse f i + + emerge f i = f <> [i] + keep f i = appendToLast f [i] + collapse f i = appendToLast f $ dropInlineParent i + + appendToLast :: [Inline] -> [Inline] -> [Inline] + appendToLast [] toAppend = [setInlineChildren outer toAppend] + appendToLast flattened toAppend + | isOuter lastFlat = init flattened <> [appendTo lastFlat toAppend] + | otherwise = flattened <> [setInlineChildren outer toAppend] + where lastFlat = last flattened + appendTo o i = mapNested (<> i) o + isOuter i = emptyParent i == emptyParent outer + emptyParent i = setInlineChildren i [] + +mapNested :: ([Inline] -> [Inline]) -> Inline -> Inline +mapNested f i = setInlineChildren i (f (dropInlineParent i)) + +dropInlineParent :: Inline -> [Inline] +dropInlineParent (Link _ i _) = i +dropInlineParent (Emph i) = i +dropInlineParent (Strong i) = i +dropInlineParent (Strikeout i) = i +dropInlineParent (Superscript i) = i +dropInlineParent (Subscript i) = i +dropInlineParent (SmallCaps i) = i +dropInlineParent (Cite _ i) = i +dropInlineParent (Image _ i _) = i +dropInlineParent (Span _ i) = i +dropInlineParent (Quoted _ i) = i +dropInlineParent i = [i] -- not a parent, like Str or Space + +setInlineChildren :: Inline -> [Inline] -> Inline +setInlineChildren (Link a _ t) i = Link a i t +setInlineChildren (Emph _) i = Emph i +setInlineChildren (Strong _) i = Strong i +setInlineChildren (Strikeout _) i = Strikeout i +setInlineChildren (Superscript _) i = Superscript i +setInlineChildren (Subscript _) i = Subscript i +setInlineChildren (SmallCaps _) i = SmallCaps i +setInlineChildren (Quoted q _) i = Quoted q i +setInlineChildren (Cite c _) i = Cite c i +setInlineChildren (Image a _ t) i = Image a i t +setInlineChildren (Span a _) i = Span a i +setInlineChildren leaf _ = leaf + inlineListToRST :: PandocMonad m => [Inline] -> RST m Doc inlineListToRST = writeInlines . walk transformInlines diff --git a/stack.lts9.yaml b/stack.lts9.yaml index 947247d0b..9507d961d 100644 --- a/stack.lts9.yaml +++ b/stack.lts9.yaml @@ -17,15 +17,15 @@ extra-deps: - skylighting-0.7.0.2 - skylighting-core-0.7.0.2 - ansi-terminal-0.8.0.2 -- texmath-0.10.1.1 - cmark-gfm-0.1.3 - QuickCheck-2.11.3 - tasty-1.0.1.1 - tasty-quickcheck-0.9.1 - doctemplates-0.2.2.1 - hs-bibutils-6.2.0.1 -- pandoc-citeproc-0.14.3 +- pandoc-citeproc-0.14.3.1 - tagsoup-0.14.6 - pandoc-types-1.17.4.2 - haddock-library-1.5.0.1 +- texmath-0.10.1.2 resolver: lts-9.14 diff --git a/stack.yaml b/stack.yaml index 22fa98223..9c59e5e44 100644 --- a/stack.yaml +++ b/stack.yaml @@ -12,15 +12,16 @@ flags: packages: - '.' extra-deps: -- pandoc-citeproc-0.14.3 +- pandoc-citeproc-0.14.3.1 - skylighting-0.7.0.2 - skylighting-core-0.7.0.2 - ansi-terminal-0.8.0.2 - tasty-1.0.1.1 +- test-framework-0.8.2.0 - pandoc-types-1.17.4.2 - cmark-gfm-0.1.3 -#- haddock-library-1.5.0.1 - hslua-module-text-0.1.2.1 +- texmath-0.10.1.2 ghc-options: "$locals": -fhide-source-paths -XNoImplicitPrelude resolver: lts-10.10 diff --git a/test/Tests/Command.hs.orig b/test/Tests/Command.hs.orig new file mode 100644 index 000000000..de83d0639 --- /dev/null +++ b/test/Tests/Command.hs.orig @@ -0,0 +1,95 @@ +module Tests.Command (findPandoc, runTest, tests) +where + +import Data.Algorithm.Diff +import qualified Data.ByteString as BS +import Data.List (isSuffixOf) +import Prelude hiding (readFile) +import System.Directory +import System.Exit +import System.FilePath (joinPath, splitDirectories, takeDirectory, (</>)) +import System.IO (hPutStr, stderr) +import System.IO.Unsafe (unsafePerformIO) +import System.Process +import Test.Tasty +import Test.Tasty.HUnit +import Tests.Helpers +import Text.Pandoc +import qualified Text.Pandoc.UTF8 as UTF8 + +-- | Run a test with normalize function, return True if test passed. +runTest :: String -- ^ Title of test + -> FilePath -- ^ Path to pandoc + -> String -- ^ Shell command + -> String -- ^ Input text + -> String -- ^ Expected output + -> TestTree +runTest testname pandocpath cmd inp norm = testCase testname $ do + let findDynlibDir [] = Nothing + findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build" + findDynlibDir (_:xs) = findDynlibDir xs + let mbDynlibDir = findDynlibDir (reverse $ splitDirectories $ + takeDirectory $ takeWhile (/=' ') cmd) + let dynlibEnv = case mbDynlibDir of + Nothing -> [] + Just d -> [("DYLD_LIBRARY_PATH", d), + ("LD_LIBRARY_PATH", d)] + let env' = dynlibEnv ++ [("PATH",takeDirectory pandocpath),("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./"),("pandoc_datadir", "..")] + let pr = (shell cmd){ env = Just env' } + (ec, out', err') <- readCreateProcessWithExitCode pr inp + -- filter \r so the tests will work on Windows machines + let out = filter (/= '\r') $ err' ++ out' + result <- if ec == ExitSuccess + then + if out == norm + then return TestPassed + else return + $ TestFailed cmd "expected" + $ getDiff (lines out) (lines norm) + else do + hPutStr stderr err' + return $ TestError ec + assertBool (show result) (result == TestPassed) + +tests :: TestTree +{-# NOINLINE tests #-} +tests = unsafePerformIO $ do + pandocpath <- findPandoc + files <- filter (".md" `isSuffixOf`) <$> + getDirectoryContents "command" + let cmds = map (extractCommandTest pandocpath) files + return $ testGroup "Command:" cmds + +isCodeBlock :: Block -> Bool +isCodeBlock (CodeBlock _ _) = True +isCodeBlock _ = False + +extractCode :: Block -> String +extractCode (CodeBlock _ code) = code +extractCode _ = "" + +dropPercent :: String -> String +dropPercent ('%':xs) = dropWhile (== ' ') xs +dropPercent xs = xs + +runCommandTest :: FilePath -> (Int, String) -> TestTree +runCommandTest pandocpath (num, code) = + let codelines = lines code + (continuations, r1) = span ("\\" `isSuffixOf`) codelines + (cmd, r2) = (dropPercent (unwords (map init continuations ++ take 1 r1)), + drop 1 r1) + (inplines, r3) = break (=="^D") r2 + normlines = takeWhile (/=".") (drop 1 r3) + input = unlines inplines + norm = unlines normlines + shcmd = cmd -- trimr $ takeDirectory pandocpath </> cmd + in runTest ("#" ++ show num) pandocpath shcmd input norm + +extractCommandTest :: FilePath -> FilePath -> TestTree +extractCommandTest pandocpath fp = unsafePerformIO $ do + contents <- UTF8.toText <$> BS.readFile ("command" </> fp) + Pandoc _ blocks <- runIOorExplode (readMarkdown + def{ readerExtensions = pandocExtensions } contents) + let codeblocks = map extractCode $ filter isCodeBlock blocks + let cases = map (runCommandTest pandocpath) $ zip [1..] codeblocks + return $ testGroup fp cases diff --git a/test/Tests/Helpers.hs.orig b/test/Tests/Helpers.hs.orig new file mode 100644 index 000000000..2a6543ea0 --- /dev/null +++ b/test/Tests/Helpers.hs.orig @@ -0,0 +1,138 @@ +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE TypeSynonymInstances #-} +-- Utility functions for the test suite. + +module Tests.Helpers ( test + , TestResult(..) + , showDiff + , findPandoc + , (=?>) + , purely + , ToString(..) + , ToPandoc(..) + ) + where + +import Data.Algorithm.Diff +import qualified Data.Map as M +import Data.Text (Text, unpack) +import System.Directory +import System.Environment.Executable (getExecutablePath) +import System.Exit +import System.FilePath +import Test.Tasty +import Test.Tasty.HUnit +import Text.Pandoc.Builder (Blocks, Inlines, doc, plain) +import Text.Pandoc.Class +import Text.Pandoc.Definition +import Text.Pandoc.Options +import Text.Pandoc.Shared (trimr) +import Text.Pandoc.Writers.Native (writeNative) +import Text.Printf + +test :: (ToString a, ToString b, ToString c) + => (a -> b) -- ^ function to test + -> String -- ^ name of test case + -> (a, c) -- ^ (input, expected value) + -> TestTree +test fn name (input, expected) = + testCase name' $ assertBool msg (actual' == expected') + where msg = nl ++ dashes "input" ++ nl ++ input' ++ nl ++ + dashes "result" ++ nl ++ + unlines (map vividize diff) ++ + dashes "" + nl = "\n" + name' = if length name > 54 + then take 52 name ++ "..." -- avoid wide output + else name + input' = toString input + actual' = lines $ toString $ fn input + expected' = lines $ toString expected + diff = getDiff expected' actual' + dashes "" = replicate 72 '-' + dashes x = replicate (72 - length x - 5) '-' ++ " " ++ x ++ " ---" + +data TestResult = TestPassed + | TestError ExitCode + | TestFailed String FilePath [Diff String] + deriving (Eq) + +instance Show TestResult where + show TestPassed = "PASSED" + show (TestError ec) = "ERROR " ++ show ec + show (TestFailed cmd file d) = '\n' : dash ++ + "\n--- " ++ file ++ + "\n+++ " ++ cmd ++ "\n" ++ showDiff (1,1) d ++ + dash + where dash = replicate 72 '-' + +showDiff :: (Int,Int) -> [Diff String] -> String +showDiff _ [] = "" +showDiff (l,r) (First ln : ds) = + printf "+%4d " l ++ ln ++ "\n" ++ showDiff (l+1,r) ds +showDiff (l,r) (Second ln : ds) = + printf "-%4d " r ++ ln ++ "\n" ++ showDiff (l,r+1) ds +showDiff (l,r) (Both _ _ : ds) = + showDiff (l+1,r+1) ds + +-- | Find pandoc executable relative to test-pandoc +-- First, try in same directory (e.g. if both in ~/.cabal/bin) +-- Second, try ../pandoc (e.g. if in dist/XXX/build/test-pandoc) +findPandoc :: IO FilePath +findPandoc = do + testExePath <- getExecutablePath + let testExeDir = takeDirectory testExePath + found <- doesFileExist (testExeDir </> "pandoc") + return $ if found + then testExeDir </> "pandoc" + else case splitDirectories testExeDir of + [] -> error "test-pandoc: empty testExeDir" + xs -> joinPath (init xs) </> "pandoc" </> "pandoc" + + +vividize :: Diff String -> String +vividize (Both s _) = " " ++ s +vividize (First s) = "- " ++ s +vividize (Second s) = "+ " ++ s + +purely :: (b -> PandocPure a) -> b -> a +purely f = either (error . show) id . runPure . f + +infix 5 =?> +(=?>) :: a -> b -> (a,b) +x =?> y = (x, y) + +class ToString a where + toString :: a -> String + +instance ToString Pandoc where + toString d = unpack $ + purely (writeNative def{ writerTemplate = s }) $ toPandoc d + where s = case d of + (Pandoc (Meta m) _) + | M.null m -> Nothing + | otherwise -> Just "" -- need this to get meta output + +instance ToString Blocks where + toString = unpack . purely (writeNative def) . toPandoc + +instance ToString Inlines where + toString = trimr . unpack . purely (writeNative def) . toPandoc + +instance ToString String where + toString = id + +instance ToString Text where + toString = unpack + +class ToPandoc a where + toPandoc :: a -> Pandoc + +instance ToPandoc Pandoc where + toPandoc = id + +instance ToPandoc Blocks where + toPandoc = doc + +instance ToPandoc Inlines where + toPandoc = doc . plain diff --git a/test/Tests/Lua.hs.orig b/test/Tests/Lua.hs.orig new file mode 100644 index 000000000..5fe015265 --- /dev/null +++ b/test/Tests/Lua.hs.orig @@ -0,0 +1,196 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Lua ( tests ) where + +import Control.Monad (when) +import Data.Version (Version (versionBranch)) +import System.FilePath ((</>)) +import Test.Tasty (TestTree, localOption) +import Test.Tasty.HUnit (Assertion, assertEqual, testCase) +import Test.Tasty.QuickCheck (QuickCheckTests (..), ioProperty, testProperty) +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder (bulletList, divWith, doc, doubleQuoted, emph, + header, linebreak, para, plain, rawBlock, + singleQuoted, space, str, strong) +import Text.Pandoc.Class (runIOorExplode, setUserDataDir) +import Text.Pandoc.Definition (Block (BlockQuote, Div, Para), Inline (Emph, Str), + Attr, Meta, Pandoc, pandocTypesVersion) +import Text.Pandoc.Lua (runLuaFilter, runPandocLua) +import Text.Pandoc.Options (def) +import Text.Pandoc.Shared (pandocVersion) + +import qualified Foreign.Lua as Lua + +tests :: [TestTree] +tests = map (localOption (QuickCheckTests 20)) + [ testProperty "inline elements can be round-tripped through the lua stack" $ + \x -> ioProperty (roundtripEqual (x::Inline)) + + , testProperty "block elements can be round-tripped through the lua stack" $ + \x -> ioProperty (roundtripEqual (x::Block)) + + , testProperty "meta blocks can be round-tripped through the lua stack" $ + \x -> ioProperty (roundtripEqual (x::Meta)) + + , testProperty "documents can be round-tripped through the lua stack" $ + \x -> ioProperty (roundtripEqual (x::Pandoc)) + + , testCase "macro expansion via filter" $ + assertFilterConversion "a '{{helloworld}}' string is expanded" + "strmacro.lua" + (doc . para $ str "{{helloworld}}") + (doc . para . emph $ str "Hello, World") + + , testCase "convert all plains to paras" $ + assertFilterConversion "plains become para" + "plain-to-para.lua" + (doc $ bulletList [plain (str "alfa"), plain (str "bravo")]) + (doc $ bulletList [para (str "alfa"), para (str "bravo")]) + + , testCase "make hello world document" $ + assertFilterConversion "Document contains 'Hello, World!'" + "hello-world-doc.lua" + (doc . para $ str "Hey!" <> linebreak <> str "What's up?") + (doc . para $ str "Hello," <> space <> str "World!") + + , testCase "implicit doc filter" $ + assertFilterConversion "Document contains 'Hello, World!'" + "implicit-doc-filter.lua" + (doc . plain $ linebreak) + (doc . para $ str "Hello," <> space <> str "World!") + + , testCase "parse raw markdown blocks" $ + assertFilterConversion "raw markdown block is converted" + "markdown-reader.lua" + (doc $ rawBlock "markdown" "*charly* **delta**") + (doc . para $ emph "charly" <> space <> strong "delta") + + , testCase "allow shorthand functions for quote types" $ + assertFilterConversion "single quoted becomes double quoted string" + "single-to-double-quoted.lua" + (doc . para . singleQuoted $ str "simple") + (doc . para . doubleQuoted $ str "simple") + + , testCase "Count inlines via metatable catch-all" $ + assertFilterConversion "filtering with metatable catch-all failed" + "metatable-catch-all.lua" + (doc . para $ "four words, three spaces") + (doc . para $ str "7") + + , testCase "Count blocks via Block-specific catch-all" $ + assertFilterConversion "filtering with Block catch-all failed" + "block-count.lua" + (doc $ para "one" <> para "two") + (doc $ para "2") + + , testCase "Convert header upper case" $ + assertFilterConversion "converting header to upper case failed" + "uppercase-header.lua" + (doc $ header 1 "les états-unis" <> para "text") + (doc $ header 1 "LES ÉTATS-UNIS" <> para "text") + + , testCase "Attribute lists are convenient to use" $ + let kv_before = [("one", "1"), ("two", "2"), ("three", "3")] + kv_after = [("one", "eins"), ("three", "3"), ("five", "5")] + in assertFilterConversion "Attr doesn't behave as expected" + "attr-test.lua" + (doc $ divWith ("", [], kv_before) (para "nil")) + (doc $ divWith ("", [], kv_after) (para "nil")) + + , testCase "Test module pandoc.utils" $ + assertFilterConversion "pandoc.utils doesn't work as expected." + "test-pandoc-utils.lua" + (doc $ para "doesn't matter") + (doc $ mconcat [ plain (str "hierarchicalize: OK") + , plain (str "normalize_date: OK") + , plain (str "pipe: OK") + , plain (str "failing pipe: OK") + , plain (str "read: OK") + , plain (str "failing read: OK") + , plain (str "sha1: OK") + , plain (str "stringify: OK") + , plain (str "to_roman_numeral: OK") + ]) + + , testCase "Script filename is set" $ + assertFilterConversion "unexpected script name" + "script-name.lua" + (doc $ para "ignored") + (doc $ para (str $ "lua" </> "script-name.lua")) + + , testCase "Pandoc version is set" . runPandocLua' $ do + Lua.getglobal' "table.concat" + Lua.getglobal "PANDOC_VERSION" + Lua.push ("." :: String) -- seperator + Lua.call 2 1 + Lua.liftIO . assertEqual "pandoc version is wrong" pandocVersion + =<< Lua.peek Lua.stackTop + + , testCase "Pandoc types version is set" . runPandocLua' $ do + let versionNums = versionBranch pandocTypesVersion + Lua.getglobal "PANDOC_API_VERSION" + Lua.liftIO . assertEqual "pandoc-types version is wrong" versionNums + =<< Lua.peek Lua.stackTop + + , testCase "Allow singleton inline in constructors" . runPandocLua' $ do + Lua.liftIO . assertEqual "Not the exptected Emph" (Emph [Str "test"]) + =<< Lua.callFunc "pandoc.Emph" (Str "test") + Lua.liftIO . assertEqual "Unexpected element" (Para [Str "test"]) + =<< Lua.callFunc "pandoc.Para" ("test" :: String) + Lua.liftIO . assertEqual "Unexptected element" + (BlockQuote [Para [Str "foo"]]) =<< ( + do + Lua.getglobal' "pandoc.BlockQuote" + Lua.push (Para [Str "foo"]) + _ <- Lua.call 1 1 + Lua.peek Lua.stackTop + ) + + , testCase "Elements with Attr have `attr` accessor" . runPandocLua' $ do + Lua.push (Div ("hi", ["moin"], []) + [Para [Str "ignored"]]) + Lua.getfield Lua.stackTop "attr" + Lua.liftIO . assertEqual "no accessor" (("hi", ["moin"], []) :: Attr) + =<< Lua.peek Lua.stackTop + + , testCase "informative error messages" . runPandocLua' $ do + Lua.pushboolean True + err <- Lua.peekEither Lua.stackTop :: Lua.Lua (Either String Pandoc) + case err of + Left msg -> do + let expectedMsg = "Could not get Pandoc value: " + ++ "expected table but got boolean." + Lua.liftIO $ assertEqual "unexpected error message" expectedMsg msg + Right _ -> error "Getting a Pandoc element from a bool should fail." + ] + +assertFilterConversion :: String -> FilePath -> Pandoc -> Pandoc -> Assertion +assertFilterConversion msg filterPath docIn docExpected = do + docEither <- runIOorExplode $ do + setUserDataDir (Just "../data") + runLuaFilter def ("lua" </> filterPath) [] docIn + case docEither of + Left _ -> fail "lua filter failed" + Right docRes -> assertEqual msg docExpected docRes + +roundtripEqual :: (Eq a, Lua.FromLuaStack a, Lua.ToLuaStack a) => a -> IO Bool +roundtripEqual x = (x ==) <$> roundtripped + where + roundtripped :: (Lua.FromLuaStack a, Lua.ToLuaStack a) => IO a + roundtripped = runPandocLua' $ do + oldSize <- Lua.gettop + Lua.push x + size <- Lua.gettop + when (size - oldSize /= 1) $ + error ("not exactly one additional element on the stack: " ++ show size) + res <- Lua.peekEither (-1) + case res of + Left e -> error (show e) + Right y -> return y + +runPandocLua' :: Lua.Lua a -> IO a +runPandocLua' op = runIOorExplode $ do + setUserDataDir (Just "../data") + res <- runPandocLua op + case res of + Left e -> error (show e) + Right x -> return x diff --git a/test/Tests/Old.hs b/test/Tests/Old.hs index f2b43640b..b426ffd07 100644 --- a/test/Tests/Old.hs +++ b/test/Tests/Old.hs @@ -59,7 +59,7 @@ tests = [ testGroup "markdown" ] , testGroup "s5" [ s5WriterTest "basic" ["-s"] "s5" - , s5WriterTest "fancy" ["-s","-m","-i"] "s5" + , s5WriterTest "fancy" ["-s","--mathjax","-i"] "s5" , s5WriterTest "fragment" [] "html4" , s5WriterTest "inserts" ["-s", "-H", "insert", "-B", "insert", "-A", "insert", "-c", "main.css"] "html4" @@ -95,6 +95,7 @@ tests = [ testGroup "markdown" , fb2WriterTest "images" [] "fb2/images.markdown" "fb2/images.fb2" , fb2WriterTest "images-embedded" [] "fb2/images-embedded.html" "fb2/images-embedded.fb2" , fb2WriterTest "math" [] "fb2/math.markdown" "fb2/math.fb2" + , fb2WriterTest "meta" [] "fb2/meta.markdown" "fb2/meta.fb2" , fb2WriterTest "tables" [] "tables.native" "tables.fb2" , fb2WriterTest "testsuite" [] "testsuite.native" "writer.fb2" ] diff --git a/test/Tests/Old.hs.orig b/test/Tests/Old.hs.orig new file mode 100644 index 000000000..ed4dcc076 --- /dev/null +++ b/test/Tests/Old.hs.orig @@ -0,0 +1,288 @@ +module Tests.Old (tests) where + +import Data.Algorithm.Diff +import Prelude hiding (readFile) +import System.Exit +import System.FilePath (joinPath, splitDirectories, (<.>), (</>)) +import System.IO.Temp (withTempFile) +import System.Process (runProcess, waitForProcess) +import Test.Tasty (TestTree, testGroup) +import Test.Tasty.Golden.Advanced (goldenTest) +import Tests.Helpers hiding (test) +import qualified Text.Pandoc.UTF8 as UTF8 + +tests :: [TestTree] +tests = [ testGroup "markdown" + [ testGroup "writer" + $ writerTests "markdown" ++ lhsWriterTests "markdown" + , testGroup "reader" + [ test "basic" ["-r", "markdown", "-w", "native", "-s"] + "testsuite.txt" "testsuite.native" + , test "tables" ["-r", "markdown", "-w", "native", "--columns=80"] + "tables.txt" "tables.native" + , test "pipe tables" ["-r", "markdown", "-w", "native", "--columns=80"] + "pipe-tables.txt" "pipe-tables.native" + , test "more" ["-r", "markdown", "-w", "native", "-s"] + "markdown-reader-more.txt" "markdown-reader-more.native" + , lhsReaderTest "markdown+lhs" + ] + , testGroup "citations" + [ test "citations" ["-r", "markdown", "-w", "native"] + "markdown-citations.txt" "markdown-citations.native" + ] + ] + , testGroup "rst" + [ testGroup "writer" (writerTests "rst" ++ lhsWriterTests "rst") + , testGroup "reader" + [ test "basic" ["-r", "rst+smart", "-w", "native", + "-s", "--columns=80"] "rst-reader.rst" "rst-reader.native" + , test "tables" ["-r", "rst", "-w", "native", "--columns=80"] + "tables.rst" "tables-rstsubset.native" + , lhsReaderTest "rst+lhs" + ] + ] + , testGroup "latex" + [ testGroup "writer" (writerTests "latex" ++ lhsWriterTests "latex") + , testGroup "reader" + [ test "basic" ["-r", "latex+raw_tex", "-w", "native", "-s"] + "latex-reader.latex" "latex-reader.native" + , lhsReaderTest "latex+lhs" + ] + ] + , testGroup "html" + [ testGroup "writer" (writerTests "html4" ++ writerTests "html5" ++ + lhsWriterTests "html") + , test "reader" ["-r", "html", "-w", "native", "-s"] + "html-reader.html" "html-reader.native" + ] + , testGroup "s5" + [ s5WriterTest "basic" ["-s"] "s5" + , s5WriterTest "fancy" ["-s","-m","-i"] "s5" + , s5WriterTest "fragment" [] "html4" + , s5WriterTest "inserts" ["-s", "-H", "insert", + "-B", "insert", "-A", "insert", "-c", "main.css"] "html4" + ] + , testGroup "textile" + [ testGroup "writer" $ writerTests "textile" + , test "reader" ["-r", "textile", "-w", "native", "-s"] + "textile-reader.textile" "textile-reader.native" + ] + , testGroup "docbook" + [ testGroup "writer" $ writerTests "docbook4" + , test "reader" ["-r", "docbook", "-w", "native", "-s"] + "docbook-reader.docbook" "docbook-reader.native" + , test "reader" ["-r", "docbook", "-w", "native", "-s"] + "docbook-xref.docbook" "docbook-xref.native" + ] + , testGroup "docbook5" + [ testGroup "writer" $ writerTests "docbook5" + ] + , testGroup "jats" + [ testGroup "writer" $ writerTests "jats" + , test "reader" ["-r", "jats", "-w", "native", "-s"] + "jats-reader.xml" "jats-reader.native" + ] + , testGroup "native" + [ testGroup "writer" $ writerTests "native" + , test "reader" ["-r", "native", "-w", "native", "-s"] + "testsuite.native" "testsuite.native" + ] + , testGroup "fb2" + [ fb2WriterTest "basic" [] "fb2/basic.markdown" "fb2/basic.fb2" + , fb2WriterTest "titles" [] "fb2/titles.markdown" "fb2/titles.fb2" + , fb2WriterTest "images" [] "fb2/images.markdown" "fb2/images.fb2" + , fb2WriterTest "images-embedded" [] "fb2/images-embedded.html" "fb2/images-embedded.fb2" + , fb2WriterTest "math" [] "fb2/math.markdown" "fb2/math.fb2" + , fb2WriterTest "tables" [] "tables.native" "tables.fb2" + , fb2WriterTest "testsuite" [] "testsuite.native" "writer.fb2" + ] + , testGroup "mediawiki" + [ testGroup "writer" $ writerTests "mediawiki" + , test "reader" ["-r", "mediawiki", "-w", "native", "-s"] + "mediawiki-reader.wiki" "mediawiki-reader.native" + ] + , testGroup "vimwiki" + [ test "reader" ["-r", "vimwiki", "-w", "native", "-s"] + "vimwiki-reader.wiki" "vimwiki-reader.native" + ] + , testGroup "dokuwiki" + [ testGroup "writer" $ writerTests "dokuwiki" + , test "inline_formatting" ["-r", "native", "-w", "dokuwiki", "-s"] + "dokuwiki_inline_formatting.native" "dokuwiki_inline_formatting.dokuwiki" + , test "multiblock table" ["-r", "native", "-w", "dokuwiki", "-s"] + "dokuwiki_multiblock_table.native" "dokuwiki_multiblock_table.dokuwiki" + , test "external images" ["-r", "native", "-w", "dokuwiki", "-s"] + "dokuwiki_external_images.native" "dokuwiki_external_images.dokuwiki" + ] + , testGroup "opml" + [ test "basic" ["-r", "native", "-w", "opml", "--columns=78", "-s"] + "testsuite.native" "writer.opml" + , test "reader" ["-r", "opml", "-w", "native", "-s"] + "opml-reader.opml" "opml-reader.native" + ] + , testGroup "haddock" + [ testGroup "writer" $ writerTests "haddock" + , test "reader" ["-r", "haddock", "-w", "native", "-s"] + "haddock-reader.haddock" "haddock-reader.native" + ] + , testGroup "txt2tags" + [ test "reader" ["-r", "t2t", "-w", "native", "-s"] + "txt2tags.t2t" "txt2tags.native" ] + , testGroup "epub" [ + test "features" ["-r", "epub", "-w", "native"] + "epub/features.epub" "epub/features.native" + , test "wasteland" ["-r", "epub", "-w", "native"] + "epub/wasteland.epub" "epub/wasteland.native" + , test "formatting" ["-r", "epub", "-w", "native"] + "epub/formatting.epub" "epub/formatting.native" + ] + , testGroup "twiki" + [ test "reader" ["-r", "twiki", "-w", "native", "-s"] + "twiki-reader.twiki" "twiki-reader.native" ] + , testGroup "tikiwiki" + [ test "reader" ["-r", "tikiwiki", "-w", "native", "-s"] + "tikiwiki-reader.tikiwiki" "tikiwiki-reader.native" ] + , testGroup "other writers" $ map (\f -> testGroup f $ writerTests f) + [ "opendocument" , "context" , "texinfo", "icml", "tei" + , "man" , "plain" , "rtf", "org", "asciidoc", "zimwiki" + ] + , testGroup "writers-lang-and-dir" + [ test "latex" ["-f", "native", "-t", "latex", "-s"] + "writers-lang-and-dir.native" "writers-lang-and-dir.latex" + , test "context" ["-f", "native", "-t", "context", "-s"] + "writers-lang-and-dir.native" "writers-lang-and-dir.context" + ] + , testGroup "muse" + [ testGroup "writer" $ writerTests "muse" + ] + , testGroup "ms" + [ testGroup "writer" $ writerTests "ms" + ] + , testGroup "creole" + [ test "reader" ["-r", "creole", "-w", "native", "-s"] + "creole-reader.txt" "creole-reader.native" + ] + , testGroup "custom writer" + [ test "basic" ["-f", "native", "-t", "../data/sample.lua"] + "testsuite.native" "writer.custom" + , test "tables" ["-f", "native", "-t", "../data/sample.lua"] + "tables.native" "tables.custom" + ] + ] + +-- makes sure file is fully closed after reading +readFile' :: FilePath -> IO String +readFile' f = do s <- UTF8.readFile f + return $! (length s `seq` s) + +lhsWriterTests :: String -> [TestTree] +lhsWriterTests format + = [ t "lhs to normal" format + , t "lhs to lhs" (format ++ "+lhs") + ] + where + t n f = test n ["--wrap=preserve", "-r", "native", "-s", "-w", f] + "lhs-test.native" ("lhs-test" <.> f) + +lhsReaderTest :: String -> TestTree +lhsReaderTest format = + test "lhs" ["-r", format, "-w", "native"] + ("lhs-test" <.> format) norm + where norm = if format == "markdown+lhs" + then "lhs-test-markdown.native" + else "lhs-test.native" + +writerTests :: String -> [TestTree] +writerTests format + = [ test "basic" (opts ++ ["-s"]) "testsuite.native" ("writer" <.> format) + , test "tables" opts "tables.native" ("tables" <.> format) + ] + where + opts = ["-r", "native", "-w", format, "--columns=78", + "--variable", "pandoc-version="] + +s5WriterTest :: String -> [String] -> String -> TestTree +s5WriterTest modifier opts format + = test (format ++ " writer (" ++ modifier ++ ")") + (["-r", "native", "-w", format] ++ opts) + "s5.native" ("s5-" ++ modifier <.> "html") + +fb2WriterTest :: String -> [String] -> String -> String -> TestTree +fb2WriterTest title opts inputfile normfile = + testWithNormalize (ignoreBinary . formatXML) + title (["-t", "fb2"]++opts) inputfile normfile + where + formatXML xml = splitTags $ zip xml (drop 1 xml) + splitTags [] = [] + splitTags [end] = fst end : snd end : [] + splitTags (('>','<'):rest) = ">\n" ++ splitTags rest + splitTags ((c,_):rest) = c : splitTags rest + ignoreBinary = unlines . filter (not . startsWith "<binary ") . lines + startsWith tag str = all (uncurry (==)) $ zip tag str + +-- | Run a test without normalize function, return True if test passed. +test :: String -- ^ Title of test + -> [String] -- ^ Options to pass to pandoc + -> String -- ^ Input filepath + -> FilePath -- ^ Norm (for test results) filepath + -> TestTree +test = testWithNormalize id + +-- | Run a test with normalize function, return True if test passed. +testWithNormalize :: (String -> String) -- ^ Normalize function for output + -> String -- ^ Title of test + -> [String] -- ^ Options to pass to pandoc + -> String -- ^ Input filepath + -> FilePath -- ^ Norm (for test results) filepath + -> TestTree +testWithNormalize normalizer testname opts inp norm = + goldenTest testname getExpected getActual + (compareValues norm options) updateGolden + where getExpected = normalizer <$> readFile' norm + getActual = + withTempFile "." "pandoc-test" $ \outputPath hOut -> do + withTempFile "." "pandoc-test" $ \errorPath hErr -> do + pandocPath <- findPandoc + let mbDynlibDir = findDynlibDir (reverse $ + splitDirectories pandocPath) + let dynlibEnv = case mbDynlibDir of + Nothing -> [] + Just d -> [("DYLD_LIBRARY_PATH", d), + ("LD_LIBRARY_PATH", d)] + let env = dynlibEnv ++ + [("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./"), + ("pandoc_datadir","..")] + ph <- runProcess pandocPath options Nothing + (Just env) Nothing (Just hOut) (Just hErr) + ec <- waitForProcess ph + if ec == ExitSuccess + then + -- filter \r so the tests will work on Windows machines + (filter (/='\r') . normalizer) <$> readFile' outputPath + else do + errcontents <- UTF8.readFile errorPath + fail $ "Pandoc failed with " ++ show ec ++ + if null errcontents + then "" + else '\n':errcontents + updateGolden = UTF8.writeFile norm + options = ["--quiet"] ++ [inp] ++ opts + +compareValues :: FilePath -> [String] -> String -> String -> IO (Maybe String) +compareValues norm options expected actual = do + pandocPath <- findPandoc + let cmd = pandocPath ++ " " ++ unwords options + let dash = replicate 72 '-' + let diff = getDiff (lines actual) (lines expected) + if expected == actual + then return Nothing + else return $ Just $ + '\n' : dash ++ + "\n--- " ++ norm ++ + "\n+++ " ++ cmd ++ "\n" ++ + showDiff (1,1) diff ++ dash + +findDynlibDir :: [FilePath] -> Maybe FilePath +findDynlibDir [] = Nothing +findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build" +findDynlibDir (_:xs) = findDynlibDir xs diff --git a/test/Tests/Readers/Creole.hs.orig b/test/Tests/Readers/Creole.hs.orig new file mode 100644 index 000000000..3f60a523d --- /dev/null +++ b/test/Tests/Readers/Creole.hs.orig @@ -0,0 +1,286 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Creole (tests) where + +import Data.Text (Text) +import qualified Data.Text as T +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +creole :: Text -> Pandoc +creole = purely $ readCreole def{ readerStandalone = True } + +infix 4 =: +(=:) :: ToString c + => String -> (Text, c) -> TestTree +(=:) = test creole + +tests :: [TestTree] +tests = [ + testGroup "Basic Text Formatting" [ + "bold, single line, fully delimited" =: + "only **bold** is bold" + =?> para ("only " <> strong "bold" <> " is bold") + , "italics, single line, fully delimited" =: + "only //this// is in italics" + =?> para ("only " <> emph "this" <> " is in italics") + , "bold in italics, fully delimited" =: + "//**this**// is in bold italics" + =?> para (emph (strong "this") <> " is in bold italics") + , "italics in bold, fully delimited" =: + "**//this//** is in bold italics" + =?> para (strong (emph "this") <> " is in bold italics") + + , "escape bold marker" =: + "~**not bold" =?> para "**not bold" + , "escape italics marker" =: + "~//not in italics" =?> para "//not in italics" + + , "inline nowiki, simple" =: + "this is {{{**not** ~interpreted}}} at all" + =?> para ("this is " <> code "**not** ~interpreted" <> " at all") + , "inline nowiki, curly braces inside" =: + "this is {{{{{{//including// some `}' chars}}}}}}" + =?> para ("this is " <> code "{{{//including// some `}' chars}}}") + + , "placeholder" =: + "foo <<<place holder>>> bar" + =?> para "foo bar" + , "placeholder escaped" =: + "foo ~<<<no place holder>>> bar" + =?> para "foo <<<no place holder>>> bar" + ] + , testGroup "Headers" [ + "header level 1, no space, no trailing =" =: + "= Top-Level Header" + =?> header 1 (str "Top-Level Header") + , "header level 1, leading space, trailing =" =: + " = Top-Level Header = " + =?> header 1 (str "Top-Level Header") + , "header level 2, no space, no trailing =" =: + "== Second Level" + =?> header 2 (str "Second Level") + , "header level 2, leading space, no trailing =" =: + " == Second Level" + =?> header 2 (str "Second Level") + , "header level 3, no space, no trailing =" =: + "=== Third" + =?> header 3 (str "Third") + , "header level 3, no space, > 3 trailing =" =: + "=== Third =======" + =?> header 3 (str "Third") + , "header level 4, no space, no trailing =" =: + "==== Fourth Level Heading" + =?> header 4 (str "Fourth Level Heading") + , "header level 4, no space, < 4 trailing =" =: + "==== Fourth Level Heading ==" + =?> header 4 (str "Fourth Level Heading") + , "header level 5, no space, no trailing =" =: + "===== Fifth" + =?> header 5 (str "Fifth") + , "header level 6, no space, no trailing =" =: + "====== Sixth" + =?> header 6 (str "Sixth") + ] + , testGroup "Paragraphs" [ + "paragraphs: multiple, one line" =: + "first line\n\nanother line\n" + =?> para "first line" <> para "another line" + ] + , testGroup "Lists" [ + "unordered list, two entries, one separating space" =: + "* foo\n* bar" + =?> bulletList [ plain "foo", plain "bar" ] + , "unordered list, three entries, one separating space" =: + "* foo\n* bar\n* baz" + =?> bulletList [ plain "foo", plain "bar", plain "baz" ] + , "para followed by, unordered list, two entries, one separating space" =: + "blubber\n* foo\n* bar" + =?> para "blubber" <> bulletList [ plain "foo", plain "bar" ] + , "nested unordered list, one separating space" =: + "* foo\n** bar\n** baz\n* blubb" + =?> bulletList [ plain "foo" + <> bulletList [ plain "bar", plain "baz" ] + , plain "blubb" ] + , "nested many unordered lists, one separating space" =: + ("* foo\n** bar\n*** third\n*** third two\n** baz\n*** third again\n" + <> "**** fourth\n***** fith\n* blubb") + =?> bulletList [ plain "foo" + <> bulletList [ plain "bar" + <> bulletList [ plain "third" + , plain "third two"] + , plain "baz" + <> bulletList [ plain "third again" + <> bulletList [ + plain "fourth" + <> bulletList [ + plain "fith" + ] + ] + ] + ] + , plain "blubb" ] + , "nested unordered list, mixed separating space" =: + "*foo\n ** bar\n **baz\n * blubb" + =?> bulletList [ plain "foo" + <> bulletList [ plain "bar", plain "baz" ] + , plain "blubb" ] + , "nested unordered list, one separating space, trailing space" =: + "* foo \n** bar \n** baz \n* blubb " + =?> bulletList [ plain "foo" + <> bulletList [ plain "bar", plain "baz" ] + , plain "blubb" ] + , "ordered list, two entries, one separating space" =: + "# foo\n# bar" + =?> orderedList [ plain "foo", plain "bar" ] + , "ordered list, three entries, one separating space" =: + "# foo\n# bar\n# baz" + =?> orderedList [ plain "foo", plain "bar", plain "baz" ] + , "para followed by, ordered list, two entries, one separating space" =: + "blubber\n# foo\n# bar" + =?> para "blubber" <> orderedList [ plain "foo", plain "bar" ] + , "nested ordered list, one separating space" =: + "# foo\n## bar\n## baz\n# blubb" + =?> orderedList [ plain "foo" + <> orderedList [ plain "bar", plain "baz" ] + , plain "blubb" ] + , "nested ordered list, one separating space, trailing space" =: + "# foo \n## bar \n## baz \n# blubb " + =?> orderedList [ plain "foo" + <> orderedList [ plain "bar", plain "baz" ] + , plain "blubb" ] + , "nested many ordered lists, one separating space" =: + ("# foo\n## bar\n### third\n### third two\n## baz\n### third again\n" + <> "#### fourth\n##### fith\n# blubb") + =?> orderedList [ plain "foo" + <> orderedList [ plain "bar" + <> orderedList [ plain "third" + , plain "third two"] + , plain "baz" + <> orderedList [ plain "third again" + <> orderedList [ + plain "fourth" + <> orderedList [ + plain "fith" + ] + ] + ] + ] + , plain "blubb" ] + , "nested ordered list, mixed separating space" =: + "#foo\n ## bar\n ##baz\n # blubb" + =?> orderedList [ plain "foo" + <> orderedList [ plain "bar", plain "baz" ] + , plain "blubb" ] + , "mixed nested ordered and unordered lists, one separating space" =: + ("# foo\n** bar\n### third\n### third two\n** baz\n### third again\n" + <> "#### fourth\n***** fith\n# blubb") + =?> orderedList [ plain "foo" + <> bulletList [ plain "bar" + <> orderedList [ plain "third" + , plain "third two"] + , plain "baz" + <> orderedList [ plain "third again" + <> orderedList [ + plain "fourth" + <> bulletList [ + plain "fith" + ] + ] + ] + ] + , plain "blubb" ] + ] + , testGroup "NoWiki" [ + "quoted block, simple" =: + "{{{\nfoo bar\n //baz//\n}}}" + =?> codeBlock "foo bar\n //baz//" + , "quoted block, curly bracket exception" =: + "{{{\nfoo bar\n }}}\nbaz\n }}}\n}}}" + =?> codeBlock "foo bar\n }}}\nbaz\n}}}" + , "forced line breaks" =: + "{{{no break!\\\\here}}} but a break\\\\here!" + =?> para (code "no break!\\\\here" <> " but a break" + <> linebreak <> "here!"), + "quoted block, after trailing white space" =: + "this is a paragraph \n{{{\nfoo bar\n //baz//\n}}}" + =?> para "this is a paragraph" <> codeBlock "foo bar\n //baz//" + ] + , testGroup "Images and Links" [ + "image simple" =: + "{{foo.png}}" =?> para (image "foo.png" "" (str "")) + , "image with alt text" =: + "Image of a bar: {{/path/to/bar.png|A Bar}} look at it!" + =?> para ("Image of a bar: " + <> image "/path/to/bar.png" "" (str "A Bar") <> " look at it!") + + , "auto link" =: + "foo http://foo.example.com/bar/baz.html bar" + =?> para ("foo " + <> link "http://foo.example.com/bar/baz.html" "" + (str "http://foo.example.com/bar/baz.html") + <> " bar") + , "escaped auto link" =: + "foo ~http://foo.example.com/bar/baz.html bar" + =?> para "foo http://foo.example.com/bar/baz.html bar" + , "wiki link simple" =: + "foo [[http://foo.example.com/foo.png]] bar" + =?> para ("foo " + <> link "http://foo.example.com/foo.png" "" + (str "http://foo.example.com/foo.png") + <> " bar") + , "wiki link with name" =: + "foo [[http://foo.example.com/foo.png|my link]] bar" + =?> para ("foo " + <> link "http://foo.example.com/foo.png" "" + (str "my link") + <> " bar") + , "image link" =: + "[[http://foo.example.com/|{{foo.png}}]]" + =?> para (link "http://foo.example.com/" "" (image "foo.png" "" (str ""))) + ] + , testGroup "Table" [ + "Table with Header" =: + T.unlines [ "|= Foo |= Bar |= Baz |" + , "| One | Two | Three |" + , "| 1 | 2 | 3 |" + , "| A | B | C |" + ] + =?> simpleTable + [plain "Foo", plain "Bar" , plain "Baz"] + [[plain "One", plain "Two" , plain "Three"] + ,[plain "1", plain "2" , plain "3"] + ,[plain "A", plain "B" , plain "C"]] + , "Table without Header" =: + T.unlines [ "| One | Two | Three |" + , "| 1 | 2 | 3 |" + , "| A | B | C |" + ] + =?> simpleTable [mempty] + [[plain "One", plain "Two" , plain "Three"] + ,[plain "1", plain "2" , plain "3"] + ,[plain "A", plain "B" , plain "C"]] + , "Table without Header, no markers at line ends" =: + T.unlines [ "| One | Two | Three" + , "| 1 | 2 | 3" + , "| A | B | C " + ] + =?> simpleTable [mempty] + [[plain "One", plain "Two" , plain "Three"] + ,[plain "1", plain "2" , plain "3"] + ,[plain "A", plain "B" , plain "C"]] + , "Table with Header, with formatting" =: + T.unlines [ "|= **Foo** |= **Bar** |= **Baz** |" + , "|//one// element |//second// elt|Three |" + , "| {{{1}}} | {{{{}}}} | [[link]] |" + ] + =?> simpleTable + [plain $ strong "Foo", plain $ strong "Bar" , plain $ strong "Baz"] + [[plain (emph "one" <> " element"), plain (emph "second" <> " elt") + ,plain "Three"] + ,[plain $ code "1", plain $ code "{}" + ,plain $ link "link" "" (str "link")]] + ] + ] diff --git a/test/Tests/Readers/Docx.hs b/test/Tests/Readers/Docx.hs index 4f2ad524a..a02e1f35a 100644 --- a/test/Tests/Readers/Docx.hs +++ b/test/Tests/Readers/Docx.hs @@ -291,6 +291,10 @@ tests = [ testGroup "inlines" "docx/codeblock.docx" "docx/codeblock.native" , testCompare + "combine adjacent code blocks" + "docx/adjacent_codeblocks.docx" + "docx/adjacent_codeblocks.native" + , testCompare "dropcap paragraphs" "docx/drop_cap.docx" "docx/drop_cap.native" diff --git a/test/Tests/Readers/Docx.hs.orig b/test/Tests/Readers/Docx.hs.orig new file mode 100644 index 000000000..9bbe85cba --- /dev/null +++ b/test/Tests/Readers/Docx.hs.orig @@ -0,0 +1,405 @@ +module Tests.Readers.Docx (tests) where + +import Codec.Archive.Zip +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as B +import qualified Data.Map as M +import qualified Data.Text as T +import Data.Maybe +import System.IO.Unsafe +import Test.Tasty +import Test.Tasty.HUnit +import Tests.Helpers +import Text.Pandoc +import qualified Text.Pandoc.Class as P +import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory) +import Text.Pandoc.UTF8 as UTF8 + +-- We define a wrapper around pandoc that doesn't normalize in the +-- tests. Since we do our own normalization, we want to make sure +-- we're doing it right. + +data NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc} + deriving Show + +noNorm :: Pandoc -> NoNormPandoc +noNorm = NoNormPandoc + +defopts :: ReaderOptions +defopts = def{ readerExtensions = getDefaultExtensions "docx" } + +instance ToString NoNormPandoc where + toString d = T.unpack $ purely (writeNative def{ writerTemplate = s }) $ toPandoc d + where s = case d of + NoNormPandoc (Pandoc (Meta m) _) + | M.null m -> Nothing + | otherwise -> Just "" -- need this to get meta output + +instance ToPandoc NoNormPandoc where + toPandoc = unNoNorm + +compareOutput :: ReaderOptions + -> FilePath + -> FilePath + -> IO (NoNormPandoc, NoNormPandoc) +compareOutput opts docxFile nativeFile = do + df <- B.readFile docxFile + nf <- UTF8.toText <$> BS.readFile nativeFile + p <- runIOorExplode $ readDocx opts df + df' <- runIOorExplode $ readNative def nf + return (noNorm p, noNorm df') + +testCompareWithOptsIO :: ReaderOptions -> String -> FilePath -> FilePath -> IO TestTree +testCompareWithOptsIO opts name docxFile nativeFile = do + (dp, np) <- compareOutput opts docxFile nativeFile + return $ test id name (dp, np) + +testCompareWithOpts :: ReaderOptions -> String -> FilePath -> FilePath -> TestTree +testCompareWithOpts opts name docxFile nativeFile = + unsafePerformIO $ testCompareWithOptsIO opts name docxFile nativeFile + +testCompare :: String -> FilePath -> FilePath -> TestTree +testCompare = testCompareWithOpts defopts + +testForWarningsWithOptsIO :: ReaderOptions -> String -> FilePath -> [String] -> IO TestTree +testForWarningsWithOptsIO opts name docxFile expected = do + df <- B.readFile docxFile + logs <- runIOorExplode $ setVerbosity ERROR >> readDocx opts df >> P.getLog + let warns = [m | DocxParserWarning m <- logs] + return $ test id name (unlines warns, unlines expected) + +testForWarningsWithOpts :: ReaderOptions -> String -> FilePath -> [String] -> TestTree +testForWarningsWithOpts opts name docxFile expected = + unsafePerformIO $ testForWarningsWithOptsIO opts name docxFile expected + +-- testForWarnings :: String -> FilePath -> [String] -> TestTree +-- testForWarnings = testForWarningsWithOpts defopts + +getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString) +getMedia archivePath mediaPath = do + zf <- B.readFile archivePath >>= return . toArchive + return $ findEntryByPath ("word/" ++ mediaPath) zf >>= (Just . fromEntry) + +compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool +compareMediaPathIO mediaPath mediaBag docxPath = do + docxMedia <- getMedia docxPath mediaPath + let mbBS = case lookupMedia mediaPath mediaBag of + Just (_, bs) -> bs + Nothing -> error ("couldn't find " ++ + mediaPath ++ + " in media bag") + docxBS = fromMaybe (error ("couldn't find " ++ + mediaPath ++ + " in media bag")) docxMedia + return $ mbBS == docxBS + +compareMediaBagIO :: FilePath -> IO Bool +compareMediaBagIO docxFile = do + df <- B.readFile docxFile + mb <- runIOorExplode $ readDocx defopts df >> P.getMediaBag + bools <- mapM + (\(fp, _, _) -> compareMediaPathIO fp mb docxFile) + (mediaDirectory mb) + return $ and bools + +testMediaBagIO :: String -> FilePath -> IO TestTree +testMediaBagIO name docxFile = do + outcome <- compareMediaBagIO docxFile + return $ testCase name (assertBool + ("Media didn't match media bag in file " ++ docxFile) + outcome) + +testMediaBag :: String -> FilePath -> TestTree +testMediaBag name docxFile = unsafePerformIO $ testMediaBagIO name docxFile + +tests :: [TestTree] +tests = [ testGroup "inlines" + [ testCompare + "font formatting" + "docx/inline_formatting.docx" + "docx/inline_formatting.native" + , testCompare + "font formatting with character styles" + "docx/char_styles.docx" + "docx/char_styles.native" + , testCompare + "hyperlinks" + "docx/links.docx" + "docx/links.native" + , testCompare + "hyperlinks in <w:instrText> tag" + "docx/instrText_hyperlink.docx" + "docx/instrText_hyperlink.native" + , testCompare + "inline image" + "docx/image.docx" + "docx/image_no_embed.native" + , testCompare + "VML image" + "docx/image_vml.docx" + "docx/image_vml.native" + , testCompare + "inline image in links" + "docx/inline_images.docx" + "docx/inline_images.native" + , testCompare + "handling unicode input" + "docx/unicode.docx" + "docx/unicode.native" + , testCompare + "literal tabs" + "docx/tabs.docx" + "docx/tabs.native" + , testCompare + "special punctuation" + "docx/special_punctuation.docx" + "docx/special_punctuation.native" + , testCompare + "normalizing inlines" + "docx/normalize.docx" + "docx/normalize.native" + , testCompare + "normalizing inlines deep inside blocks" + "docx/deep_normalize.docx" + "docx/deep_normalize.native" + , testCompare + "move trailing spaces outside of formatting" + "docx/trailing_spaces_in_formatting.docx" + "docx/trailing_spaces_in_formatting.native" + , testCompare + "inline code (with VerbatimChar style)" + "docx/inline_code.docx" + "docx/inline_code.native" + , testCompare + "inline code in subscript and superscript" + "docx/verbatim_subsuper.docx" + "docx/verbatim_subsuper.native" + , testCompare + "inlines inside of Structured Document Tags" + "docx/sdt_elements.docx" + "docx/sdt_elements.native" + , testCompare + "nested Structured Document Tags" + "docx/nested_sdt.docx" + "docx/nested_sdt.native" + , testCompare + "nested Smart Tags" + "docx/nested_smart_tags.docx" + "docx/nested_smart_tags.native" + , testCompare + "remove anchor spans with nothing pointing to them" + "docx/unused_anchors.docx" + "docx/unused_anchors.native" + , testCompare + "collapse overlapping targets (anchor spans)" + "docx/overlapping_targets.docx" + "docx/overlapping_targets.native" + ] + , testGroup "blocks" + [ testCompare + "headers" + "docx/headers.docx" + "docx/headers.native" + , testCompare + "headers already having auto identifiers" + "docx/already_auto_ident.docx" + "docx/already_auto_ident.native" + , testCompare + "avoid zero-level headers" + "docx/0_level_headers.docx" + "docx/0_level_headers.native" + , testCompare + "nested anchor spans in header" + "docx/nested_anchors_in_header.docx" + "docx/nested_anchors_in_header.native" + , testCompare + "single numbered item not made into list" + "docx/numbered_header.docx" + "docx/numbered_header.native" + , testCompare + "enumerated headers not made into numbered list" + "docx/enumerated_headings.docx" + "docx/enumerated_headings.native" + , testCompare + "i18n blocks (headers and blockquotes)" + "docx/i18n_blocks.docx" + "docx/i18n_blocks.native" + , testCompare + "lists" + "docx/lists.docx" + "docx/lists.native" + , testCompare + "lists continuing after interruption" + "docx/lists_continuing.docx" + "docx/lists_continuing.native" + , testCompare + "lists restarting after interruption" + "docx/lists_restarting.docx" + "docx/lists_restarting.native" + , testCompare + "definition lists" + "docx/definition_list.docx" + "docx/definition_list.native" + , testCompare + "custom defined lists in styles" + "docx/german_styled_lists.docx" + "docx/german_styled_lists.native" + , testCompare + "user deletes bullet after list item (=> part of item par)" + "docx/dummy_item_after_list_item.docx" + "docx/dummy_item_after_list_item.native" + , testCompare + "user deletes bullet after par (=> new par)" + "docx/dummy_item_after_paragraph.docx" + "docx/dummy_item_after_paragraph.native" + , testCompare + "footnotes and endnotes" + "docx/notes.docx" + "docx/notes.native" + , testCompare + "links in footnotes and endnotes" + "docx/link_in_notes.docx" + "docx/link_in_notes.native" + , testCompare + "blockquotes (parsing indent as blockquote)" + "docx/block_quotes.docx" + "docx/block_quotes_parse_indent.native" + , testCompare + "hanging indents" + "docx/hanging_indent.docx" + "docx/hanging_indent.native" + , testCompare + "tables" + "docx/tables.docx" + "docx/tables.native" + , testCompare + "tables with lists in cells" + "docx/table_with_list_cell.docx" + "docx/table_with_list_cell.native" + , testCompare + "tables with one row" + "docx/table_one_row.docx" + "docx/table_one_row.native" + , testCompare + "tables with variable width" + "docx/table_variable_width.docx" + "docx/table_variable_width.native" + , testCompare + "code block" + "docx/codeblock.docx" + "docx/codeblock.native" + , testCompare + "dropcap paragraphs" + "docx/drop_cap.docx" + "docx/drop_cap.native" + ] + , testGroup "track changes" + [ testCompare + "insertion (default)" + "docx/track_changes_insertion.docx" + "docx/track_changes_insertion_accept.native" + , testCompareWithOpts def{readerTrackChanges=AcceptChanges} + "insert insertion (accept)" + "docx/track_changes_insertion.docx" + "docx/track_changes_insertion_accept.native" + , testCompareWithOpts def{readerTrackChanges=RejectChanges} + "remove insertion (reject)" + "docx/track_changes_insertion.docx" + "docx/track_changes_insertion_reject.native" + , testCompare + "deletion (default)" + "docx/track_changes_deletion.docx" + "docx/track_changes_deletion_accept.native" + , testCompareWithOpts def{readerTrackChanges=AcceptChanges} + "remove deletion (accept)" + "docx/track_changes_deletion.docx" + "docx/track_changes_deletion_accept.native" + , testCompareWithOpts def{readerTrackChanges=RejectChanges} + "insert deletion (reject)" + "docx/track_changes_deletion.docx" + "docx/track_changes_deletion_reject.native" + , testCompareWithOpts def{readerTrackChanges=AllChanges} + "keep insertion (all)" + "docx/track_changes_deletion.docx" + "docx/track_changes_deletion_all.native" + , testCompareWithOpts def{readerTrackChanges=AllChanges} + "keep deletion (all)" + "docx/track_changes_deletion.docx" + "docx/track_changes_deletion_all.native" + , testCompareWithOpts def{readerTrackChanges=AcceptChanges} + "move text (accept)" + "docx/track_changes_move.docx" + "docx/track_changes_move_accept.native" + , testCompareWithOpts def{readerTrackChanges=RejectChanges} + "move text (reject)" + "docx/track_changes_move.docx" + "docx/track_changes_move_reject.native" + , testCompareWithOpts def{readerTrackChanges=AllChanges} + "move text (all)" + "docx/track_changes_move.docx" + "docx/track_changes_move_all.native" + , testCompareWithOpts def{readerTrackChanges=AcceptChanges} + "comments (accept -- no comments)" + "docx/comments.docx" + "docx/comments_no_comments.native" + , testCompareWithOpts def{readerTrackChanges=RejectChanges} + "comments (reject -- comments)" + "docx/comments.docx" + "docx/comments_no_comments.native" + , testCompareWithOpts def{readerTrackChanges=AllChanges} + "comments (all comments)" + "docx/comments.docx" + "docx/comments.native" + , testCompareWithOpts def{readerTrackChanges=AcceptChanges} + "paragraph insertion/deletion (accept)" + "docx/paragraph_insertion_deletion.docx" + "docx/paragraph_insertion_deletion_accept.native" + , testCompareWithOpts def{readerTrackChanges=RejectChanges} + "paragraph insertion/deletion (reject)" + "docx/paragraph_insertion_deletion.docx" + "docx/paragraph_insertion_deletion_reject.native" + , testCompareWithOpts def{readerTrackChanges=AllChanges} + "paragraph insertion/deletion (all)" + "docx/paragraph_insertion_deletion.docx" + "docx/paragraph_insertion_deletion_all.native" + , testForWarningsWithOpts def{readerTrackChanges=AcceptChanges} + "comment warnings (accept -- no warnings)" + "docx/comments_warning.docx" + [] + , testForWarningsWithOpts def{readerTrackChanges=RejectChanges} + "comment warnings (reject -- no warnings)" + "docx/comments_warning.docx" + [] + , testForWarningsWithOpts def{readerTrackChanges=AllChanges} + "comment warnings (all)" + "docx/comments_warning.docx" + ["Docx comment 1 will not retain formatting"] + ] + , testGroup "media" + [ testMediaBag + "image extraction" + "docx/image.docx" + ] + , testGroup "custom styles" + [ testCompare + "custom styles (`+styles`) not enabled (default)" + "docx/custom-style-reference.docx" + "docx/custom-style-no-styles.native" + , testCompareWithOpts + def{readerExtensions=extensionsFromList [Ext_styles]} + "custom styles (`+styles`) enabled" + "docx/custom-style-reference.docx" + "docx/custom-style-with-styles.native" + ] + , testGroup "metadata" + [ testCompareWithOpts def{readerStandalone=True} + "metadata fields" + "docx/metadata.docx" + "docx/metadata.native" + , testCompareWithOpts def{readerStandalone=True} + "stop recording metadata with normal text" + "docx/metadata_after_normal.docx" + "docx/metadata_after_normal.native" + ] + + ] diff --git a/test/Tests/Readers/EPUB.hs.orig b/test/Tests/Readers/EPUB.hs.orig new file mode 100644 index 000000000..1337a9c11 --- /dev/null +++ b/test/Tests/Readers/EPUB.hs.orig @@ -0,0 +1,40 @@ +module Tests.Readers.EPUB (tests) where + +import qualified Data.ByteString.Lazy as BL +import Test.Tasty +import Test.Tasty.HUnit +import qualified Text.Pandoc.Class as P +import Text.Pandoc.MediaBag (MediaBag, mediaDirectory) +import Text.Pandoc.Options +import Text.Pandoc.Readers.EPUB + +getMediaBag :: FilePath -> IO MediaBag +getMediaBag fp = do + bs <- BL.readFile fp + P.runIOorExplode $ do + readEPUB def bs + P.getMediaBag + +testMediaBag :: FilePath -> [(String, String, Int)] -> IO () +testMediaBag fp bag = do + actBag <- mediaDirectory <$> getMediaBag fp + assertBool (show "MediaBag did not match:\nExpected: " + ++ show bag + ++ "\nActual: " + ++ show actBag) + (actBag == bag) + +featuresBag :: [(String, String, Int)] +featuresBag = [("img/check.gif","image/gif",1340) + ,("img/check.jpg","image/jpeg",2661) + ,("img/check.png","image/png",2815) + ,("img/multiscripts_and_greek_alphabet.png","image/png",10060) + ] + +tests :: [TestTree] +tests = + [ testGroup "EPUB Mediabag" + [ testCase "features bag" + (testMediaBag "epub/img.epub" featuresBag) + ] + ] diff --git a/test/Tests/Readers/HTML.hs.orig b/test/Tests/Readers/HTML.hs.orig new file mode 100644 index 000000000..70f33d2b2 --- /dev/null +++ b/test/Tests/Readers/HTML.hs.orig @@ -0,0 +1,54 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.HTML (tests) where + +import Data.Text (Text) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +html :: Text -> Pandoc +html = purely $ readHtml def + +htmlNativeDivs :: Text -> Pandoc +htmlNativeDivs = purely $ readHtml def { readerExtensions = enableExtension Ext_native_divs $ readerExtensions def } + +tests :: [TestTree] +tests = [ testGroup "base tag" + [ test html "simple" $ + "<head><base href=\"http://www.w3schools.com/images/foo\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?> + plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman")) + , test html "slash at end of base" $ + "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?> + plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman")) + , test html "slash at beginning of href" $ + "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"/stickman.gif\" alt=\"Stickman\"></head>" =?> + plain (image "http://www.w3schools.com/stickman.gif" "" (text "Stickman")) + , test html "absolute URL" $ + "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"http://example.com/stickman.gif\" alt=\"Stickman\"></head>" =?> + plain (image "http://example.com/stickman.gif" "" (text "Stickman")) + ] + , testGroup "anchors" + [ test html "anchor without href" $ "<a name=\"anchor\"/>" =?> + plain (spanWith ("anchor",[],[]) mempty) + ] + , testGroup "lang" + [ test html "lang on <html>" $ "<html lang=\"es\">hola" =?> + setMeta "lang" (text "es") (doc (plain (text "hola"))) + , test html "xml:lang on <html>" $ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"es\"><head></head><body>hola</body></html>" =?> + setMeta "lang" (text "es") (doc (plain (text "hola"))) + ] + , testGroup "main" + [ test htmlNativeDivs "<main> becomes <div role=main>" $ "<main>hello</main>" =?> + doc (divWith ("", [], [("role", "main")]) (plain (text "hello"))) + , test htmlNativeDivs "<main role=X> becomes <div role=X>" $ "<main role=foobar>hello</main>" =?> + doc (divWith ("", [], [("role", "foobar")]) (plain (text "hello"))) + , test htmlNativeDivs "<main> has attributes preserved" $ "<main id=foo class=bar data-baz=qux>hello</main>" =?> + doc (divWith ("foo", ["bar"], [("role", "main"), ("data-baz", "qux")]) (plain (text "hello"))) + , test htmlNativeDivs "<main> closes <p>" $ "<p>hello<main>main content</main>" =?> + doc (para (text "hello") <> divWith ("", [], [("role", "main")]) (plain (text "main content"))) + , test htmlNativeDivs "<main> followed by text" $ "<main>main content</main>non-main content" =?> + doc (divWith ("", [], [("role", "main")]) (plain (text "main content")) <> plain (text "non-main content")) + ] + ] diff --git a/test/Tests/Readers/JATS.hs.orig b/test/Tests/Readers/JATS.hs.orig new file mode 100644 index 000000000..5c7dfa77c --- /dev/null +++ b/test/Tests/Readers/JATS.hs.orig @@ -0,0 +1,116 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.JATS (tests) where + +import Data.Text (Text) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +jats :: Text -> Pandoc +jats = purely $ readJATS def + +tests :: [TestTree] +tests = [ testGroup "inline code" + [ test jats "basic" $ "<p>\n <monospace>@&</monospace>\n</p>" =?> para (code "@&") + , test jats "lang" $ "<p>\n <code language=\"c\">@&</code>\n</p>" =?> para (codeWith ("", ["c"], []) "@&") + ] + , testGroup "block code" + [ test jats "basic" $ "<preformat>@&</preformat>" =?> codeBlock "@&" + , test jats "lang" $ "<code language=\"c\">@&</code>" =?> codeBlockWith ("", ["c"], []) "@&" + ] + , testGroup "images" + [ test jats "basic" $ "<graphic mimetype=\"image\" mime-subtype=\"\" xlink:href=\"/url\" xlink:title=\"title\" />" + =?> para (image "/url" "title" mempty) + ] + , test jats "bullet list" $ + "<list list-type=\"bullet\">\n\ + \ <list-item>\n\ + \ <p>\n\ + \ first\n\ + \ </p>\n\ + \ </list-item>\n\ + \ <list-item>\n\ + \ <p>\n\ + \ second\n\ + \ </p>\n\ + \ </list-item>\n\ + \ <list-item>\n\ + \ <p>\n\ + \ third\n\ + \ </p>\n\ + \ </list-item>\n\ + \</list>" + =?> bulletList [ para $ text "first" + , para $ text "second" + , para $ text "third" + ] + , testGroup "definition lists" + [ test jats "with internal link" $ + "<def-list>\n\ + \ <def-item>\n\ + \ <term>\n\ + \ <xref alt=\"testing\" rid=\"go\">testing</xref>\n\ + \ </term>\n\ + \ <def>\n\ + \ <p>\n\ + \ hi there\n\ + \ </p>\n\ + \ </def>\n\ + \ </def-item>\n\ + \</def-list>" + =?> definitionList [(link "#go" "" (str "testing"), + [para (text "hi there")])] + ] + , testGroup "math" + [ test jats "escape |" $ + "<p>\n\ + \ <inline-formula><alternatives>\n\ + \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\ + \ <mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>\n\ + \</p>" + =?> para (math "\\sigma|_{\\{x\\}}") + , test jats "tex-math only" $ + "<p>\n\ + \ <inline-formula><alternatives>\n\ + \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\ + \</p>" + =?> para (math "\\sigma|_{\\{x\\}}") + , test jats "math ml only" $ + "<p>\n\ + \ <inline-formula><alternatives>\n\ + \ <mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>\n\ + \</p>" + =?> para (math "\\sigma|_{\\{ x\\}}") + ] + , testGroup "headers" +-- TODO fix footnotes in headers +-- [ test jats "unnumbered header" $ +-- "<sec>\n\ +-- \ <title>Header 1<fn>\n\ +-- \ <p>\n\ +-- \ note\n\ +-- \ </p>\n\ +-- \ </fn></title>\n\ +-- \</sec>" +-- =?> header 1 +-- (text "Header 1" <> note (plain $ text "note")) + [ test jats "unnumbered sub header" $ + "<sec id=\"foo\">\n\ + \ <title>Header</title>\n\ + \ <sec id=\"foo2\">\n\ + \ <title>Sub-Header</title>\n\ + \ </sec>\n\ + \</sec>" + =?> headerWith ("foo", [], []) 1 + (text "Header") + <> headerWith ("foo2", [], []) 2 + (text "Sub-Header") + , test jats "containing image" $ + "<sec>\n\ + \ <title><inline-graphic mimetype=\"image\" mime-subtype=\"jpeg\" xlink:href=\"imgs/foo.jpg\" /></title>\n\ + \</sec>" + =?> header 1 (image "imgs/foo.jpg" "" mempty) + ] + ] diff --git a/test/Tests/Readers/LaTeX.hs.orig b/test/Tests/Readers/LaTeX.hs.orig new file mode 100644 index 000000000..4396d550f --- /dev/null +++ b/test/Tests/Readers/LaTeX.hs.orig @@ -0,0 +1,341 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.LaTeX (tests) where + +import Data.Text (Text) +import qualified Data.Text as T +import qualified Text.Pandoc.UTF8 as UTF8 +import Text.Pandoc.Readers.LaTeX (tokenize, untokenize) +import Test.Tasty +import Test.Tasty.HUnit +import Test.Tasty.QuickCheck +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +latex :: Text -> Pandoc +latex = purely $ readLaTeX def{ + readerExtensions = getDefaultExtensions "latex" } + +infix 4 =: +(=:) :: ToString c + => String -> (Text, c) -> TestTree +(=:) = test latex + +simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks +simpleTable' aligns = table "" (zip aligns (repeat 0.0)) + (map (const mempty) aligns) + +tokUntokRt :: String -> Bool +tokUntokRt s = untokenize (tokenize "random" t) == t + where t = T.pack s + +tests :: [TestTree] +tests = [ testGroup "tokenization" + [ testCase "tokenizer round trip on test case" $ do + orig <- T.pack <$> UTF8.readFile "../test/latex-reader.latex" + let new = untokenize $ tokenize "../test/latex-reader.latex" + orig + assertEqual "untokenize . tokenize is identity" orig new + , testProperty "untokenize . tokenize is identity" tokUntokRt + ] + + , testGroup "basic" + [ "simple" =: + "word" =?> para "word" + , "space" =: + "some text" =?> para "some text" + , "emphasized" =: + "\\emph{emphasized}" =?> para (emph "emphasized") + ] + + , testGroup "headers" + [ "level 1" =: + "\\section{header}" =?> headerWith ("header",[],[]) 1 "header" + , "level 2" =: + "\\subsection{header}" =?> headerWith ("header",[],[]) 2 "header" + , "level 3" =: + "\\subsubsection{header}" =?> headerWith ("header",[],[]) 3 "header" + , "emph" =: + "\\section{text \\emph{emph}}" =?> + headerWith ("text-emph",[],[]) 1 ("text" <> space <> emph "emph") + , "link" =: + "\\section{text \\href{/url}{link}}" =?> + headerWith ("text-link",[],[]) 1 ("text" <> space <> link "/url" "" "link") + ] + + , testGroup "math" + [ "escaped $" =: + "$x=\\$4$" =?> para (math "x=\\$4") + ] + + , testGroup "space and comments" + [ "blank lines + space at beginning" =: + "\n \n hi" =?> para "hi" + , "blank lines + space + comments" =: + "% my comment\n\n \n % another\n\nhi" =?> para "hi" + , "comment in paragraph" =: + "hi % this is a comment\nthere\n" =?> + para ("hi" <> softbreak <> "there") + ] + + , testGroup "code blocks" + [ "identifier" =: + "\\begin{lstlisting}[label=test]\\end{lstlisting}" =?> codeBlockWith ("test", [], [("label","test")]) "" + , "no identifier" =: + "\\begin{lstlisting}\\end{lstlisting}" =?> codeBlock "" + ] + + , testGroup "tables" + [ "Single cell table" =: + "\\begin{tabular}{|l|}Test\\\\\\end{tabular}" =?> + simpleTable' [AlignLeft] [[plain "Test"]] + , "Multi cell table" =: + "\\begin{tabular}{|rl|}One & Two\\\\ \\end{tabular}" =?> + simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]] + , "Multi line table" =: + T.unlines [ "\\begin{tabular}{|c|}" + , "One\\\\" + , "Two\\\\" + , "Three\\\\" + , "\\end{tabular}" ] =?> + simpleTable' [AlignCenter] + [[plain "One"], [plain "Two"], [plain "Three"]] + , "Empty table" =: + "\\begin{tabular}{}\\end{tabular}" =?> + simpleTable' [] [] + , "Table with fixed column width" =: + "\\begin{tabular}{|p{5cm}r|}One & Two\\\\ \\end{tabular}" =?> + simpleTable' [AlignLeft,AlignRight] [[plain "One", plain "Two"]] + , "Table with empty column separators" =: + "\\begin{tabular}{@{}r@{}l}One & Two\\\\ \\end{tabular}" =?> + simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]] + , "Table with custom column separators" =: + T.unlines [ "\\begin{tabular}{@{($\\to$)}r@{\\hspace{2cm}}l}" + , "One&Two\\\\" + , "\\end{tabular}" ] =?> + simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]] + , "Table with vertical alignment argument" =: + "\\begin{tabular}[t]{r|r}One & Two\\\\ \\end{tabular}" =?> + simpleTable' [AlignRight,AlignRight] [[plain "One", plain "Two"]] + ] + + , testGroup "citations" + [ natbibCitations + , biblatexCitations + ] + + , testGroup "images" + [ "Basic image" =: + "\\includegraphics{foo.png}" =?> + para (image "foo.png" "" (text "image")) + , "Basic image with blank options" =: + "\\includegraphics[]{foo.png}" =?> + para (image "foo.png" "" (text "image")) + , "Image with both width and height" =: + "\\includegraphics[width=17cm,height=5cm]{foo.png}" =?> + para (imageWith ("", [], [("width", "17cm"), ("height", "5cm")]) "foo.png" "" "image") + , "Image with width and height and a bunch of other options" =: + "\\includegraphics[width=17cm,height=5cm,clip,keepaspectratio]{foo.png}" =?> + para (imageWith ("", [], [("width", "17cm"), ("height", "5cm")]) "foo.png" "" "image") + , "Image with just width" =: + "\\includegraphics[width=17cm]{foo.png}" =?> + para (imageWith ("", [], [("width", "17cm")]) "foo.png" "" "image") + , "Image with just height" =: + "\\includegraphics[height=17cm]{foo.png}" =?> + para (imageWith ("", [], [("height", "17cm")]) "foo.png" "" "image") + , "Image width relative to textsize" =: + "\\includegraphics[width=0.6\\textwidth]{foo.png}" =?> + para (imageWith ("", [], [("width", "60%")]) "foo.png" "" "image") + , "Image with options with spaces" =: + "\\includegraphics[width=12cm, height = 5cm]{foo.png}" =?> + para (imageWith ("", [], [("width", "12cm"), ("height", "5cm")]) "foo.png" "" "image") + ] + + , let hex = ['0'..'9']++['a'..'f'] in + testGroup "Character Escapes" + [ "Two-character escapes" =: + mconcat ["^^" <> T.pack [i,j] | i <- hex, j <- hex] =?> + para (str ['\0'..'\255']) + , "One-character escapes" =: + mconcat ["^^" <> T.pack [i] | i <- hex] =?> + para (str $ ['p'..'y']++['!'..'&']) + ] + , testGroup "memoir scene breaks" + [ "plainbreak" =: + "hello\\plainbreak{2}goodbye" =?> + para (str "hello") <> horizontalRule <> para (str "goodbye") + , "plainbreak*" =: + "hello\\plainbreak*{2}goodbye" =?> + para (str "hello") <> horizontalRule <> para (str "goodbye") + , "fancybreak" =: + "hello\\fancybreak{b r e a k}goodbye" =?> + para (str "hello") <> horizontalRule <> para (str "goodbye") + , "fancybreak*" =: + "hello\\fancybreak*{b r e a k}goodbye" =?> + para (str "hello") <> horizontalRule <> para (str "goodbye") + , "plainfancybreak" =: + "hello\\plainfancybreak{4}{2}{b r e a k}goodbye" =?> + para (str "hello") <> horizontalRule <> para (str "goodbye") + , "plainfancybreak*" =: + "hello\\plainfancybreak*{4}{2}{b r e a k}goodbye" =?> + para (str "hello") <> horizontalRule <> para (str "goodbye") + , "pfbreak" =: + "hello\\pfbreak{}goodbye" =?> + para (str "hello") <> horizontalRule <> para (str "goodbye") + , "pfbreak*" =: + "hello\\pfbreak*{}goodbye" =?> + para (str "hello") <> horizontalRule <> para (str "goodbye") + ] + , testGroup "biblatex roman numerals" + [ "upper" =: + "number \\RN{12}" =?> + para (str "number" <> space <> str "XII") + , "lower" =: + "number \\Rn{29}" =?> + para (str "number" <> space <> str "xxix") + , "leading zero" =: + "\\Rn{014}" =?> + para (str "xiv") + , "surrounding spaces" =: + "number \\Rn{ 41 }" =?> + para (str "number" <> space <> str "xli") + , "zero" =: + "\\RN{0}" =?> + para (str "") + , "space then unbraced argument" =: + "\\RN 7 ok" =?> + para (str "VII" <> space <> str "ok") + , "space before braced argument" =: + "\\Rn {13}ok" =?> + para (str "xiiiok") + ] + , testGroup "polyglossia language spans" + [ "french" =: + "hello \\textfrench{bonjour}" =?> + para (str "hello" <> space <> spanWith ("", [], [("lang", "fr")]) (str "bonjour")) + , "nested" =: + "\\textfrench{quelle c'est \\textlatin{primus}?}" =?> + para (spanWith ("", [], [("lang", "fr")]) $ + str "quelle" <> space <> str "c\8217est" <> space <> + spanWith ("", [], [("lang", "la")]) (str "primus") <> str "?") + , "with formatting" =: + "\\textgerman{wie \\emph{spaet} ist es?}" =?> + para (spanWith ("", [], [("lang", "de")]) $ + str "wie" <> space <> emph (str "spaet") <> space <> str "ist" <> space <> str "es?") + , "language options" =: + "\\textgerman[variant=swiss]{hoechdeutsche}" =?> + para (spanWith ("", [], [("lang", "de-CH")]) $ str "hoechdeutsche") + , "unknown option fallback" =: + "\\textgerman[variant=moon]{ueberhoechdeutsche}" =?> + para (spanWith ("", [], [("lang", "de")]) $ str "ueberhoechdeutsche") + ] + ] + +baseCitation :: Citation +baseCitation = Citation{ citationId = "item1" + , citationPrefix = [] + , citationSuffix = [] + , citationMode = AuthorInText + , citationNoteNum = 0 + , citationHash = 0 + } + +rt :: String -> Inlines +rt = rawInline "latex" + +natbibCitations :: TestTree +natbibCitations = testGroup "natbib" + [ "citet" =: "\\citet{item1}" + =?> para (cite [baseCitation] (rt "\\citet{item1}")) + , "suffix" =: "\\citet[p.~30]{item1}" + =?> para + (cite [baseCitation{ citationSuffix = toList $ text "p.\160\&30" }] (rt "\\citet[p.~30]{item1}")) + , "suffix long" =: "\\citet[p.~30, with suffix]{item1}" + =?> para (cite [baseCitation{ citationSuffix = + toList $ text "p.\160\&30, with suffix" }] (rt "\\citet[p.~30, with suffix]{item1}")) + , "multiple" =: "\\citeauthor{item1} \\citetext{\\citeyear{item1}; \\citeyear[p.~30]{item2}; \\citealp[see also][]{item3}}" + =?> para (cite [baseCitation{ citationMode = AuthorInText } + ,baseCitation{ citationMode = SuppressAuthor + , citationSuffix = [Str "p.\160\&30"] + , citationId = "item2" } + ,baseCitation{ citationId = "item3" + , citationPrefix = [Str "see",Space,Str "also"] + , citationMode = NormalCitation } + ] (rt "\\citetext{\\citeyear{item1}; \\citeyear[p.~30]{item2}; \\citealp[see also][]{item3}}")) + , "group" =: "\\citetext{\\citealp[see][p.~34--35]{item1}; \\citealp[also][chap. 3]{item3}}" + =?> para (cite [baseCitation{ citationMode = NormalCitation + , citationPrefix = [Str "see"] + , citationSuffix = [Str "p.\160\&34\8211\&35"] } + ,baseCitation{ citationMode = NormalCitation + , citationId = "item3" + , citationPrefix = [Str "also"] + , citationSuffix = [Str "chap.",Space,Str "3"] } + ] (rt "\\citetext{\\citealp[see][p.~34--35]{item1}; \\citealp[also][chap. 3]{item3}}")) + , "suffix and locator" =: "\\citep[pp.~33, 35--37, and nowhere else]{item1}" + =?> para (cite [baseCitation{ citationMode = NormalCitation + , citationSuffix = [Str "pp.\160\&33,",Space,Str "35\8211\&37,",Space,Str "and",Space,Str "nowhere",Space, Str "else"] }] (rt "\\citep[pp.~33, 35--37, and nowhere else]{item1}")) + , "suffix only" =: "\\citep[and nowhere else]{item1}" + =?> para (cite [baseCitation{ citationMode = NormalCitation + , citationSuffix = toList $ text "and nowhere else" }] (rt "\\citep[and nowhere else]{item1}")) + , "no author" =: "\\citeyearpar{item1}, and now Doe with a locator \\citeyearpar[p.~44]{item2}" + =?> para (cite [baseCitation{ citationMode = SuppressAuthor }] (rt "\\citeyearpar{item1}") <> + text ", and now Doe with a locator " <> + cite [baseCitation{ citationMode = SuppressAuthor + , citationSuffix = [Str "p.\160\&44"] + , citationId = "item2" }] (rt "\\citeyearpar[p.~44]{item2}")) + , "markup" =: "\\citep[\\emph{see}][p. \\textbf{32}]{item1}" + =?> para (cite [baseCitation{ citationMode = NormalCitation + , citationPrefix = [Emph [Str "see"]] + , citationSuffix = [Str "p.",Space, + Strong [Str "32"]] }] (rt "\\citep[\\emph{see}][p. \\textbf{32}]{item1}")) + ] + +biblatexCitations :: TestTree +biblatexCitations = testGroup "biblatex" + [ "textcite" =: "\\textcite{item1}" + =?> para (cite [baseCitation] (rt "\\textcite{item1}")) + , "suffix" =: "\\textcite[p.~30]{item1}" + =?> para + (cite [baseCitation{ citationSuffix = toList $ text "p.\160\&30" }] (rt "\\textcite[p.~30]{item1}")) + , "suffix long" =: "\\textcite[p.~30, with suffix]{item1}" + =?> para (cite [baseCitation{ citationSuffix = + toList $ text "p.\160\&30, with suffix" }] (rt "\\textcite[p.~30, with suffix]{item1}")) + , "multiple" =: "\\textcites{item1}[p.~30]{item2}[see also][]{item3}" + =?> para (cite [baseCitation{ citationMode = AuthorInText } + ,baseCitation{ citationMode = NormalCitation + , citationSuffix = [Str "p.\160\&30"] + , citationId = "item2" } + ,baseCitation{ citationId = "item3" + , citationPrefix = [Str "see",Space,Str "also"] + , citationMode = NormalCitation } + ] (rt "\\textcites{item1}[p.~30]{item2}[see also][]{item3}")) + , "group" =: "\\autocites[see][p.~34--35]{item1}[also][chap. 3]{item3}" + =?> para (cite [baseCitation{ citationMode = NormalCitation + , citationPrefix = [Str "see"] + , citationSuffix = [Str "p.\160\&34\8211\&35"] } + ,baseCitation{ citationMode = NormalCitation + , citationId = "item3" + , citationPrefix = [Str "also"] + , citationSuffix = [Str "chap.",Space,Str "3"] } + ] (rt "\\autocites[see][p.~34--35]{item1}[also][chap. 3]{item3}")) + , "suffix and locator" =: "\\autocite[pp.~33, 35--37, and nowhere else]{item1}" + =?> para (cite [baseCitation{ citationMode = NormalCitation + , citationSuffix = [Str "pp.\160\&33,",Space,Str "35\8211\&37,",Space,Str "and",Space,Str "nowhere",Space, Str "else"] }] (rt "\\autocite[pp.~33, 35--37, and nowhere else]{item1}")) + , "suffix only" =: "\\autocite[and nowhere else]{item1}" + =?> para (cite [baseCitation{ citationMode = NormalCitation + , citationSuffix = toList $ text "and nowhere else" }] (rt "\\autocite[and nowhere else]{item1}")) + , "no author" =: "\\autocite*{item1}, and now Doe with a locator \\autocite*[p.~44]{item2}" + =?> para (cite [baseCitation{ citationMode = SuppressAuthor }] (rt "\\autocite*{item1}") <> + text ", and now Doe with a locator " <> + cite [baseCitation{ citationMode = SuppressAuthor + , citationSuffix = [Str "p.\160\&44"] + , citationId = "item2" }] (rt "\\autocite*[p.~44]{item2}")) + , "markup" =: "\\autocite[\\emph{see}][p. \\textbf{32}]{item1}" + =?> para (cite [baseCitation{ citationMode = NormalCitation + , citationPrefix = [Emph [Str "see"]] + , citationSuffix = [Str "p.",Space, + Strong [Str "32"]] }] (rt "\\autocite[\\emph{see}][p. \\textbf{32}]{item1}")) + , "parencite" =: "\\parencite{item1}" + =?> para (cite [baseCitation{ citationMode = NormalCitation }] (rt "\\parencite{item1}")) + ] diff --git a/test/Tests/Readers/Markdown.hs b/test/Tests/Readers/Markdown.hs index 0943aa4b1..e44c7fc19 100644 --- a/test/Tests/Readers/Markdown.hs +++ b/test/Tests/Readers/Markdown.hs @@ -295,6 +295,9 @@ tests = [ testGroup "inline code" , test markdownSmart "apostrophe after math" $ -- issue #1909 "The value of the $x$'s and the systems' condition." =?> para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.") + , test markdownSmart "unclosed double quote" + ("**this should \"be bold**" + =?> para (strong "this should \"be bold")) ] , testGroup "footnotes" [ "indent followed by newline and flush-left text" =: diff --git a/test/Tests/Readers/Markdown.hs.orig b/test/Tests/Readers/Markdown.hs.orig new file mode 100644 index 000000000..1cd32b87d --- /dev/null +++ b/test/Tests/Readers/Markdown.hs.orig @@ -0,0 +1,462 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Markdown (tests) where + +import Data.Text (Text, unpack) +import qualified Data.Text as T +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +markdown :: Text -> Pandoc +markdown = purely $ readMarkdown def { readerExtensions = + disableExtension Ext_smart pandocExtensions } + +markdownSmart :: Text -> Pandoc +markdownSmart = purely $ readMarkdown def { readerExtensions = + enableExtension Ext_smart pandocExtensions } + +markdownCDL :: Text -> Pandoc +markdownCDL = purely $ readMarkdown def { readerExtensions = enableExtension + Ext_compact_definition_lists pandocExtensions } + +markdownGH :: Text -> Pandoc +markdownGH = purely $ readMarkdown def { + readerExtensions = githubMarkdownExtensions } + +infix 4 =: +(=:) :: ToString c + => String -> (Text, c) -> TestTree +(=:) = test markdown + +testBareLink :: (Text, Inlines) -> TestTree +testBareLink (inp, ils) = + test (purely $ readMarkdown def{ readerExtensions = + extensionsFromList [Ext_autolink_bare_uris, Ext_raw_html] }) + (unpack inp) (inp, doc $ para ils) + +autolink :: String -> Inlines +autolink = autolinkWith nullAttr + +autolinkWith :: Attr -> String -> Inlines +autolinkWith attr s = linkWith attr s "" (str s) + +bareLinkTests :: [(Text, Inlines)] +bareLinkTests = + [ ("http://google.com is a search engine.", + autolink "http://google.com" <> " is a search engine.") + , ("<a href=\"http://foo.bar.baz\">http://foo.bar.baz</a>", + rawInline "html" "<a href=\"http://foo.bar.baz\">" <> + "http://foo.bar.baz" <> rawInline "html" "</a>") + , ("Try this query: http://google.com?search=fish&time=hour.", + "Try this query: " <> autolink "http://google.com?search=fish&time=hour" <> ".") + , ("HTTPS://GOOGLE.COM,", + autolink "HTTPS://GOOGLE.COM" <> ",") + , ("http://el.wikipedia.org/wiki/Τεχνολογία,", + autolink "http://el.wikipedia.org/wiki/Τεχνολογία" <> ",") + , ("doi:10.1000/182,", + autolink "doi:10.1000/182" <> ",") + , ("git://github.com/foo/bar.git,", + autolink "git://github.com/foo/bar.git" <> ",") + , ("file:///Users/joe/joe.txt, and", + autolink "file:///Users/joe/joe.txt" <> ", and") + , ("mailto:someone@somedomain.com.", + autolink "mailto:someone@somedomain.com" <> ".") + , ("Use http: this is not a link!", + "Use http: this is not a link!") + , ("(http://google.com).", + "(" <> autolink "http://google.com" <> ").") + , ("http://en.wikipedia.org/wiki/Sprite_(computer_graphics)", + autolink "http://en.wikipedia.org/wiki/Sprite_(computer_graphics)") + , ("http://en.wikipedia.org/wiki/Sprite_[computer_graphics]", + link "http://en.wikipedia.org/wiki/Sprite_%5Bcomputer_graphics%5D" "" + (str "http://en.wikipedia.org/wiki/Sprite_[computer_graphics]")) + , ("http://en.wikipedia.org/wiki/Sprite_{computer_graphics}", + link "http://en.wikipedia.org/wiki/Sprite_%7Bcomputer_graphics%7D" "" + (str "http://en.wikipedia.org/wiki/Sprite_{computer_graphics}")) + , ("http://example.com/Notification_Center-GitHub-20101108-140050.jpg", + autolink "http://example.com/Notification_Center-GitHub-20101108-140050.jpg") + , ("https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20", + autolink "https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20") + , ("http://www.rubyonrails.com", + autolink "http://www.rubyonrails.com") + , ("http://www.rubyonrails.com:80", + autolink "http://www.rubyonrails.com:80") + , ("http://www.rubyonrails.com/~minam", + autolink "http://www.rubyonrails.com/~minam") + , ("https://www.rubyonrails.com/~minam", + autolink "https://www.rubyonrails.com/~minam") + , ("http://www.rubyonrails.com/~minam/url%20with%20spaces", + autolink "http://www.rubyonrails.com/~minam/url%20with%20spaces") + , ("http://www.rubyonrails.com/foo.cgi?something=here", + autolink "http://www.rubyonrails.com/foo.cgi?something=here") + , ("http://www.rubyonrails.com/foo.cgi?something=here&and=here", + autolink "http://www.rubyonrails.com/foo.cgi?something=here&and=here") + , ("http://www.rubyonrails.com/contact;new", + autolink "http://www.rubyonrails.com/contact;new") + , ("http://www.rubyonrails.com/contact;new%20with%20spaces", + autolink "http://www.rubyonrails.com/contact;new%20with%20spaces") + , ("http://www.rubyonrails.com/contact;new?with=query&string=params", + autolink "http://www.rubyonrails.com/contact;new?with=query&string=params") + , ("http://www.rubyonrails.com/~minam/contact;new?with=query&string=params", + autolink "http://www.rubyonrails.com/~minam/contact;new?with=query&string=params") + , ("http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007", + autolink "http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007") + , ("http://www.mail-archive.com/rails@lists.rubyonrails.org/", + autolink "http://www.mail-archive.com/rails@lists.rubyonrails.org/") + , ("http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1", + autolink "http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1") + , ("http://en.wikipedia.org/wiki/Texas_hold%27em", + autolink "http://en.wikipedia.org/wiki/Texas_hold%27em") + , ("https://www.google.com/doku.php?id=gps:resource:scs:start", + autolink "https://www.google.com/doku.php?id=gps:resource:scs:start") + , ("http://www.rubyonrails.com", + autolink "http://www.rubyonrails.com") + , ("http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281", + autolink "http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281") + , ("http://foo.example.com/controller/action?parm=value&p2=v2#anchor123", + autolink "http://foo.example.com/controller/action?parm=value&p2=v2#anchor123") + , ("http://foo.example.com:3000/controller/action", + autolink "http://foo.example.com:3000/controller/action") + , ("http://foo.example.com:3000/controller/action+pack", + autolink "http://foo.example.com:3000/controller/action+pack") + , ("http://business.timesonline.co.uk/article/0,,9065-2473189,00.html", + autolink "http://business.timesonline.co.uk/article/0,,9065-2473189,00.html") + , ("http://www.mail-archive.com/ruby-talk@ruby-lang.org/", + autolink "http://www.mail-archive.com/ruby-talk@ruby-lang.org/") + , ("https://example.org/?anchor=lala-", + autolink "https://example.org/?anchor=lala-") + , ("https://example.org/?anchor=-lala", + autolink "https://example.org/?anchor=-lala") + ] + +{- +p_markdown_round_trip :: Block -> Bool +p_markdown_round_trip b = matches d' d'' + where d' = normalize $ Pandoc (Meta [] [] []) [b] + d'' = normalize + $ readMarkdown def { readerSmart = True } + $ writeMarkdown def d' + matches (Pandoc _ [Plain []]) (Pandoc _ []) = True + matches (Pandoc _ [Para []]) (Pandoc _ []) = True + matches (Pandoc _ [Plain xs]) (Pandoc _ [Para xs']) = xs == xs' + matches x y = x == y +-} + +tests :: [TestTree] +tests = [ testGroup "inline code" + [ "with attribute" =: + "`document.write(\"Hello\");`{.javascript}" + =?> para + (codeWith ("",["javascript"],[]) "document.write(\"Hello\");") + , "with attribute space" =: + "`*` {.haskell .special x=\"7\"}" + =?> para (code "*" <> space <> str "{.haskell" <> space <> + str ".special" <> space <> str "x=\"7\"}") + ] + , testGroup "emph and strong" + [ "two strongs in emph" =: + "***a**b **c**d*" =?> para (emph (strong (str "a") <> str "b" <> space + <> strong (str "c") <> str "d")) + , "emph and strong emph alternating" =: + "*xxx* ***xxx*** xxx\n*xxx* ***xxx*** xxx" + =?> para (emph "xxx" <> space <> strong (emph "xxx") <> + space <> "xxx" <> softbreak <> + emph "xxx" <> space <> strong (emph "xxx") <> + space <> "xxx") + , "emph with spaced strong" =: + "*x **xx** x*" + =?> para (emph ("x" <> space <> strong "xx" <> space <> "x")) + , "intraword underscore with opening underscore (#1121)" =: + "_foot_ball_" =?> para (emph (text "foot_ball")) + ] + , testGroup "raw LaTeX" + [ "in URL" =: + "\\begin\n" =?> para (text "\\begin") + ] + , testGroup "raw HTML" + [ "nesting (issue #1330)" =: + "<del>test</del>" =?> + rawBlock "html" "<del>" <> plain (str "test") <> + rawBlock "html" "</del>" + , "invalid tag (issue #1820" =: + "</ div></.div>" =?> + para (text "</ div></.div>") + , "technically invalid comment" =: + "<!-- pandoc --help -->" =?> + rawBlock "html" "<!-- pandoc --help -->" + , test markdownGH "issue 2469" $ + "<\n\na>" =?> + para (text "<") <> para (text "a>") + ] + , testGroup "raw email addresses" + [ test markdownGH "issue 2940" $ + "**@user**" =?> + para (strong (text "@user")) + ] + , testGroup "emoji" + [ test markdownGH "emoji symbols" $ + ":smile: and :+1:" =?> para (text "😄 and 👍") + ] + , "unbalanced brackets" =: + "[[[[[[[[[[[[hi" =?> para (text "[[[[[[[[[[[[hi") + , testGroup "backslash escapes" + [ "in URL" =: + "[hi](/there\\))" + =?> para (link "/there)" "" "hi") + , "in title" =: + "[hi](/there \"a\\\"a\")" + =?> para (link "/there" "a\"a" "hi") + , "in reference link title" =: + "[hi]\n\n[hi]: /there (a\\)a)" + =?> para (link "/there" "a)a" "hi") + , "in reference link URL" =: + "[hi]\n\n[hi]: /there\\.0" + =?> para (link "/there.0" "" "hi") + ] + , testGroup "bare URIs" + (map testBareLink bareLinkTests) + , testGroup "autolinks" + [ "with unicode dash following" =: + "<http://foo.bar>\8212" =?> para (autolink "http://foo.bar" <> + str "\8212") + , "a partial URL (#2277)" =: + "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>" =?> + para (text "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>") + , "with some attributes" =: + "<http://foo.bar>{#i .j .z k=v}" =?> + para (autolinkWith ("i", ["j", "z"], [("k", "v")]) "http://foo.bar") + , "with some attributes and spaces" =: + "<http://foo.bar> {#i .j .z k=v}" =?> + para (autolink "http://foo.bar" <> space <> text "{#i .j .z k=v}") + ] + , testGroup "links" + [ "no autolink inside link" =: + "[<https://example.org>](url)" =?> + para (link "url" "" (text "<https://example.org>")) + , "no inline link inside link" =: + "[[a](url2)](url)" =?> + para (link "url" "" (text "[a](url2)")) + , "no bare URI inside link" =: + "[https://example.org(](url)" =?> + para (link "url" "" (text "https://example.org(")) + ] + , testGroup "Headers" + [ "blank line before header" =: + "\n# Header\n" + =?> headerWith ("header",[],[]) 1 "Header" + , "bracketed text (#2062)" =: + "# [hi]\n" + =?> headerWith ("hi",[],[]) 1 "[hi]" + , "ATX header without trailing #s" =: + "# Foo bar\n\n" =?> + headerWith ("foo-bar",[],[]) 1 "Foo bar" + , "ATX header without trailing #s" =: + "# Foo bar with # #" =?> + headerWith ("foo-bar-with",[],[]) 1 "Foo bar with #" + , "setext header" =: + "Foo bar\n=\n\n Foo bar 2 \n=" =?> + headerWith ("foo-bar",[],[]) 1 "Foo bar" + <> headerWith ("foo-bar-2",[],[]) 1 "Foo bar 2" + ] + , testGroup "Implicit header references" + [ "ATX header without trailing #s" =: + "# Header\n[header]\n\n[header ]\n\n[ header]" =?> + headerWith ("header",[],[]) 1 "Header" + <> para (link "#header" "" (text "header")) + <> para (link "#header" "" (text "header")) + <> para (link "#header" "" (text "header")) + , "ATX header with trailing #s" =: + "# Foo bar #\n[foo bar]\n\n[foo bar ]\n\n[ foo bar]" =?> + headerWith ("foo-bar",[],[]) 1 "Foo bar" + <> para (link "#foo-bar" "" (text "foo bar")) + <> para (link "#foo-bar" "" (text "foo bar")) + <> para (link "#foo-bar" "" (text "foo bar")) + , "setext header" =: + " Header \n=\n\n[header]\n\n[header ]\n\n[ header]" =?> + headerWith ("header",[],[]) 1 "Header" + <> para (link "#header" "" (text "header")) + <> para (link "#header" "" (text "header")) + <> para (link "#header" "" (text "header")) + ] + , testGroup "smart punctuation" + [ test markdownSmart "quote before ellipses" + ("'...hi'" + =?> para (singleQuoted "…hi")) + , test markdownSmart "apostrophe before emph" + ("D'oh! A l'*aide*!" + =?> para ("D’oh! A l’" <> emph "aide" <> "!")) + , test markdownSmart "apostrophe in French" + ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»" + =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»") + , test markdownSmart "apostrophe after math" $ -- issue #1909 + "The value of the $x$'s and the systems' condition." =?> + para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.") + ] + , testGroup "footnotes" + [ "indent followed by newline and flush-left text" =: + "[^1]\n\n[^1]: my note\n\n \nnot in note\n" + =?> para (note (para "my note")) <> para "not in note" + , "indent followed by newline and indented text" =: + "[^1]\n\n[^1]: my note\n \n in note\n" + =?> para (note (para "my note" <> para "in note")) + , "recursive note" =: + "[^1]\n\n[^1]: See [^1]\n" + =?> para (note (para "See [^1]")) + ] + , testGroup "lhs" + [ test (purely $ readMarkdown def{ readerExtensions = enableExtension + Ext_literate_haskell pandocExtensions }) + "inverse bird tracks and html" $ + "> a\n\n< b\n\n<div>\n" + =?> codeBlockWith ("",["sourceCode","literate","haskell"],[]) "a" + <> + codeBlockWith ("",["sourceCode","haskell"],[]) "b" + <> + rawBlock "html" "<div>\n\n" + ] +-- the round-trip properties frequently fail +-- , testGroup "round trip" +-- [ property "p_markdown_round_trip" p_markdown_round_trip +-- ] + , testGroup "definition lists" + [ "no blank space" =: + "foo1\n : bar\n\nfoo2\n : bar2\n : bar3\n" =?> + definitionList [ (text "foo1", [plain (text "bar")]) + , (text "foo2", [plain (text "bar2"), + plain (text "bar3")]) + ] + , "blank space before first def" =: + "foo1\n\n : bar\n\nfoo2\n\n : bar2\n : bar3\n" =?> + definitionList [ (text "foo1", [para (text "bar")]) + , (text "foo2", [para (text "bar2"), + plain (text "bar3")]) + ] + , "blank space before second def" =: + "foo1\n : bar\n\nfoo2\n : bar2\n\n : bar3\n" =?> + definitionList [ (text "foo1", [plain (text "bar")]) + , (text "foo2", [plain (text "bar2"), + para (text "bar3")]) + ] + , "laziness" =: + "foo1\n : bar\nbaz\n : bar2\n" =?> + definitionList [ (text "foo1", [plain (text "bar" <> + softbreak <> text "baz"), + plain (text "bar2")]) + ] + , "no blank space before first of two paragraphs" =: + "foo1\n : bar\n\n baz\n" =?> + definitionList [ (text "foo1", [para (text "bar") <> + para (text "baz")]) + ] + , "first line not indented" =: + "foo\n: bar\n" =?> + definitionList [ (text "foo", [plain (text "bar")]) ] + , "list in definition" =: + "foo\n: - bar\n" =?> + definitionList [ (text "foo", [bulletList [plain (text "bar")]]) ] + , "in div" =: + "<div>foo\n: - bar\n</div>" =?> + divWith nullAttr (definitionList + [ (text "foo", [bulletList [plain (text "bar")]]) ]) + ] + , testGroup "+compact_definition_lists" + [ test markdownCDL "basic compact list" $ + "foo1\n: bar\n baz\nfoo2\n: bar2\n" =?> + definitionList [ (text "foo1", [plain (text "bar" <> softbreak <> + text "baz")]) + , (text "foo2", [plain (text "bar2")]) + ] + ] + , testGroup "lists" + [ "issue #1154" =: + " - <div>\n first div breaks\n </div>\n\n <button>if this button exists</button>\n\n <div>\n with this div too.\n </div>\n" + =?> bulletList [divWith nullAttr (para $ text "first div breaks") <> + rawBlock "html" "<button>" <> + plain (text "if this button exists") <> + rawBlock "html" "</button>" <> + divWith nullAttr (para $ text "with this div too.")] + , test markdownGH "issue #1636" $ + T.unlines [ "* a" + , "* b" + , "* c" + , " * d" ] + =?> + bulletList [ plain "a" + , plain "b" + , plain "c" <> bulletList [plain "d"] ] + ] + , testGroup "entities" + [ "character references" =: + "⟨ ö" =?> para (text "\10216 ö") + , "numeric" =: + ",DD" =?> para (text ",DD") + , "in link title" =: + "[link](/url \"title ⟨ ö ,\")" =?> + para (link "/url" "title \10216 ö ," (text "link")) + ] + , testGroup "citations" + [ "simple" =: + "@item1" =?> para (cite [ + Citation{ citationId = "item1" + , citationPrefix = [] + , citationSuffix = [] + , citationMode = AuthorInText + , citationNoteNum = 0 + , citationHash = 0 + } + ] "@item1") + , "key starts with digit" =: + "@1657:huyghens" =?> para (cite [ + Citation{ citationId = "1657:huyghens" + , citationPrefix = [] + , citationSuffix = [] + , citationMode = AuthorInText + , citationNoteNum = 0 + , citationHash = 0 + } + ] "@1657:huyghens") + ] + , let citation = cite [Citation "cita" [] [] AuthorInText 0 0] (str "@cita") + in testGroup "footnote/link following citation" -- issue #2083 + [ "footnote" =: + T.unlines [ "@cita[^note]" + , "" + , "[^note]: note" ] =?> + para ( + citation <> note (para $ str "note") + ) + , "normal link" =: + "@cita [link](http://www.com)" =?> + para ( + citation <> space <> link "http://www.com" "" (str "link") + ) + , "reference link" =: + T.unlines [ "@cita [link][link]" + , "" + , "[link]: http://www.com" ] =?> + para ( + citation <> space <> link "http://www.com" "" (str "link") + ) + , "short reference link" =: + T.unlines [ "@cita [link]" + , "" + , "[link]: http://www.com" ] =?> + para ( + citation <> space <> link "http://www.com" "" (str "link") + ) + , "implicit header link" =: + T.unlines [ "# Header" + , "@cita [Header]" ] =?> + headerWith ("header",[],[]) 1 (str "Header") <> para ( + citation <> space <> link "#header" "" (str "Header") + ) + , "regular citation" =: + "@cita [foo]" =?> + para ( + cite [Citation "cita" [] [Str "foo"] AuthorInText 0 0] + (str "@cita" <> space <> str "[foo]") + ) + ] + ] diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index fd96c892e..ecdd5fdb0 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -209,6 +209,10 @@ tests = -- This test also makes sure '=' without whitespace is not treated as code markup , "No implicit links" =: "http://example.org/index.php?action=view&id=1" =?> para "http://example.org/index.php?action=view&id=1" + , "Link with empty URL" =: "[[][empty URL]]" =?> para (link "" "" (text "empty URL")) + , "No footnotes inside links" =: + "[[https://amusewiki.org/][foo[1]]" =?> + para (link "https://amusewiki.org/" "" (text "foo[1")) ] , testGroup "Literal" @@ -281,6 +285,23 @@ tests = ] =?> divWith ("foo", [], []) (para "Foo bar") ] + , "Biblio" =: + T.unlines [ "<biblio>" + , "" + , "Author, *Title*, description" + , "" + , "Another author, *Another title*, another description" + , "" + , "</biblio>" + ] =?> + divWith ("", ["biblio"], []) (para (text "Author, " <> emph "Title" <> ", description") <> + para (text "Another author, " <> emph "Another title" <> text ", another description")) + , "Play" =: + T.unlines [ "<play>" + , "Foo bar" + , "</play>" + ] =?> + divWith ("", ["play"], []) (para "Foo bar") , "Verse" =: T.unlines [ "> This is" , "> First stanza" @@ -504,6 +525,7 @@ tests = , "Text after empty comment" =: ";\nfoo" =?> para "foo" -- Make sure we don't consume newline while looking for whitespace , "Not a comment (does not start with a semicolon)" =: " ; Not a comment" =?> para (text "; Not a comment") , "Not a comment (has no space after semicolon)" =: ";Not a comment" =?> para (text ";Not a comment") + , "Not a comment (semicolon not in the first column)" =: " - ; foo" =?> bulletList [para "; foo"] ] , testGroup "Headers" [ "Part" =: @@ -541,18 +563,32 @@ tests = ] =?> headerWith ("bar",[],[]) 2 "Foo" , "Headers don't consume anchors separated with a blankline" =: - T.unlines [ "** Foo" - , "" + T.unlines [ "; A comment to make sure anchor is not parsed as a directive" , "#bar" + , "" + , "** Foo" + ] =?> + para (spanWith ("bar", [], []) mempty) <> + header 2 "Foo" + , "Headers terminate paragraph" =: + T.unlines [ "foo" + , "* bar" ] =?> - header 2 "Foo" <> - para (spanWith ("bar", [], []) mempty) + para "foo" <> header 1 "bar" , "Headers terminate lists" =: T.unlines [ " - foo" , "* bar" ] =?> bulletList [ para "foo" ] <> header 1 "bar" + , test emacsMuse "Paragraphs terminate Emacs Muse headers" + (T.unlines [ "* Foo" + , "bar" + ] =?> header 1 "Foo" <> para "bar") + , "Paragraphs don't terminate Text::Amuse headers" =: + T.unlines [ "* Foo" + , "bar" + ] =?> header 1 "Foo\nbar" ] , testGroup "Directives" [ "Title" =: @@ -601,6 +637,11 @@ tests = , "#anchor and ends here." ] =?> para ("Paragraph starts here\n" <> spanWith ("anchor", [], []) mempty <> "and ends here.") + , "Anchor with \"-\"" =: + T.unlines [ "; A comment to make sure anchor is not parsed as a directive" + , "#anchor-id Target" + ] =?> + para (spanWith ("anchor-id", [], []) mempty <> "Target") ] , testGroup "Footnotes" [ "Simple footnote" =: @@ -618,6 +659,15 @@ tests = ] =?> para (text "Start recursion here" <> note (para "Recursion continues here[1]")) + , "Nested footnotes" =: + T.unlines [ "Footnote: [1]" + , "" + , "[1] Nested: [2]" + , "" + , "[2] No recursion: [1]" + ] =?> + para (text "Footnote: " <> + note (para (text "Nested: " <> note (para $ text "No recursion: [1]")))) , "No zero footnotes" =: T.unlines [ "Here is a footnote[0]." , "" @@ -1117,6 +1167,24 @@ tests = definitionList [ ("First term", [ para "Definition of first term\nand its continuation." ]) , ("Second term", [ para "Definition of second term." ]) ] + , "Definition list with verse" =: + T.unlines + [ " First term :: Definition of first term" + , " > First verse" + , " > Second line of first verse" + , "" + , " > Second verse" + , " > Second line of second verse" + ] =?> + definitionList [ ("First term", [ para "Definition of first term" <> + lineBlock [ text "First verse" + , text "Second line of first verse" + ] <> + lineBlock [ text "Second verse" + , text "Second line of second verse" + ] + ]) + ] , test emacsMuse "Multi-line definition lists from Emacs Muse manual" (T.unlines [ "Term1 ::" @@ -1229,7 +1297,7 @@ tests = , " - <quote>" , " foo" , " </quote>" - , " bar" -- Do not consume whitespace while looking for arbitraritly indented </quote> + , " bar" -- Do not consume whitespace while looking for arbitrarily indented </quote> , "</quote>" ] =?> blockQuote (bulletList [ blockQuote $ para "foo" ] <> para "bar") diff --git a/test/Tests/Readers/Muse.hs.orig b/test/Tests/Readers/Muse.hs.orig new file mode 100644 index 000000000..89dbbc345 --- /dev/null +++ b/test/Tests/Readers/Muse.hs.orig @@ -0,0 +1,1262 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Muse (tests) where + +import Data.List (intersperse) +import Data.Text (Text) +import qualified Data.Text as T +import Test.Tasty +import Test.Tasty.QuickCheck +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder +import Text.Pandoc.Shared (underlineSpan) +import Text.Pandoc.Walk (walk) + +amuse :: Text -> Pandoc +amuse = purely $ readMuse def { readerExtensions = extensionsFromList [Ext_amuse]} + +emacsMuse :: Text -> Pandoc +emacsMuse = purely $ readMuse def { readerExtensions = emptyExtensions } + +infix 4 =: +(=:) :: ToString c + => String -> (Text, c) -> TestTree +(=:) = test amuse + +spcSep :: [Inlines] -> Inlines +spcSep = mconcat . intersperse space + +-- Tables don't round-trip yet +-- +makeRoundTrip :: Block -> Block +makeRoundTrip Table{} = Para [Str "table was here"] +makeRoundTrip (OrderedList (start, LowerAlpha, _) items) = OrderedList (start, Decimal, Period) items +makeRoundTrip (OrderedList (start, UpperAlpha, _) items) = OrderedList (start, Decimal, Period) items +makeRoundTrip x = x + +-- Demand that any AST produced by Muse reader and written by Muse writer can be read back exactly the same way. +-- Currently we remove tables and compare first rewrite to the second. +roundTrip :: Block -> Bool +roundTrip b = d' == d'' + where d = walk makeRoundTrip $ Pandoc nullMeta [b] + d' = rewrite d + d'' = rewrite d' + rewrite = amuse . T.pack . (++ "\n") . T.unpack . + purely (writeMuse def { writerExtensions = extensionsFromList [Ext_amuse] + , writerWrapText = WrapPreserve + }) + +tests :: [TestTree] +tests = + [ testGroup "Inlines" + [ "Plain String" =: + "Hello, World" =?> + para "Hello, World" + + , "Muse is not XML" =: "<" =?> para "<" + + , "Emphasis" =: + "*Foo bar*" =?> + para (emph . spcSep $ ["Foo", "bar"]) + + , "Comma after closing *" =: + "Foo *bar*, baz" =?> + para ("Foo " <> emph "bar" <> ", baz") + + , "Letter after closing *" =: + "Foo *bar*x baz" =?> + para "Foo *bar*x baz" + + , "Letter before opening *" =: + "Foo x*bar* baz" =?> + para "Foo x*bar* baz" + + , "Emphasis tag" =: + "<em>Foo bar</em>" =?> + para (emph . spcSep $ ["Foo", "bar"]) + + , "Strong" =: + "**Cider**" =?> + para (strong "Cider") + + , "Strong tag" =: "<strong>Strong</strong>" =?> para (strong "Strong") + + , "Strong Emphasis" =: + "***strength***" =?> + para (strong . emph $ "strength") + + , test emacsMuse "Underline" + ("_Underline_" =?> para (underlineSpan "Underline")) + + , "Superscript tag" =: "<sup>Superscript</sup>" =?> para (superscript "Superscript") + + , "Subscript tag" =: "<sub>Subscript</sub>" =?> para (subscript "Subscript") + + , "Strikeout tag" =: "<del>Strikeout</del>" =?> para (strikeout "Strikeout") + + , "Opening inline tags" =: "foo <em> bar <strong>baz" =?> para "foo <em> bar <strong>baz" + + , "Closing inline tags" =: "foo </em> bar </strong>baz" =?> para "foo </em> bar </strong>baz" + + , "Tag soup" =: "foo <em> bar </strong>baz" =?> para "foo <em> bar </strong>baz" + + -- Both inline tags must be within the same paragraph + , "No multiparagraph inline tags" =: + T.unlines [ "First line" + , "<em>Second line" + , "" + , "Fourth line</em>" + ] =?> + para "First line\n<em>Second line" <> + para "Fourth line</em>" + + , "Linebreak" =: "Line <br> break" =?> para ("Line" <> linebreak <> "break") + + , "Trailing whitespace inside paragraph" =: + T.unlines [ "First line " -- trailing whitespace here + , "second line" + ] + =?> para "First line\nsecond line" + + , "Non-breaking space" =: "Foo~~bar" =?> para "Foo\160bar" + , "Single ~" =: "Foo~bar" =?> para "Foo~bar" + + , testGroup "Code markup" + [ "Code" =: "=foo(bar)=" =?> para (code "foo(bar)") + + , "Not code" =: "a=b= =c=d" =?> para (text "a=b= =c=d") + + -- Emacs Muse 3.20 parses this as code, we follow Amusewiki + , "Not code if closing = is detached" =: "=this is not a code =" =?> para "=this is not a code =" + + , "Not code if opening = is detached" =: "= this is not a code=" =?> para "= this is not a code=" + + , "Code if followed by comma" =: + "Foo =bar=, baz" =?> + para (text "Foo " <> code "bar" <> text ", baz") + + , "One character code" =: "=c=" =?> para (code "c") + + , "Three = characters is not a code" =: "===" =?> para "===" + + , "Multiline code markup" =: + "foo =bar\nbaz= end of code" =?> + para (text "foo " <> code "bar\nbaz" <> text " end of code") + +{- Emacs Muse 3.20 has a bug: it publishes + - <p>foo <code>bar + - + - baz</code> foo</p> + - which is displayed as one paragraph by browsers. + - We follow Amusewiki here and avoid joining paragraphs. + -} + , "No multiparagraph code" =: + T.unlines [ "foo =bar" + , "" + , "baz= foo" + ] =?> + para "foo =bar" <> + para "baz= foo" + + , "Code at the beginning of paragraph but not first column" =: + " - =foo=" =?> bulletList [ para $ code "foo" ] + ] + + , "Code tag" =: "<code>foo(bar)</code>" =?> para (code "foo(bar)") + + , "Verbatim tag" =: "*<verbatim>*</verbatim>*" =?> para (emph "*") + + , "Verbatim inside code" =: "<code><verbatim>foo</verbatim></code>" =?> para (code "<verbatim>foo</verbatim>") + + , "Verbatim tag after text" =: "Foo <verbatim>bar</verbatim>" =?> para "Foo bar" + + , "Class tag" =: "<class name=\"foo\">bar</class>" =?> para (spanWith ("", ["foo"], []) "bar") + , "Class tag without name" =: "<class>foobar</class>" =?> para (spanWith ("", [], []) "foobar") + + -- <em> tag should match with the last </em> tag, not verbatim one + , "Nested \"</em>\" inside em tag" =: "<em>foo<verbatim></em></verbatim>bar</em>" =?> para (emph "foo</em>bar") + + , testGroup "Links" + [ "Link without description" =: + "[[https://amusewiki.org/]]" =?> + para (link "https://amusewiki.org/" "" (str "https://amusewiki.org/")) + , "Link with description" =: + "[[https://amusewiki.org/][A Muse Wiki]]" =?> + para (link "https://amusewiki.org/" "" (text "A Muse Wiki")) + , "Image" =: + "[[image.jpg]]" =?> + para (image "image.jpg" "" mempty) + , "Image with description" =: + "[[image.jpg][Image]]" =?> + para (image "image.jpg" "" (text "Image")) + , "Image link" =: + "[[URL:image.jpg]]" =?> + para (link "image.jpg" "" (str "image.jpg")) + , "Image link with description" =: + "[[URL:image.jpg][Image]]" =?> + para (link "image.jpg" "" (text "Image")) + -- Implicit links are supported in Emacs Muse, but not in Amusewiki: + -- https://github.com/melmothx/text-amuse/issues/18 + -- + -- This test also makes sure '=' without whitespace is not treated as code markup + , "No implicit links" =: "http://example.org/index.php?action=view&id=1" + =?> para "http://example.org/index.php?action=view&id=1" + ] + + , testGroup "Literal" + [ test emacsMuse "Inline literal" + ("Foo<literal style=\"html\">lit</literal>bar" =?> + para (text "Foo" <> rawInline "html" "lit" <> text "bar")) + ] + ] + + , testGroup "Blocks" + [ testProperty "Round trip" roundTrip, + "Block elements end paragraphs" =: + T.unlines [ "First paragraph" + , "----" + , "Second paragraph" + ] =?> para (text "First paragraph") <> horizontalRule <> para (text "Second paragraph") + , testGroup "Horizontal rule" + [ "Less than 4 dashes is not a horizontal rule" =: "---" =?> para (text "---") + , "4 dashes is a horizontal rule" =: "----" =?> horizontalRule + , "5 dashes is a horizontal rule" =: "-----" =?> horizontalRule + , "4 dashes with spaces is a horizontal rule" =: "---- " =?> horizontalRule + ] + , testGroup "Paragraphs" + [ "Simple paragraph" =: + T.unlines [ "First line" + , "second line." + ] =?> + para "First line\nsecond line." + , "Indented paragraph" =: + T.unlines [ " First line" + , "second line." + ] =?> + para "First line\nsecond line." + -- Emacs Muse starts a blockquote on the second line. + -- We copy Amusewiki behavior and require a blank line to start a blockquote. + , "Indentation in the middle of paragraph" =: + T.unlines [ "First line" + , " second line" + , "third line" + ] =?> + para "First line\nsecond line\nthird line" + , "Quote" =: + " This is a quotation\n" =?> + blockQuote (para "This is a quotation") + , "Indentation does not indicate quote inside quote tag" =: + T.unlines [ "<quote>" + , " Not a nested quote" + , "</quote>" + ] =?> + blockQuote (para "Not a nested quote") + , "Multiline quote" =: + T.unlines [ " This is a quotation" + , " with a continuation" + ] =?> + blockQuote (para "This is a quotation\nwith a continuation") + , testGroup "Div" + [ "Div without id" =: + T.unlines [ "<div>" + , "Foo bar" + , "</div>" + ] =?> + divWith nullAttr (para "Foo bar") + , "Div with id" =: + T.unlines [ "<div id=\"foo\">" + , "Foo bar" + , "</div>" + ] =?> + divWith ("foo", [], []) (para "Foo bar") + ] + , "Verse" =: + T.unlines [ "> This is" + , "> First stanza" + , ">" -- Emacs produces verbatim ">" here, we follow Amusewiki + , "> And this is" + , "> Second stanza" + , ">" + , "" + , ">" + , "" + , "> Another verse" + , "> is here" + ] =?> + lineBlock [ "This is" + , "First stanza" + , "" + , "And this is" + , "\160\160Second stanza" + , "" + ] <> + lineBlock [ "" ] <> + lineBlock [ "Another verse" + , "\160\160\160is here" + ] + ] + , "Verse in list" =: " - > foo" =?> bulletList [ lineBlock [ "foo" ] ] + , "Verse line starting with emphasis" =: "> *foo* bar" =?> lineBlock [ emph "foo" <> text " bar" ] + , "Multiline verse in list" =: + T.unlines [ " - > foo" + , " > bar" + ] =?> + bulletList [ lineBlock [ "foo", "bar" ] ] + , "Paragraph after verse in list" =: + T.unlines [ " - > foo" + , " bar" + ] =?> + bulletList [ lineBlock [ "foo" ] <> para "bar" ] + , "Empty quote tag" =: + T.unlines [ "<quote>" + , "</quote>" + ] + =?> blockQuote mempty + , "Quote tag" =: + T.unlines [ "<quote>" + , "Hello, world" + , "</quote>" + ] + =?> blockQuote (para $ text "Hello, world") + , "Nested quote tag" =: + T.unlines [ "<quote>" + , "foo" + , "<quote>" + , "bar" + , "</quote>" + , "baz" + , "</quote>" + ] =?> + blockQuote (para "foo" <> blockQuote (para "bar") <> para "baz") + , "Indented quote inside list" =: + T.unlines [ " - <quote>" + , " foo" + , " </quote>" + ] =?> + bulletList [ blockQuote (para "foo") ] + , "Verse tag" =: + T.unlines [ "<verse>" + , "" + , "Foo bar baz" + , " One two three" + , "" + , "</verse>" + ] =?> + lineBlock [ "" + , text "Foo bar baz" + , text "\160\160One two three" + , "" + ] + , "Verse tag with empty line inside" =: + T.unlines [ "<verse>" + , "" + , "</verse>" + ] =?> + lineBlock [ "" ] + , testGroup "Example" + [ "Braces on separate lines" =: + T.unlines [ "{{{" + , "Example line" + , "}}}" + ] =?> + codeBlock "Example line" + , "Spaces after opening braces" =: + T.unlines [ "{{{ " + , "Example line" + , "}}}" + ] =?> + codeBlock "Example line" + , "One blank line in the beginning" =: + T.unlines [ "{{{" + , "" + , "Example line" + , "}}}" + ] =?> + codeBlock "\nExample line" + , "One blank line in the end" =: + T.unlines [ "{{{" + , "Example line" + , "" + , "}}}" + ] =?> + codeBlock "Example line\n" + -- Amusewiki requires braces to be on separate line, + -- this is an extension. + , "One line" =: + "{{{Example line}}}" =?> + codeBlock "Example line" + ] + , testGroup "Example tag" + [ "Tags on separate lines" =: + T.unlines [ "<example>" + , "Example line" + , "</example>" + ] =?> + codeBlock "Example line" + , "One line" =: + "<example>Example line</example>" =?> + codeBlock "Example line" + , "One blank line in the beginning" =: + T.unlines [ "<example>" + , "" + , "Example line" + , "</example>" + ] =?> + codeBlock "\nExample line" + , "One blank line in the end" =: + T.unlines [ "<example>" + , "Example line" + , "" + , "</example>" + ] =?> + codeBlock "Example line\n" + , "Example inside list" =: + T.unlines [ " - <example>" + , " foo" + , " </example>" + ] =?> + bulletList [ codeBlock "foo" ] + , "Empty example inside list" =: + T.unlines [ " - <example>" + , " </example>" + ] =?> + bulletList [ codeBlock "" ] + , "Example inside list with empty lines" =: + T.unlines [ " - <example>" + , " foo" + , " </example>" + , "" + , " bar" + , "" + , " <example>" + , " baz" + , " </example>" + ] =?> + bulletList [ codeBlock "foo" <> para "bar" <> codeBlock "baz" ] + , "Indented example inside list" =: + T.unlines [ " - <example>" + , " foo" + , " </example>" + ] =?> + bulletList [ codeBlock "foo" ] + , "Example inside definition list" =: + T.unlines [ " foo :: <example>" + , " bar" + , " </example>" + ] =?> + definitionList [ ("foo", [codeBlock "bar"]) ] + , "Example inside list definition with empty lines" =: + T.unlines [ " term :: <example>" + , " foo" + , " </example>" + , "" + , " bar" + , "" + , " <example>" + , " baz" + , " </example>" + ] =?> + definitionList [ ("term", [codeBlock "foo" <> para "bar" <> codeBlock "baz"]) ] + , "Example inside note" =: + T.unlines [ "Foo[1]" + , "" + , "[1] <example>" + , " bar" + , " </example>" + ] =?> + para ("Foo" <> note (codeBlock "bar")) + ] + , testGroup "Literal blocks" + [ test emacsMuse "Literal block" + (T.unlines [ "<literal style=\"latex\">" + , "\\newpage" + , "</literal>" + ] =?> + rawBlock "latex" "\\newpage") + ] + , "Center" =: + T.unlines [ "<center>" + , "Hello, world" + , "</center>" + ] =?> + para (text "Hello, world") + , "Right" =: + T.unlines [ "<right>" + , "Hello, world" + , "</right>" + ] =?> + para (text "Hello, world") + , testGroup "Comments" + [ "Comment tag" =: "<comment>\nThis is a comment\n</comment>" =?> (mempty::Blocks) + , "Line comment" =: "; Comment" =?> (mempty::Blocks) + , "Empty comment" =: ";" =?> (mempty::Blocks) + , "Text after empty comment" =: ";\nfoo" =?> para "foo" -- Make sure we don't consume newline while looking for whitespace + , "Not a comment (does not start with a semicolon)" =: " ; Not a comment" =?> para (text "; Not a comment") + , "Not a comment (has no space after semicolon)" =: ";Not a comment" =?> para (text ";Not a comment") + ] + , testGroup "Headers" + [ "Part" =: + "* First level" =?> + header 1 "First level" + , "Chapter" =: + "** Second level" =?> + header 2 "Second level" + , "Section" =: + "*** Third level" =?> + header 3 "Third level" + , "Subsection" =: + "**** Fourth level" =?> + header 4 "Fourth level" + , "Subsubsection" =: + "***** Fifth level" =?> + header 5 "Fifth level" + , "Whitespace is required after *" =: "**Not a header" =?> para "**Not a header" + , "No headers in footnotes" =: + T.unlines [ "Foo[1]" + , "[1] * Bar" + ] =?> + para (text "Foo" <> + note (para "* Bar")) + , "No headers in quotes" =: + T.unlines [ "<quote>" + , "* Hi" + , "</quote>" + ] =?> + blockQuote (para "* Hi") + , "Headers consume anchors" =: + T.unlines [ "** Foo" + , "#bar" + ] =?> + headerWith ("bar",[],[]) 2 "Foo" + , "Headers don't consume anchors separated with a blankline" =: + T.unlines [ "** Foo" + , "" + , "#bar" + ] =?> + header 2 "Foo" <> + para (spanWith ("bar", [], []) mempty) + , "Headers terminate lists" =: + T.unlines [ " - foo" + , "* bar" + ] =?> + bulletList [ para "foo" ] <> + header 1 "bar" + ] + , testGroup "Directives" + [ "Title" =: + "#title Document title" =?> + let titleInline = toList "Document title" + meta = setMeta "title" (MetaInlines titleInline) nullMeta + in Pandoc meta mempty + -- Emacs Muse documentation says that "You can use any combination + -- of uppercase and lowercase letters for directives", + -- but also allows '-', which is not documented, but used for disable-tables. + , test emacsMuse "Disable tables" + ("#disable-tables t" =?> + Pandoc (setMeta "disable-tables" (MetaInlines $ toList "t") nullMeta) mempty) + , "Multiple directives" =: + T.unlines [ "#title Document title" + , "#subtitle Document subtitle" + ] =?> + Pandoc (setMeta "title" (MetaInlines $ toList "Document title") $ + setMeta "subtitle" (MetaInlines $ toList "Document subtitle") nullMeta) mempty + , "Multiline directive" =: + T.unlines [ "#title Document title" + , "#notes First line" + , "and second line" + , "#author Name" + ] =?> + Pandoc (setMeta "title" (MetaInlines $ toList "Document title") $ + setMeta "notes" (MetaInlines $ toList "First line\nand second line") $ + setMeta "author" (MetaInlines $ toList "Name") nullMeta) mempty + ] + , testGroup "Anchors" + [ "Anchor" =: + T.unlines [ "; A comment to make sure anchor is not parsed as a directive" + , "#anchor Target" + ] =?> + para (spanWith ("anchor", [], []) mempty <> "Target") + , "Anchor cannot start with a number" =: + T.unlines [ "; A comment to make sure anchor is not parsed as a directive" + , "#0notanchor Target" + ] =?> + para "#0notanchor Target" + , "Not anchor if starts with a space" =: + " #notanchor Target" =?> + para "#notanchor Target" + , "Anchor inside a paragraph" =: + T.unlines [ "Paragraph starts here" + , "#anchor and ends here." + ] =?> + para ("Paragraph starts here\n" <> spanWith ("anchor", [], []) mempty <> "and ends here.") + ] + , testGroup "Footnotes" + [ "Simple footnote" =: + T.unlines [ "Here is a footnote[1]." + , "" + , "[1] Footnote contents" + ] =?> + para (text "Here is a footnote" <> + note (para "Footnote contents") <> + str ".") + , "Recursive footnote" =: + T.unlines [ "Start recursion here[1]" + , "" + , "[1] Recursion continues here[1]" + ] =?> + para (text "Start recursion here" <> + note (para "Recursion continues here[1]")) + , "No zero footnotes" =: + T.unlines [ "Here is a footnote[0]." + , "" + , "[0] Footnote contents" + ] =?> + para "Here is a footnote[0]." <> + para "[0] Footnote contents" + , "Footnotes can't start with zero" =: + T.unlines [ "Here is a footnote[01]." + , "" + , "[01] Footnote contents" + ] =?> + para "Here is a footnote[01]." <> + para "[01] Footnote contents" + , testGroup "Multiparagraph footnotes" + [ "Amusewiki multiparagraph footnotes" =: + T.unlines [ "Multiparagraph[1] footnotes[2]" + , "" + , "[1] First footnote paragraph" + , "" + , " Second footnote paragraph" + , "with continuation" + , "" + , "Not a note" + , "[2] Second footnote" + ] =?> + para (text "Multiparagraph" <> + note (para "First footnote paragraph" <> + para "Second footnote paragraph\nwith continuation") <> + text " footnotes" <> + note (para "Second footnote")) <> + para (text "Not a note") + + -- Verse requires precise indentation, so it is good to test indentation requirements + , "Note continuation with verse" =: + T.unlines [ "Foo[1]" + , "" + , "[1] Bar" + , "" + , " > Baz" + ] =?> + para ("Foo" <> note (para "Bar" <> lineBlock ["Baz"])) + , test emacsMuse "Emacs multiparagraph footnotes" + (T.unlines + [ "First footnote reference[1] and second footnote reference[2]." + , "" + , "[1] First footnote paragraph" + , "" + , "Second footnote" + , "paragraph" + , "" + , "[2] Third footnote paragraph" + , "" + , "Fourth footnote paragraph" + ] =?> + para (text "First footnote reference" <> + note (para "First footnote paragraph" <> + para "Second footnote\nparagraph") <> + text " and second footnote reference" <> + note (para "Third footnote paragraph" <> + para "Fourth footnote paragraph") <> + text ".")) + ] + ] + ] + , testGroup "Tables" + [ "Two cell table" =: + "One | Two" =?> + table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)] + [] + [[plain "One", plain "Two"]] + , "Table with multiple words" =: + "One two | three four" =?> + table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)] + [] + [[plain "One two", plain "three four"]] + , "Not a table" =: + "One| Two" =?> + para (text "One| Two") + , "Not a table again" =: + "One |Two" =?> + para (text "One |Two") + , "Two line table" =: + T.unlines + [ "One | Two" + , "Three | Four" + ] =?> + table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)] + [] + [[plain "One", plain "Two"], + [plain "Three", plain "Four"]] + , "Table with one header" =: + T.unlines + [ "First || Second" + , "Third | Fourth" + ] =?> + table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)] + [plain "First", plain "Second"] + [[plain "Third", plain "Fourth"]] + , "Table with two headers" =: + T.unlines + [ "First || header" + , "Second || header" + , "Foo | bar" + ] =?> + table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)] + [plain "First", plain "header"] + [[plain "Second", plain "header"], + [plain "Foo", plain "bar"]] + , "Header and footer reordering" =: + T.unlines + [ "Foo ||| bar" + , "Baz || foo" + , "Bar | baz" + ] =?> + table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)] + [plain "Baz", plain "foo"] + [[plain "Bar", plain "baz"], + [plain "Foo", plain "bar"]] + , "Table with caption" =: + T.unlines + [ "Foo || bar || baz" + , "First | row | here" + , "Second | row | there" + , "|+ Table caption +|" + ] =?> + table (text "Table caption") (replicate 3 (AlignDefault, 0.0)) + [plain "Foo", plain "bar", plain "baz"] + [[plain "First", plain "row", plain "here"], + [plain "Second", plain "row", plain "there"]] + , "Caption without table" =: + "|+ Foo bar baz +|" =?> + table (text "Foo bar baz") [] [] [] + , "Table indented with space" =: + T.unlines + [ " Foo | bar" + , " Baz | foo" + , " Bar | baz" + ] =?> + table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)] + [] + [[plain "Foo", plain "bar"], + [plain "Baz", plain "foo"], + [plain "Bar", plain "baz"]] + , "Empty cells" =: + T.unlines + [ " | Foo" + , " |" + , " bar |" + , " || baz" + ] =?> + table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)] + [plain "", plain "baz"] + [[plain "", plain "Foo"], + [plain "", plain ""], + [plain "bar", plain ""]] + ] + , testGroup "Lists" + [ "Bullet list" =: + T.unlines + [ " - Item1" + , "" + , " - Item2" + ] =?> + bulletList [ para "Item1" + , para "Item2" + ] + , "Ordered list" =: + T.unlines + [ " 1. Item1" + , "" + , " 2. Item2" + ] =?> + orderedListWith (1, Decimal, Period) [ para "Item1" + , para "Item2" + ] + , "Ordered list with implicit numbers" =: + T.unlines + [ " 1. Item1" + , "" + , " 1. Item2" + , "" + , " 1. Item3" + ] =?> + orderedListWith (1, Decimal, Period) [ para "Item1" + , para "Item2" + , para "Item3" + ] + , "Ordered list with roman numerals" =: + T.unlines + [ " i. First" + , " ii. Second" + , " iii. Third" + , " iv. Fourth" + ] =?> + orderedListWith (1, LowerRoman, Period) [ para "First" + , para "Second" + , para "Third" + , para "Fourth" + ] + , "Bullet list with empty items" =: + T.unlines + [ " -" + , "" + , " - Item2" + ] =?> + bulletList [ mempty + , para "Item2" + ] + , "Ordered list with empty items" =: + T.unlines + [ " 1." + , "" + , " 2." + , "" + , " 3. Item3" + ] =?> + orderedListWith (1, Decimal, Period) [ mempty + , mempty + , para "Item3" + ] + , "Bullet list with last item empty" =: + T.unlines + [ " -" + , "" + , "foo" + ] =?> + bulletList [ mempty ] <> + para "foo" + , testGroup "Nested lists" + [ "Nested bullet list" =: + T.unlines [ " - Item1" + , " - Item2" + , " - Item3" + , " - Item4" + , " - Item5" + , " - Item6" + ] =?> + bulletList [ para "Item1" <> + bulletList [ para "Item2" <> + bulletList [ para "Item3" ] + , para "Item4" <> + bulletList [ para "Item5" ] + ] + , para "Item6" + ] + , "Nested ordered list" =: + T.unlines [ " 1. Item1" + , " 1. Item2" + , " 1. Item3" + , " 2. Item4" + , " 1. Item5" + , " 2. Item6" + ] =?> + orderedListWith (1, Decimal, Period) [ para "Item1" <> + orderedListWith (1, Decimal, Period) [ para "Item2" <> + orderedListWith (1, Decimal, Period) [ para "Item3" ] + , para "Item4" <> + orderedListWith (1, Decimal, Period) [ para "Item5" ] + ] + , para "Item6" + ] + , "Mixed nested list" =: + T.unlines + [ " - Item1" + , " - Item2" + , " - Item3" + , " - Item4" + , " 1. Nested" + , " 2. Ordered" + , " 3. List" + ] =?> + bulletList [ mconcat [ para "Item1" + , bulletList [ para "Item2" + , para "Item3" + ] + ] + , mconcat [ para "Item4" + , orderedListWith (1, Decimal, Period) [ para "Nested" + , para "Ordered" + , para "List" + ] + ] + ] + , "Text::Amuse includes only one space in list marker" =: + T.unlines + [ " - First item" + , " - Nested item" + ] =?> + bulletList [ para "First item" <> bulletList [ para "Nested item"]] + ] + , "List continuation" =: + T.unlines + [ " - a" + , "" + , " b" + , "" + , " c" + ] =?> + bulletList [ mconcat [ para "a" + , para "b" + , para "c" + ] + ] + , "List continuation afeter nested list" =: + T.unlines + [ " - - foo" + , "" + , " bar" + ] =?> + bulletList [ bulletList [ para "foo" ] <> + para "bar" + ] + -- Emacs Muse allows to separate lists with two or more blank lines. + -- Text::Amuse (Amusewiki engine) always creates a single list as of version 0.82. + -- pandoc follows Emacs Muse behavior + , testGroup "Blank lines" + [ "Blank lines between list items are not required" =: + T.unlines + [ " - Foo" + , " - Bar" + ] =?> + bulletList [ para "Foo" + , para "Bar" + ] + , "One blank line between list items is allowed" =: + T.unlines + [ " - Foo" + , "" + , " - Bar" + ] =?> + bulletList [ para "Foo" + , para "Bar" + ] + , "Two blank lines separate lists" =: + T.unlines + [ " - Foo" + , "" + , "" + , " - Bar" + ] =?> + bulletList [ para "Foo" ] <> bulletList [ para "Bar" ] + , "No blank line after multiline first item" =: + T.unlines + [ " - Foo" + , " bar" + , " - Baz" + ] =?> + bulletList [ para "Foo\nbar" + , para "Baz" + ] + , "One blank line after multiline first item" =: + T.unlines + [ " - Foo" + , " bar" + , "" + , " - Baz" + ] =?> + bulletList [ para "Foo\nbar" + , para "Baz" + ] + , "Two blank lines after multiline first item" =: + T.unlines + [ " - Foo" + , " bar" + , "" + , "" + , " - Baz" + ] =?> + bulletList [ para "Foo\nbar" ] <> bulletList [ para "Baz" ] + , "No blank line after list continuation" =: + T.unlines + [ " - Foo" + , "" + , " bar" + , " - Baz" + ] =?> + bulletList [ para "Foo" <> para "bar" + , para "Baz" + ] + , "One blank line after list continuation" =: + T.unlines + [ " - Foo" + , "" + , " bar" + , "" + , " - Baz" + ] =?> + bulletList [ para "Foo" <> para "bar" + , para "Baz" + ] + , "Two blank lines after list continuation" =: + T.unlines + [ " - Foo" + , "" + , " bar" + , "" + , "" + , " - Baz" + ] =?> + bulletList [ para "Foo" <> para "bar" ] <> bulletList [ para "Baz" ] + , "No blank line after blockquote" =: + T.unlines + [ " - <quote>" + , " foo" + , " </quote>" + , " - bar" + ] =?> + bulletList [ blockQuote $ para "foo", para "bar" ] + , "One blank line after blockquote" =: + T.unlines + [ " - <quote>" + , " foo" + , " </quote>" + , "" + , " - bar" + ] =?> + bulletList [ blockQuote $ para "foo", para "bar" ] + , "Two blank lines after blockquote" =: + T.unlines + [ " - <quote>" + , " foo" + , " </quote>" + , "" + , "" + , " - bar" + ] =?> + bulletList [ blockQuote $ para "foo" ] <> bulletList [ para "bar" ] + , "No blank line after verse" =: + T.unlines + [ " - > foo" + , " - bar" + ] =?> + bulletList [ lineBlock [ "foo" ], para "bar" ] + , "One blank line after verse" =: + T.unlines + [ " - > foo" + , "" + , " - bar" + ] =?> + bulletList [ lineBlock [ "foo" ], para "bar" ] + , "Two blank lines after verse" =: + T.unlines + [ " - > foo" + , "" + , "" + , " - bar" + ] =?> + bulletList [ lineBlock [ "foo" ] ] <> bulletList [ para "bar" ] + ] + -- Test that definition list requires a leading space. + -- Emacs Muse does not require a space, we follow Amusewiki here. + , "Not a definition list" =: + T.unlines + [ "First :: second" + , "Foo :: bar" + ] =?> + para "First :: second\nFoo :: bar" + , test emacsMuse "Emacs Muse definition list" + (T.unlines + [ "First :: second" + , "Foo :: bar" + ] =?> + definitionList [ ("First", [ para "second" ]) + , ("Foo", [ para "bar" ]) + ]) + , "Definition list" =: + T.unlines + [ " First :: second" + , " Foo :: bar" + ] =?> + definitionList [ ("First", [ para "second" ]) + , ("Foo", [ para "bar" ]) + ] + , "Definition list term cannot include newline" =: + T.unlines + [ " Foo" -- "Foo" is not a part of the definition list term + , " Bar :: baz" + ] =?> + para "Foo" <> + definitionList [ ("Bar", [ para "baz" ]) ] + , "One-line definition list" =: " foo :: bar" =?> + definitionList [ ("foo", [ para "bar" ]) ] + , "Definition list term may include single colon" =: + " foo:bar :: baz" =?> + definitionList [ ("foo:bar", [ para "baz" ]) ] + , "Definition list term with emphasis" =: " *Foo* :: bar\n" =?> + definitionList [ (emph "Foo", [ para "bar" ]) ] + , "Definition list term with :: inside code" =: " foo <code> :: </code> :: bar <code> :: </code> baz\n" =?> + definitionList [ ("foo " <> code " :: ", [ para $ "bar " <> code " :: " <> " baz" ]) ] + , "Multi-line definition lists" =: + T.unlines + [ " First term :: Definition of first term" + , "and its continuation." + , " Second term :: Definition of second term." + ] =?> + definitionList [ ("First term", [ para "Definition of first term\nand its continuation." ]) + , ("Second term", [ para "Definition of second term." ]) + ] + , test emacsMuse "Multi-line definition lists from Emacs Muse manual" + (T.unlines + [ "Term1 ::" + , " This is a first definition" + , " And it has two lines;" + , "no, make that three." + , "" + , "Term2 :: This is a second definition" + ] =?> + definitionList [ ("Term1", [ para "This is a first definition\nAnd it has two lines;\nno, make that three."]) + , ("Term2", [ para "This is a second definition"]) + ]) + -- Text::Amuse requires indentation with one space + , "Multi-line definition lists from Emacs Muse manual with initial space" =: + (T.unlines + [ " Term1 ::" + , " This is a first definition" + , " And it has two lines;" + , "no, make that three." + , "" + , " Term2 :: This is a second definition" + ] =?> + definitionList [ ("Term1", [ para "This is a first definition\nAnd it has two lines;\nno, make that three."]) + , ("Term2", [ para "This is a second definition"]) + ]) + , "One-line nested definition list" =: + " Foo :: bar :: baz" =?> + definitionList [ ("Foo", [ definitionList [ ("bar", [ para "baz" ])]])] + , "Nested definition list" =: + T.unlines + [ " First :: Second :: Third" + , " Fourth :: Fifth :: Sixth" + , " Seventh :: Eighth" + ] =?> + definitionList [ ("First", [ definitionList [ ("Second", [ para "Third" ]), + ("Fourth", [ definitionList [ ("Fifth", [ para "Sixth"] ) ] ] ) ] ] ) + , ("Seventh", [ para "Eighth" ]) + ] + , testGroup "Definition lists with multiple descriptions" + [ "Correctly indented second description" =: + T.unlines + [ " First term :: first description" + , " :: second description" + ] =?> + definitionList [ ("First term", [ para "first description" + , para "second description" + ]) + ] + , "Incorrectly indented second description" =: + T.unlines + [ " First term :: first description" + , " :: second description" + ] =?> + definitionList [ ("First term", [ para "first description" ]) + , ("", [ para "second description" ]) + ] + ] + , "Two blank lines separate definition lists" =: + T.unlines + [ " First :: list" + , "" + , "" + , " Second :: list" + ] =?> + definitionList [ ("First", [ para "list" ]) ] <> + definitionList [ ("Second", [ para "list" ]) ] + -- Headers in first column of list continuation are not allowed + , "No headers in list continuation" =: + T.unlines + [ " - Foo" + , "" + , " * Bar" + ] =?> + bulletList [ mconcat [ para "Foo" + , para "* Bar" + ] + ] + , "Bullet list inside a tag" =: + T.unlines + [ "<quote>" + , " - First" + , "" + , " - Second" + , "" + , " - Third" + , "</quote>" + ] =?> + blockQuote (bulletList [ para "First" + , para "Second" + , para "Third" + ]) + , "Ordered list inside a tag" =: + T.unlines + [ "<quote>" + , " 1. First" + , "" + , " 2. Second" + , "" + , " 3. Third" + , "</quote>" + ] =?> + blockQuote (orderedListWith (1, Decimal, Period) [ para "First" + , para "Second" + , para "Third" + ]) + -- Regression test for a bug caught by round-trip test + , "Do not consume whitespace while looking for end tag" =: + T.unlines + [ "<quote>" + , " - <quote>" + , " foo" + , " </quote>" + , " bar" -- Do not consume whitespace while looking for arbitraritly indented </quote> + , "</quote>" + ] =?> + blockQuote (bulletList [ blockQuote $ para "foo" ] <> para "bar") + + , "Unclosed quote tag" =: + T.unlines + [ "<quote>" + , "<verse>" + , "</quote>" + , "</verse>" + ] =?> + para "<quote>" <> lineBlock [ "</quote>" ] + + , "Unclosed quote tag inside list" =: + T.unlines + [ " - <quote>" + , " <verse>" + , " </quote>" + , " </verse>" + ] =?> + bulletList [ para "<quote>" <> lineBlock [ "</quote>" ] ] + + -- Allowing indented closing tags is dangerous, + -- as they may terminate lists + , "No indented closing tags" =: + T.unlines + [ "<quote>" + , "" + , " - Foo" + , "" + , " </quote>" + , "" + , " bar" + , "" + , " <verse>" + , " </quote>" + , " </verse>" + ] =?> + para "<quote>" <> bulletList [ para "Foo" <> para "</quote>" <> para "bar" <> lineBlock [ "</quote>" ] ] + ] + ] diff --git a/test/Tests/Readers/Odt.hs.orig b/test/Tests/Readers/Odt.hs.orig new file mode 100644 index 000000000..4b7058cf9 --- /dev/null +++ b/test/Tests/Readers/Odt.hs.orig @@ -0,0 +1,170 @@ +module Tests.Readers.Odt (tests) where + +import Control.Monad (liftM) +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as B +import qualified Data.Map as M +import Data.Text (unpack) +import System.IO.Unsafe (unsafePerformIO) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import qualified Text.Pandoc.UTF8 as UTF8 + +defopts :: ReaderOptions +defopts = def{ readerExtensions = getDefaultExtensions "odt" } + +tests :: [TestTree] +tests = testsComparingToMarkdown ++ testsComparingToNative + +testsComparingToMarkdown :: [TestTree] +testsComparingToMarkdown = map nameToTest namesOfTestsComparingToMarkdown + where nameToTest name = createTest + compareOdtToMarkdown + name + (toOdtPath name) + (toMarkdownPath name) + toOdtPath name = "odt/odt/" ++ name ++ ".odt" + toMarkdownPath name = "odt/markdown/" ++ name ++ ".md" + +testsComparingToNative :: [TestTree] +testsComparingToNative = map nameToTest namesOfTestsComparingToNative + where nameToTest name = createTest + compareOdtToNative + name + (toOdtPath name) + (toNativePath name) + toOdtPath name = "odt/odt/" ++ name ++ ".odt" + toNativePath name = "odt/native/" ++ name ++ ".native" + + +newtype NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc} + deriving ( Show ) + +instance ToString NoNormPandoc where + toString d = unpack $ + purely (writeNative def{ writerTemplate = s }) $ toPandoc d + where s = case d of + NoNormPandoc (Pandoc (Meta m) _) + | M.null m -> Nothing + | otherwise -> Just "" -- need this for Meta output + +instance ToPandoc NoNormPandoc where + toPandoc = unNoNorm + +getNoNormVia :: (a -> Pandoc) -> String -> Either PandocError a -> NoNormPandoc +getNoNormVia _ readerName (Left _) = error (readerName ++ " reader failed") +getNoNormVia f _ (Right a) = NoNormPandoc (f a) + +type TestCreator = ReaderOptions + -> FilePath -> FilePath + -> IO (NoNormPandoc, NoNormPandoc) + +compareOdtToNative :: TestCreator +compareOdtToNative opts odtPath nativePath = do + nativeFile <- UTF8.toText <$> BS.readFile nativePath + odtFile <- B.readFile odtPath + native <- getNoNormVia id "native" <$> runIO (readNative def nativeFile) + odt <- getNoNormVia id "odt" <$> runIO (readOdt opts odtFile) + return (odt,native) + +compareOdtToMarkdown :: TestCreator +compareOdtToMarkdown opts odtPath markdownPath = do + markdownFile <- UTF8.toText <$> BS.readFile markdownPath + odtFile <- B.readFile odtPath + markdown <- getNoNormVia id "markdown" <$> + runIO (readMarkdown def{ readerExtensions = pandocExtensions } + markdownFile) + odt <- getNoNormVia id "odt" <$> runIO (readOdt opts odtFile) + return (odt,markdown) + + +createTest :: TestCreator + -> TestName + -> FilePath -> FilePath + -> TestTree +createTest creator name path1 path2 = + unsafePerformIO $ liftM (test id name) (creator defopts path1 path2) + +{- +-- + +getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString) +getMedia archivePath mediaPath = do + zf <- B.readFile archivePath >>= return . toArchive + return $ findEntryByPath ("Pictures/" ++ mediaPath) zf >>= (Just . fromEntry) + +compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool +compareMediaPathIO mediaPath mediaBag odtPath = do + odtMedia <- getMedia odtPath mediaPath + let mbBS = case lookupMedia mediaPath mediaBag of + Just (_, bs) -> bs + Nothing -> error ("couldn't find " ++ + mediaPath ++ + " in media bag") + odtBS = case odtMedia of + Just bs -> bs + Nothing -> error ("couldn't find " ++ + mediaPath ++ + " in media bag") + return $ mbBS == odtBS + +compareMediaBagIO :: FilePath -> IO Bool +compareMediaBagIO odtFile = do + df <- B.readFile odtFile + let (_, mb) = readOdt def df + bools <- mapM + (\(fp, _, _) -> compareMediaPathIO fp mb odtFile) + (mediaDirectory mb) + return $ and bools + +testMediaBagIO :: String -> FilePath -> IO TestTree +testMediaBagIO name odtFile = do + outcome <- compareMediaBagIO odtFile + return $ testCase name (assertBool + ("Media didn't match media bag in file " ++ odtFile) + outcome) + +testMediaBag :: String -> FilePath -> TestTree +testMediaBag name odtFile = buildTest $ testMediaBagIO name odtFile +-} +-- + + + +namesOfTestsComparingToMarkdown :: [ String ] +namesOfTestsComparingToMarkdown = [ "bold" +-- , "citation" + , "endnote" + , "externalLink" + , "footnote" + , "headers" +-- , "horizontalRule" + , "italic" +-- , "listBlocks" + , "paragraph" + , "strikeout" +-- , "trackedChanges" + , "underlined" + ] + +namesOfTestsComparingToNative :: [ String ] +namesOfTestsComparingToNative = [ "blockquote" + , "image" + , "imageIndex" + , "imageWithCaption" + , "inlinedCode" + , "orderedListMixed" + , "orderedListRoman" + , "orderedListSimple" + , "referenceToChapter" + , "referenceToListItem" + , "referenceToText" + , "simpleTable" + , "simpleTableWithCaption" +-- , "table" + , "textMixedStyles" + , "tableWithContents" + , "unicode" + , "unorderedList" + ] diff --git a/test/Tests/Readers/Org.hs.orig b/test/Tests/Readers/Org.hs.orig new file mode 100644 index 000000000..de7f14e32 --- /dev/null +++ b/test/Tests/Readers/Org.hs.orig @@ -0,0 +1,16 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org (tests) where + +import Test.Tasty (TestTree, testGroup) +import qualified Tests.Readers.Org.Block as Block +import qualified Tests.Readers.Org.Directive as Directive +import qualified Tests.Readers.Org.Inline as Inline +import qualified Tests.Readers.Org.Meta as Meta + +tests :: [TestTree] +tests = + [ testGroup "Inlines" Inline.tests + , testGroup "Basic Blocks" Block.tests + , testGroup "Meta Information" Meta.tests + , testGroup "Directives" Directive.tests + ] diff --git a/test/Tests/Readers/Org/Block.hs.orig b/test/Tests/Readers/Org/Block.hs.orig new file mode 100644 index 000000000..15dc63554 --- /dev/null +++ b/test/Tests/Readers/Org/Block.hs.orig @@ -0,0 +1,192 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Block (tests) where + +import Test.Tasty (TestTree, testGroup) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:), spcSep) +import Text.Pandoc.Builder +import qualified Data.Text as T +import qualified Tests.Readers.Org.Block.CodeBlock as CodeBlock +import qualified Tests.Readers.Org.Block.Figure as Figure +import qualified Tests.Readers.Org.Block.Header as Header +import qualified Tests.Readers.Org.Block.List as List +import qualified Tests.Readers.Org.Block.Table as Table + +tests :: [TestTree] +tests = + [ "Paragraph" =: + "Paragraph\n" =?> + para "Paragraph" + + , "Paragraph starting with an asterisk" =: + "*five" =?> + para "*five" + + , "Paragraph containing asterisk at beginning of line" =: + T.unlines [ "lucky" + , "*star" + ] =?> + para ("lucky" <> softbreak <> "*star") + + , "Example block" =: + T.unlines [ ": echo hello" + , ": echo dear tester" + ] =?> + codeBlockWith ("", ["example"], []) "echo hello\necho dear tester\n" + + , "Example block surrounded by text" =: + T.unlines [ "Greetings" + , ": echo hello" + , ": echo dear tester" + , "Bye" + ] =?> + mconcat [ para "Greetings" + , codeBlockWith ("", ["example"], []) + "echo hello\necho dear tester\n" + , para "Bye" + ] + + , "Horizontal Rule" =: + T.unlines [ "before" + , "-----" + , "after" + ] =?> + mconcat [ para "before" + , horizontalRule + , para "after" + ] + + , "Not a Horizontal Rule" =: + "----- em and en dash" =?> + para "\8212\8211 em and en dash" + + , "Comment Block" =: + T.unlines [ "#+BEGIN_COMMENT" + , "stuff" + , "bla" + , "#+END_COMMENT"] =?> + (mempty::Blocks) + + , testGroup "Blocks and fragments" + [ "HTML block" =: + T.unlines [ "#+BEGIN_HTML" + , "<aside>HTML5 is pretty nice.</aside>" + , "#+END_HTML" + ] =?> + rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n" + + , "Quote block" =: + T.unlines [ "#+BEGIN_QUOTE" + , "/Niemand/ hat die Absicht, eine Mauer zu errichten!" + , "#+END_QUOTE" + ] =?> + blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht," + , "eine", "Mauer", "zu", "errichten!" + ])) + + , "Verse block" =: + T.unlines [ "The first lines of Goethe's /Faust/:" + , "#+begin_verse" + , "Habe nun, ach! Philosophie," + , "Juristerei und Medizin," + , "Und leider auch Theologie!" + , "Durchaus studiert, mit heißem Bemühn." + , "#+end_verse" + ] =?> + mconcat + [ para $ spcSep [ "The", "first", "lines", "of" + , "Goethe's", emph "Faust" <> ":"] + , lineBlock + [ "Habe nun, ach! Philosophie," + , "Juristerei und Medizin," + , "Und leider auch Theologie!" + , "Durchaus studiert, mit heißem Bemühn." + ] + ] + + , "Verse block with blank lines" =: + T.unlines [ "#+BEGIN_VERSE" + , "foo" + , "" + , "bar" + , "#+END_VERSE" + ] =?> + lineBlock [ "foo", mempty, "bar" ] + + , "Verse block with varying indentation" =: + T.unlines [ "#+BEGIN_VERSE" + , " hello darkness" + , "my old friend" + , "#+END_VERSE" + ] =?> + lineBlock [ "\160\160hello darkness", "my old friend" ] + + , "Raw block LaTeX" =: + T.unlines [ "#+BEGIN_LaTeX" + , "The category $\\cat{Set}$ is adhesive." + , "#+END_LaTeX" + ] =?> + rawBlock "latex" "The category $\\cat{Set}$ is adhesive.\n" + + , "Raw LaTeX line" =: + "#+LATEX: \\let\\foo\\bar" =?> + rawBlock "latex" "\\let\\foo\\bar" + + , "Raw Beamer line" =: + "#+beamer: \\pause" =?> + rawBlock "beamer" "\\pause" + + , "Raw HTML line" =: + "#+HTML: <aside>not important</aside>" =?> + rawBlock "html" "<aside>not important</aside>" + + , "Export block HTML" =: + T.unlines [ "#+BEGIN_export html" + , "<samp>Hello, World!</samp>" + , "#+END_export" + ] =?> + rawBlock "html" "<samp>Hello, World!</samp>\n" + + , "LaTeX fragment" =: + T.unlines [ "\\begin{equation}" + , "X_i = \\begin{cases}" + , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) = \\alpha(i)\\\\" + , " C_{\\alpha(i)} & \\text{otherwise}" + , " \\end{cases}" + , "\\end{equation}" + ] =?> + rawBlock "latex" + (unlines [ "\\begin{equation}" + , "X_i = \\begin{cases}" + , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" <> + " \\alpha(i)\\\\" + , " C_{\\alpha(i)} & \\text{otherwise}" + , " \\end{cases}" + , "\\end{equation}" + ]) + + , "Convert blank lines in blocks to single newlines" =: + T.unlines [ "#+begin_html" + , "" + , "<span>boring</span>" + , "" + , "#+end_html" + ] =?> + rawBlock "html" "\n<span>boring</span>\n\n" + + , "Accept `ATTR_HTML` attributes for generic block" =: + T.unlines [ "#+ATTR_HTML: :title hello, world :id test :class fun code" + , "#+BEGIN_TEST" + , "nonsense" + , "#+END_TEST" + ] =?> + let attr = ("test", ["fun", "code", "TEST"], [("title", "hello, world")]) + in divWith attr (para "nonsense") + ] + + , testGroup "Headers" Header.tests + , testGroup "Figures" Figure.tests + , testGroup "Lists" List.tests + , testGroup "CodeBlocks" CodeBlock.tests + , testGroup "Tables" Table.tests + ] diff --git a/test/Tests/Readers/Org/Block/CodeBlock.hs.orig b/test/Tests/Readers/Org/Block/CodeBlock.hs.orig new file mode 100644 index 000000000..8fa822089 --- /dev/null +++ b/test/Tests/Readers/Org/Block/CodeBlock.hs.orig @@ -0,0 +1,194 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Block.CodeBlock (tests) where + +import Test.Tasty (TestTree) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:), spcSep) +import Text.Pandoc.Builder +import qualified Data.Text as T + +tests :: [TestTree] +tests = + [ "Source block" =: + T.unlines [ " #+BEGIN_SRC haskell" + , " main = putStrLn greeting" + , " where greeting = \"moin\"" + , " #+END_SRC" ] =?> + let attr' = ("", ["haskell"], []) + code' = "main = putStrLn greeting\n" <> + " where greeting = \"moin\"\n" + in codeBlockWith attr' code' + + , "Source block with indented code" =: + T.unlines [ " #+BEGIN_SRC haskell" + , " main = putStrLn greeting" + , " where greeting = \"moin\"" + , " #+END_SRC" ] =?> + let attr' = ("", ["haskell"], []) + code' = "main = putStrLn greeting\n" <> + " where greeting = \"moin\"\n" + in codeBlockWith attr' code' + + , "Source block with tab-indented code" =: + T.unlines [ "\t#+BEGIN_SRC haskell" + , "\tmain = putStrLn greeting" + , "\t where greeting = \"moin\"" + , "\t#+END_SRC" ] =?> + let attr' = ("", ["haskell"], []) + code' = "main = putStrLn greeting\n" <> + " where greeting = \"moin\"\n" + in codeBlockWith attr' code' + + , "Empty source block" =: + T.unlines [ " #+BEGIN_SRC haskell" + , " #+END_SRC" ] =?> + let attr' = ("", ["haskell"], []) + code' = "" + in codeBlockWith attr' code' + + , "Source block between paragraphs" =: + T.unlines [ "Low German greeting" + , " #+BEGIN_SRC haskell" + , " main = putStrLn greeting" + , " where greeting = \"Moin!\"" + , " #+END_SRC" ] =?> + let attr' = ("", ["haskell"], []) + code' = "main = putStrLn greeting\n" <> + " where greeting = \"Moin!\"\n" + in mconcat [ para $ spcSep [ "Low", "German", "greeting" ] + , codeBlockWith attr' code' + ] + , "Source block with babel arguments" =: + T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both" + , "(progn (message \"Hello, World!\")" + , " (+ 23 42))" + , "#+END_SRC" ] =?> + let classes = [ "commonlisp" ] -- as kate doesn't know emacs-lisp syntax + params = [ ("org-language", "emacs-lisp") + , ("exports", "both") + ] + code' = unlines [ "(progn (message \"Hello, World!\")" + , " (+ 23 42))" ] + in codeBlockWith ("", classes, params) code' + + , "Source block with results and :exports both" =: + T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both" + , "(progn (message \"Hello, World!\")" + , " (+ 23 42))" + , "#+END_SRC" + , "" + , "#+RESULTS:" + , ": 65"] =?> + let classes = [ "commonlisp" ] + params = [ ("org-language", "emacs-lisp") + , ("exports", "both") + ] + code' = unlines [ "(progn (message \"Hello, World!\")" + , " (+ 23 42))" ] + results' = "65\n" + in codeBlockWith ("", classes, params) code' + <> + codeBlockWith ("", ["example"], []) results' + + , "Source block with results and :exports code" =: + T.unlines [ "#+BEGIN_SRC emacs-lisp :exports code" + , "(progn (message \"Hello, World!\")" + , " (+ 23 42))" + , "#+END_SRC" + , "" + , "#+RESULTS:" + , ": 65" ] =?> + let classes = [ "commonlisp" ] + params = [ ("org-language", "emacs-lisp") + , ("exports", "code") + ] + code' = unlines [ "(progn (message \"Hello, World!\")" + , " (+ 23 42))" ] + in codeBlockWith ("", classes, params) code' + + , "Source block with results and :exports results" =: + T.unlines [ "#+BEGIN_SRC emacs-lisp :exports results" + , "(progn (message \"Hello, World!\")" + , " (+ 23 42))" + , "#+END_SRC" + , "" + , "#+RESULTS:" + , ": 65" ] =?> + let results' = "65\n" + in codeBlockWith ("", ["example"], []) results' + + , "Source block with results and :exports none" =: + T.unlines [ "#+BEGIN_SRC emacs-lisp :exports none" + , "(progn (message \"Hello, World!\")" + , " (+ 23 42))" + , "#+END_SRC" + , "" + , "#+RESULTS:" + , ": 65" ] =?> + (mempty :: Blocks) + + , "Source block with toggling header arguments" =: + T.unlines [ "#+BEGIN_SRC sh :noeval" + , "echo $HOME" + , "#+END_SRC" + ] =?> + let classes = [ "bash" ] + params = [ ("org-language", "sh"), ("noeval", "yes") ] + in codeBlockWith ("", classes, params) "echo $HOME\n" + + , "Source block with line number switch" =: + T.unlines [ "#+BEGIN_SRC sh -n 10" + , ":() { :|:& };:" + , "#+END_SRC" + ] =?> + let classes = [ "bash", "numberLines" ] + params = [ ("org-language", "sh"), ("startFrom", "10") ] + in codeBlockWith ("", classes, params) ":() { :|:& };:\n" + + , "Source block with multi-word parameter values" =: + T.unlines [ "#+BEGIN_SRC dot :cmdline -Kdot -Tpng " + , "digraph { id [label=\"ID\"] }" + , "#+END_SRC" + ] =?> + let classes = [ "dot" ] + params = [ ("cmdline", "-Kdot -Tpng") ] + in codeBlockWith ("", classes, params) "digraph { id [label=\"ID\"] }\n" + + , "Example block" =: + T.unlines [ "#+begin_example" + , "A chosen representation of" + , "a rule." + , "#+eND_exAMPle" + ] =?> + codeBlockWith ("", ["example"], []) + "A chosen representation of\na rule.\n" + + , "Code block with caption" =: + T.unlines [ "#+CAPTION: Functor laws in Haskell" + , "#+NAME: functor-laws" + , "#+BEGIN_SRC haskell" + , "fmap id = id" + , "fmap (p . q) = (fmap p) . (fmap q)" + , "#+END_SRC" + ] =?> + divWith + nullAttr + (mappend + (plain $ spanWith ("", ["label"], []) + (spcSep [ "Functor", "laws", "in", "Haskell" ])) + (codeBlockWith ("functor-laws", ["haskell"], []) + (unlines [ "fmap id = id" + , "fmap (p . q) = (fmap p) . (fmap q)" + ]))) + + , "Non-letter chars in source block parameters" =: + T.unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich" + , "code body" + , "#+END_SRC" + ] =?> + let params = [ ("org-language", "C") + , ("tangle", "xxxx.c") + , ("city", "Zürich") + ] + in codeBlockWith ( "", ["c"], params) "code body\n" + ] diff --git a/test/Tests/Readers/Org/Block/Figure.hs.orig b/test/Tests/Readers/Org/Block/Figure.hs.orig new file mode 100644 index 000000000..cae6ef179 --- /dev/null +++ b/test/Tests/Readers/Org/Block/Figure.hs.orig @@ -0,0 +1,57 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Block.Figure (tests) where + +import Test.Tasty (TestTree) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:)) +import Text.Pandoc.Builder (image, imageWith, para) +import qualified Data.Text as T + +tests :: [TestTree] +tests = + [ "Figure" =: + T.unlines [ "#+caption: A very courageous man." + , "#+name: goodguy" + , "[[file:edward.jpg]]" + ] =?> + para (image "edward.jpg" "fig:goodguy" "A very courageous man.") + + , "Figure with no name" =: + T.unlines [ "#+caption: I've been through the desert on this" + , "[[file:horse.png]]" + ] =?> + para (image "horse.png" "fig:" "I've been through the desert on this") + + , "Figure with `fig:` prefix in name" =: + T.unlines [ "#+caption: Used as a metapher in evolutionary biology." + , "#+name: fig:redqueen" + , "[[./the-red-queen.jpg]]" + ] =?> + para (image "./the-red-queen.jpg" "fig:redqueen" + "Used as a metapher in evolutionary biology.") + + , "Figure with HTML attributes" =: + T.unlines [ "#+CAPTION: mah brain just explodid" + , "#+NAME: lambdacat" + , "#+ATTR_HTML: :style color: blue :role button" + , "[[file:lambdacat.jpg]]" + ] =?> + let kv = [("style", "color: blue"), ("role", "button")] + name = "fig:lambdacat" + caption = "mah brain just explodid" + in para (imageWith (mempty, mempty, kv) "lambdacat.jpg" name caption) + + , "Labelled figure" =: + T.unlines [ "#+CAPTION: My figure" + , "#+LABEL: fig:myfig" + , "[[file:blub.png]]" + ] =?> + let attr = ("fig:myfig", mempty, mempty) + in para (imageWith attr "blub.png" "fig:" "My figure") + + , "Figure with empty caption" =: + T.unlines [ "#+CAPTION:" + , "[[file:guess.jpg]]" + ] =?> + para (image "guess.jpg" "fig:" "") + ] diff --git a/test/Tests/Readers/Org/Block/Header.hs.orig b/test/Tests/Readers/Org/Block/Header.hs.orig new file mode 100644 index 000000000..e8ad88558 --- /dev/null +++ b/test/Tests/Readers/Org/Block/Header.hs.orig @@ -0,0 +1,182 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Block.Header (tests) where + +import Test.Tasty (TestTree, testGroup) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:), spcSep, tagSpan) +import Text.Pandoc.Builder +import qualified Data.Text as T + +tests :: [TestTree] +tests = + [ "First Level Header" =: + "* Headline\n" =?> + headerWith ("headline", [], []) 1 "Headline" + + , "Third Level Header" =: + "*** Third Level Headline\n" =?> + headerWith ("third-level-headline", [], []) + 3 + ("Third" <> space <> "Level" <> space <> "Headline") + + , "Compact Headers with Paragraph" =: + T.unlines [ "* First Level" + , "** Second Level" + , " Text" + ] =?> + mconcat [ headerWith ("first-level", [], []) + 1 + ("First" <> space <> "Level") + , headerWith ("second-level", [], []) + 2 + ("Second" <> space <> "Level") + , para "Text" + ] + + , "Separated Headers with Paragraph" =: + T.unlines [ "* First Level" + , "" + , "** Second Level" + , "" + , " Text" + ] =?> + mconcat [ headerWith ("first-level", [], []) + 1 + ("First" <> space <> "Level") + , headerWith ("second-level", [], []) + 2 + ("Second" <> space <> "Level") + , para "Text" + ] + + , "Headers not preceded by a blank line" =: + T.unlines [ "** eat dinner" + , "Spaghetti and meatballs tonight." + , "** walk dog" + ] =?> + mconcat [ headerWith ("eat-dinner", [], []) + 2 + ("eat" <> space <> "dinner") + , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ] + , headerWith ("walk-dog", [], []) + 2 + ("walk" <> space <> "dog") + ] + + , testGroup "Todo keywords" + [ "Header with known todo keyword" =: + "* TODO header" =?> + let todoSpan = spanWith ("", ["todo", "TODO"], []) "TODO" + in headerWith ("header", [], []) 1 (todoSpan <> space <> "header") + + , "Header marked as done" =: + "* DONE header" =?> + let todoSpan = spanWith ("", ["done", "DONE"], []) "DONE" + in headerWith ("header", [], []) 1 (todoSpan <> space <> "header") + + , "Header with unknown todo keyword" =: + "* WAITING header" =?> + headerWith ("waiting-header", [], []) 1 "WAITING header" + + , "Custom todo keywords" =: + T.unlines [ "#+TODO: WAITING CANCELLED" + , "* WAITING compile" + , "* CANCELLED lunch" + ] =?> + let todoSpan = spanWith ("", ["todo", "WAITING"], []) "WAITING" + doneSpan = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED" + in headerWith ("compile", [], []) 1 (todoSpan <> space <> "compile") + <> headerWith ("lunch", [], []) 1 (doneSpan <> space <> "lunch") + + , "Custom todo keywords with multiple done-states" =: + T.unlines [ "#+TODO: WAITING | DONE CANCELLED " + , "* WAITING compile" + , "* CANCELLED lunch" + , "* DONE todo-feature" + ] =?> + let waiting = spanWith ("", ["todo", "WAITING"], []) "WAITING" + cancelled = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED" + done = spanWith ("", ["done", "DONE"], []) "DONE" + in headerWith ("compile", [], []) 1 (waiting <> space <> "compile") + <> headerWith ("lunch", [], []) 1 (cancelled <> space <> "lunch") + <> headerWith ("todo-feature", [], []) 1 (done <> space <> "todo-feature") + ] + + , "Tagged headers" =: + T.unlines [ "* Personal :PERSONAL:" + , "** Call Mom :@PHONE:" + , "** Call John :@PHONE:JOHN: " + ] =?> + mconcat [ headerWith ("personal", [], []) + 1 + ("Personal " <> tagSpan "PERSONAL") + , headerWith ("call-mom", [], []) + 2 + ("Call Mom " <> tagSpan "@PHONE") + , headerWith ("call-john", [], []) + 2 + ("Call John " <> tagSpan "@PHONE" <> "\160" <> tagSpan "JOHN") + ] + + , "Untagged header containing colons" =: + "* This: is not: tagged" =?> + headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged" + + , "Header starting with strokeout text" =: + T.unlines [ "foo" + , "" + , "* +thing+ other thing" + ] =?> + mconcat [ para "foo" + , headerWith ("thing-other-thing", [], []) + 1 + (strikeout "thing" <> " other thing") + ] + + , "Comment Trees" =: + T.unlines [ "* COMMENT A comment tree" + , " Not much going on here" + , "** This will be dropped" + , "* Comment tree above" + ] =?> + headerWith ("comment-tree-above", [], []) 1 "Comment tree above" + + , "Nothing but a COMMENT header" =: + "* COMMENT Test" =?> + (mempty::Blocks) + + , "Tree with :noexport:" =: + T.unlines [ "* Should be ignored :archive:noexport:old:" + , "** Old stuff" + , " This is not going to be exported" + ] =?> + (mempty::Blocks) + + , "Subtree with :noexport:" =: + T.unlines [ "* Exported" + , "** This isn't exported :noexport:" + , "*** This neither" + , "** But this is" + ] =?> + mconcat [ headerWith ("exported", [], []) 1 "Exported" + , headerWith ("but-this-is", [], []) 2 "But this is" + ] + + , "Preferences are treated as header attributes" =: + T.unlines [ "* foo" + , " :PROPERTIES:" + , " :custom_id: fubar" + , " :bar: baz" + , " :END:" + ] =?> + headerWith ("fubar", [], [("bar", "baz")]) 1 "foo" + + + , "Headers marked with a unnumbered property get a class of the same name" =: + T.unlines [ "* Not numbered" + , " :PROPERTIES:" + , " :UNNUMBERED: t" + , " :END:" + ] =?> + headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered" + ] diff --git a/test/Tests/Readers/Org/Block/List.hs.orig b/test/Tests/Readers/Org/Block/List.hs.orig new file mode 100644 index 000000000..343682a80 --- /dev/null +++ b/test/Tests/Readers/Org/Block/List.hs.orig @@ -0,0 +1,244 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Block.List (tests) where + +import Test.Tasty (TestTree) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:), spcSep) +import Text.Pandoc.Builder +import qualified Data.Text as T + +tests :: [TestTree] +tests = + [ "Simple Bullet Lists" =: + ("- Item1\n" <> + "- Item2\n") =?> + bulletList [ plain "Item1" + , plain "Item2" + ] + + , "Indented Bullet Lists" =: + (" - Item1\n" <> + " - Item2\n") =?> + bulletList [ plain "Item1" + , plain "Item2" + ] + + , "Unindented *" =: + ("- Item1\n" <> + "* Item2\n") =?> + bulletList [ plain "Item1" + ] <> + headerWith ("item2", [], []) 1 "Item2" + + , "Multi-line Bullet Lists" =: + ("- *Fat\n" <> + " Tony*\n" <> + "- /Sideshow\n" <> + " Bob/") =?> + bulletList [ plain $ strong ("Fat" <> softbreak <> "Tony") + , plain $ emph ("Sideshow" <> softbreak <> "Bob") + ] + + , "Nested Bullet Lists" =: + ("- Discovery\n" <> + " + One More Time\n" <> + " + Harder, Better, Faster, Stronger\n" <> + "- Homework\n" <> + " + Around the World\n"<> + "- Human After All\n" <> + " + Technologic\n" <> + " + Robot Rock\n") =?> + bulletList [ mconcat + [ plain "Discovery" + , bulletList [ plain ("One" <> space <> + "More" <> space <> + "Time") + , plain ("Harder," <> space <> + "Better," <> space <> + "Faster," <> space <> + "Stronger") + ] + ] + , mconcat + [ plain "Homework" + , bulletList [ plain ("Around" <> space <> + "the" <> space <> + "World") + ] + ] + , mconcat + [ plain ("Human" <> space <> "After" <> space <> "All") + , bulletList [ plain "Technologic" + , plain ("Robot" <> space <> "Rock") + ] + ] + ] + + , "Bullet List with Decreasing Indent" =: + " - Discovery\n\ + \ - Human After All\n" =?> + mconcat [ bulletList [ plain "Discovery" ] + , bulletList [ plain ("Human" <> space <> "After" <> space <> "All")] + ] + + , "Header follows Bullet List" =: + " - Discovery\n\ + \ - Human After All\n\ + \* Homework" =?> + mconcat [ bulletList [ plain "Discovery" + , plain ("Human" <> space <> "After" <> space <> "All") + ] + , headerWith ("homework", [], []) 1 "Homework" + ] + + , "Bullet List Unindented with trailing Header" =: + "- Discovery\n\ + \- Homework\n\ + \* NotValidListItem" =?> + mconcat [ bulletList [ plain "Discovery" + , plain "Homework" + ] + , headerWith ("notvalidlistitem", [], []) 1 "NotValidListItem" + ] + + , "Empty bullet points" =: + T.unlines [ "-" + , "- " + ] =?> + bulletList [ plain "", plain "" ] + + , "Simple Ordered List" =: + ("1. Item1\n" <> + "2. Item2\n") =?> + let listStyle = (1, DefaultStyle, DefaultDelim) + listStructure = [ plain "Item1" + , plain "Item2" + ] + in orderedListWith listStyle listStructure + + , "Simple Ordered List with Parens" =: + ("1) Item1\n" <> + "2) Item2\n") =?> + let listStyle = (1, DefaultStyle, DefaultDelim) + listStructure = [ plain "Item1" + , plain "Item2" + ] + in orderedListWith listStyle listStructure + + , "Indented Ordered List" =: + (" 1. Item1\n" <> + " 2. Item2\n") =?> + let listStyle = (1, DefaultStyle, DefaultDelim) + listStructure = [ plain "Item1" + , plain "Item2" + ] + in orderedListWith listStyle listStructure + + , "Empty ordered list item" =: + T.unlines [ "1." + , "3. " + ] =?> + orderedList [ plain "", plain "" ] + + , "Nested Ordered Lists" =: + ("1. One\n" <> + " 1. One-One\n" <> + " 2. One-Two\n" <> + "2. Two\n" <> + " 1. Two-One\n"<> + " 2. Two-Two\n") =?> + let listStyle = (1, DefaultStyle, DefaultDelim) + listStructure = [ mconcat + [ plain "One" + , orderedList [ plain "One-One" + , plain "One-Two" + ] + ] + , mconcat + [ plain "Two" + , orderedList [ plain "Two-One" + , plain "Two-Two" + ] + ] + ] + in orderedListWith listStyle listStructure + + , "Ordered List in Bullet List" =: + ("- Emacs\n" <> + " 1. Org\n") =?> + bulletList [ plain "Emacs" <> + orderedList [ plain "Org"] + ] + + , "Bullet List in Ordered List" =: + ("1. GNU\n" <> + " - Freedom\n") =?> + orderedList [ plain "GNU" <> bulletList [ plain "Freedom" ] ] + + , "Definition List" =: + T.unlines [ "- PLL :: phase-locked loop" + , "- TTL ::" + , " transistor-transistor logic" + , "- PSK :: phase-shift keying" + , "" + , " a digital modulation scheme" + ] =?> + definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ]) + , ("TTL", [ plain $ "transistor-transistor" <> space <> + "logic" ]) + , ("PSK", [ mconcat + [ para $ "phase-shift" <> space <> "keying" + , para $ spcSep [ "a", "digital" + , "modulation", "scheme" ] + ] + ]) + ] + , "Definition list with multi-word term" =: + " - Elijah Wood :: He plays Frodo" =?> + definitionList [ ("Elijah" <> space <> "Wood", [plain $ "He" <> space <> "plays" <> space <> "Frodo"])] + , "Compact definition list" =: + T.unlines [ "- ATP :: adenosine 5' triphosphate" + , "- DNA :: deoxyribonucleic acid" + , "- PCR :: polymerase chain reaction" + , "" + ] =?> + definitionList + [ ("ATP", [ plain $ spcSep [ "adenosine", "5'", "triphosphate" ] ]) + , ("DNA", [ plain $ spcSep [ "deoxyribonucleic", "acid" ] ]) + , ("PCR", [ plain $ spcSep [ "polymerase", "chain", "reaction" ] ]) + ] + + , "Definition List With Trailing Header" =: + "- definition :: list\n\ + \- cool :: defs\n\ + \* header" =?> + mconcat [ definitionList [ ("definition", [plain "list"]) + , ("cool", [plain "defs"]) + ] + , headerWith ("header", [], []) 1 "header" + ] + + , "Definition lists double-colon markers must be surrounded by whitespace" =: + "- std::cout" =?> + bulletList [ plain "std::cout" ] + + , "Loose bullet list" =: + T.unlines [ "- apple" + , "" + , "- orange" + , "" + , "- peach" + ] =?> + bulletList [ para "apple" + , para "orange" + , para "peach" + ] + + , "Recognize preceding paragraphs in non-list contexts" =: + T.unlines [ "CLOSED: [2015-10-19 Mon 15:03]" + , "- Note taken on [2015-10-19 Mon 13:24]" + ] =?> + mconcat [ para "CLOSED: [2015-10-19 Mon 15:03]" + , bulletList [ plain "Note taken on [2015-10-19 Mon 13:24]" ] + ] + ] diff --git a/test/Tests/Readers/Org/Block/Table.hs.orig b/test/Tests/Readers/Org/Block/Table.hs.orig new file mode 100644 index 000000000..db6e756f8 --- /dev/null +++ b/test/Tests/Readers/Org/Block/Table.hs.orig @@ -0,0 +1,150 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Block.Table (tests) where + +import Test.Tasty (TestTree) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:), spcSep) +import Text.Pandoc.Builder +import qualified Data.Text as T + +simpleTable' :: Int + -> [Blocks] + -> [[Blocks]] + -> Blocks +simpleTable' n = table "" (replicate n (AlignDefault, 0.0)) + +tests :: [TestTree] +tests = + [ "Single cell table" =: + "|Test|" =?> + simpleTable' 1 mempty [[plain "Test"]] + + , "Multi cell table" =: + "| One | Two |" =?> + simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ] + + , "Multi line table" =: + T.unlines [ "| One |" + , "| Two |" + , "| Three |" + ] =?> + simpleTable' 1 mempty + [ [ plain "One" ] + , [ plain "Two" ] + , [ plain "Three" ] + ] + + , "Empty table" =: + "||" =?> + simpleTable' 1 mempty [[mempty]] + + , "Glider Table" =: + T.unlines [ "| 1 | 0 | 0 |" + , "| 0 | 1 | 1 |" + , "| 1 | 1 | 0 |" + ] =?> + simpleTable' 3 mempty + [ [ plain "1", plain "0", plain "0" ] + , [ plain "0", plain "1", plain "1" ] + , [ plain "1", plain "1", plain "0" ] + ] + + , "Table between Paragraphs" =: + T.unlines [ "Before" + , "| One | Two |" + , "After" + ] =?> + mconcat [ para "Before" + , simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ] + , para "After" + ] + + , "Table with Header" =: + T.unlines [ "| Species | Status |" + , "|--------------+--------------|" + , "| cervisiae | domesticated |" + , "| paradoxus | wild |" + ] =?> + simpleTable [ plain "Species", plain "Status" ] + [ [ plain "cervisiae", plain "domesticated" ] + , [ plain "paradoxus", plain "wild" ] + ] + + , "Table with final hline" =: + T.unlines [ "| cervisiae | domesticated |" + , "| paradoxus | wild |" + , "|--------------+--------------|" + ] =?> + simpleTable' 2 mempty + [ [ plain "cervisiae", plain "domesticated" ] + , [ plain "paradoxus", plain "wild" ] + ] + + , "Table in a box" =: + T.unlines [ "|---------|---------|" + , "| static | Haskell |" + , "| dynamic | Lisp |" + , "|---------+---------|" + ] =?> + simpleTable' 2 mempty + [ [ plain "static", plain "Haskell" ] + , [ plain "dynamic", plain "Lisp" ] + ] + + , "Table with empty cells" =: + "|||c|" =?> + simpleTable' 3 mempty [[mempty, mempty, plain "c"]] + + , "Table with empty rows" =: + T.unlines [ "| first |" + , "| |" + , "| third |" + ] =?> + simpleTable' 1 mempty [[plain "first"], [mempty], [plain "third"]] + + , "Table with alignment row" =: + T.unlines [ "| Numbers | Text | More |" + , "| <c> | <r> | |" + , "| 1 | One | foo |" + , "| 2 | Two | bar |" + ] =?> + table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0]) + [] + [ [ plain "Numbers", plain "Text", plain "More" ] + , [ plain "1" , plain "One" , plain "foo" ] + , [ plain "2" , plain "Two" , plain "bar" ] + ] + + , "Pipe within text doesn't start a table" =: + "Ceci n'est pas une | pipe " =?> + para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ]) + + , "Missing pipe at end of row" =: + "|incomplete-but-valid" =?> + simpleTable' 1 mempty [ [ plain "incomplete-but-valid" ] ] + + , "Table with differing row lengths" =: + T.unlines [ "| Numbers | Text " + , "|-" + , "| <c> | <r> |" + , "| 1 | One | foo |" + , "| 2" + ] =?> + table "" (zip [AlignCenter, AlignRight] [0, 0]) + [ plain "Numbers", plain "Text" ] + [ [ plain "1" , plain "One" , plain "foo" ] + , [ plain "2" ] + ] + + , "Table with caption" =: + T.unlines [ "#+CAPTION: Hitchhiker's Multiplication Table" + , "| x | 6 |" + , "| 9 | 42 |" + ] =?> + table "Hitchhiker's Multiplication Table" + [(AlignDefault, 0), (AlignDefault, 0)] + [] + [ [ plain "x", plain "6" ] + , [ plain "9", plain "42" ] + ] + ] diff --git a/test/Tests/Readers/Org/Directive.hs.orig b/test/Tests/Readers/Org/Directive.hs.orig new file mode 100644 index 000000000..7e2c0fb8d --- /dev/null +++ b/test/Tests/Readers/Org/Directive.hs.orig @@ -0,0 +1,199 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Directive (tests) where + +import Data.Time (UTCTime (UTCTime), secondsToDiffTime) +import Data.Time.Calendar (Day (ModifiedJulianDay)) +import Test.Tasty (TestTree, testGroup) +import Tests.Helpers ((=?>), ToString, purely, test) +import Tests.Readers.Org.Shared ((=:), tagSpan) +import Text.Pandoc +import Text.Pandoc.Builder +import qualified Data.ByteString as BS +import qualified Data.Text as T + +testWithFiles :: (ToString c) + => [(FilePath, BS.ByteString)] + -> String -- ^ name of test case + -> (T.Text, c) -- ^ (input, expected value) + -> TestTree +testWithFiles fileDefs = test (orgWithFiles fileDefs) + where +orgWithFiles :: [(FilePath, BS.ByteString)] -> T.Text -> Pandoc +orgWithFiles fileDefs input = + let readOrg' = readOrg def{ readerExtensions = getDefaultExtensions "org" } + in flip purely input $ \inp -> do + modifyPureState (\st -> st { stFiles = files fileDefs }) + readOrg' inp + + +files :: [(FilePath, BS.ByteString)] -> FileTree +files fileDefs = + let dummyTime = UTCTime (ModifiedJulianDay 125) (secondsToDiffTime 0) + in foldr (\(fp, bs) -> insertInFileTree fp (FileInfo dummyTime bs)) + mempty fileDefs + +tests :: [TestTree] +tests = + [ testGroup "export options" + [ "disable simple sub/superscript syntax" =: + T.unlines [ "#+OPTIONS: ^:nil" + , "a^b" + ] =?> + para "a^b" + + , "directly select drawers to be exported" =: + T.unlines [ "#+OPTIONS: d:(\"IMPORTANT\")" + , ":IMPORTANT:" + , "23" + , ":END:" + , ":BORING:" + , "very boring" + , ":END:" + ] =?> + divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "23") + + , "exclude drawers from being exported" =: + T.unlines [ "#+OPTIONS: d:(not \"BORING\")" + , ":IMPORTANT:" + , "5" + , ":END:" + , ":BORING:" + , "very boring" + , ":END:" + ] =?> + divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "5") + + , "don't include archive trees" =: + T.unlines [ "#+OPTIONS: arch:nil" + , "* old :ARCHIVE:" + ] =?> + (mempty ::Blocks) + + , "include complete archive trees" =: + T.unlines [ "#+OPTIONS: arch:t" + , "* old :ARCHIVE:" + , " boring" + ] =?> + mconcat [ headerWith ("old", [], mempty) 1 + ("old" <> space <> tagSpan "ARCHIVE") + , para "boring" + ] + + , "include archive tree header only" =: + T.unlines [ "#+OPTIONS: arch:headline" + , "* old :ARCHIVE:" + , " boring" + ] =?> + headerWith ("old", [], mempty) 1 ("old" <> space <> tagSpan "ARCHIVE") + + , "limit headline depth" =: + T.unlines [ "#+OPTIONS: H:2" + , "* top-level section" + , "** subsection" + , "*** list item 1" + , "*** list item 2" + ] =?> + mconcat [ headerWith ("top-level-section", [], []) 1 "top-level section" + , headerWith ("subsection", [], []) 2 "subsection" + , orderedList [ para "list item 1", para "list item 2" ] + ] + + , "turn all headlines into lists" =: + T.unlines [ "#+OPTIONS: H:0" + , "first block" + , "* top-level section 1" + , "** subsection" + , "* top-level section 2" + ] =?> + mconcat [ para "first block" + , orderedList + [ para "top-level section 1" <> + orderedList [ para "subsection" ] + , para "top-level section 2" ] + ] + + , "preserve linebreaks as hard breaks" =: + T.unlines [ "#+OPTIONS: \\n:t" + , "first" + , "second" + ] =?> + para ("first" <> linebreak <> "second") + + , "disable author export" =: + T.unlines [ "#+OPTIONS: author:nil" + , "#+AUTHOR: ShyGuy" + ] =?> + Pandoc nullMeta mempty + + , "disable creator export" =: + T.unlines [ "#+OPTIONS: creator:nil" + , "#+creator: The Architect" + ] =?> + Pandoc nullMeta mempty + + , "disable email export" =: + T.unlines [ "#+OPTIONS: email:nil" + , "#+email: no-mail-please@example.com" + ] =?> + Pandoc nullMeta mempty + + , "disable inclusion of todo keywords" =: + T.unlines [ "#+OPTIONS: todo:nil" + , "** DONE todo export" + ] =?> + headerWith ("todo-export", [], []) 2 "todo export" + + , "remove tags from headlines" =: + T.unlines [ "#+OPTIONS: tags:nil" + , "* Headline :hello:world:" + ] =?> + headerWith ("headline", [], mempty) 1 "Headline" + ] + + , testGroup "Include" + [ testWithFiles [("./other.org", "content of other file\n")] + "file inclusion" + (T.unlines [ "#+include: \"other.org\"" ] =?> + plain "content of other file") + + , testWithFiles [("./world.org", "World\n\n")] + "Included file belongs to item" + (T.unlines [ "- Hello,\n #+include: \"world.org\"" ] =?> + bulletList [para "Hello," <> para "World"]) + + , testWithFiles [("./level3.org", "*** Level3\n\n")] + "Default include preserves level" + (T.unlines [ "#+include: \"level3.org\"" ] =?> + headerWith ("level3", [], []) 3 "Level3") + + , testWithFiles [("./level3.org", "*** Level3\n\n")] + "Minlevel shifts level" + (T.unlines [ "#+include: \"level3.org\" :minlevel 1" ] =?> + headerWith ("level3", [], []) 1 "Level3") + + , testWithFiles [("./src.hs", "putStrLn outString\n")] + "Include file as source code snippet" + (T.unlines [ "#+include: \"src.hs\" src haskell" ] =?> + codeBlockWith ("", ["haskell"], []) "putStrLn outString\n") + + , testWithFiles [("./export-latex.org", "\\emph{Hello}\n")] + "Include file as export snippet" + (T.unlines [ "#+include: \"export-latex.org\" export latex" ] =?> + rawBlock "latex" "\\emph{Hello}\n") + + , testWithFiles [("./subdir/foo-bar.latex", "foo\n"), + ("./hello.lisp", "(print \"Hello!\")\n") + ] + "include directive is limited to one line" + (T.unlines [ "#+INCLUDE: \"hello.lisp\" src lisp" + , "#+include: \"subdir/foo-bar.latex\" export latex" + , "bar" + ] =?> + mconcat + [ codeBlockWith ("", ["lisp"], []) "(print \"Hello!\")\n" + , rawBlock "latex" "foo\n" + , para "bar" + ] + ) + ] + ] diff --git a/test/Tests/Readers/Org/Inline.hs.orig b/test/Tests/Readers/Org/Inline.hs.orig new file mode 100644 index 000000000..9bf5556d2 --- /dev/null +++ b/test/Tests/Readers/Org/Inline.hs.orig @@ -0,0 +1,352 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Inline (tests) where + +import Data.List (intersperse) +import Test.Tasty (TestTree, testGroup) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:), spcSep) +import Text.Pandoc.Builder +import Text.Pandoc.Shared (underlineSpan) +import qualified Data.Text as T +import qualified Tests.Readers.Org.Inline.Citation as Citation +import qualified Tests.Readers.Org.Inline.Note as Note +import qualified Tests.Readers.Org.Inline.Smart as Smart + +tests :: [TestTree] +tests = + [ "Plain String" =: + "Hello, World" =?> + para (spcSep [ "Hello,", "World" ]) + + , "Emphasis" =: + "/Planet Punk/" =?> + para (emph . spcSep $ ["Planet", "Punk"]) + + , "Strong" =: + "*Cider*" =?> + para (strong "Cider") + + , "Strong Emphasis" =: + "/*strength*/" =?> + para (emph . strong $ "strength") + + , "Emphasized Strong preceded by space" =: + " */super/*" =?> + para (strong . emph $ "super") + + , "Underline" =: + "_underline_" =?> + para (underlineSpan "underline") + + , "Strikeout" =: + "+Kill Bill+" =?> + para (strikeout . spcSep $ [ "Kill", "Bill" ]) + + , "Verbatim" =: + "=Robot.rock()=" =?> + para (code "Robot.rock()") + + , "Code" =: + "~word for word~" =?> + para (code "word for word") + + , "Math $..$" =: + "$E=mc^2$" =?> + para (math "E=mc^2") + + , "Math $$..$$" =: + "$$E=mc^2$$" =?> + para (displayMath "E=mc^2") + + , "Math \\[..\\]" =: + "\\[E=ℎν\\]" =?> + para (displayMath "E=ℎν") + + , "Math \\(..\\)" =: + "\\(σ_x σ_p ≥ \\frac{ℏ}{2}\\)" =?> + para (math "σ_x σ_p ≥ \\frac{ℏ}{2}") + + , "Symbol" =: + "A * symbol" =?> + para (str "A" <> space <> str "*" <> space <> "symbol") + + , "Superscript simple expression" =: + "2^-λ" =?> + para (str "2" <> superscript "-λ") + + , "Superscript multi char" =: + "2^{n-1}" =?> + para (str "2" <> superscript "n-1") + + , "Subscript simple expression" =: + "a_n" =?> + para (str "a" <> subscript "n") + + , "Subscript multi char" =: + "a_{n+1}" =?> + para (str "a" <> subscript "n+1") + + , "Linebreak" =: + "line \\\\ \nbreak" =?> + para ("line" <> linebreak <> "break") + + , "Inline note" =: + "[fn::Schreib mir eine E-Mail]" =?> + para (note $ para "Schreib mir eine E-Mail") + + , "Markup-chars not occuring on word break are symbols" =: + T.unlines [ "this+that+ +so+on" + , "seven*eight* nine*" + , "+not+funny+" + ] =?> + para ("this+that+ +so+on" <> softbreak <> + "seven*eight* nine*" <> softbreak <> + strikeout "not+funny") + + , "No empty markup" =: + "// ** __ <> == ~~ $$" =?> + para (spcSep [ "//", "**", "__", "<>", "==", "~~", "$$" ]) + + , "Adherence to Org's rules for markup borders" =: + "/t/& a/ / ./r/ (*l*) /e/! /b/." =?> + para (spcSep [ emph $ "t/&" <> space <> "a" + , "/" + , "./r/" + , "(" <> strong "l" <> ")" + , emph "e" <> "!" + , emph "b" <> "." + ]) + + , "Quotes are allowed border chars" =: + "/'yep/ *sure\"*" =?> + para (emph "'yep" <> space <> strong "sure\"") + + , "Spaces are forbidden border chars" =: + "/nada /" =?> + para "/nada /" + + , "Markup should work properly after a blank line" =: + T.unlines ["foo", "", "/bar/"] =?> + para (text "foo") <> + para (emph $ text "bar") + + , "Inline math must stay within three lines" =: + T.unlines [ "$a", "b", "c$", "$d", "e", "f", "g$" ] =?> + para (math "a\nb\nc" <> softbreak <> + "$d" <> softbreak <> "e" <> softbreak <> + "f" <> softbreak <> "g$") + + , "Single-character math" =: + "$a$ $b$! $c$?" =?> + para (spcSep [ math "a" + , "$b$!" + , math "c" <> "?" + ]) + + , "Markup may not span more than two lines" =: + "/this *is +totally\nnice+ not*\nemph/" =?> + para ("/this" <> space <> + strong ("is" <> space <> + strikeout ("totally" <> + softbreak <> "nice") <> + space <> "not") <> + softbreak <> "emph/") + + , "Sub- and superscript expressions" =: + T.unlines [ "a_(a(b)(c)d)" + , "e^(f(g)h)" + , "i_(jk)l)" + , "m^()n" + , "o_{p{q{}r}}" + , "s^{t{u}v}" + , "w_{xy}z}" + , "1^{}2" + , "3_{{}}" + , "4^(a(*b(c*)d))" + ] =?> + para (mconcat $ intersperse softbreak + [ "a" <> subscript "(a(b)(c)d)" + , "e" <> superscript "(f(g)h)" + , "i" <> subscript "(jk)" <> "l)" + , "m" <> superscript "()" <> "n" + , "o" <> subscript "p{q{}r}" + , "s" <> superscript "t{u}v" + , "w" <> subscript "xy" <> "z}" + , "1" <> superscript "" <> "2" + , "3" <> subscript "{}" + , "4" <> superscript ("(a(" <> strong "b(c" <> ")d))") + ]) + , "Verbatim text can contain equal signes (=)" =: + "=is_subst = True=" =?> + para (code "is_subst = True") + + , testGroup "Images" + [ "Image" =: + "[[./sunset.jpg]]" =?> + para (image "./sunset.jpg" "" "") + + , "Image with explicit file: prefix" =: + "[[file:sunrise.jpg]]" =?> + para (image "sunrise.jpg" "" "") + + , "Multiple images within a paragraph" =: + T.unlines [ "[[file:sunrise.jpg]]" + , "[[file:sunset.jpg]]" + ] =?> + para ((image "sunrise.jpg" "" "") + <> softbreak + <> (image "sunset.jpg" "" "")) + + , "Image with html attributes" =: + T.unlines [ "#+ATTR_HTML: :width 50%" + , "[[file:guinea-pig.gif]]" + ] =?> + para (imageWith ("", [], [("width", "50%")]) "guinea-pig.gif" "" "") + ] + + , "Explicit link" =: + "[[http://zeitlens.com/][pseudo-random /nonsense/]]" =?> + para (link "http://zeitlens.com/" "" + ("pseudo-random" <> space <> emph "nonsense")) + + , "Self-link" =: + "[[http://zeitlens.com/]]" =?> + para (link "http://zeitlens.com/" "" "http://zeitlens.com/") + + , "Absolute file link" =: + "[[/url][hi]]" =?> + para (link "file:///url" "" "hi") + + , "Link to file in parent directory" =: + "[[../file.txt][moin]]" =?> + para (link "../file.txt" "" "moin") + + , "Empty link (for gitit interop)" =: + "[[][New Link]]" =?> + para (link "" "" "New Link") + + , "Image link" =: + "[[sunset.png][file:dusk.svg]]" =?> + para (link "sunset.png" "" (image "dusk.svg" "" "")) + + , "Image link with non-image target" =: + "[[http://example.com][./logo.png]]" =?> + para (link "http://example.com" "" (image "./logo.png" "" "")) + + , "Plain link" =: + "Posts on http://zeitlens.com/ can be funny at times." =?> + para (spcSep [ "Posts", "on" + , link "http://zeitlens.com/" "" "http://zeitlens.com/" + , "can", "be", "funny", "at", "times." + ]) + + , "Angle link" =: + "Look at <http://moltkeplatz.de> for fnords." =?> + para (spcSep [ "Look", "at" + , link "http://moltkeplatz.de" "" "http://moltkeplatz.de" + , "for", "fnords." + ]) + + , "Absolute file link" =: + "[[file:///etc/passwd][passwd]]" =?> + para (link "file:///etc/passwd" "" "passwd") + + , "File link" =: + "[[file:target][title]]" =?> + para (link "target" "" "title") + + , "Anchor" =: + "<<anchor>> Link here later." =?> + para (spanWith ("anchor", [], []) mempty <> + "Link" <> space <> "here" <> space <> "later.") + + , "Inline code block" =: + "src_emacs-lisp{(message \"Hello\")}" =?> + para (codeWith ( "" + , [ "commonlisp" ] + , [ ("org-language", "emacs-lisp") ]) + "(message \"Hello\")") + + , "Inline code block with arguments" =: + "src_sh[:export both :results output]{echo 'Hello, World'}" =?> + para (codeWith ( "" + , [ "bash" ] + , [ ("org-language", "sh") + , ("export", "both") + , ("results", "output") + ] + ) + "echo 'Hello, World'") + + , "Inline code block with toggle" =: + "src_sh[:toggle]{echo $HOME}" =?> + para (codeWith ( "" + , [ "bash" ] + , [ ("org-language", "sh") + , ("toggle", "yes") + ] + ) + "echo $HOME") + + , "Inline LaTeX symbol" =: + "\\dots" =?> + para "…" + + , "Inline LaTeX command" =: + "\\textit{Emphasised}" =?> + para (emph "Emphasised") + + , "Inline LaTeX command with spaces" =: + "\\emph{Emphasis mine}" =?> + para (emph "Emphasis mine") + + , "Inline LaTeX math symbol" =: + "\\tau" =?> + para (emph "τ") + + , "Unknown inline LaTeX command" =: + "\\notacommand{foo}" =?> + para (rawInline "latex" "\\notacommand{foo}") + + , "Export snippet" =: + "@@html:<kbd>M-x org-agenda</kbd>@@" =?> + para (rawInline "html" "<kbd>M-x org-agenda</kbd>") + + , "MathML symbol in LaTeX-style" =: + "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: '\\nbsp')." =?> + para "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: ' ')." + + , "MathML symbol in LaTeX-style, including braces" =: + "\\Aacute{}stor" =?> + para "Ástor" + + , "MathML copy sign" =: + "\\copy" =?> + para "©" + + , "MathML symbols, space separated" =: + "\\ForAll \\Auml" =?> + para "∀ Ä" + + , "Macro" =: + T.unlines [ "#+MACRO: HELLO /Hello, $1/" + , "{{{HELLO(World)}}}" + ] =?> + para (emph "Hello, World") + + , "Macro repeting its argument" =: + T.unlines [ "#+MACRO: HELLO $1$1" + , "{{{HELLO(moin)}}}" + ] =?> + para "moinmoin" + + , "Macro called with too few arguments" =: + T.unlines [ "#+MACRO: HELLO Foo $1 $2 Bar" + , "{{{HELLO()}}}" + ] =?> + para "Foo Bar" + + , testGroup "Citations" Citation.tests + , testGroup "Footnotes" Note.tests + , testGroup "Smart punctuation" Smart.tests + ] diff --git a/test/Tests/Readers/Org/Inline/Citation.hs.orig b/test/Tests/Readers/Org/Inline/Citation.hs.orig new file mode 100644 index 000000000..d7e38a6b0 --- /dev/null +++ b/test/Tests/Readers/Org/Inline/Citation.hs.orig @@ -0,0 +1,179 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Inline.Citation (tests) where + +import Test.Tasty (TestTree, testGroup) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:)) +import Text.Pandoc.Builder + +tests :: [TestTree] +tests = + [ testGroup "Markdown-style citations" + [ "Citation" =: + "[@nonexistent]" =?> + let citation = Citation + { citationId = "nonexistent" + , citationPrefix = [] + , citationSuffix = [] + , citationMode = NormalCitation + , citationNoteNum = 0 + , citationHash = 0} + in (para $ cite [citation] "[@nonexistent]") + + , "Citation containing text" =: + "[see @item1 p. 34-35]" =?> + let citation = Citation + { citationId = "item1" + , citationPrefix = [Str "see"] + , citationSuffix = [Space ,Str "p.",Space,Str "34-35"] + , citationMode = NormalCitation + , citationNoteNum = 0 + , citationHash = 0} + in (para $ cite [citation] "[see @item1 p. 34-35]") + ] + + , testGroup "org-ref citations" + [ "simple citation" =: + "cite:pandoc" =?> + let citation = Citation + { citationId = "pandoc" + , citationPrefix = mempty + , citationSuffix = mempty + , citationMode = AuthorInText + , citationNoteNum = 0 + , citationHash = 0 + } + in (para $ cite [citation] "cite:pandoc") + + , "simple citation with underscores" =: + "cite:pandoc_org_ref" =?> + let citation = Citation + { citationId = "pandoc_org_ref" + , citationPrefix = mempty + , citationSuffix = mempty + , citationMode = AuthorInText + , citationNoteNum = 0 + , citationHash = 0 + } + in (para $ cite [citation] "cite:pandoc_org_ref") + + , "simple citation succeeded by comma" =: + "cite:pandoc," =?> + let citation = Citation + { citationId = "pandoc" + , citationPrefix = mempty + , citationSuffix = mempty + , citationMode = AuthorInText + , citationNoteNum = 0 + , citationHash = 0 + } + in (para $ cite [citation] "cite:pandoc" <> str ",") + + , "simple citation succeeded by dot" =: + "cite:pandoc." =?> + let citation = Citation + { citationId = "pandoc" + , citationPrefix = mempty + , citationSuffix = mempty + , citationMode = AuthorInText + , citationNoteNum = 0 + , citationHash = 0 + } + in (para $ cite [citation] "cite:pandoc" <> str ".") + + , "simple citation succeeded by colon" =: + "cite:pandoc:" =?> + let citation = Citation + { citationId = "pandoc" + , citationPrefix = mempty + , citationSuffix = mempty + , citationMode = AuthorInText + , citationNoteNum = 0 + , citationHash = 0 + } + in (para $ cite [citation] "cite:pandoc" <> str ":") + + , "simple citep citation" =: + "citep:pandoc" =?> + let citation = Citation + { citationId = "pandoc" + , citationPrefix = mempty + , citationSuffix = mempty + , citationMode = NormalCitation + , citationNoteNum = 0 + , citationHash = 0 + } + in (para $ cite [citation] "citep:pandoc") + + , "extended citation" =: + "[[citep:Dominik201408][See page 20::, for example]]" =?> + let citation = Citation + { citationId = "Dominik201408" + , citationPrefix = toList "See page 20" + , citationSuffix = toList ", for example" + , citationMode = NormalCitation + , citationNoteNum = 0 + , citationHash = 0 + } + in (para $ cite [citation] "[[citep:Dominik201408][See page 20::, for example]]") + ] + + , testGroup "Berkeley-style citations" $ + let pandocCite = Citation + { citationId = "Pandoc" + , citationPrefix = mempty + , citationSuffix = mempty + , citationMode = NormalCitation + , citationNoteNum = 0 + , citationHash = 0 + } + pandocInText = pandocCite { citationMode = AuthorInText } + dominikCite = Citation + { citationId = "Dominik201408" + , citationPrefix = mempty + , citationSuffix = mempty + , citationMode = NormalCitation + , citationNoteNum = 0 + , citationHash = 0 + } + dominikInText = dominikCite { citationMode = AuthorInText } + in + [ "Berkeley-style in-text citation" =: + "See @Dominik201408." =?> + para ("See " + <> cite [dominikInText] "@Dominik201408" + <> ".") + + , "Berkeley-style parenthetical citation list" =: + "[(cite): see; @Dominik201408;also @Pandoc; and others]" =?> + let pandocCite' = pandocCite { + citationPrefix = toList "also" + , citationSuffix = toList "and others" + } + dominikCite' = dominikCite { + citationPrefix = toList "see" + } + in (para $ cite [dominikCite', pandocCite'] "") + + , "Berkeley-style plain citation list" =: + "[cite: See; @Dominik201408; and @Pandoc; and others]" =?> + let pandocCite' = pandocInText { citationPrefix = toList "and" } + in (para $ "See " + <> cite [dominikInText] "" + <> "," <> space + <> cite [pandocCite'] "" + <> "," <> space <> "and others") + ] + + , "LaTeX citation" =: + "\\cite{Coffee}" =?> + let citation = Citation + { citationId = "Coffee" + , citationPrefix = [] + , citationSuffix = [] + , citationMode = NormalCitation + , citationNoteNum = 0 + , citationHash = 0} + in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}") + + ] diff --git a/test/Tests/Readers/Org/Inline/Note.hs.orig b/test/Tests/Readers/Org/Inline/Note.hs.orig new file mode 100644 index 000000000..9eb1d02d6 --- /dev/null +++ b/test/Tests/Readers/Org/Inline/Note.hs.orig @@ -0,0 +1,86 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Inline.Note (tests) where + +import Test.Tasty (TestTree) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:)) +import Text.Pandoc.Builder +import qualified Data.Text as T + +tests :: [TestTree] +tests = + [ "Footnote" =: + T.unlines [ "A footnote[1]" + , "" + , "[1] First paragraph" + , "" + , "second paragraph" + ] =?> + para (mconcat + [ "A", space, "footnote" + , note $ mconcat [ para ("First" <> space <> "paragraph") + , para ("second" <> space <> "paragraph") + ] + ]) + + , "Two footnotes" =: + T.unlines [ "Footnotes[fn:1][fn:2]" + , "" + , "[fn:1] First note." + , "" + , "[fn:2] Second note." + ] =?> + para (mconcat + [ "Footnotes" + , note $ para ("First" <> space <> "note.") + , note $ para ("Second" <> space <> "note.") + ]) + + , "Emphasized text before footnote" =: + T.unlines [ "/text/[fn:1]" + , "" + , "[fn:1] unicorn" + ] =?> + para (mconcat + [ emph "text" + , note . para $ "unicorn" + ]) + + , "Footnote that starts with emphasized text" =: + T.unlines [ "text[fn:1]" + , "" + , "[fn:1] /emphasized/" + ] =?> + para (mconcat + [ "text" + , note . para $ emph "emphasized" + ]) + + , "Footnote followed by header" =: + T.unlines [ "Another note[fn:yay]" + , "" + , "[fn:yay] This is great!" + , "" + , "** Headline" + ] =?> + mconcat + [ para (mconcat + [ "Another", space, "note" + , note $ para ("This" <> space <> "is" <> space <> "great!") + ]) + , headerWith ("headline", [], []) 2 "Headline" + ] + + , "Footnote followed by two blank lines" =: + T.unlines [ "footnote[fn:blanklines]" + , "" + , "[fn:blanklines] followed by blank lines" + , "" + , "" + , "next" + ] =?> + mconcat + [ para ("footnote" <> note (para "followed by blank lines")) + , para "next" + ] + ] diff --git a/test/Tests/Readers/Org/Inline/Smart.hs.orig b/test/Tests/Readers/Org/Inline/Smart.hs.orig new file mode 100644 index 000000000..77f10699d --- /dev/null +++ b/test/Tests/Readers/Org/Inline/Smart.hs.orig @@ -0,0 +1,46 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Inline.Smart (tests) where + +import Data.Text (Text) +import Test.Tasty (TestTree) +import Tests.Helpers ((=?>), purely, test) +import Text.Pandoc (ReaderOptions (readerExtensions), + Extension (Ext_smart), def, enableExtension, + getDefaultExtensions, readOrg) +import Text.Pandoc.Builder + +orgSmart :: Text -> Pandoc +orgSmart = purely $ + let extensionsSmart = enableExtension Ext_smart (getDefaultExtensions "org") + in readOrg def{ readerExtensions = extensionsSmart } + +tests :: [TestTree] +tests = + [ test orgSmart "quote before ellipses" + ("'...hi'" + =?> para (singleQuoted "…hi")) + + , test orgSmart "apostrophe before emph" + ("D'oh! A l'/aide/!" + =?> para ("D’oh! A l’" <> emph "aide" <> "!")) + + , test orgSmart "apostrophe in French" + ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»" + =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»") + + , test orgSmart "Quotes cannot occur at the end of emphasized text" + ("/say \"yes\"/" =?> + para ("/say" <> space <> doubleQuoted "yes" <> "/")) + + , test orgSmart "Dashes are allowed at the borders of emphasis'" + ("/foo---/" =?> + para (emph "foo—")) + + , test orgSmart "Single quotes can be followed by emphasized text" + ("Singles on the '/meat market/'" =?> + para ("Singles on the " <> singleQuoted (emph "meat market"))) + + , test orgSmart "Double quotes can be followed by emphasized text" + ("Double income, no kids: \"/DINK/\"" =?> + para ("Double income, no kids: " <> doubleQuoted (emph "DINK"))) + ] diff --git a/test/Tests/Readers/Org/Meta.hs.orig b/test/Tests/Readers/Org/Meta.hs.orig new file mode 100644 index 000000000..6bd1b02e7 --- /dev/null +++ b/test/Tests/Readers/Org/Meta.hs.orig @@ -0,0 +1,191 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Org.Meta (tests) where + +import Test.Tasty (TestTree, testGroup) +import Tests.Helpers ((=?>)) +import Tests.Readers.Org.Shared ((=:), spcSep) +import Text.Pandoc +import Text.Pandoc.Builder +import qualified Data.Text as T + +tests :: [TestTree] +tests = + [ "Comment" =: + "# Nothing to see here" =?> + (mempty::Blocks) + + , "Not a comment" =: + "#-tag" =?> + para "#-tag" + + , "Comment surrounded by Text" =: + T.unlines [ "Before" + , "# Comment" + , "After" + ] =?> + mconcat [ para "Before" + , para "After" + ] + + , "Title" =: + "#+TITLE: Hello, World" =?> + let titleInline = toList $ "Hello," <> space <> "World" + meta = setMeta "title" (MetaInlines titleInline) nullMeta + in Pandoc meta mempty + + , "Author" =: + "#+author: John /Emacs-Fanboy/ Doe" =?> + let author = toList . spcSep $ [ "John", emph "Emacs-Fanboy", "Doe" ] + meta = setMeta "author" (MetaList [MetaInlines author]) nullMeta + in Pandoc meta mempty + + , "Multiple authors" =: + "#+author: James Dewey Watson, Francis Harry Compton Crick " =?> + let watson = MetaInlines $ toList "James Dewey Watson" + crick = MetaInlines $ toList "Francis Harry Compton Crick" + meta = setMeta "author" (MetaList [watson, crick]) nullMeta + in Pandoc meta mempty + + , "Date" =: + "#+Date: Feb. *28*, 2014" =?> + let date = toList . spcSep $ [ "Feb.", strong "28" <> ",", "2014" ] + meta = setMeta "date" (MetaInlines date) nullMeta + in Pandoc meta mempty + + , "Description" =: + "#+DESCRIPTION: Explanatory text" =?> + let description = "Explanatory text" + meta = setMeta "description" (MetaString description) nullMeta + in Pandoc meta mempty + + , "Properties drawer" =: + T.unlines [ " :PROPERTIES:" + , " :setting: foo" + , " :END:" + ] =?> + (mempty::Blocks) + + , "LaTeX_headers options are translated to header-includes" =: + "#+LaTeX_header: \\usepackage{tikz}" =?> + let latexInlines = rawInline "latex" "\\usepackage{tikz}" + inclList = MetaList [MetaInlines (toList latexInlines)] + meta = setMeta "header-includes" inclList nullMeta + in Pandoc meta mempty + + , "LaTeX_class option is translated to documentclass" =: + "#+LATEX_CLASS: article" =?> + let meta = setMeta "documentclass" (MetaString "article") nullMeta + in Pandoc meta mempty + + , "LaTeX_class_options is translated to classoption" =: + "#+LATEX_CLASS_OPTIONS: [a4paper]" =?> + let meta = setMeta "classoption" (MetaString "a4paper") nullMeta + in Pandoc meta mempty + + , "LaTeX_class_options is translated to classoption" =: + "#+html_head: <meta/>" =?> + let html = rawInline "html" "<meta/>" + inclList = MetaList [MetaInlines (toList html)] + meta = setMeta "header-includes" inclList nullMeta + in Pandoc meta mempty + + , "later meta definitions take precedence" =: + T.unlines [ "#+AUTHOR: this will not be used" + , "#+author: Max" + ] =?> + let author = MetaInlines [Str "Max"] + meta = setMeta "author" (MetaList [author]) nullMeta + in Pandoc meta mempty + + , "Logbook drawer" =: + T.unlines [ " :LogBook:" + , " - State \"DONE\" from \"TODO\" [2014-03-03 Mon 11:00]" + , " :END:" + ] =?> + (mempty::Blocks) + + , "Drawer surrounded by text" =: + T.unlines [ "Before" + , ":PROPERTIES:" + , ":END:" + , "After" + ] =?> + para "Before" <> para "After" + + , "Drawer markers must be the only text in the line" =: + T.unlines [ " :LOGBOOK: foo" + , " :END: bar" + ] =?> + para (":LOGBOOK: foo" <> softbreak <> ":END: bar") + + , "Drawers can be arbitrary" =: + T.unlines [ ":FOO:" + , "/bar/" + , ":END:" + ] =?> + divWith (mempty, ["FOO", "drawer"], mempty) (para $ emph "bar") + + , "Anchor reference" =: + T.unlines [ "<<link-here>> Target." + , "" + , "[[link-here][See here!]]" + ] =?> + (para (spanWith ("link-here", [], []) mempty <> "Target.") <> + para (link "#link-here" "" ("See" <> space <> "here!"))) + + , "Search links are read as emph" =: + "[[Wally][Where's Wally?]]" =?> + para (emph $ "Where's" <> space <> "Wally?") + + , "Link to nonexistent anchor" =: + T.unlines [ "<<link-here>> Target." + , "" + , "[[link$here][See here!]]" + ] =?> + (para (spanWith ("link-here", [], []) mempty <> "Target.") <> + para (emph ("See" <> space <> "here!"))) + + , "Link abbreviation" =: + T.unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s" + , "[[wp:Org_mode][Wikipedia on Org-mode]]" + ] =?> + para (link "https://en.wikipedia.org/wiki/Org_mode" "" + ("Wikipedia" <> space <> "on" <> space <> "Org-mode")) + + , "Link abbreviation, defined after first use" =: + T.unlines [ "[[zl:non-sense][Non-sense articles]]" + , "#+LINK: zl http://zeitlens.com/tags/%s.html" + ] =?> + para (link "http://zeitlens.com/tags/non-sense.html" "" + ("Non-sense" <> space <> "articles")) + + , "Link abbreviation, URL encoded arguments" =: + T.unlines [ "#+link: expl http://example.com/%h/foo" + , "[[expl:Hello, World!][Moin!]]" + ] =?> + para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!") + + , "Link abbreviation, append arguments" =: + T.unlines [ "#+link: expl http://example.com/" + , "[[expl:foo][bar]]" + ] =?> + para (link "http://example.com/foo" "" "bar") + + , testGroup "emphasis config" + [ "Changing pre and post chars for emphasis" =: + T.unlines [ "#+pandoc-emphasis-pre: \"[)\"" + , "#+pandoc-emphasis-post: \"]\\n\"" + , "([/emph/])*foo*" + ] =?> + para ("([" <> emph "emph" <> "])" <> strong "foo") + + , "setting an invalid value restores the default" =: + T.unlines [ "#+pandoc-emphasis-pre: \"[\"" + , "#+pandoc-emphasis-post: \"]\"" + , "#+pandoc-emphasis-pre:" + , "#+pandoc-emphasis-post:" + , "[/noemph/]" + ] =?> + para ("[/noemph/]") + ] + ] diff --git a/test/Tests/Readers/Org/Shared.hs.orig b/test/Tests/Readers/Org/Shared.hs.orig new file mode 100644 index 000000000..5e8f6dd54 --- /dev/null +++ b/test/Tests/Readers/Org/Shared.hs.orig @@ -0,0 +1,29 @@ +module Tests.Readers.Org.Shared + ( (=:) + , org + , spcSep + , tagSpan + ) where + +import Data.List (intersperse) +import Data.Text (Text) +import Tests.Helpers (ToString, purely, test) +import Test.Tasty (TestTree) +import Text.Pandoc (Pandoc, ReaderOptions (readerExtensions), + def, getDefaultExtensions, readOrg) +import Text.Pandoc.Builder (Inlines, smallcaps, space, spanWith, str) + +org :: Text -> Pandoc +org = purely $ readOrg def{ readerExtensions = getDefaultExtensions "org" } + +infix 4 =: +(=:) :: ToString c + => String -> (Text, c) -> TestTree +(=:) = test org + +spcSep :: [Inlines] -> Inlines +spcSep = mconcat . intersperse space + +-- | Create a span for the given tag. +tagSpan :: String -> Inlines +tagSpan t = spanWith ("", ["tag"], [("tag-name", t)]) . smallcaps $ str t diff --git a/test/Tests/Readers/RST.hs.orig b/test/Tests/Readers/RST.hs.orig new file mode 100644 index 000000000..305c7060b --- /dev/null +++ b/test/Tests/Readers/RST.hs.orig @@ -0,0 +1,189 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +module Tests.Readers.RST (tests) where + +import Data.Text (Text) +import qualified Data.Text as T +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +rst :: Text -> Pandoc +rst = purely $ readRST def{ readerStandalone = True } + +infix 4 =: +(=:) :: ToString c + => String -> (Text, c) -> TestTree +(=:) = test rst + +tests :: [TestTree] +tests = [ "line block with blank line" =: + "| a\n|\n| b" =?> lineBlock [ "a", mempty, "\160b" ] + , testGroup "field list" + [ "general" =: T.unlines + [ "para" + , "" + , ":Hostname: media08" + , ":IP address: 10.0.0.19" + , ":Size: 3ru" + , ":Version: 1" + , ":Indentation: Since the field marker may be quite long, the second" + , " and subsequent lines of the field body do not have to line up" + , " with the first line, but they must be indented relative to the" + , " field name marker, and they must line up with each other." + , ":Parameter i: integer" + , ":Final: item" + , " on two lines" ] + =?> + doc (para "para" <> + definitionList [ (str "Hostname", [para "media08"]) + , (text "IP address", [para "10.0.0.19"]) + , (str "Size", [para "3ru"]) + , (str "Version", [para "1"]) + , (str "Indentation", [para "Since the field marker may be quite long, the second\nand subsequent lines of the field body do not have to line up\nwith the first line, but they must be indented relative to the\nfield name marker, and they must line up with each other."]) + , (text "Parameter i", [para "integer"]) + , (str "Final", [para "item\non two lines"]) + ]) + , "metadata" =: T.unlines + [ "=====" + , "Title" + , "=====" + , "--------" + , "Subtitle" + , "--------" + , "" + , ":Version: 1" + ] + =?> + setMeta "version" (para "1") (setMeta "title" ("Title" :: Inlines) + $ setMeta "subtitle" ("Subtitle" :: Inlines) + $ doc mempty) + , "with inline markup" =: T.unlines + [ ":*Date*: today" + , "" + , ".." + , "" + , ":*one*: emphasis" + , ":two_: reference" + , ":`three`_: another one" + , ":``four``: literal" + , "" + , ".. _two: http://example.com" + , ".. _three: http://example.org" + ] + =?> + setMeta "date" (str "today") (doc + $ definitionList [ (emph "one", [para "emphasis"]) + , (link "http://example.com" "" "two", [para "reference"]) + , (link "http://example.org" "" "three", [para "another one"]) + , (code "four", [para "literal"]) + ]) + ] + , "URLs with following punctuation" =: + ("http://google.com, http://yahoo.com; http://foo.bar.baz.\n" <> + "http://foo.bar/baz_(bam) (http://foo.bar)") =?> + para (link "http://google.com" "" "http://google.com" <> ", " <> + link "http://yahoo.com" "" "http://yahoo.com" <> "; " <> + link "http://foo.bar.baz" "" "http://foo.bar.baz" <> ". " <> + softbreak <> + link "http://foo.bar/baz_(bam)" "" "http://foo.bar/baz_(bam)" + <> " (" <> link "http://foo.bar" "" "http://foo.bar" <> ")") + , "Reference names with special characters" =: + ("A-1-B_2_C:3:D+4+E.5.F_\n\n" <> + ".. _A-1-B_2_C:3:D+4+E.5.F: https://example.com\n") =?> + para (link "https://example.com" "" "A-1-B_2_C:3:D+4+E.5.F") + , "Code directive with class and number-lines" =: T.unlines + [ ".. code::python" + , " :number-lines: 34" + , " :class: class1 class2 class3" + , "" + , " def func(x):" + , " return y" + ] =?> + doc (codeBlockWith + ( "" + , ["sourceCode", "python", "numberLines", "class1", "class2", "class3"] + , [ ("startFrom", "34") ] + ) + "def func(x):\n return y") + , "Code directive with number-lines, no line specified" =: T.unlines + [ ".. code::python" + , " :number-lines: " + , "" + , " def func(x):" + , " return y" + ] =?> + doc (codeBlockWith + ( "" + , ["sourceCode", "python", "numberLines"] + , [ ("startFrom", "") ] + ) + "def func(x):\n return y") + , testGroup "literal / line / code blocks" + [ "indented literal block" =: T.unlines + [ "::" + , "" + , " block quotes" + , "" + , " can go on for many lines" + , "but must stop here"] + =?> + doc ( + codeBlock "block quotes\n\ncan go on for many lines" <> + para "but must stop here") + , "line block with 3 lines" =: "| a\n| b\n| c" + =?> lineBlock ["a", "b", "c"] + , "line blocks with blank lines" =: T.unlines + [ "|" + , "" + , "|" + , "| a" + , "| b" + , "|" + , "" + , "|" + ] =?> + lineBlock [""] <> + lineBlock ["", "a", "b", ""] <> + lineBlock [""] + , "quoted literal block using >" =: "::\n\n> quoted\n> block\n\nOrdinary paragraph" + =?> codeBlock "> quoted\n> block" <> para "Ordinary paragraph" + , "quoted literal block using | (not a line block)" =: "::\n\n| quoted\n| block\n\nOrdinary paragraph" + =?> codeBlock "| quoted\n| block" <> para "Ordinary paragraph" + , "class directive with single paragraph" =: ".. class:: special\n\nThis is a \"special\" paragraph." + =?> divWith ("", ["special"], []) (para "This is a \"special\" paragraph.") + , "class directive with two paragraphs" =: ".. class:: exceptional remarkable\n\n First paragraph.\n\n Second paragraph." + =?> divWith ("", ["exceptional", "remarkable"], []) (para "First paragraph." <> para "Second paragraph.") + , "class directive around literal block" =: ".. class:: classy\n\n::\n\n a\n b" + =?> divWith ("", ["classy"], []) (codeBlock "a\nb")] + , testGroup "interpreted text roles" + [ "literal role prefix" =: ":literal:`a`" =?> para (code "a") + , "literal role postfix" =: "`a`:literal:" =?> para (code "a") + , "literal text" =: "``text``" =?> para (code "text") + , "code role" =: ":code:`a`" =?> para (codeWith ("", ["sourceCode"], []) "a") + , "inherited code role" =: ".. role:: codeLike(code)\n\n:codeLike:`a`" + =?> para (codeWith ("", ["codeLike", "sourceCode"], []) "a") + , "custom code role with language field" + =: ".. role:: lhs(code)\n :language: haskell\n\n:lhs:`a`" + =?> para (codeWith ("", ["lhs", "haskell","sourceCode"], []) "a") + , "custom role with unspecified parent role" + =: ".. role:: classy\n\n:classy:`text`" + =?> para (spanWith ("", ["classy"], []) "text") + , "role with recursive inheritance" + =: ".. role:: haskell(code)\n.. role:: lhs(haskell)\n\n:lhs:`text`" + =?> para (codeWith ("", ["lhs", "haskell", "sourceCode"], []) "text") + , "unknown role" =: ":unknown:`text`" =?> + para (spanWith ("",[],[("role","unknown")]) (str "text")) + ] + , testGroup "footnotes" + [ "remove space before note" =: T.unlines + [ "foo [1]_" + , "" + , ".. [1]" + , " bar" + ] =?> + para ("foo" <> note (para "bar")) + ] + ] diff --git a/test/Tests/Readers/Txt2Tags.hs.orig b/test/Tests/Readers/Txt2Tags.hs.orig new file mode 100644 index 000000000..e3646e95e --- /dev/null +++ b/test/Tests/Readers/Txt2Tags.hs.orig @@ -0,0 +1,437 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Readers.Txt2Tags (tests) where + +import Data.List (intersperse) +import Data.Text (Text) +import qualified Data.Text as T +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder +import Text.Pandoc.Shared (underlineSpan) + +t2t :: Text -> Pandoc +-- t2t = handleError . readTxt2Tags (T2TMeta "date" "mtime" "in" "out") def +t2t = purely $ \s -> do + setInputFiles ["in"] + setOutputFile (Just "out") + readTxt2Tags def s + +infix 4 =: +(=:) :: ToString c + => String -> (Text, c) -> TestTree +(=:) = test t2t + +spcSep :: [Inlines] -> Inlines +spcSep = mconcat . intersperse space + +simpleTable' :: Int + -> [Blocks] + -> [[Blocks]] + -> Blocks +simpleTable' n = table "" (replicate n (AlignCenter, 0.0)) + +tests :: [TestTree] +tests = + [ testGroup "Inlines" + [ "Plain String" =: + "Hello, World" =?> + para (spcSep [ "Hello,", "World" ]) + + , "Emphasis" =: + "//Planet Punk//" =?> + para (emph . spcSep $ ["Planet", "Punk"]) + + , "Strong" =: + "**Cider**" =?> + para (strong "Cider") + + , "Strong Emphasis" =: + "//**strength**//" =?> + para (emph . strong $ "strength") + + , "Strikeout" =: + "--Kill Bill--" =?> + para (strikeout . spcSep $ [ "Kill", "Bill" ]) + + , "Verbatim" =: + "``Robot.rock()``" =?> + para (code "Robot.rock()") + + , "Symbol" =: + "A * symbol" =?> + para (str "A" <> space <> str "*" <> space <> "symbol") + + , "No empty markup" =: + "//// **** ____ ---- ```` \"\"\"\" ''''" =?> + para (spcSep [ "////", "****", "____", "----", "````", "\"\"\"\"", "''''" ]) + + , "Inline markup is greedy" =: + "***** ///// _____ ----- ````` \"\"\"\"\" '''''" =?> + para (spcSep [strong "*", emph "/", underlineSpan "_" + , strikeout "-", code "`", text "\"" + , rawInline "html" "'"]) + , "Markup must be greedy" =: + "********** ////////// __________ ---------- `````````` \"\"\"\"\"\"\"\"\"\" ''''''''''" =?> + para (spcSep [strong "******", emph "//////", underlineSpan "______" + , strikeout "------", code "``````", text "\"\"\"\"\"\"" + , rawInline "html" "''''''"]) + , "Inlines must be glued" =: + "** a** **a ** ** a **" =?> + para (text "** a** **a ** ** a **") + + , "Macros: Date" =: + "%%date" =?> + para "1970-01-01" + , "Macros: Mod Time" =: + "%%mtime" =?> + para (str "") + , "Macros: Infile" =: + "%%infile" =?> + para "in" + , "Macros: Outfile" =: + "%%outfile" =?> + para "out" + , "Autolink" =: + "http://www.google.com" =?> + para (link "http://www.google.com" "" (str "http://www.google.com")) + , "JPEG Image" =: + "[image.jpg]" =?> + para (image "image.jpg" "" mempty) + , "PNG Image" =: + "[image.png]" =?> + para (image "image.png" "" mempty) + + , "Link" =: + "[title http://google.com]" =?> + para (link "http://google.com" "" (str "title")) + + , "Image link" =: + "[[image.jpg] abc]" =?> + para (link "abc" "" (image "image.jpg" "" mempty)) + , "Invalid link: No trailing space" =: + "[title invalid ]" =?> + para (text "[title invalid ]") + + + ] + + , testGroup "Basic Blocks" + ["Paragraph, lines grouped together" =: + "A paragraph\n A blank line ends the \n current paragraph\n" + =?> para "A paragraph\n A blank line ends the\n current paragraph" + , "Paragraph, ignore leading and trailing spaces" =: + " Leading and trailing spaces are ignored. \n" =?> + para "Leading and trailing spaces are ignored." + , "Comment line in paragraph" =: + "A comment line can be placed inside a paragraph.\n% this comment will be ignored \nIt will not affect it.\n" + =?> para "A comment line can be placed inside a paragraph.\nIt will not affect it." + , "Paragraph" =: + "Paragraph\n" =?> + para "Paragraph" + + , "First Level Header" =: + "+ Headline +\n" =?> + header 1 "Headline" + + , "Third Level Header" =: + "=== Third Level Headline ===\n" =?> + header 3 ("Third" <> space <> + "Level" <> space <> + "Headline") + + , "Header with label" =: + "= header =[label]" =?> + headerWith ("label", [], []) 1 "header" + + , "Invalid header, mismatched delimiters" =: + "== header =" =?> + para (text "== header =") + + , "Invalid header, spaces in label" =: + "== header ==[ haha ]" =?> + para (text "== header ==[ haha ]") + + , "Invalid header, invalid label character" =: + "== header ==[lab/el]" =?> + para (text "== header ==[lab/el]") + , "Headers not preceded by a blank line" =: + T.unlines [ "++ eat dinner ++" + , "Spaghetti and meatballs tonight." + , "== walk dog ==" + ] =?> + mconcat [ header 2 ("eat" <> space <> "dinner") + , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ] + , header 2 ("walk" <> space <> "dog") + ] + + , "Paragraph starting with an equals" =: + "=five" =?> + para "=five" + + , "Paragraph containing asterisk at beginning of line" =: + T.unlines [ "lucky" + , "*star" + ] =?> + para ("lucky" <> softbreak <> "*star") + + , "Horizontal Rule" =: + T.unlines [ "before" + , T.replicate 20 "-" + , T.replicate 20 "=" + , T.replicate 20 "_" + , "after" + ] =?> + mconcat [ para "before" + , horizontalRule + , horizontalRule + , horizontalRule + , para "after" + ] + + , "Comment Block" =: + T.unlines [ "%%%" + , "stuff" + , "bla" + , "%%%"] =?> + (mempty::Blocks) + + + ] + + , testGroup "Lists" + [ "Simple Bullet Lists" =: + ("- Item1\n" <> + "- Item2\n") =?> + bulletList [ plain "Item1" + , plain "Item2" + ] + + , "Indented Bullet Lists" =: + (" - Item1\n" <> + " - Item2\n") =?> + bulletList [ plain "Item1" + , plain "Item2" + ] + + + + , "Nested Bullet Lists" =: + ("- Discovery\n" <> + " + One More Time\n" <> + " + Harder, Better, Faster, Stronger\n" <> + "- Homework\n" <> + " + Around the World\n"<> + "- Human After All\n" <> + " + Technologic\n" <> + " + Robot Rock\n") =?> + bulletList [ mconcat + [ plain "Discovery" + , orderedList [ plain ("One" <> space <> + "More" <> space <> + "Time") + , plain ("Harder," <> space <> + "Better," <> space <> + "Faster," <> space <> + "Stronger") + ] + ] + , mconcat + [ plain "Homework" + , orderedList [ plain ("Around" <> space <> + "the" <> space <> + "World") + ] + ] + , mconcat + [ plain ("Human" <> space <> "After" <> space <> "All") + , orderedList [ plain "Technologic" + , plain ("Robot" <> space <> "Rock") + ] + ] + ] + + , "Simple Ordered List" =: + ("+ Item1\n" <> + "+ Item2\n") =?> + let listStyle = (1, DefaultStyle, DefaultDelim) + listStructure = [ plain "Item1" + , plain "Item2" + ] + in orderedListWith listStyle listStructure + + + , "Indented Ordered List" =: + (" + Item1\n" <> + " + Item2\n") =?> + let listStyle = (1, DefaultStyle, DefaultDelim) + listStructure = [ plain "Item1" + , plain "Item2" + ] + in orderedListWith listStyle listStructure + + , "Nested Ordered Lists" =: + ("+ One\n" <> + " + One-One\n" <> + " + One-Two\n" <> + "+ Two\n" <> + " + Two-One\n"<> + " + Two-Two\n") =?> + let listStyle = (1, DefaultStyle, DefaultDelim) + listStructure = [ mconcat + [ plain "One" + , orderedList [ plain "One-One" + , plain "One-Two" + ] + ] + , mconcat + [ plain "Two" + , orderedList [ plain "Two-One" + , plain "Two-Two" + ] + ] + ] + in orderedListWith listStyle listStructure + + , "Ordered List in Bullet List" =: + ("- Emacs\n" <> + " + Org\n") =?> + bulletList [ (plain "Emacs") <> + (orderedList [ plain "Org"]) + ] + + , "Bullet List in Ordered List" =: + ("+ GNU\n" <> + " - Freedom\n") =?> + orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ] + + , "Definition List" =: + T.unlines [ ": PLL" + , " phase-locked loop" + , ": TTL" + , " transistor-transistor logic" + , ": PSK" + , " a digital" + ] =?> + definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ]) + , ("TTL", [ plain $ "transistor-transistor" <> space <> "logic" ]) + , ("PSK", [ plain $ "a" <> space <> "digital" ]) + ] + + + , "Loose bullet list" =: + T.unlines [ "- apple" + , "" + , "- orange" + , "" + , "- peach" + ] =?> + bulletList [ para "apple" + , para "orange" + , para "peach" + ] + ] + + , testGroup "Tables" + [ "Single cell table" =: + "| Test " =?> + simpleTable' 1 mempty [[plain "Test"]] + + , "Multi cell table" =: + "| One | Two |" =?> + simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ] + + , "Multi line table" =: + T.unlines [ "| One |" + , "| Two |" + , "| Three |" + ] =?> + simpleTable' 1 mempty + [ [ plain "One" ] + , [ plain "Two" ] + , [ plain "Three" ] + ] + + , "Empty table" =: + "| |" =?> + simpleTable' 1 mempty [[mempty]] + + , "Glider Table" =: + T.unlines [ "| 1 | 0 | 0 |" + , "| 0 | 1 | 1 |" + , "| 1 | 1 | 0 |" + ] =?> + simpleTable' 3 mempty + [ [ plain "1", plain "0", plain "0" ] + , [ plain "0", plain "1", plain "1" ] + , [ plain "1", plain "1", plain "0" ] + ] + + + , "Table with Header" =: + T.unlines [ "|| Species | Status |" + , "| cervisiae | domesticated |" + , "| paradoxus | wild |" + ] =?> + simpleTable [ plain "Species", plain "Status" ] + [ [ plain "cervisiae", plain "domesticated" ] + , [ plain "paradoxus", plain "wild" ] + ] + + , "Table alignment determined by spacing" =: + T.unlines [ "| Numbers | Text | More |" + , "| 1 | One | foo |" + , "| 2 | Two | bar |" + ] =?> + table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0]) + [] + [ [ plain "Numbers", plain "Text", plain "More" ] + , [ plain "1" , plain "One" , plain "foo" ] + , [ plain "2" , plain "Two" , plain "bar" ] + ] + + , "Pipe within text doesn't start a table" =: + "Ceci n'est pas une | pipe " =?> + para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ]) + + + , "Table with differing row lengths" =: + T.unlines [ "|| Numbers | Text " + , "| 1 | One | foo |" + , "| 2 " + ] =?> + table "" (zip [AlignCenter, AlignLeft, AlignLeft] [0, 0, 0]) + [ plain "Numbers", plain "Text" , plain mempty ] + [ [ plain "1" , plain "One" , plain "foo" ] + , [ plain "2" , plain mempty , plain mempty ] + ] + + ] + + , testGroup "Blocks and fragments" + [ "Source block" =: + T.unlines [ "```" + , "main = putStrLn greeting" + , " where greeting = \"moin\"" + , "```" ] =?> + let code' = "main = putStrLn greeting\n" <> + " where greeting = \"moin\"\n" + in codeBlock code' + + , "tagged block" =: + T.unlines [ "'''" + , "<aside>HTML5 is pretty nice.</aside>" + , "'''" + ] =?> + rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n" + + , "Quote block" =: + T.unlines ["\t//Niemand// hat die Absicht, eine Mauer zu errichten!" + ] =?> + blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht," + , "eine", "Mauer", "zu", "errichten!" + ])) + + ] + ] diff --git a/test/Tests/Shared.hs.orig b/test/Tests/Shared.hs.orig new file mode 100644 index 000000000..cc448419c --- /dev/null +++ b/test/Tests/Shared.hs.orig @@ -0,0 +1,39 @@ +module Tests.Shared (tests) where + +import System.FilePath.Posix (joinPath) +import Test.Tasty +import Test.Tasty.HUnit (assertBool, testCase, (@?=)) +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder +import Text.Pandoc.Shared + +tests :: [TestTree] +tests = [ testGroup "compactifyDL" + [ testCase "compactifyDL with empty def" $ + assertBool "compactifyDL" + (let x = [(str "word", [para (str "def"), mempty])] + in compactifyDL x == x) + ] + , testGroup "collapseFilePath" testCollapse + ] + +testCollapse :: [TestTree] +testCollapse = map (testCase "collapse") + [ collapseFilePath (joinPath [ ""]) @?= (joinPath [ ""]) + , collapseFilePath (joinPath [ ".","foo"]) @?= (joinPath [ "foo"]) + , collapseFilePath (joinPath [ ".",".","..","foo"]) @?= (joinPath [ joinPath ["..", "foo"]]) + , collapseFilePath (joinPath [ "..","foo"]) @?= (joinPath [ "..","foo"]) + , collapseFilePath (joinPath [ "","bar","..","baz"]) @?= (joinPath [ "","baz"]) + , collapseFilePath (joinPath [ "","..","baz"]) @?= (joinPath [ "","..","baz"]) + , collapseFilePath (joinPath [ ".","foo","..",".","bar","..",".",".","baz"]) @?= (joinPath [ "baz"]) + , collapseFilePath (joinPath [ ".",""]) @?= (joinPath [ ""]) + , collapseFilePath (joinPath [ ".",".",""]) @?= (joinPath [ ""]) + , collapseFilePath (joinPath [ "..",""]) @?= (joinPath [ ".."]) + , collapseFilePath (joinPath [ "..",".",""]) @?= (joinPath [ ".."]) + , collapseFilePath (joinPath [ ".","..",""]) @?= (joinPath [ ".."]) + , collapseFilePath (joinPath [ "..","..",""]) @?= (joinPath [ "..",".."]) + , collapseFilePath (joinPath [ "parent","foo","baz","..","bar"]) @?= (joinPath [ "parent","foo","bar"]) + , collapseFilePath (joinPath [ "parent","foo","baz","..","..","bar"]) @?= (joinPath [ "parent","bar"]) + , collapseFilePath (joinPath [ "parent","foo",".."]) @?= (joinPath [ "parent"]) + , collapseFilePath (joinPath [ "","parent","foo","..","..","bar"]) @?= (joinPath [ "","bar"]) + , collapseFilePath (joinPath [ "",".","parent","foo"]) @?= (joinPath [ "","parent","foo"])] diff --git a/test/Tests/Writers/AsciiDoc.hs.orig b/test/Tests/Writers/AsciiDoc.hs.orig new file mode 100644 index 000000000..6b97c0761 --- /dev/null +++ b/test/Tests/Writers/AsciiDoc.hs.orig @@ -0,0 +1,56 @@ +module Tests.Writers.AsciiDoc (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +asciidoc :: (ToPandoc a) => a -> String +asciidoc = unpack . purely (writeAsciiDoc def{ writerWrapText = WrapNone }) . toPandoc + +tests :: [TestTree] +tests = [ testGroup "emphasis" + [ test asciidoc "emph word before" $ + para (text "foo" <> emph (text "bar")) =?> + "foo__bar__" + , test asciidoc "emph word after" $ + para (emph (text "foo") <> text "bar") =?> + "__foo__bar" + , test asciidoc "emph quoted" $ + para (doubleQuoted (emph (text "foo"))) =?> + "``__foo__''" + , test asciidoc "strong word before" $ + para (text "foo" <> strong (text "bar")) =?> + "foo**bar**" + , test asciidoc "strong word after" $ + para (strong (text "foo") <> text "bar") =?> + "**foo**bar" + , test asciidoc "strong quoted" $ + para (singleQuoted (strong (text "foo"))) =?> + "`**foo**'" + ] + , testGroup "tables" + [ test asciidoc "empty cells" $ + simpleTable [] [[mempty],[mempty]] =?> unlines + [ "[cols=\"\",]" + , "|====" + , "|" + , "|" + , "|====" + ] + , test asciidoc "multiblock cells" $ + simpleTable [] [[para (text "Para 1") <> para (text "Para 2")]] + =?> unlines + [ "[cols=\"\",]" + , "|=====" + , "a|" + , "Para 1" + , "" + , "Para 2" + , "" + , "|=====" + ] + ] + ] diff --git a/test/Tests/Writers/ConTeXt.hs.orig b/test/Tests/Writers/ConTeXt.hs.orig new file mode 100644 index 000000000..812aab4a6 --- /dev/null +++ b/test/Tests/Writers/ConTeXt.hs.orig @@ -0,0 +1,149 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.ConTeXt (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Test.Tasty.QuickCheck +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +context :: (ToPandoc a) => a -> String +context = unpack . purely (writeConTeXt def) . toPandoc + +context' :: (ToPandoc a) => a -> String +context' = unpack . purely (writeConTeXt def{ writerWrapText = WrapNone }) . toPandoc + +contextNtb :: (ToPandoc a) => a -> String +contextNtb = unpack . purely (writeConTeXt def{ writerExtensions = enableExtension Ext_ntb pandocExtensions }) . toPandoc + +contextDiv :: (ToPandoc a) => a -> String +contextDiv = unpack . purely (writeConTeXt def{ writerSectionDivs = True }) . toPandoc + +{- + "my test" =: X =?> Y + +is shorthand for + + test context "my test" $ X =?> Y + +which is in turn shorthand for + + test context "my test" (X,Y) +-} + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test context + +tests :: [TestTree] +tests = [ testGroup "inline code" + [ "with '}'" =: code "}" =?> "\\mono{\\}}" + , "without '}'" =: code "]" =?> "\\type{]}" + , testProperty "code property" $ \s -> null s || + if '{' `elem` s || '}' `elem` s + then context' (code s) == "\\mono{" ++ + context' (str s) ++ "}" + else context' (code s) == "\\type{" ++ s ++ "}" + ] + , testGroup "headers" + [ "level 1" =: + headerWith ("my-header",[],[]) 1 "My header" =?> "\\section[title={My header},reference={my-header}]" + , test contextDiv "section-divs" $ + ( headerWith ("header1", [], []) 1 (text "Header1") + <> headerWith ("header2", [], []) 2 (text "Header2") + <> headerWith ("header3", [], []) 3 (text "Header3") + <> headerWith ("header4", [], []) 4 (text "Header4") + <> headerWith ("header5", [], []) 5 (text "Header5") + <> headerWith ("header6", [], []) 6 (text "Header6")) + =?> + unlines [ "\\startsection[title={Header1},reference={header1}]\n" + , "\\startsubsection[title={Header2},reference={header2}]\n" + , "\\startsubsubsection[title={Header3},reference={header3}]\n" + , "\\startsubsubsubsection[title={Header4},reference={header4}]\n" + , "\\startsubsubsubsubsection[title={Header5},reference={header5}]\n" + , "\\startsubsubsubsubsubsection[title={Header6},reference={header6}]\n" + , "\\stopsubsubsubsubsubsection\n" + , "\\stopsubsubsubsubsection\n" + , "\\stopsubsubsubsection\n" + , "\\stopsubsubsection\n" + , "\\stopsubsection\n" + , "\\stopsection" ] + ] + , testGroup "bullet lists" + [ "nested" =: + bulletList [ + plain (text "top") + <> bulletList [ + plain (text "next") + <> bulletList [plain (text "bot")] + ] + ] =?> unlines + [ "\\startitemize[packed]" + , "\\item" + , " top" + , " \\startitemize[packed]" + , " \\item" + , " next" + , " \\startitemize[packed]" + , " \\item" + , " bot" + , " \\stopitemize" + , " \\stopitemize" + , "\\stopitemize" ] + ] + , testGroup "natural tables" + [ test contextNtb "table with header and caption" $ + let caption = text "Table 1" + aligns = [(AlignRight, 0.0), (AlignLeft, 0.0), (AlignCenter, 0.0), (AlignDefault, 0.0)] + headers = [plain $ text "Right", + plain $ text "Left", + plain $ text "Center", + plain $ text "Default"] + rows = [[plain $ text "1.1", + plain $ text "1.2", + plain $ text "1.3", + plain $ text "1.4"] + ,[plain $ text "2.1", + plain $ text "2.2", + plain $ text "2.3", + plain $ text "2.4"] + ,[plain $ text "3.1", + plain $ text "3.2", + plain $ text "3.3", + plain $ text "3.4"]] + in table caption aligns headers rows + =?> unlines [ "\\startplacetable[title={Table 1}]" + , "\\startTABLE" + , "\\startTABLEhead" + , "\\NC[align=left] Right" + , "\\NC[align=right] Left" + , "\\NC[align=middle] Center" + , "\\NC Default" + , "\\NC\\NR" + , "\\stopTABLEhead" + , "\\startTABLEbody" + , "\\NC[align=left] 1.1" + , "\\NC[align=right] 1.2" + , "\\NC[align=middle] 1.3" + , "\\NC 1.4" + , "\\NC\\NR" + , "\\NC[align=left] 2.1" + , "\\NC[align=right] 2.2" + , "\\NC[align=middle] 2.3" + , "\\NC 2.4" + , "\\NC\\NR" + , "\\stopTABLEbody" + , "\\startTABLEfoot" + , "\\NC[align=left] 3.1" + , "\\NC[align=right] 3.2" + , "\\NC[align=middle] 3.3" + , "\\NC 3.4" + , "\\NC\\NR" + , "\\stopTABLEfoot" + , "\\stopTABLE" + , "\\stopplacetable" ] + ] + ] diff --git a/test/Tests/Writers/Docbook.hs.orig b/test/Tests/Writers/Docbook.hs.orig new file mode 100644 index 000000000..89ea76586 --- /dev/null +++ b/test/Tests/Writers/Docbook.hs.orig @@ -0,0 +1,303 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.Docbook (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +docbook :: (ToPandoc a) => a -> String +docbook = docbookWithOpts def{ writerWrapText = WrapNone } + +docbookWithOpts :: ToPandoc a => WriterOptions -> a -> String +docbookWithOpts opts = unpack . purely (writeDocbook4 opts) . toPandoc + +{- + "my test" =: X =?> Y + +is shorthand for + + test docbook "my test" $ X =?> Y + +which is in turn shorthand for + + test docbook "my test" (X,Y) +-} + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test docbook + +lineblock :: Blocks +lineblock = para ("some text" <> linebreak <> + "and more lines" <> linebreak <> + "and again") +lineblock_out :: [String] +lineblock_out = [ "<literallayout>some text" + , "and more lines" + , "and again</literallayout>" + ] + +tests :: [TestTree] +tests = [ testGroup "line blocks" + [ "none" =: para "This is a test" + =?> unlines + [ "<para>" + , " This is a test" + , "</para>" + ] + , "basic" =: lineblock + =?> unlines lineblock_out + , "blockquote" =: blockQuote lineblock + =?> unlines + ( [ "<blockquote>" ] ++ + lineblock_out ++ + [ "</blockquote>" ] + ) + , "footnote" =: para ("This is a test" <> + note lineblock <> + " of footnotes") + =?> unlines + ( [ "<para>" + , " This is a test<footnote>" ] ++ + lineblock_out ++ + [ " </footnote> of footnotes" + , "</para>" ] + ) + ] + , testGroup "compact lists" + [ testGroup "bullet" + [ "compact" =: bulletList [plain "a", plain "b", plain "c"] + =?> unlines + [ "<itemizedlist spacing=\"compact\">" + , " <listitem>" + , " <para>" + , " a" + , " </para>" + , " </listitem>" + , " <listitem>" + , " <para>" + , " b" + , " </para>" + , " </listitem>" + , " <listitem>" + , " <para>" + , " c" + , " </para>" + , " </listitem>" + , "</itemizedlist>" + ] + , "loose" =: bulletList [para "a", para "b", para "c"] + =?> unlines + [ "<itemizedlist>" + , " <listitem>" + , " <para>" + , " a" + , " </para>" + , " </listitem>" + , " <listitem>" + , " <para>" + , " b" + , " </para>" + , " </listitem>" + , " <listitem>" + , " <para>" + , " c" + , " </para>" + , " </listitem>" + , "</itemizedlist>" + ] + ] + , testGroup "ordered" + [ "compact" =: orderedList [plain "a", plain "b", plain "c"] + =?> unlines + [ "<orderedlist spacing=\"compact\">" + , " <listitem>" + , " <para>" + , " a" + , " </para>" + , " </listitem>" + , " <listitem>" + , " <para>" + , " b" + , " </para>" + , " </listitem>" + , " <listitem>" + , " <para>" + , " c" + , " </para>" + , " </listitem>" + , "</orderedlist>" + ] + , "loose" =: orderedList [para "a", para "b", para "c"] + =?> unlines + [ "<orderedlist>" + , " <listitem>" + , " <para>" + , " a" + , " </para>" + , " </listitem>" + , " <listitem>" + , " <para>" + , " b" + , " </para>" + , " </listitem>" + , " <listitem>" + , " <para>" + , " c" + , " </para>" + , " </listitem>" + , "</orderedlist>" + ] + ] + , testGroup "definition" + [ "compact" =: definitionList [ ("an", [plain "apple" ]) + , ("a", [plain "banana"]) + , ("an", [plain "orange"])] + =?> unlines + [ "<variablelist spacing=\"compact\">" + , " <varlistentry>" + , " <term>" + , " an" + , " </term>" + , " <listitem>" + , " <para>" + , " apple" + , " </para>" + , " </listitem>" + , " </varlistentry>" + , " <varlistentry>" + , " <term>" + , " a" + , " </term>" + , " <listitem>" + , " <para>" + , " banana" + , " </para>" + , " </listitem>" + , " </varlistentry>" + , " <varlistentry>" + , " <term>" + , " an" + , " </term>" + , " <listitem>" + , " <para>" + , " orange" + , " </para>" + , " </listitem>" + , " </varlistentry>" + , "</variablelist>" + ] + , "loose" =: definitionList [ ("an", [para "apple" ]) + , ("a", [para "banana"]) + , ("an", [para "orange"])] + =?> unlines + [ "<variablelist>" + , " <varlistentry>" + , " <term>" + , " an" + , " </term>" + , " <listitem>" + , " <para>" + , " apple" + , " </para>" + , " </listitem>" + , " </varlistentry>" + , " <varlistentry>" + , " <term>" + , " a" + , " </term>" + , " <listitem>" + , " <para>" + , " banana" + , " </para>" + , " </listitem>" + , " </varlistentry>" + , " <varlistentry>" + , " <term>" + , " an" + , " </term>" + , " <listitem>" + , " <para>" + , " orange" + , " </para>" + , " </listitem>" + , " </varlistentry>" + , "</variablelist>" + ] + ] + ] + , testGroup "writer options" + [ testGroup "top-level division" $ + let + headers = header 1 (text "header1") + <> header 2 (text "header2") + <> header 3 (text "header3") + + docbookTopLevelDiv :: (ToPandoc a) + => TopLevelDivision -> a -> String + docbookTopLevelDiv division = + docbookWithOpts def{ writerTopLevelDivision = division } + in + [ test (docbookTopLevelDiv TopLevelSection) "sections as top-level" $ + headers =?> + unlines [ "<sect1>" + , " <title>header1</title>" + , " <sect2>" + , " <title>header2</title>" + , " <sect3>" + , " <title>header3</title>" + , " <para>" + , " </para>" + , " </sect3>" + , " </sect2>" + , "</sect1>" + ] + , test (docbookTopLevelDiv TopLevelChapter) "chapters as top-level" $ + headers =?> + unlines [ "<chapter>" + , " <title>header1</title>" + , " <sect1>" + , " <title>header2</title>" + , " <sect2>" + , " <title>header3</title>" + , " <para>" + , " </para>" + , " </sect2>" + , " </sect1>" + , "</chapter>" + ] + , test (docbookTopLevelDiv TopLevelPart) "parts as top-level" $ + headers =?> + unlines [ "<part>" + , " <title>header1</title>" + , " <chapter>" + , " <title>header2</title>" + , " <sect1>" + , " <title>header3</title>" + , " <para>" + , " </para>" + , " </sect1>" + , " </chapter>" + , "</part>" + ] + , test (docbookTopLevelDiv TopLevelDefault) "default top-level" $ + headers =?> + unlines [ "<sect1>" + , " <title>header1</title>" + , " <sect2>" + , " <title>header2</title>" + , " <sect3>" + , " <title>header3</title>" + , " <para>" + , " </para>" + , " </sect3>" + , " </sect2>" + , "</sect1>" + ] + ] + ] + ] diff --git a/test/Tests/Writers/Docx.hs.orig b/test/Tests/Writers/Docx.hs.orig new file mode 100644 index 000000000..3ded0aa38 --- /dev/null +++ b/test/Tests/Writers/Docx.hs.orig @@ -0,0 +1,157 @@ +module Tests.Writers.Docx (tests) where + +import Text.Pandoc +import Test.Tasty +import Tests.Writers.OOXML +import Test.Tasty.HUnit +import Data.List (isPrefixOf) + +-- we add an extra check to make sure that we're not writing in the +-- toplevel docx directory. We don't want to accidentally overwrite an +-- Word-generated docx file used to test the reader. +docxTest :: String -> WriterOptions -> FilePath -> FilePath -> TestTree +docxTest testName opts nativeFP goldenFP = + if "docx/golden/" `isPrefixOf` goldenFP + then ooxmlTest writeDocx testName opts nativeFP goldenFP + else testCase testName $ + assertFailure $ + goldenFP ++ " is not in `test/docx/golden`" + +tests :: [TestTree] +tests = [ testGroup "inlines" + [ docxTest + "font formatting" + def + "docx/inline_formatting.native" + "docx/golden/inline_formatting.docx" + , docxTest + "hyperlinks" + def + "docx/links.native" + "docx/golden/links.docx" + , docxTest + "inline image" + def + "docx/image_writer_test.native" + "docx/golden/image.docx" + , docxTest + "inline images" + def + "docx/inline_images_writer_test.native" + "docx/golden/inline_images.docx" + , docxTest + "handling unicode input" + def + "docx/unicode.native" + "docx/golden/unicode.docx" + , docxTest + "inline code" + def + "docx/inline_code.native" + "docx/golden/inline_code.docx" + , docxTest + "inline code in subscript and superscript" + def + "docx/verbatim_subsuper.native" + "docx/golden/verbatim_subsuper.docx" + ] + , testGroup "blocks" + [ docxTest + "headers" + def + "docx/headers.native" + "docx/golden/headers.docx" + , docxTest + "nested anchor spans in header" + def + "docx/nested_anchors_in_header.native" + "docx/golden/nested_anchors_in_header.docx" + , docxTest + "lists" + def + "docx/lists.native" + "docx/golden/lists.docx" + , docxTest + "lists continuing after interruption" + def + "docx/lists_continuing.native" + "docx/golden/lists_continuing.docx" + , docxTest + "lists restarting after interruption" + def + "docx/lists_restarting.native" + "docx/golden/lists_restarting.docx" + , docxTest + "definition lists" + def + "docx/definition_list.native" + "docx/golden/definition_list.docx" + , docxTest + "footnotes and endnotes" + def + "docx/notes.native" + "docx/golden/notes.docx" + , docxTest + "links in footnotes and endnotes" + def + "docx/link_in_notes.native" + "docx/golden/link_in_notes.docx" + , docxTest + "blockquotes" + def + "docx/block_quotes_parse_indent.native" + "docx/golden/block_quotes.docx" + , docxTest + "tables" + def + "docx/tables.native" + "docx/golden/tables.docx" + , docxTest + "tables with lists in cells" + def + "docx/table_with_list_cell.native" + "docx/golden/table_with_list_cell.docx" + , docxTest + "tables with one row" + def + "docx/table_one_row.native" + "docx/golden/table_one_row.docx" + , docxTest + "code block" + def + "docx/codeblock.native" + "docx/golden/codeblock.docx" + ] + , testGroup "track changes" + [ docxTest + "insertion" + def + "docx/track_changes_insertion_all.native" + "docx/golden/track_changes_insertion.docx" + , docxTest + "deletion" + def + "docx/track_changes_deletion_all.native" + "docx/golden/track_changes_deletion.docx" + , docxTest + "move text" + def + "docx/track_changes_move_all.native" + "docx/golden/track_changes_move.docx" + , docxTest + "comments" + def + "docx/comments.native" + "docx/golden/comments.docx" + ] + , testGroup "custom styles" + [ docxTest "custom styles without reference.docx" + def + "docx/custom_style.native" + "docx/golden/custom_style_no_reference.docx" + , docxTest "custom styles with reference.docx" + def{writerReferenceDoc = Just "docx/custom-style-reference.docx"} + "docx/custom_style.native" + "docx/golden/custom_style_reference.docx" + ] + ] diff --git a/test/Tests/Writers/FB2.hs.orig b/test/Tests/Writers/FB2.hs.orig new file mode 100644 index 000000000..6663c42f8 --- /dev/null +++ b/test/Tests/Writers/FB2.hs.orig @@ -0,0 +1,34 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.FB2 (tests) where + +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +fb2 :: String -> String +fb2 x = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ++ + "<FictionBook xmlns=\"http://www.gribuser.ru/xml/fictionbook/2.0\" xmlns:l=\"http://www.w3.org/1999/xlink\"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section>" ++ x ++ "</section></body></FictionBook>" + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test (purely (writeFB2 def) . toPandoc) + +tests :: [TestTree] +tests = [ testGroup "block elements" + ["para" =: para "Lorem ipsum cetera." + =?> fb2 "<p>Lorem ipsum cetera.</p>" + ] + , testGroup "inlines" + [ + "Emphasis" =: emph "emphasized" + =?> fb2 "<emphasis>emphasized</emphasis>" + ] + , "bullet list" =: bulletList [ plain $ text "first" + , plain $ text "second" + , plain $ text "third" + ] + =?> fb2 "<p>\x2022 first</p><p>\x2022 second</p><p>\x2022 third</p>" + ] diff --git a/test/Tests/Writers/HTML.hs.orig b/test/Tests/Writers/HTML.hs.orig new file mode 100644 index 000000000..23ff718d3 --- /dev/null +++ b/test/Tests/Writers/HTML.hs.orig @@ -0,0 +1,44 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.HTML (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +html :: (ToPandoc a) => a -> String +html = unpack . purely (writeHtml4String def{ writerWrapText = WrapNone }) . toPandoc + +{- + "my test" =: X =?> Y + +is shorthand for + + test html "my test" $ X =?> Y + +which is in turn shorthand for + + test html "my test" (X,Y) +-} + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test html + +tests :: [TestTree] +tests = [ testGroup "inline code" + [ "basic" =: code "@&" =?> "<code>@&</code>" + , "haskell" =: codeWith ("",["haskell"],[]) ">>=" + =?> "<code class=\"sourceCode haskell\"><span class=\"fu\">>>=</span></code>" + , "nolanguage" =: codeWith ("",["nolanguage"],[]) ">>=" + =?> "<code class=\"nolanguage\">>>=</code>" + ] + , testGroup "images" + [ "alt with formatting" =: + image "/url" "title" ("my " <> emph "image") + =?> "<img src=\"/url\" title=\"title\" alt=\"my image\" />" + ] + ] diff --git a/test/Tests/Writers/JATS.hs.orig b/test/Tests/Writers/JATS.hs.orig new file mode 100644 index 000000000..723c0e8a8 --- /dev/null +++ b/test/Tests/Writers/JATS.hs.orig @@ -0,0 +1,108 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.JATS (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +jats :: (ToPandoc a) => a -> String +jats = unpack . purely (writeJATS def{ writerWrapText = WrapNone }) . toPandoc + +{- + "my test" =: X =?> Y + +is shorthand for + + test jats "my test" $ X =?> Y + +which is in turn shorthand for + + test jats "my test" (X,Y) +-} + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test jats + +tests :: [TestTree] +tests = [ testGroup "inline code" + [ "basic" =: code "@&" =?> "<p><monospace>@&</monospace></p>" + , "lang" =: codeWith ("", ["c"], []) "@&" =?> "<p><code language=\"c\">@&</code></p>" + ] + , testGroup "block code" + [ "basic" =: codeBlock "@&" =?> "<preformat>@&</preformat>" + , "lang" =: codeBlockWith ("", ["c"], []) "@&" =?> "<code language=\"c\">@&</code>" + ] + , testGroup "images" + [ "basic" =: + image "/url" "title" mempty + =?> "<graphic mimetype=\"image\" mime-subtype=\"\" xlink:href=\"/url\" xlink:title=\"title\" />" + ] + , testGroup "inlines" + [ "Emphasis" =: emph "emphasized" + =?> "<p><italic>emphasized</italic></p>" + ] + , "bullet list" =: bulletList [ plain $ text "first" + , plain $ text "second" + , plain $ text "third" + ] + =?> "<list list-type=\"bullet\">\n\ + \ <list-item>\n\ + \ <p>first</p>\n\ + \ </list-item>\n\ + \ <list-item>\n\ + \ <p>second</p>\n\ + \ </list-item>\n\ + \ <list-item>\n\ + \ <p>third</p>\n\ + \ </list-item>\n\ + \</list>" + , testGroup "definition lists" + [ "with internal link" =: definitionList [(link "#go" "" (str "testing"), + [plain (text "hi there")])] =?> + "<def-list>\n\ + \ <def-item>\n\ + \ <term><xref alt=\"testing\" rid=\"go\">testing</xref></term>\n\ + \ <def>\n\ + \ <p>hi there</p>\n\ + \ </def>\n\ + \ </def-item>\n\ + \</def-list>" + ] + , testGroup "math" + [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?> + "<p><inline-formula><alternatives>\n\ + \<tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\ + \<mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula></p>" + ] + , testGroup "headers" + [ "unnumbered header" =: + headerWith ("foo",["unnumbered"],[]) 1 + (text "Header 1" <> note (plain $ text "note")) =?> + "<sec id=\"foo\">\n\ + \ <title>Header 1<fn>\n\ + \ <p>note</p>\n\ + \ </fn></title>\n\ + \</sec>" + , "unnumbered sub header" =: + headerWith ("foo",["unnumbered"],[]) 1 + (text "Header") + <> headerWith ("foo",["unnumbered"],[]) 2 + (text "Sub-Header") =?> + "<sec id=\"foo\">\n\ + \ <title>Header</title>\n\ + \ <sec id=\"foo\">\n\ + \ <title>Sub-Header</title>\n\ + \ </sec>\n\ + \</sec>" + , "containing image" =: + header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?> + "<sec>\n\ + \ <title><inline-graphic mimetype=\"image\" mime-subtype=\"jpeg\" xlink:href=\"imgs/foo.jpg\" /></title>\n\ + \</sec>" + ] + ] diff --git a/test/Tests/Writers/LaTeX.hs.orig b/test/Tests/Writers/LaTeX.hs.orig new file mode 100644 index 000000000..471d9d9e7 --- /dev/null +++ b/test/Tests/Writers/LaTeX.hs.orig @@ -0,0 +1,176 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.LaTeX (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +latex :: (ToPandoc a) => a -> String +latex = latexWithOpts def + +latexListing :: (ToPandoc a) => a -> String +latexListing = latexWithOpts def{ writerListings = True } + +latexWithOpts :: (ToPandoc a) => WriterOptions -> a -> String +latexWithOpts opts = unpack . purely (writeLaTeX opts) . toPandoc + +beamerWithOpts :: (ToPandoc a) => WriterOptions -> a -> String +beamerWithOpts opts = unpack . purely (writeBeamer opts) . toPandoc + +{- + "my test" =: X =?> Y + +is shorthand for + + test latex "my test" $ X =?> Y + +which is in turn shorthand for + + test latex "my test" (X,Y) +-} + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test latex + +tests :: [TestTree] +tests = [ testGroup "code blocks" + [ "in footnotes" =: note (para "hi" <> codeBlock "hi") =?> + "\\footnote{hi\n\n\\begin{Verbatim}\nhi\n\\end{Verbatim}\n}" + , test latexListing "identifier" $ codeBlockWith ("id",[],[]) "hi" =?> + ("\\begin{lstlisting}[label=id]\nhi\n\\end{lstlisting}" :: String) + , test latexListing "no identifier" $ codeBlock "hi" =?> + ("\\begin{lstlisting}\nhi\n\\end{lstlisting}" :: String) + ] + , testGroup "definition lists" + [ "with internal link" =: definitionList [(link "#go" "" (str "testing"), + [plain (text "hi there")])] =?> + "\\begin{description}\n\\tightlist\n\\item[{\\protect\\hyperlink{go}{testing}}]\nhi there\n\\end{description}" + ] + , testGroup "math" + [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?> + "\\(\\sigma|_{\\{x\\}}\\)" + ] + , testGroup "headers" + [ "unnumbered header" =: + headerWith ("foo",["unnumbered"],[]) 1 + (text "Header 1" <> note (plain $ text "note")) =?> + "\\hypertarget{foo}{%\n\\section*{\\texorpdfstring{Header 1\\footnote{note}}{Header 1}}\\label{foo}}\n\\addcontentsline{toc}{section}{Header 1}\n" + , "in list item" =: + bulletList [header 2 (text "foo")] =?> + "\\begin{itemize}\n\\item ~\n \\subsection{foo}\n\\end{itemize}" + , "in definition list item" =: + definitionList [(text "foo", [header 2 (text "bar"), + para $ text "baz"])] =?> + "\\begin{description}\n\\item[foo] ~ \n\\subsection{bar}\n\nbaz\n\\end{description}" + , "containing image" =: + header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?> + "\\section{\\texorpdfstring{\\protect\\includegraphics{imgs/foo.jpg}}{Alt text}}" + ] + , testGroup "inline code" + [ "struck out and highlighted" =: + strikeout (codeWith ("",["haskell"],[]) "foo" <> space + <> str "bar") =?> + "\\sout{\\mbox{\\VERB|\\NormalTok{foo}|} bar}" + , "struck out and not highlighted" =: + strikeout (code "foo" <> space + <> str "bar") =?> + "\\sout{\\texttt{foo} bar}" + , "single quotes" =: + code "dog's" =?> "\\texttt{dog\\textquotesingle{}s}" + , "backtick" =: + code "`nu?`" =?> "\\texttt{\\textasciigrave{}nu?\\textasciigrave{}}" + ] + , testGroup "writer options" + [ testGroup "top-level division" $ + let + headers = header 1 (text "header1") + <> header 2 (text "header2") + <> header 3 (text "header3") + + latexTopLevelDiv :: (ToPandoc a) => TopLevelDivision -> a -> String + latexTopLevelDiv division = + latexWithOpts def{ writerTopLevelDivision = division } + + beamerTopLevelDiv :: (ToPandoc a) + => TopLevelDivision -> a -> String + beamerTopLevelDiv division = + beamerWithOpts def { writerTopLevelDivision = division } + in + [ test (latexTopLevelDiv TopLevelSection) + "sections as top-level" $ headers =?> + unlines [ "\\section{header1}\n" + , "\\subsection{header2}\n" + , "\\subsubsection{header3}" + ] + , test (latexTopLevelDiv TopLevelChapter) + "chapters as top-level" $ headers =?> + unlines [ "\\chapter{header1}\n" + , "\\section{header2}\n" + , "\\subsection{header3}" + ] + , test (latexTopLevelDiv TopLevelPart) + "parts as top-level" $ headers =?> + unlines [ "\\part{header1}\n" + , "\\chapter{header2}\n" + , "\\section{header3}" + ] + , test (latexTopLevelDiv TopLevelDefault) + "default top-level" $ headers =?> + unlines [ "\\section{header1}\n" + , "\\subsection{header2}\n" + , "\\subsubsection{header3}" + ] + , test (beamerTopLevelDiv TopLevelSection) + "sections as top-level in beamer" $ headers =?> + unlines [ "\\section{header1}\n" + , "\\subsection{header2}\n" + , "\\subsubsection{header3}" + ] + , test (beamerTopLevelDiv TopLevelChapter) + "chapters are as part in beamer" $ headers =?> + unlines [ "\\part{header1}\n" + , "\\section{header2}\n" + , "\\subsection{header3}" + ] + , test (beamerTopLevelDiv TopLevelPart) + "parts as top-level in beamer" $ headers =?> + unlines [ "\\part{header1}\n" + , "\\section{header2}\n" + , "\\subsection{header3}" + ] + , test (beamerTopLevelDiv TopLevelDefault) + "default top-level in beamer" $ headers =?> + unlines [ "\\section{header1}\n" + , "\\subsection{header2}\n" + , "\\subsubsection{header3}" + ] + , test (latexTopLevelDiv TopLevelPart) + "part top-level, section not in toc" $ + ( headerWith ("", ["unnumbered"], []) 1 (text "header1") + <> headerWith ("", ["unnumbered"], []) 2 (text "header2") + <> headerWith ("", ["unnumbered"], []) 3 (text "header3") + <> headerWith ("", ["unnumbered"], []) 4 (text "header4") + <> headerWith ("", ["unnumbered"], []) 5 (text "header5") + <> headerWith ("", ["unnumbered"], []) 6 (text "header6")) + =?> + unlines [ "\\part*{header1}" + , "\\addcontentsline{toc}{part}{header1}\n" + , "\\chapter*{header2}" + , "\\addcontentsline{toc}{chapter}{header2}\n" + , "\\section*{header3}" + , "\\addcontentsline{toc}{section}{header3}\n" + , "\\subsection*{header4}" + , "\\addcontentsline{toc}{subsection}{header4}\n" + , "\\subsubsection*{header5}" + , "\\addcontentsline{toc}{subsubsection}{header5}\n" + , "\\paragraph{header6}" + , "\\addcontentsline{toc}{paragraph}{header6}" + ] + ] + ] + ] diff --git a/test/Tests/Writers/Markdown.hs.orig b/test/Tests/Writers/Markdown.hs.orig new file mode 100644 index 000000000..7f9ac3627 --- /dev/null +++ b/test/Tests/Writers/Markdown.hs.orig @@ -0,0 +1,267 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# OPTIONS_GHC -fno-warn-name-shadowing #-} +module Tests.Writers.Markdown (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +defopts :: WriterOptions +defopts = def{ writerExtensions = pandocExtensions } + +markdown :: (ToPandoc a) => a -> String +markdown = unpack . purely (writeMarkdown defopts) . toPandoc + +markdownWithOpts :: (ToPandoc a) => WriterOptions -> a -> String +markdownWithOpts opts x = unpack . purely (writeMarkdown opts) $ toPandoc x + +{- + "my test" =: X =?> Y + +is shorthand for + + test markdown "my test" $ X =?> Y + +which is in turn shorthand for + + test markdown "my test" (X,Y) +-} + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test markdown + +tests :: [TestTree] +tests = [ "indented code after list" + =: (orderedList [ para "one" <> para "two" ] <> codeBlock "test") + =?> "1. one\n\n two\n\n<!-- -->\n\n test" + , "list with tight sublist" + =: bulletList [ plain "foo" <> bulletList [ plain "bar" ], + plain "baz" ] + =?> "- foo\n - bar\n- baz\n" + ] ++ [noteTests] ++ [shortcutLinkRefsTests] + +{- + +Testing with the following text: + +First Header +============ + +This is a footnote.[^1] And this is a [link](https://www.google.com). + +> A note inside a block quote.[^2] +> +> A second paragraph. + +Second Header +============= + +Some more text. + + +[^1]: Down here. + +[^2]: The second note. + +-} + +noteTestDoc :: Blocks +noteTestDoc = + header 1 "First Header" <> + para ("This is a footnote." <> + note (para "Down here.") <> + " And this is a " <> + link "https://www.google.com" "" "link" <> + ".") <> + blockQuote (para ("A note inside a block quote." <> + note (para "The second note.")) <> + para "A second paragraph.") <> + header 1 "Second Header" <> + para "Some more text." + + + +noteTests :: TestTree +noteTests = testGroup "note and reference location" + [ test (markdownWithOpts defopts) + "footnotes at the end of a document" $ + noteTestDoc =?> + (unlines [ "First Header" + , "============" + , "" + , "This is a footnote.[^1] And this is a [link](https://www.google.com)." + , "" + , "> A note inside a block quote.[^2]" + , ">" + , "> A second paragraph." + , "" + , "Second Header" + , "=============" + , "" + , "Some more text." + , "" + , "[^1]: Down here." + , "" + , "[^2]: The second note." + ]) + , test (markdownWithOpts defopts{writerReferenceLocation=EndOfBlock}) + "footnotes at the end of blocks" $ + noteTestDoc =?> + (unlines [ "First Header" + , "============" + , "" + , "This is a footnote.[^1] And this is a [link](https://www.google.com)." + , "" + , "[^1]: Down here." + , "" + , "> A note inside a block quote.[^2]" + , ">" + , "> A second paragraph." + , "" + , "[^2]: The second note." + , "" + , "Second Header" + , "=============" + , "" + , "Some more text." + ]) + , test (markdownWithOpts defopts{writerReferenceLocation=EndOfBlock, writerReferenceLinks=True}) + "footnotes and reference links at the end of blocks" $ + noteTestDoc =?> + (unlines [ "First Header" + , "============" + , "" + , "This is a footnote.[^1] And this is a [link]." + , "" + , "[^1]: Down here." + , "" + , " [link]: https://www.google.com" + , "" + , "> A note inside a block quote.[^2]" + , ">" + , "> A second paragraph." + , "" + , "[^2]: The second note." + , "" + , "Second Header" + , "=============" + , "" + , "Some more text." + ]) + , test (markdownWithOpts defopts{writerReferenceLocation=EndOfSection}) + "footnotes at the end of section" $ + noteTestDoc =?> + (unlines [ "First Header" + , "============" + , "" + , "This is a footnote.[^1] And this is a [link](https://www.google.com)." + , "" + , "> A note inside a block quote.[^2]" + , ">" + , "> A second paragraph." + , "" + , "[^1]: Down here." + , "" + , "[^2]: The second note." + , "" + , "Second Header" + , "=============" + , "" + , "Some more text." + ]) + + ] + +shortcutLinkRefsTests :: TestTree +shortcutLinkRefsTests = + let infix 4 =: + (=:) :: (ToString a, ToPandoc a) + + => String -> (a, String) -> TestTree + (=:) = test (purely (writeMarkdown defopts{writerReferenceLinks = True}) . toPandoc) + in testGroup "Shortcut reference links" + [ "Simple link (shortcutable)" + =: para (link "/url" "title" "foo") + =?> "[foo]\n\n [foo]: /url \"title\"" + , "Followed by another link (unshortcutable)" + =: para ((link "/url1" "title1" "first") + <> (link "/url2" "title2" "second")) + =?> unlines [ "[first][][second]" + , "" + , " [first]: /url1 \"title1\"" + , " [second]: /url2 \"title2\"" + ] + , "Followed by space and another link (unshortcutable)" + =: para ((link "/url1" "title1" "first") <> " " + <> (link "/url2" "title2" "second")) + =?> unlines [ "[first][] [second]" + , "" + , " [first]: /url1 \"title1\"" + , " [second]: /url2 \"title2\"" + ] + , "Reference link is used multiple times (unshortcutable)" + =: para ((link "/url1" "" "foo") <> (link "/url2" "" "foo") + <> (link "/url3" "" "foo")) + =?> unlines [ "[foo][][foo][1][foo][2]" + , "" + , " [foo]: /url1" + , " [1]: /url2" + , " [2]: /url3" + ] + , "Reference link is used multiple times (unshortcutable)" + =: para ((link "/url1" "" "foo") <> " " <> (link "/url2" "" "foo") + <> " " <> (link "/url3" "" "foo")) + =?> unlines [ "[foo][] [foo][1] [foo][2]" + , "" + , " [foo]: /url1" + , " [1]: /url2" + , " [2]: /url3" + ] + , "Reference link is followed by text in brackets" + =: para ((link "/url" "" "link") <> "[text in brackets]") + =?> unlines [ "[link][]\\[text in brackets\\]" + , "" + , " [link]: /url" + ] + , "Reference link is followed by space and text in brackets" + =: para ((link "/url" "" "link") <> " [text in brackets]") + =?> unlines [ "[link][] \\[text in brackets\\]" + , "" + , " [link]: /url" + ] + , "Reference link is followed by RawInline" + =: para ((link "/url" "" "link") <> rawInline "markdown" "[rawText]") + =?> unlines [ "[link][][rawText]" + , "" + , " [link]: /url" + ] + , "Reference link is followed by space and RawInline" + =: para ((link "/url" "" "link") <> space <> rawInline "markdown" "[rawText]") + =?> unlines [ "[link][] [rawText]" + , "" + , " [link]: /url" + ] + , "Reference link is followed by RawInline with space" + =: para ((link "/url" "" "link") <> rawInline "markdown" " [rawText]") + =?> unlines [ "[link][] [rawText]" + , "" + , " [link]: /url" + ] + , "Reference link is followed by citation" + =: para ((link "/url" "" "link") <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]")) + =?> unlines [ "[link][][@author]" + , "" + , " [link]: /url" + ] + , "Reference link is followed by space and citation" + =: para ((link "/url" "" "link") <> space <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]")) + =?> unlines [ "[link][] [@author]" + , "" + , " [link]: /url" + ] + ] diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index 115a00f83..ff66d1d65 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -112,6 +112,24 @@ tests = [ testGroup "block elements" , " <verbatim></verbatim> :: second description" , " <verbatim></verbatim> :: third description" ] + , "definition list terms starting with space" =: + definitionList [ (text "first definition", [plain $ text "first description"]) + , (space <> str "foo", [plain $ text "second description"]) + , (str " > bar", [plain $ text "third description"]) + ] + =?> unlines [ " first definition :: first description" + , " <verbatim></verbatim> foo :: second description" + , " <verbatim></verbatim> > bar :: third description" + ] + , "definition list terms starting with list markers" =: + definitionList [ (text "first definition", [plain $ text "first description"]) + , (str "-", [plain $ text "second description"]) + , (str "1.", [plain $ text "third description"]) + ] + =?> unlines [ " first definition :: first description" + , " <verbatim></verbatim>- :: second description" + , " <verbatim></verbatim>1. :: third description" + ] ] -- Test that lists of the same type and style are separated with two blanklines , testGroup "sequential lists" @@ -257,17 +275,20 @@ tests = [ testGroup "block elements" unlines [ "#bar" , "** Foo" ] + , "empty heading" =: header 4 (mempty) =?> "**** <verbatim></verbatim>" ] , "horizontal rule" =: horizontalRule =?> "----" , "escape horizontal rule" =: para (text "----") =?> "<verbatim></verbatim>----" , "escape long horizontal rule" =: para (text "----------") =?> "<verbatim></verbatim>----------" , "don't escape horizontal inside paragraph" =: para (text "foo ---- bar") =?> "foo ---- bar" , "escape nonbreaking space" =: para (text "~~") =?> "<verbatim>~~</verbatim>" + , "escape > in the beginning of line" =: para (text "> foo bar") =?> "<verbatim></verbatim>> foo bar" , testGroup "tables" [ "table without header" =: let rows = [[para $ text "Para 1.1", para $ text "Para 1.2"] ,[para $ text "Para 2.1", para $ text "Para 2.2"]] - in simpleTable [] rows + in table mempty [(AlignDefault,0.0),(AlignDefault,0.0)] + [mempty, mempty] rows =?> unlines [ " Para 1.1 | Para 1.2" , " Para 2.1 | Para 2.2" @@ -287,7 +308,8 @@ tests = [ testGroup "block elements" headers = [plain $ text "header 1", plain $ text "header 2"] rows = [[para $ text "Para 1.1", para $ text "Para 1.2"] ,[para $ text "Para 2.1", para $ text "Para 2.2"]] - in table caption mempty headers rows + in table caption [(AlignDefault,0.0),(AlignDefault,0.0)] + headers rows =?> unlines [ " header 1 || header 2" , " Para 1.1 | Para 1.2" , " Para 2.1 | Para 2.2" @@ -357,6 +379,8 @@ tests = [ testGroup "block elements" "remove soft break" $ text "a" <> softbreak <> text "b" =?> "a b" , "line break" =: text "a" <> linebreak <> text "b" =?> "a<br>\nb" + , "no newline after line break in header" =: header 1 (text "a" <> linebreak <> text "b") =?> "* a<br>b" + , "no softbreak in header" =: header 1 (text "a" <> softbreak <> text "b") =?> "* a b" ] , testGroup "math" [ "inline math" =: math "2^3" =?> "2<sup>3</sup>" diff --git a/test/Tests/Writers/Muse.hs.orig b/test/Tests/Writers/Muse.hs.orig new file mode 100644 index 000000000..b86dee5e1 --- /dev/null +++ b/test/Tests/Writers/Muse.hs.orig @@ -0,0 +1,410 @@ +module Tests.Writers.Muse (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +muse :: (ToPandoc a) => a -> String +muse = museWithOpts def{ writerWrapText = WrapNone, + writerExtensions = extensionsFromList [Ext_amuse, + Ext_auto_identifiers] } + +museWithOpts :: (ToPandoc a) => WriterOptions -> a -> String +museWithOpts opts = unpack . purely (writeMuse opts) . toPandoc + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test muse + +tests :: [TestTree] +tests = [ testGroup "block elements" + [ "plain" =: plain (text "Foo bar.") =?> "Foo bar." + , testGroup "paragraphs" + [ "single paragraph" =: para (text "Sample paragraph.") + =?> "Sample paragraph." + , "two paragraphs" =: para (text "First paragraph.") <> + para (text "Second paragraph.") + =?> unlines [ "First paragraph." + , "" + , "Second paragraph." + ] + ] + , "line block" =: lineBlock [text "Foo", text "bar", text "baz"] + =?> unlines [ "> Foo" + , "> bar" + , "> baz" + ] + , "code block" =: codeBlock "int main(void) {\n\treturn 0;\n}" + =?> unlines [ "<example>" + , "int main(void) {" + , "\treturn 0;" + , "}" + , "</example>" + ] + , "html raw block" =: rawBlock "html" "<hr>" + =?> unlines [ "<literal style=\"html\">" + , "<hr>" + , "</literal>" + ] + , "block quote" =: blockQuote (para (text "Foo")) + =?> unlines [ "<quote>" + , "Foo" + , "</quote>" + ] + , testGroup "lists" + [ testGroup "simple lists" + [ + "ordered list" =: orderedList [ plain $ text "first" + , plain $ text "second" + , plain $ text "third" + ] + =?> unlines [ " 1. first" + , " 2. second" + , " 3. third" + ] + , "ordered list with Roman numerals" + =: orderedListWith (1, UpperRoman, DefaultDelim) + [ plain $ text "first" + , plain $ text "second" + , plain $ text "third" + ] + =?> unlines [ " I. first" + , " II. second" + , " III. third" + ] + , "bullet list" =: bulletList [ plain $ text "first" + , plain $ text "second" + , plain $ text "third" + ] + =?> unlines [ " - first" + , " - second" + , " - third" + ] + , "definition list" =: definitionList [ (text "first definition", [plain $ text "first description"]) + , (text "second definition", [plain $ text "second description"]) + , (text "third definition", [plain $ text "third description"]) + ] + =?> unlines [ " first definition :: first description" + , " second definition :: second description" + , " third definition :: third description" + ] + , "definition list with multiple descriptions" =: + definitionList [ (text "first definition", [plain $ text "first description" + ,plain $ text "second description"]) + , (text "second definition", [plain $ text "third description"]) + ] + =?> unlines [ " first definition :: first description" + , " :: second description" + , " second definition :: third description" + ] + , "definition list with empty term" =: + definitionList [ (text "first definition", [plain $ text "first description"]) + , (mempty, [plain $ text "second description"]) + , (str "", [plain $ text "third description"]) + ] + =?> unlines [ " first definition :: first description" + , " <verbatim></verbatim> :: second description" + , " <verbatim></verbatim> :: third description" + ] + ] + -- Test that lists of the same type and style are separated with two blanklines + , testGroup "sequential lists" + [ "bullet lists" =: + bulletList [ para $ text "First" + , para $ text "Second" + , para $ text "Third" + ] <> + bulletList [ para $ text "Fourth" + , para $ text "Fifth" + ] =?> + unlines [ " - First" + , " - Second" + , " - Third" + , "" + , "" + , " - Fourth" + , " - Fifth" + ] + , "ordered lists of the same style" =: + orderedListWith (1, UpperRoman, DefaultDelim) [ para $ text "First" + , para $ text "Second" + ] <> + orderedListWith (1, UpperRoman, DefaultDelim) [ para $ text "Third" + , para $ text "Fourth" + ] =?> + unlines [ " I. First" + , " II. Second" + , "" + , "" + , " I. Third" + , " II. Fourth" + ] + , "ordered lists with equal styles" =: + orderedList [ para $ text "First" + , para $ text "Second" + ] <> + orderedListWith (1, Decimal, DefaultDelim) [ para $ text "Third" + , para $ text "Fourth" + ] =?> + unlines [ " 1. First" + , " 2. Second" + , "" + , "" + , " 1. Third" + , " 2. Fourth" + ] + , "bullet and ordered lists" =: + bulletList [ para $ text "First" + , para $ text "Second" + ] <> + orderedListWith (1, UpperRoman, DefaultDelim) [ para $ text "Third" + , para $ text "Fourth" + ] =?> + unlines [ " - First" + , " - Second" + , "" + , " I. Third" + , " II. Fourth" + ] + , "different style ordered lists" =: + orderedListWith (1, UpperRoman, DefaultDelim) [ para $ text "First" + , para $ text "Second" + ] <> + orderedListWith (1, Decimal, DefaultDelim) [ para $ text "Third" + , para $ text "Fourth" + ] =?> + unlines [ " I. First" + , " II. Second" + , "" + , " 1. Third" + , " 2. Fourth" + ] + ] + , testGroup "nested lists" + [ "nested ordered list" =: orderedList [ plain $ text "First outer" + , plain (text "Second outer:") <> + orderedList [ plain $ text "first" + , plain $ text "second" + ] + , plain $ text "Third outer" + ] + =?> unlines [ " 1. First outer" + , " 2. Second outer:" + , " 1. first" + , " 2. second" + , " 3. Third outer" + ] + , "nested bullet lists" =: bulletList [ plain $ text "First outer" + , plain (text "Second outer:") <> + bulletList [ plain $ text "first" + , plain $ text "second" + ] + , plain $ text "Third outer" + ] + =?> unlines [ " - First outer" + , " - Second outer:" + , " - first" + , " - second" + , " - Third outer" + ] + , "nested definition lists" =: definitionList [ (text "first definition", [plain $ text "first description"]) + , (text "second definition", + [ plain (text "second description") <> + definitionList [ ( text "first inner definition" + , [plain $ text "first inner description"]) + , ( text "second inner definition" + , [plain $ text "second inner description"]) + ] + ] + ) + ] + =?> unlines [ " first definition :: first description" + , " second definition :: second description" + , " first inner definition :: first inner description" + , " second inner definition :: second inner description" + ] + ] + -- Check that list is intended with one space even inside a quote + , "List inside block quote" =: blockQuote (orderedList [ plain $ text "first" + , plain $ text "second" + , plain $ text "third" + ]) + =?> unlines [ "<quote>" + , " 1. first" + , " 2. second" + , " 3. third" + , "</quote>" + ] + ] + , testGroup "headings" + [ "normal heading" =: + header 1 (text "foo") =?> "* foo" + , "heading levels" =: + header 1 (text "First level") <> + header 3 (text "Third level") =?> + unlines [ "* First level" + , "" + , "*** Third level" + ] + , "heading with ID" =: + headerWith ("bar", [], []) 2 (text "Foo") =?> + unlines [ "** Foo" + , "#bar" + ] + ] + , "horizontal rule" =: horizontalRule =?> "----" + , "escape horizontal rule" =: para (text "----") =?> "<verbatim>----</verbatim>" + , "escape nonbreaking space" =: para (text "~~") =?> "<verbatim>~~</verbatim>" + , testGroup "tables" + [ "table without header" =: + let rows = [[para $ text "Para 1.1", para $ text "Para 1.2"] + ,[para $ text "Para 2.1", para $ text "Para 2.2"]] + in simpleTable [] rows + =?> + unlines [ " Para 1.1 | Para 1.2" + , " Para 2.1 | Para 2.2" + ] + , "table with header" =: + let headers = [plain $ text "header 1", plain $ text "header 2"] + rows = [[para $ text "Para 1.1", para $ text "Para 1.2"] + ,[para $ text "Para 2.1", para $ text "Para 2.2"]] + in simpleTable headers rows + =?> + unlines [ " header 1 || header 2" + , " Para 1.1 | Para 1.2" + , " Para 2.1 | Para 2.2" + ] + , "table with header and caption" =: + let caption = text "Table 1" + headers = [plain $ text "header 1", plain $ text "header 2"] + rows = [[para $ text "Para 1.1", para $ text "Para 1.2"] + ,[para $ text "Para 2.1", para $ text "Para 2.2"]] + in table caption mempty headers rows + =?> unlines [ " header 1 || header 2" + , " Para 1.1 | Para 1.2" + , " Para 2.1 | Para 2.2" + , " |+ Table 1 +|" + ] + ] + , "div with bullet list" =: + divWith nullAttr (bulletList [para $ text "foo"]) =?> + unlines [ " - foo" ] -- Making sure bullets are indented + -- Null is trivial + ] + , testGroup "inline elements" + [ testGroup "string" + [ "string" =: str "foo" =?> "foo" + , "escape footnote" =: str "[1]" =?> "<verbatim>[1]</verbatim>" + , "escape verbatim close tag" =: str "foo</verbatim>bar" + =?> "<verbatim>foo<</verbatim><verbatim>/verbatim>bar</verbatim>" + , "escape pipe to avoid accidental tables" =: str "foo | bar" + =?> "<verbatim>foo | bar</verbatim>" + , "escape hash to avoid accidental anchors" =: text "#foo bar" + =?> "<verbatim>#foo</verbatim> bar" + , "escape definition list markers" =: str "::" =?> "<verbatim>::</verbatim>" + , "normalize strings before escaping" =: fromList [Str ":", Str ":"] =?> "<verbatim>::</verbatim>" + -- We don't want colons to be escaped if they can't be confused + -- with definition list item markers. + , "do not escape colon" =: str ":" =?> ":" + , "escape - to avoid accidental unordered lists" =: text " - foo" =?> " <verbatim>-</verbatim> foo" + , "escape - inside a list to avoid accidental nested unordered lists" =: + bulletList [ (para $ text "foo") <> + (para $ text "- bar") + ] =?> + unlines [ " - foo" + , "" + , " <verbatim>-</verbatim> bar" + ] + ] + , testGroup "emphasis" + [ "emph" =: emph (text "foo") =?> "<em>foo</em>" + , "strong" =: strong (text "foo") =?> "<strong>foo</strong>" + , "strikeout" =: strikeout (text "foo") =?> "<del>foo</del>" + ] + , "superscript" =: superscript (text "foo") =?> "<sup>foo</sup>" + , "subscript" =: subscript (text "foo") =?> "<sub>foo</sub>" + , "smallcaps" =: smallcaps (text "foo") =?> "<em>foo</em>" + , "smallcaps near emphasis" =: emph (str "foo") <> smallcaps (str "bar") =?> "<em>foobar</em>" + , "single quoted" =: singleQuoted (text "foo") =?> "‘foo’" + , "double quoted" =: doubleQuoted (text "foo") =?> "“foo”" + -- Cite is trivial + , testGroup "code" + [ "simple" =: code "foo" =?> "<code>foo</code>" + , "escape tag" =: code "<code>foo = bar</code> baz" =?> "<code><code>foo = bar<</code><code>/code> baz</code>" + , "normalization with attributes" =: codeWith ("",["haskell"],[]) "foo" <> code "bar" =?> "<code>foobar</code>" + , "normalization" =: code "</co" <> code "de>" =?> "<code><</code><code>/code></code>" + , "normalization with empty string" =: code "</co" <> str "" <> code "de>" =?> "<code><</code><code>/code></code>" + ] + , testGroup "spaces" + [ "space" =: text "a" <> space <> text "b" =?> "a b" + , "soft break" =: text "a" <> softbreak <> text "b" =?> "a b" + , test (museWithOpts def{ writerWrapText = WrapPreserve }) + "preserve soft break" $ text "a" <> softbreak <> text "b" + =?> "a\nb" + , "line break" =: text "a" <> linebreak <> text "b" =?> "a<br>\nb" + ] + , testGroup "math" + [ "inline math" =: math "2^3" =?> "2<sup>3</sup>" + , "display math" =: displayMath "2^3" =?> "2<sup>3</sup>" + , "multiple letters in inline math" =: math "abc" =?> "<em>abc</em>" + , "expand math before normalization" =: math "[" <> str "2]" =?> "<verbatim>[2]</verbatim>" + , "multiple math expressions inside one inline list" =: math "5_4" <> text ", " <> displayMath "3^2" =?> "5<sub>4</sub>, 3<sup>2</sup>" + ] + , "raw inline" + =: rawInline "html" "<mark>marked text</mark>" + =?> "<literal style=\"html\"><mark>marked text</mark></literal>" + , testGroup "links" + [ "link with description" =: link "https://example.com" "" (str "Link 1") + =?> "[[https://example.com][Link 1]]" + , "link without description" =: link "https://example.com" "" (str "https://example.com") + =?> "[[https://example.com]]" + -- Internal links in Muse include '#' + , "link to anchor" =: link "#intro" "" (str "Introduction") + =?> "[[#intro][Introduction]]" + -- According to Emacs Muse manual, links to images should be prefixed with "URL:" + , "link to image with description" =: link "1.png" "" (str "Link to image") + =?> "[[URL:1.png][Link to image]]" + , "link to image without description" =: link "1.png" "" (str "1.png") + =?> "[[URL:1.png]]" + ] + , "image" =: image "image.png" "Image 1" (str "") =?> "[[image.png][Image 1]]" + , "image with width" =: + imageWith ("", [], [("width", "60%")]) "image.png" "Image" (str "") =?> + "[[image.png 60][Image]]" + , "note" =: note (plain (text "Foo")) + =?> unlines [ "[1]" + , "" + , "[1] Foo" + ] + , "span with class" =: spanWith ("",["foobar"],[]) (text "Some text") + =?> "<class name=\"foobar\">Some text</class>" + , "span with anchor" =: spanWith ("anchor", [], []) (text "Foo bar") + =?> "#anchor Foo bar" + , "span with class and anchor" =: spanWith ("anchor", ["foo"], []) (text "bar") + =?> "#anchor <class name=\"foo\">bar</class>" + , testGroup "combined" + [ "emph word before" =: + para (text "foo" <> emph (text "bar")) =?> + "foo<em>bar</em>" + , "emph word after" =: + para (emph (text "foo") <> text "bar") =?> + "<em>foo</em>bar" + , "emph quoted" =: + para (doubleQuoted (emph (text "foo"))) =?> + "“<em>foo</em>”" + , "strong word before" =: + para (text "foo" <> strong (text "bar")) =?> + "foo<strong>bar</strong>" + , "strong word after" =: + para (strong (text "foo") <> text "bar") =?> + "<strong>foo</strong>bar" + , "strong quoted" =: + para (singleQuoted (strong (text "foo"))) =?> + "‘<strong>foo</strong>’" + ] + ] + ] diff --git a/test/Tests/Writers/Native.hs.orig b/test/Tests/Writers/Native.hs.orig new file mode 100644 index 000000000..0c4bf7623 --- /dev/null +++ b/test/Tests/Writers/Native.hs.orig @@ -0,0 +1,22 @@ +module Tests.Writers.Native (tests) where + +import Data.Text (unpack) +import Test.Tasty +import Test.Tasty.QuickCheck +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () + +p_write_rt :: Pandoc -> Bool +p_write_rt d = + read (unpack $ purely (writeNative def{ writerTemplate = Just "" }) d) == d + +p_write_blocks_rt :: [Block] -> Bool +p_write_blocks_rt bs = + read (unpack $ purely (writeNative def) (Pandoc nullMeta bs)) == bs + +tests :: [TestTree] +tests = [ testProperty "p_write_rt" p_write_rt + , testProperty "p_write_blocks_rt" $ mapSize + (\x -> if x > 3 then 3 else x) p_write_blocks_rt + ] diff --git a/test/Tests/Writers/OOXML.hs.orig b/test/Tests/Writers/OOXML.hs.orig new file mode 100644 index 000000000..bdfdea145 --- /dev/null +++ b/test/Tests/Writers/OOXML.hs.orig @@ -0,0 +1,184 @@ +{-# LANGUAGE PatternGuards #-} +{-# LANGUAGE OverloadedStrings #-} + +module Tests.Writers.OOXML (ooxmlTest) where + +import Text.Pandoc +import Test.Tasty +import Test.Tasty.Golden.Advanced +import Codec.Archive.Zip +import Text.XML.Light +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as BL +import qualified Data.Text.IO as T +import Data.List (isSuffixOf, sort, (\\), intercalate, union) +import Data.Maybe (catMaybes, mapMaybe) +import Tests.Helpers +import Data.Algorithm.Diff +import System.FilePath.Glob (compile, match) + +compareXMLBool :: Content -> Content -> Bool +-- We make a special exception for times at the moment, and just pass +-- them because we can't control the utctime when running IO. Besides, +-- so long as we have two times, we're okay. +compareXMLBool (Elem myElem) (Elem goodElem) + | (QName "created" _ (Just "dcterms")) <- elName myElem + , (QName "created" _ (Just "dcterms")) <- elName goodElem = + True +compareXMLBool (Elem myElem) (Elem goodElem) + | (QName "modified" _ (Just "dcterms")) <- elName myElem + , (QName "modified" _ (Just "dcterms")) <- elName goodElem = + True +compareXMLBool (Elem myElem) (Elem goodElem) = + elName myElem == elName goodElem && + elAttribs myElem == elAttribs goodElem && + and (zipWith compareXMLBool (elContent myElem) (elContent goodElem)) +compareXMLBool (Text myCData) (Text goodCData) = + cdVerbatim myCData == cdVerbatim goodCData && + cdData myCData == cdData goodCData && + cdLine myCData == cdLine goodCData +compareXMLBool (CRef myStr) (CRef goodStr) = + myStr == goodStr +compareXMLBool _ _ = False + +displayDiff :: Content -> Content -> String +displayDiff elemA elemB = + showDiff (1,1) $ getDiff (lines $ ppContent elemA) (lines $ ppContent elemB) + +goldenArchive :: FilePath -> IO Archive +goldenArchive fp = (toArchive . BL.fromStrict) <$> BS.readFile fp + +testArchive :: (WriterOptions -> Pandoc -> PandocIO BL.ByteString) + -> WriterOptions + -> FilePath + -> IO Archive +testArchive writerFn opts fp = do + txt <- T.readFile fp + bs <- runIOorExplode $ readNative def txt >>= writerFn opts + return $ toArchive bs + +compareFileList :: FilePath -> Archive -> Archive -> Maybe String +compareFileList goldenFP goldenArch testArch = + let testFiles = filesInArchive testArch + goldenFiles = filesInArchive goldenArch + diffTestGolden = testFiles \\ goldenFiles + diffGoldenTest = goldenFiles \\ testFiles + + results = + [ if null diffGoldenTest + then Nothing + else Just $ + "Files in " ++ goldenFP ++ " but not in generated archive:\n" ++ + intercalate ", " diffGoldenTest + , if null diffTestGolden + then Nothing + else Just $ + "Files in generated archive but not in " ++ goldenFP ++ ":\n" ++ + intercalate ", " diffTestGolden + ] + in + if null $ catMaybes results + then Nothing + else Just $ intercalate "\n" $ catMaybes results + +compareXMLFile' :: FilePath -> Archive -> Archive -> Either String () +compareXMLFile' fp goldenArch testArch = do + testEntry <- case findEntryByPath fp testArch of + Just entry -> Right entry + Nothing -> Left $ + "Can't extract " ++ fp ++ " from generated archive" + testXMLDoc <- case parseXMLDoc $ fromEntry testEntry of + Just doc -> Right doc + Nothing -> Left $ + "Can't parse xml in " ++ fp ++ " from generated archive" + + goldenEntry <- case findEntryByPath fp goldenArch of + Just entry -> Right entry + Nothing -> Left $ + "Can't extract " ++ fp ++ " from archive in stored file" + goldenXMLDoc <- case parseXMLDoc $ fromEntry goldenEntry of + Just doc -> Right doc + Nothing -> Left $ + "Can't parse xml in " ++ fp ++ " from archive in stored file" + + let testContent = Elem testXMLDoc + goldenContent = Elem goldenXMLDoc + + if compareXMLBool goldenContent testContent + then Right () + else Left $ + "Non-matching xml in " ++ fp ++ ":\n" ++ displayDiff testContent goldenContent + +compareXMLFile :: FilePath -> Archive -> Archive -> Maybe String +compareXMLFile fp goldenArch testArch = + case compareXMLFile' fp goldenArch testArch of + Right _ -> Nothing + Left s -> Just s + +compareAllXMLFiles :: Archive -> Archive -> Maybe String +compareAllXMLFiles goldenArch testArch = + let allFiles = filesInArchive goldenArch `union` filesInArchive testArch + allXMLFiles = sort $ + filter + (\fp -> ".xml" `isSuffixOf` fp || ".rels" `isSuffixOf` fp) + allFiles + results = + mapMaybe (\fp -> compareXMLFile fp goldenArch testArch) allXMLFiles + in + if null results + then Nothing + else Just $ unlines results + +compareMediaFile' :: FilePath -> Archive -> Archive -> Either String () +compareMediaFile' fp goldenArch testArch = do + testEntry <- case findEntryByPath fp testArch of + Just entry -> Right entry + Nothing -> Left $ + "Can't extract " ++ fp ++ " from generated archive" + goldenEntry <- case findEntryByPath fp goldenArch of + Just entry -> Right entry + Nothing -> Left $ + "Can't extract " ++ fp ++ " from archive in stored file" + + if fromEntry testEntry == fromEntry goldenEntry + then Right () + else Left $ + "Non-matching binary file: " ++ fp + +compareMediaFile :: FilePath -> Archive -> Archive -> Maybe String +compareMediaFile fp goldenArch testArch = + case compareMediaFile' fp goldenArch testArch of + Right _ -> Nothing + Left s -> Just s + +compareAllMediaFiles :: Archive -> Archive -> Maybe String +compareAllMediaFiles goldenArch testArch = + let allFiles = filesInArchive goldenArch `union` filesInArchive testArch + mediaPattern = compile "*/media/*" + allMediaFiles = sort $ + filter (match mediaPattern) allFiles + results = + mapMaybe (\fp -> compareMediaFile fp goldenArch testArch) allMediaFiles + in + if null results + then Nothing + else Just $ unlines results + +ooxmlTest :: (WriterOptions -> Pandoc -> PandocIO BL.ByteString) + -> String + -> WriterOptions + -> FilePath + -> FilePath + -> TestTree +ooxmlTest writerFn testName opts nativeFP goldenFP = + goldenTest + testName + (goldenArchive goldenFP) + (testArchive writerFn opts nativeFP) + (\goldenArch testArch -> + let res = catMaybes [ compareFileList goldenFP goldenArch testArch + , compareAllXMLFiles goldenArch testArch + , compareAllMediaFiles goldenArch testArch + ] + in return $ if null res then Nothing else Just $ unlines res) + (\a -> BL.writeFile goldenFP $ fromArchive a) diff --git a/test/Tests/Writers/Org.hs.orig b/test/Tests/Writers/Org.hs.orig new file mode 100644 index 000000000..9cbe360da --- /dev/null +++ b/test/Tests/Writers/Org.hs.orig @@ -0,0 +1,25 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.Org (tests) where + +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test (purely (writeOrg def . toPandoc)) + +tests :: [TestTree] +tests = [ testGroup "links" + -- See http://orgmode.org/manual/Internal-links.html#Internal-links + [ "simple link" + =: link "/url" "" "foo" + =?> "[[/url][foo]]" + , "internal link to anchor" + =: link "#my-custom-id" "" "#my-custom-id" + =?> "[[#my-custom-id]]" + ] + ] diff --git a/test/Tests/Writers/Plain.hs.orig b/test/Tests/Writers/Plain.hs.orig new file mode 100644 index 000000000..ab09bca26 --- /dev/null +++ b/test/Tests/Writers/Plain.hs.orig @@ -0,0 +1,21 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.Plain (tests) where + +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test (purely (writePlain def) . toPandoc) + + +tests :: [TestTree] +tests = [ "strongly emphasized text to uppercase" + =: strong "Straße" + =?> "STRASSE" + ] diff --git a/test/Tests/Writers/Powerpoint.hs.orig b/test/Tests/Writers/Powerpoint.hs.orig new file mode 100644 index 000000000..9af8fc471 --- /dev/null +++ b/test/Tests/Writers/Powerpoint.hs.orig @@ -0,0 +1,93 @@ +module Tests.Writers.Powerpoint (tests) where + +import Tests.Writers.OOXML (ooxmlTest) +import Text.Pandoc +import Test.Tasty +import System.FilePath + +-- templating is important enough, and can break enough things, that +-- we want to run all our tests with both default formatting and a +-- template. + +modifyPptxName :: FilePath -> FilePath +modifyPptxName fp = + addExtension (dropExtension fp ++ "_templated") "pptx" + +pptxTests :: String -> WriterOptions -> FilePath -> FilePath -> (TestTree, TestTree) +pptxTests name opts native pptx = + let referenceDoc = "pptx/reference_depth.pptx" + in + ( ooxmlTest + writePowerpoint + name + opts{writerReferenceDoc=Nothing} + native + pptx + , ooxmlTest + writePowerpoint + name + opts{writerReferenceDoc=Just referenceDoc} + native + (modifyPptxName pptx) + ) + +groupPptxTests :: [(TestTree, TestTree)] -> [TestTree] +groupPptxTests pairs = + let (noRefs, refs) = unzip pairs + in + [ testGroup "Default slide formatting" noRefs + , testGroup "With `--reference-doc` pptx file" refs + ] + + +tests :: [TestTree] +tests = groupPptxTests [ pptxTests "Inline formatting" + def + "pptx/inline_formatting.native" + "pptx/inline_formatting.pptx" + , pptxTests "Slide breaks (default slide-level)" + def + "pptx/slide_breaks.native" + "pptx/slide_breaks.pptx" + , pptxTests "slide breaks (slide-level set to 1)" + def{ writerSlideLevel = Just 1 } + "pptx/slide_breaks.native" + "pptx/slide_breaks_slide_level_1.pptx" + , pptxTests "lists" + def + "pptx/lists.native" + "pptx/lists.pptx" + , pptxTests "tables" + def + "pptx/tables.native" + "pptx/tables.pptx" + , pptxTests "table of contents" + def{ writerTableOfContents = True } + "pptx/slide_breaks.native" + "pptx/slide_breaks_toc.pptx" + , pptxTests "end notes" + def + "pptx/endnotes.native" + "pptx/endnotes.pptx" + , pptxTests "end notes, with table of contents" + def { writerTableOfContents = True } + "pptx/endnotes.native" + "pptx/endnotes_toc.pptx" + , pptxTests "images" + def + "pptx/images.native" + "pptx/images.pptx" + , pptxTests "two-column layout" + def + "pptx/two_column.native" + "pptx/two_column.pptx" + , pptxTests "speaker notes" + def + "pptx/speaker_notes.native" + "pptx/speaker_notes.pptx" + , pptxTests "remove empty slides" + def + "pptx/remove_empty_slides.native" + "pptx/remove_empty_slides.pptx" + + ] diff --git a/test/Tests/Writers/RST.hs b/test/Tests/Writers/RST.hs index 64367a108..89ad1de48 100644 --- a/test/Tests/Writers/RST.hs +++ b/test/Tests/Writers/RST.hs @@ -4,10 +4,12 @@ module Tests.Writers.RST (tests) where import Prelude import Test.Tasty +import Test.Tasty.HUnit import Tests.Helpers import Text.Pandoc import Text.Pandoc.Arbitrary () import Text.Pandoc.Builder +import Text.Pandoc.Writers.RST infix 4 =: (=:) :: (ToString a, ToPandoc a) @@ -24,23 +26,23 @@ tests = [ testGroup "rubrics" para $ text "baz"])] =?> unlines [ "foo" - , " .. rubric:: bar" + , " .. rubric:: bar" , "" - , " baz"] + , " baz"] , "in block quote" =: blockQuote (header 1 (text "bar")) =?> - " .. rubric:: bar" + " .. rubric:: bar" , "with id" =: blockQuote (headerWith ("foo",[],[]) 1 (text "bar")) =?> unlines - [ " .. rubric:: bar" - , " :name: foo"] + [ " .. rubric:: bar" + , " :name: foo"] , "with id class" =: blockQuote (headerWith ("foo",["baz"],[]) 1 (text "bar")) =?> unlines - [ " .. rubric:: bar" - , " :name: foo" - , " :class: baz"] + [ " .. rubric:: bar" + , " :name: foo" + , " :class: baz"] ] , testGroup "ligatures" -- handling specific sequences of blocks [ "a list is closed by a comment before a quote" =: -- issue 4248 @@ -50,7 +52,18 @@ tests = [ testGroup "rubrics" , "" , ".." , "" - , " quoted"] + , " quoted"] + ] + , testGroup "flatten" + [ testCase "emerges nested styles as expected" $ + flatten (Emph [Str "1", Strong [Str "2"], Str "3"]) @?= + [Emph [Str "1"], Strong [Str "2"], Emph [Str "3"]] + , testCase "could introduce trailing spaces" $ + flatten (Emph [Str "f", Space, Strong [Str "2"]]) @?= + [Emph [Str "f", Space], Strong [Str "2"]] + -- the test above is the reason why we call + -- stripLeadingTrailingSpace through transformNested after + -- flatten ] , testGroup "inlines" [ "are removed when empty" =: -- #4434 @@ -64,6 +77,17 @@ tests = [ testGroup "rubrics" strong (space <> str "text" <> space <> space) =?> "**text**" , "single space stripped" =: strong space =?> "" + , "give priority to strong style over emphasis" =: + strong (emph (strong (str "s"))) =?> "**s**" + , "links are not elided by outer style" =: + strong (emph (link "loc" "" (str "text"))) =?> + "`text <loc>`__" + , "RST inlines cannot start nor end with spaces" =: + emph (str "f" <> space <> strong (str "d") <> space <> str "l") =?> + "*f*\\ **d**\\ *l*" + , "keeps quotes" =: + strong (str "f" <> doubleQuoted (str "d") <> str "l") =?> + "**f“d”l**" ] , testGroup "headings" [ "normal heading" =: diff --git a/test/Tests/Writers/RST.hs.orig b/test/Tests/Writers/RST.hs.orig new file mode 100644 index 000000000..e54ce4737 --- /dev/null +++ b/test/Tests/Writers/RST.hs.orig @@ -0,0 +1,130 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.RST (tests) where + +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test (purely (writeRST def . toPandoc)) + +tests :: [TestTree] +tests = [ testGroup "rubrics" + [ "in list item" =: + bulletList [header 2 (text "foo")] =?> + "- .. rubric:: foo" + , "in definition list item" =: + definitionList [(text "foo", [header 2 (text "bar"), + para $ text "baz"])] =?> + unlines + [ "foo" + , " .. rubric:: bar" + , "" + , " baz"] + , "in block quote" =: + blockQuote (header 1 (text "bar")) =?> + " .. rubric:: bar" + , "with id" =: + blockQuote (headerWith ("foo",[],[]) 1 (text "bar")) =?> + unlines + [ " .. rubric:: bar" + , " :name: foo"] + , "with id class" =: + blockQuote (headerWith ("foo",["baz"],[]) 1 (text "bar")) =?> + unlines + [ " .. rubric:: bar" + , " :name: foo" + , " :class: baz"] + ] + , testGroup "ligatures" -- handling specific sequences of blocks + [ "a list is closed by a comment before a quote" =: -- issue 4248 + bulletList [plain "bulleted"] <> blockQuote (plain "quoted") =?> + unlines + [ "- bulleted" + , "" + , ".." + , "" + , " quoted"] + ] + , testGroup "inlines" + [ "are removed when empty" =: -- #4434 + plain (strong (str "")) =?> "" + , "do not cause the introduction of extra spaces when removed" =: + plain (strong (str "") <> emph (str "text")) =?> "*text*" + , "spaces are stripped at beginning and end" =: + -- pandoc issue 4327 "The text within inline markup may not + -- begin or end with whitespace" + -- http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#inline-markup + strong (space <> str "text" <> space <> space) =?> "**text**" + , "single space stripped" =: + strong space =?> "" + ] + , testGroup "headings" + [ "normal heading" =: + header 1 (text "foo") =?> + unlines + [ "foo" + , "==="] + -- note: heading normalization is only done in standalone mode + , test (purely (writeRST def{ writerTemplate = Just "$body$\n" }) . toPandoc) + "heading levels" $ + header 1 (text "Header 1") <> + header 3 (text "Header 2") <> + header 2 (text "Header 2") <> + header 1 (text "Header 1") <> + header 4 (text "Header 2") <> + header 5 (text "Header 3") <> + header 3 (text "Header 2") =?> + unlines + [ "Header 1" + , "========" + , "" + , "Header 2" + , "--------" + , "" + , "Header 2" + , "--------" + , "" + , "Header 1" + , "========" + , "" + , "Header 2" + , "--------" + , "" + , "Header 3" + , "~~~~~~~~" + , "" + , "Header 2" + , "--------"] + , test (purely (writeRST def{ writerTemplate = Just "$body$\n" }) . toPandoc) + "minimal heading levels" $ + header 2 (text "Header 1") <> + header 3 (text "Header 2") <> + header 2 (text "Header 1") <> + header 4 (text "Header 2") <> + header 5 (text "Header 3") <> + header 3 (text "Header 2") =?> + unlines + [ "Header 1" + , "========" + , "" + , "Header 2" + , "--------" + , "" + , "Header 1" + , "========" + , "" + , "Header 2" + , "--------" + , "" + , "Header 3" + , "~~~~~~~~" + , "" + , "Header 2" + , "--------"] + ] + ] diff --git a/test/Tests/Writers/TEI.hs.orig b/test/Tests/Writers/TEI.hs.orig new file mode 100644 index 000000000..fa372909f --- /dev/null +++ b/test/Tests/Writers/TEI.hs.orig @@ -0,0 +1,43 @@ +{-# LANGUAGE OverloadedStrings #-} +module Tests.Writers.TEI (tests) where + +import Test.Tasty +import Tests.Helpers +import Text.Pandoc +import Text.Pandoc.Arbitrary () +import Text.Pandoc.Builder + +{- + "my test" =: X =?> Y + +is shorthand for + + test html "my test" $ X =?> Y + +which is in turn shorthand for + + test html "my test" (X,Y) +-} + +infix 4 =: +(=:) :: (ToString a, ToPandoc a) + => String -> (a, String) -> TestTree +(=:) = test (purely (writeTEI def) . toPandoc) + +tests :: [TestTree] +tests = [ testGroup "block elements" + ["para" =: para "Lorem ipsum cetera." + =?> "<p>Lorem ipsum cetera.</p>" + ] + , testGroup "inlines" + [ + "Emphasis" =: emph "emphasized" + =?> "<p><hi rendition=\"simple:italic\">emphasized</hi></p>" + ,"SingleQuoted" =: singleQuoted (text "quoted material") + =?> "<p><quote>quoted material</quote></p>" + ,"DoubleQuoted" =: doubleQuoted (text "quoted material") + =?> "<p><quote>quoted material</quote></p>" + ,"NestedQuoted" =: doubleQuoted (singleQuoted (text "quoted material")) + =?> "<p><quote><quote>quoted material</quote></quote></p>" + ] + ] diff --git a/test/command/3348.md b/test/command/3348.md index 1457373c8..6e0c07033 100644 --- a/test/command/3348.md +++ b/test/command/3348.md @@ -7,7 +7,7 @@ line of text ----- ------------------------------------------------ ^D -[Table [] [AlignRight,AlignLeft] [8.333333333333333e-2,0.6666666666666666] +[Table [] [AlignRight,AlignLeft] [8.333333333333333e-2,0.6805555555555556] [[] ,[]] [[[Plain [Str "foo"]] diff --git a/test/command/3510-src.hs.orig b/test/command/3510-src.hs.orig new file mode 100644 index 000000000..ad5744b80 --- /dev/null +++ b/test/command/3510-src.hs.orig @@ -0,0 +1 @@ +putStrLn outString diff --git a/test/command/3675.md b/test/command/3675.md index b129c7a63..f75721b56 100644 --- a/test/command/3675.md +++ b/test/command/3675.md @@ -7,9 +7,9 @@ print("hello") ^D .. code:: python - print("hello") + print("hello") .. - block quote + block quote ```` diff --git a/test/command/4320.md b/test/command/4320.md index 5b0eeb5c1..732b30a3e 100644 --- a/test/command/4320.md +++ b/test/command/4320.md @@ -7,9 +7,9 @@ ,[BlockQuote [Para [Strong [Str "thisIsGoingToBeTooLongAnyway"]]]]]]] ^D -+-------+--------------------------------------+ -| one | two | -+=======+======================================+ -| ports | **thisIsGoingToBeTooLongAnyway** | -+-------+--------------------------------------+ ++-------+-------------------------------------+ +| one | two | ++=======+=====================================+ +| ports | **thisIsGoingToBeTooLongAnyway** | ++-------+-------------------------------------+ ``` diff --git a/test/command/4529.md b/test/command/4529.md new file mode 100644 index 000000000..4a2125b9c --- /dev/null +++ b/test/command/4529.md @@ -0,0 +1,36 @@ +``` +% pandoc -f latex -t plain +\chapter{First chapter}\label{sec:chp1} +The next chapter is Chapter~\ref{sec:chp2}. +\section{First section}\label{sec:chp1sec1} +The next section is Section~\ref{sec:chp2sec1}. + +\chapter{Second chapter}\label{sec:chp2} +The previous chapter is Chapter~\ref{sec:chp1}. +\section{First section}\label{sec:chp2sec1} +The previous section is Section~\ref{sec:chp1sec1}. +^D + + +FIRST CHAPTER + + +The next chapter is Chapter 2. + + +First section + +The next section is Section 2.1. + + + +SECOND CHAPTER + + +The previous chapter is Chapter 1. + + +First section + +The previous section is Section 1.1. +``` diff --git a/test/command/4550.md b/test/command/4550.md new file mode 100644 index 000000000..bf3afce5b --- /dev/null +++ b/test/command/4550.md @@ -0,0 +1,7 @@ +``` +% pandoc -f markdown-smart -t ms +A ‘simple’ example +^D +.LP +A ‘simple’ example +``` diff --git a/test/command/4578.md b/test/command/4578.md new file mode 100644 index 000000000..8f12d0bf2 --- /dev/null +++ b/test/command/4578.md @@ -0,0 +1,14 @@ +``` +% pandoc -t markdown + ------ ------- --------------- --------------------- + One row 12.0 Example of a row that + spans multiple lines. + + ------ ------- --------------- --------------------- +^D + ------ ------- --------------- --------------------- + One row 12.0 Example of a row that + spans multiple lines. + + ------ ------- --------------- --------------------- +``` diff --git a/test/command/4579.md b/test/command/4579.md new file mode 100644 index 000000000..80f0f58c2 --- /dev/null +++ b/test/command/4579.md @@ -0,0 +1,16 @@ +``` +% pandoc -f rst -t native +.. list-table:: + :header-rows: 1 + + * - Foo + - Bar + * - spam + - ham +^D +[Table [] [AlignDefault,AlignDefault] [0.0,0.0] + [[Plain [Str "Foo"]] + ,[Plain [Str "Bar"]]] + [[[Plain [Str "spam"]] + ,[Plain [Str "ham"]]]]] +``` diff --git a/test/command/4589.md b/test/command/4589.md new file mode 100644 index 000000000..ffbe6fe6f --- /dev/null +++ b/test/command/4589.md @@ -0,0 +1,14 @@ +``` +% pandoc -f markdown -t latex +\newcommand{\one}[1]{#1} +\newcommand{\two}[1]{#1} + +Formatting *is* working **here**. But sticking \one{two }\two{commands} +together *breaks* formatting. +^D +\newcommand{\one}[1]{#1} +\newcommand{\two}[1]{#1} + +Formatting \emph{is} working \textbf{here}. But sticking two commands +together \emph{breaks} formatting. +``` diff --git a/test/command/4594.md b/test/command/4594.md new file mode 100644 index 000000000..3f08b6c12 --- /dev/null +++ b/test/command/4594.md @@ -0,0 +1,24 @@ +``` +% pandoc -f markdown -t latex +Some **bold** text here. + +\begin{figure}[htbp] +\centering +\def\svgwidth{\columnwidth} +\import{img/}{vectors.pdf_tex} +\caption{Some caption.} +\end{figure} + +Some *italic* text here. +^D +Some \textbf{bold} text here. + +\begin{figure}[htbp] +\centering +\def\svgwidth{\columnwidth} +\import{img/}{vectors.pdf_tex} +\caption{Some caption.} +\end{figure} + +Some \emph{italic} text here. +``` diff --git a/test/command/4598.md b/test/command/4598.md new file mode 100644 index 000000000..fedfe888a --- /dev/null +++ b/test/command/4598.md @@ -0,0 +1,10 @@ +``` +% pandoc -f rst +`x`__ + +__ `xy`_ + +.. _`xy`: http://xy.org +^D +<p><a href="http://xy.org">x</a></p> +``` diff --git a/test/docx/adjacent_codeblocks.docx b/test/docx/adjacent_codeblocks.docx Binary files differnew file mode 100644 index 000000000..d61fb45d5 --- /dev/null +++ b/test/docx/adjacent_codeblocks.docx diff --git a/test/docx/adjacent_codeblocks.native b/test/docx/adjacent_codeblocks.native new file mode 100644 index 000000000..ec1e2416e --- /dev/null +++ b/test/docx/adjacent_codeblocks.native @@ -0,0 +1,6 @@ +[Para [Str "Next,",Space,Str "open",Space,Str "the",Space,Str "terminal",Space,Str "window.",Space,Str "Using",Space,Str "the",Space,Str "terminal",Space,Str "window,",Space,Str "run",Space,Str "the",Space,Str "\"ifconfig",Space,Str "-a\"",Space,Str "command",Space,Str "to",Space,Str "list",Space,Str "all",Space,Str "the",Space,Str "interfaces",Space,Str "on",Space,Str "your",Space,Str "system,",Space,Str "as",Space,Str "shown",Space,Str "here."] +,CodeBlock ("",[],[]) "# ifconfig -a\neth0 Link encap:Ethernet HWaddr 00:0c:29:69:12:7c \n inet addr:172.16.0.108 Bcast:172.16.0.255 Mask:255.255.255.0\n inet6 addr: fc00:660:0:1:20c:29ff:fe69:127c/64 Scope:Global\n inet6 addr: fe80::20c:29ff:fe69:127c/64 Scope:Link\n UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1\n RX packets:9859 errors:0 dropped:0 overruns:0 frame:0\n TX packets:1399 errors:0 dropped:0 overruns:0 carrier:0\n collisions:0 txqueuelen:1000 \n RX bytes:1920894 (1.8 MiB) TX bytes:233088 (227.6 KiB)\n Interrupt:19 Base address:0x2000 \n\nlo Link encap:Local Loopback \n inet addr:127.0.0.1 Mask:255.0.0.0\n inet6 addr: ::1/128 Scope:Host\n UP LOOPBACK RUNNING MTU:65536 Metric:1\n RX packets:372 errors:0 dropped:0 overruns:0 frame:0\n TX packets:372 errors:0 dropped:0 overruns:0 carrier:0\n collisions:0 txqueuelen:0 \n RX bytes:22320 (21.7 KiB) TX bytes:22320 (21.7 KiB)\n\nwlan0 Link encap:Ethernet HWaddr 00:c0:ca:85:00:ba \n UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1\n RX packets:0 errors:0 dropped:0 overruns:0 frame:0\n TX packets:0 errors:0 dropped:0 overruns:0 carrier:0\n collisions:0 txqueuelen:1000 \n RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)" +,Para [Str "The",Space,Str "ALFA",Space,Str "wireless",Space,Str "card",Space,Str "is",Space,Str "represented",Space,Str "by",Space,Str "the",Space,Str "\"wlan0\"",Space,Str "interface."] +,Para [Str "In",Space,Str "addition",Space,Str "to",Space,Str "the",Space,Str "interfaces",Space,Str "shown",Space,Str "in",Space,Str "the",Space,Str "ifconfig",Space,Str "output,",Space,Str "there",Space,Str "is",Space,Str "another",Space,Str "interface",Space,Str "known",Space,Str "as",Space,Str "the",Space,Emph [Str "wireless",Space,Str "physical",Space,Str "interface"],Str ".",Space,Str "We",Space,Str "can",Space,Str "identify",Space,Str "this",Space,Str "interface",Space,Str "by",Space,Str "listing",Space,Str "the",Space,Str "contents",Space,Str "of",Space,Str "the",Space,Str "/sys/class/ieee80211",Space,Str "directory,",Space,Str "as",Space,Str "shown."] +,CodeBlock ("",[],[]) "# ls /sys/class/ieee80211/\nphy0" +,Para [Str "The",Space,Str "\"phy0\"",Space,Str "interface",Space,Str "is",Space,Str "the",Space,Str "parent",Space,Str "interface",Space,Str "used",Space,Str "to",Space,Str "create",Space,Str "child",Space,Str "interfaces.",Space,Str "Note",Space,Str "that",Space,Str "if",Space,Str "you",Space,Str "unplug",Space,Str "and",Space,Str "replug",Space,Str "the",Space,Str "USB",Space,Str "interface,",Space,Str "the",Space,Str "\"phy\"",Space,Str "interface",Space,Str "number",Space,Str "will",Space,Str "increment",Space,Str "by",Space,Str "one",Space,Str "until",Space,Str "you",Space,Str "reboot",Space,Str "your",Space,Str "system."]] diff --git a/test/docx/block_quotes.docx b/test/docx/block_quotes.docx Binary files differindex 729ae1f43..aa2fef00e 100644 --- a/test/docx/block_quotes.docx +++ b/test/docx/block_quotes.docx diff --git a/test/docx/char_styles.docx b/test/docx/char_styles.docx Binary files differindex 05979b9a7..ef6106215 100644 --- a/test/docx/char_styles.docx +++ b/test/docx/char_styles.docx diff --git a/test/docx/deep_normalize.docx b/test/docx/deep_normalize.docx Binary files differindex 7626d59ce..4905ebe14 100644 --- a/test/docx/deep_normalize.docx +++ b/test/docx/deep_normalize.docx diff --git a/test/docx/drop_cap.docx b/test/docx/drop_cap.docx Binary files differindex 19fab4a52..2f14c2c1d 100644 --- a/test/docx/drop_cap.docx +++ b/test/docx/drop_cap.docx diff --git a/test/docx/hanging_indent.docx b/test/docx/hanging_indent.docx Binary files differindex 6f62dc731..62d41fdad 100644 --- a/test/docx/hanging_indent.docx +++ b/test/docx/hanging_indent.docx diff --git a/test/docx/headers.docx b/test/docx/headers.docx Binary files differindex e1fbbcc75..6c4701716 100644 --- a/test/docx/headers.docx +++ b/test/docx/headers.docx diff --git a/test/docx/inline_formatting.docx b/test/docx/inline_formatting.docx Binary files differindex eccf26425..49f383e73 100644 --- a/test/docx/inline_formatting.docx +++ b/test/docx/inline_formatting.docx diff --git a/test/docx/inline_images.docx b/test/docx/inline_images.docx Binary files differindex 2f01a251e..af433bb79 100644 --- a/test/docx/inline_images.docx +++ b/test/docx/inline_images.docx diff --git a/test/docx/link_in_notes.docx b/test/docx/link_in_notes.docx Binary files differindex f3398f438..b5e4e2bf6 100644 --- a/test/docx/link_in_notes.docx +++ b/test/docx/link_in_notes.docx diff --git a/test/docx/links.docx b/test/docx/links.docx Binary files differindex 80fecacaf..f23007f11 100644 --- a/test/docx/links.docx +++ b/test/docx/links.docx diff --git a/test/docx/lists.docx b/test/docx/lists.docx Binary files differindex bf7fd8ae4..8b46351d9 100644 --- a/test/docx/lists.docx +++ b/test/docx/lists.docx diff --git a/test/docx/metadata.docx b/test/docx/metadata.docx Binary files differindex ccf50b475..d5a4fb255 100644 --- a/test/docx/metadata.docx +++ b/test/docx/metadata.docx diff --git a/test/docx/metadata_after_normal.docx b/test/docx/metadata_after_normal.docx Binary files differindex b94a016cb..f43110e96 100644 --- a/test/docx/metadata_after_normal.docx +++ b/test/docx/metadata_after_normal.docx diff --git a/test/docx/normalize.docx b/test/docx/normalize.docx Binary files differindex b4fc55818..a20c5ddd1 100644 --- a/test/docx/normalize.docx +++ b/test/docx/normalize.docx diff --git a/test/docx/notes.docx b/test/docx/notes.docx Binary files differindex eb6fa12d4..e6a63342d 100644 --- a/test/docx/notes.docx +++ b/test/docx/notes.docx diff --git a/test/docx/numbered_header.docx b/test/docx/numbered_header.docx Binary files differindex 66ce7648d..b81caea69 100644 --- a/test/docx/numbered_header.docx +++ b/test/docx/numbered_header.docx diff --git a/test/docx/table_variable_width.native b/test/docx/table_variable_width.native index 9d3b961df..b85e58d41 100644 --- a/test/docx/table_variable_width.native +++ b/test/docx/table_variable_width.native @@ -6,8 +6,11 @@ ,[Plain [Str "h5"]]] [[[Plain [Str "c11"]] ,[] + ,[] + ,[] ,[]] ,[[] ,[Plain [Str "c22"]] ,[Plain [Str "c23"]] + ,[] ,[]]]] diff --git a/test/docx/table_with_list_cell.docx b/test/docx/table_with_list_cell.docx Binary files differindex 1db065770..bf58c1abe 100644 --- a/test/docx/table_with_list_cell.docx +++ b/test/docx/table_with_list_cell.docx diff --git a/test/docx/tables.docx b/test/docx/tables.docx Binary files differindex 28087ead5..f99ea249d 100644 --- a/test/docx/tables.docx +++ b/test/docx/tables.docx diff --git a/test/fb2/basic.fb2 b/test/fb2/basic.fb2 index 9dc1926f1..df71e8456 100644 --- a/test/fb2/basic.fb2 +++ b/test/fb2/basic.fb2 @@ -1,9 +1,75 @@ <?xml version="1.0" encoding="UTF-8"?> -<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><title><p>Top-level title</p></title><section><title><p>Section</p></title><section><title><p>Subsection</p></title><p>This <emphasis>emphasized</emphasis> <strong>strong</strong> <code>verbatim</code> markdown. -See this link<a l:href="#l1" type="note"><sup>[1]</sup></a>.</p><p>Ordered list:</p><p>1. one</p><p>2. two</p><p>3. three</p><cite><p>Blockquote +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"> +<description> +<title-info> +<genre>unrecognised</genre> +</title-info> +<document-info> +<program-used>pandoc</program-used> +</document-info> +</description> +<body> +<title> +<p /> +</title> +<section> +<title> +<p>Top-level title</p> +</title> +<section> +<title> +<p>Section</p> +</title> +<section> +<title> +<p>Subsection</p> +</title> +<p>This <emphasis>emphasized</emphasis> <strong>strong</strong> <code>verbatim</code> markdown. +See this <a l:href="http://example.com/">link</a>.</p> +<p>Ordered list:</p> +<p>1. one</p> +<p>2. two</p> +<p>3. three</p> +<cite> +<p>Blockquote is for -citatons.</p></cite><empty-line /><p><code>Code</code></p><p><code>block</code></p><p><code>is</code></p><p><code>for</code></p><p><code>code.</code></p><empty-line /><p><strikethrough>Strikeout</strikethrough> is Pandoc’s extension. -Superscript and subscripts too: H<sub>2</sub>O is a liquid<a l:href="#n2" type="note"><sup>[2]</sup></a>. -2<sup>10</sup> is 1024.</p><p>Math is another Pandoc extension: <code>E = m c^2</code>.</p></section></section></section></body><body name="notes"><section id="l1"><title><p>1</p></title><p><code>http://example.com/</code></p></section><section id="n2"><title><p>2</p></title><p>Sometimes.</p></section></body></FictionBook> - +citatons.</p> +</cite> +<empty-line /> +<p> +<code>Code</code> +</p> +<p> +<code>block</code> +</p> +<p> +<code>is</code> +</p> +<p> +<code>for</code> +</p> +<p> +<code>code.</code> +</p> +<empty-line /> +<p> +<strikethrough>Strikeout</strikethrough> is Pandoc’s extension. +Superscript and subscripts too: H<sub>2</sub>O is a liquid<a l:href="#n1" type="note"> +<sup>[1]</sup> +</a>. +2<sup>10</sup> is 1024.</p> +<p>Math is another Pandoc extension: <code>E = m c^2</code>.</p> +</section> +</section> +</section> +</body> +<body name="notes"> +<section id="n1"> +<title> +<p>1</p> +</title> +<p>Sometimes.</p> +</section> +</body> +</FictionBook> diff --git a/test/fb2/meta.fb2 b/test/fb2/meta.fb2 new file mode 100644 index 000000000..04bd5f3c5 --- /dev/null +++ b/test/fb2/meta.fb2 @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre><book-title>Book title</book-title><annotation><p>This is the abstract.</p>It consists of two paragraphs.</annotation></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p>Book title</p></title></body></FictionBook> + diff --git a/test/fb2/meta.markdown b/test/fb2/meta.markdown new file mode 100644 index 000000000..5edad2981 --- /dev/null +++ b/test/fb2/meta.markdown @@ -0,0 +1,7 @@ +--- +title: Book title +abstract: | + This is the abstract. + + It consists of two paragraphs. +--- diff --git a/test/lhs-test.rst b/test/lhs-test.rst index 3de2d9ff6..4d012a9f9 100644 --- a/test/lhs-test.rst +++ b/test/lhs-test.rst @@ -6,9 +6,9 @@ return a single value: .. code:: haskell - unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d - unsplit = arr . uncurry - -- arr (\op (x,y) -> x `op` y) + unsplit :: (Arrow a) => (b -> c -> d) -> a (b, c) d + unsplit = arr . uncurry + -- arr (\op (x,y) -> x `op` y) ``(***)`` combines two arrows into a new arrow by running the two arrows on a pair of values (one arrow on the first item of the pair and one arrow on the @@ -16,8 +16,8 @@ second item of the pair). :: - f *** g = first f >>> second g + f *** g = first f >>> second g Block quote: - foo bar + foo bar diff --git a/test/lhs-test.rst+lhs b/test/lhs-test.rst+lhs index eec79c546..6196c39ab 100644 --- a/test/lhs-test.rst+lhs +++ b/test/lhs-test.rst+lhs @@ -14,8 +14,8 @@ second item of the pair). :: - f *** g = first f >>> second g + f *** g = first f >>> second g Block quote: - foo bar + foo bar diff --git a/test/pandoc-test14632-86 b/test/pandoc-test14632-86 new file mode 100644 index 000000000..507e9f672 --- /dev/null +++ b/test/pandoc-test14632-86 @@ -0,0 +1,1448 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD v1.0 20120330//EN" + "JATS-journalpublishing1.dtd"> +<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.0" article-type="other"> +<front> +<journal-meta> +<journal-title-group> +</journal-title-group> +<publisher> +<publisher-name></publisher-name> +</publisher> +</journal-meta> +<article-meta> +<title-group> +<article-title>Pandoc Test Suite</article-title> +</title-group> +<contrib-group> +<contrib contrib-type="author"> +<name> +<string-name>John MacFarlane</string-name> +</name> +</contrib> +<contrib contrib-type="author"> +<name> +<string-name>Anonymous</string-name> +</name> +</contrib> +</contrib-group> +<pub-date pub-type="epub"> +<string-date>July 17, 2006</string-date> +</pub-date> +</article-meta> +</front> +<body> +<p> + This is a set of tests for pandoc. Most of them are adapted from John + Gruber’s markdown test suite. +</p> +<sec id="headers"> + <title>Headers</title> + <sec id="level-2-with-an-embedded-link"> + <title>Level 2 with an + <ext-link ext-link-type="uri" xlink:href="/url">embedded + link</ext-link></title> + <sec id="level-3-with-emphasis"> + <title>Level 3 with <italic>emphasis</italic></title> + <sec id="level-4"> + <title>Level 4</title> + <sec id="level-5"> + <title>Level 5</title> + </sec> + </sec> + </sec> + </sec> +</sec> +<sec id="level-1"> + <title>Level 1</title> + <sec id="level-2-with-emphasis"> + <title>Level 2 with <italic>emphasis</italic></title> + <sec id="level-3"> + <title>Level 3</title> + <p> + with no blank line + </p> + </sec> + </sec> + <sec id="level-2"> + <title>Level 2</title> + <p> + with no blank line + </p> + </sec> +</sec> +<sec id="paragraphs"> + <title>Paragraphs</title> + <p> + Here’s a regular paragraph. + </p> + <p> + In Markdown 1.0.0 and earlier. Version 8. This line turns into a list + item. Because a hard-wrapped line in the middle of a paragraph looked like + a list item. + </p> + <p> + Here’s one with a bullet. * criminey. + </p> + <p> + There should be a hard line break<break />here. + </p> +</sec> +<sec id="block-quotes"> + <title>Block Quotes</title> + <p> + E-mail style: + </p> + <disp-quote> + <p> + This is a block quote. It is pretty short. + </p> + </disp-quote> + <disp-quote> + <p> + Code in a block quote: + </p> + <preformat>sub status { + print "working"; +}</preformat> + <p> + A list: + </p> + <list list-type="order"> + <list-item> + <p> + item one + </p> + </list-item> + <list-item> + <p> + item two + </p> + </list-item> + </list> + <p> + Nested block quotes: + </p> + <disp-quote> + <p> + nested + </p> + </disp-quote> + <disp-quote> + <p> + nested + </p> + </disp-quote> + </disp-quote> + <p> + This should not be a block quote: 2 > 1. + </p> + <p> + And a following paragraph. + </p> +</sec> +<sec id="code-blocks"> + <title>Code Blocks</title> + <p> + Code: + </p> + <preformat>---- (should be four hyphens) + +sub status { + print "working"; +} + +this code block is indented by one tab</preformat> + <p> + And: + </p> + <preformat> this code block is indented by two tabs + +These should not be escaped: \$ \\ \> \[ \{</preformat> +</sec> +<sec id="lists"> + <title>Lists</title> + <sec id="unordered"> + <title>Unordered</title> + <p> + Asterisks tight: + </p> + <list list-type="bullet"> + <list-item> + <p> + asterisk 1 + </p> + </list-item> + <list-item> + <p> + asterisk 2 + </p> + </list-item> + <list-item> + <p> + asterisk 3 + </p> + </list-item> + </list> + <p> + Asterisks loose: + </p> + <list list-type="bullet"> + <list-item> + <p> + asterisk 1 + </p> + </list-item> + <list-item> + <p> + asterisk 2 + </p> + </list-item> + <list-item> + <p> + asterisk 3 + </p> + </list-item> + </list> + <p> + Pluses tight: + </p> + <list list-type="bullet"> + <list-item> + <p> + Plus 1 + </p> + </list-item> + <list-item> + <p> + Plus 2 + </p> + </list-item> + <list-item> + <p> + Plus 3 + </p> + </list-item> + </list> + <p> + Pluses loose: + </p> + <list list-type="bullet"> + <list-item> + <p> + Plus 1 + </p> + </list-item> + <list-item> + <p> + Plus 2 + </p> + </list-item> + <list-item> + <p> + Plus 3 + </p> + </list-item> + </list> + <p> + Minuses tight: + </p> + <list list-type="bullet"> + <list-item> + <p> + Minus 1 + </p> + </list-item> + <list-item> + <p> + Minus 2 + </p> + </list-item> + <list-item> + <p> + Minus 3 + </p> + </list-item> + </list> + <p> + Minuses loose: + </p> + <list list-type="bullet"> + <list-item> + <p> + Minus 1 + </p> + </list-item> + <list-item> + <p> + Minus 2 + </p> + </list-item> + <list-item> + <p> + Minus 3 + </p> + </list-item> + </list> + </sec> + <sec id="ordered"> + <title>Ordered</title> + <p> + Tight: + </p> + <list list-type="order"> + <list-item> + <p> + First + </p> + </list-item> + <list-item> + <p> + Second + </p> + </list-item> + <list-item> + <p> + Third + </p> + </list-item> + </list> + <p> + and: + </p> + <list list-type="order"> + <list-item> + <p> + One + </p> + </list-item> + <list-item> + <p> + Two + </p> + </list-item> + <list-item> + <p> + Three + </p> + </list-item> + </list> + <p> + Loose using tabs: + </p> + <list list-type="order"> + <list-item> + <p> + First + </p> + </list-item> + <list-item> + <p> + Second + </p> + </list-item> + <list-item> + <p> + Third + </p> + </list-item> + </list> + <p> + and using spaces: + </p> + <list list-type="order"> + <list-item> + <p> + One + </p> + </list-item> + <list-item> + <p> + Two + </p> + </list-item> + <list-item> + <p> + Three + </p> + </list-item> + </list> + <p> + Multiple paragraphs: + </p> + <list list-type="order"> + <list-item> + <p> + Item 1, graf one. + </p> + <p> + Item 1. graf two. The quick brown fox jumped over the lazy dog’s + back. + </p> + </list-item> + <list-item> + <p> + Item 2. + </p> + </list-item> + <list-item> + <p> + Item 3. + </p> + </list-item> + </list> + </sec> + <sec id="nested"> + <title>Nested</title> + <list list-type="bullet"> + <list-item> + <p> + Tab + </p> + <list list-type="bullet"> + <list-item> + <p> + Tab + </p> + <list list-type="bullet"> + <list-item> + <p> + Tab + </p> + </list-item> + </list> + </list-item> + </list> + </list-item> + </list> + <p> + Here’s another: + </p> + <list list-type="order"> + <list-item> + <p> + First + </p> + </list-item> + <list-item> + <p> + Second: + </p> + <list list-type="bullet"> + <list-item> + <p> + Fee + </p> + </list-item> + <list-item> + <p> + Fie + </p> + </list-item> + <list-item> + <p> + Foe + </p> + </list-item> + </list> + </list-item> + <list-item> + <p> + Third + </p> + </list-item> + </list> + <p> + Same thing but with paragraphs: + </p> + <list list-type="order"> + <list-item> + <p> + First + </p> + </list-item> + <list-item> + <p> + Second: + </p> + <list list-type="bullet"> + <list-item> + <p> + Fee + </p> + </list-item> + <list-item> + <p> + Fie + </p> + </list-item> + <list-item> + <p> + Foe + </p> + </list-item> + </list> + </list-item> + <list-item> + <p> + Third + </p> + </list-item> + </list> + </sec> + <sec id="tabs-and-spaces"> + <title>Tabs and spaces</title> + <list list-type="bullet"> + <list-item> + <p> + this is a list item indented with tabs + </p> + </list-item> + <list-item> + <p> + this is a list item indented with spaces + </p> + <list list-type="bullet"> + <list-item> + <p> + this is an example list item indented with tabs + </p> + </list-item> + <list-item> + <p> + this is an example list item indented with spaces + </p> + </list-item> + </list> + </list-item> + </list> + </sec> + <sec id="fancy-list-markers"> + <title>Fancy list markers</title> + <list list-type="order"> + <list-item> + <label> + (2) + </label> + <p> + begins with 2 + </p> + </list-item> + <list-item> + <label> + (3) + </label> + <p> + and now 3 + </p> + <p> + with a continuation + </p> + <list list-type="roman-lower"> + <list-item> + <label> + iv. + </label> + <p> + sublist with roman numerals, starting with 4 + </p> + </list-item> + <list-item> + <label> + v. + </label> + <p> + more items + </p> + <list list-type="alpha-upper"> + <list-item> + <label> + (A) + </label> + <p> + a subsublist + </p> + </list-item> + <list-item> + <label> + (B) + </label> + <p> + a subsublist + </p> + </list-item> + </list> + </list-item> + </list> + </list-item> + </list> + <p> + Nesting: + </p> + <list list-type="alpha-upper"> + <list-item> + <p> + Upper Alpha + </p> + <list list-type="roman-upper"> + <list-item> + <p> + Upper Roman. + </p> + <list list-type="order"> + <list-item> + <label> + (6) + </label> + <p> + Decimal start with 6 + </p> + <list list-type="alpha-lower"> + <list-item> + <label> + c) + </label> + <p> + Lower alpha with paren + </p> + </list-item> + </list> + </list-item> + </list> + </list-item> + </list> + </list-item> + </list> + <p> + Autonumbering: + </p> + <list list-type="order"> + <list-item> + <p> + Autonumber. + </p> + </list-item> + <list-item> + <p> + More. + </p> + <list list-type="order"> + <list-item> + <p> + Nested. + </p> + </list-item> + </list> + </list-item> + </list> + <p> + Should not be a list item: + </p> + <p> + M.A. 2007 + </p> + <p> + B. Williams + </p> + </sec> +</sec> +<sec id="definition-lists"> + <title>Definition Lists</title> + <p> + Tight using spaces: + </p> + <def-list> + <def-item> + <term> + apple + </term> + <def> + <p> + red fruit + </p> + </def> + </def-item> + <def-item> + <term> + orange + </term> + <def> + <p> + orange fruit + </p> + </def> + </def-item> + <def-item> + <term> + banana + </term> + <def> + <p> + yellow fruit + </p> + </def> + </def-item> + </def-list> + <p> + Tight using tabs: + </p> + <def-list> + <def-item> + <term> + apple + </term> + <def> + <p> + red fruit + </p> + </def> + </def-item> + <def-item> + <term> + orange + </term> + <def> + <p> + orange fruit + </p> + </def> + </def-item> + <def-item> + <term> + banana + </term> + <def> + <p> + yellow fruit + </p> + </def> + </def-item> + </def-list> + <p> + Loose: + </p> + <def-list> + <def-item> + <term> + apple + </term> + <def> + <p> + red fruit + </p> + </def> + </def-item> + <def-item> + <term> + orange + </term> + <def> + <p> + orange fruit + </p> + </def> + </def-item> + <def-item> + <term> + banana + </term> + <def> + <p> + yellow fruit + </p> + </def> + </def-item> + </def-list> + <p> + Multiple blocks with italics: + </p> + <def-list> + <def-item> + <term> + <italic>apple</italic> + </term> + <def> + <p> + red fruit + </p> + <p> + contains seeds, crisp, pleasant to taste + </p> + </def> + </def-item> + <def-item> + <term> + <italic>orange</italic> + </term> + <def> + <p> + orange fruit + </p> + <preformat>{ orange code block }</preformat> + <disp-quote> + <p> + orange block quote + </p> + </disp-quote> + </def> + </def-item> + </def-list> + <p> + Multiple definitions, tight: + </p> + <def-list> + <def-item> + <term> + apple + </term> + <def> + <p> + red fruit + </p> + <p> + computer + </p> + </def> + </def-item> + <def-item> + <term> + orange + </term> + <def> + <p> + orange fruit + </p> + <p> + bank + </p> + </def> + </def-item> + </def-list> + <p> + Multiple definitions, loose: + </p> + <def-list> + <def-item> + <term> + apple + </term> + <def> + <p> + red fruit + </p> + <p> + computer + </p> + </def> + </def-item> + <def-item> + <term> + orange + </term> + <def> + <p> + orange fruit + </p> + <p> + bank + </p> + </def> + </def-item> + </def-list> + <p> + Blank line after term, indented marker, alternate markers: + </p> + <def-list> + <def-item> + <term> + apple + </term> + <def> + <p> + red fruit + </p> + <p> + computer + </p> + </def> + </def-item> + <def-item> + <term> + orange + </term> + <def> + <p> + orange fruit + </p> + <list list-type="order"> + <list-item> + <p> + sublist + </p> + </list-item> + <list-item> + <p> + sublist + </p> + </list-item> + </list> + </def> + </def-item> + </def-list> +</sec> +<sec id="html-blocks"> + <title>HTML Blocks</title> + <p> + Simple block on one line: + </p> + <boxed-text> + <p> + foo + </p> + </boxed-text> + <p> + And nested without indentation: + </p> + <boxed-text> + <boxed-text> + <boxed-text> + <p> + foo + </p> + </boxed-text> + </boxed-text> + <boxed-text> + <p> + bar + </p> + </boxed-text> + </boxed-text> + <p> + Interpreted markdown in a table: + </p> + <p> + This is <italic>emphasized</italic> + </p> + <p> + And this is <bold role="strong">strong</bold> + </p> + <p> + Here’s a simple block: + </p> + <boxed-text> + <p> + foo + </p> + </boxed-text> + <p> + This should be a code block, though: + </p> + <preformat><div> + foo +</div></preformat> + <p> + As should this: + </p> + <preformat><div>foo</div></preformat> + <p> + Now, nested: + </p> + <boxed-text> + <boxed-text> + <boxed-text> + <p> + foo + </p> + </boxed-text> + </boxed-text> + </boxed-text> + <p> + This should just be an HTML comment: + </p> + <p> + Multiline: + </p> + <p> + Code block: + </p> + <preformat><!-- Comment --></preformat> + <p> + Just plain comment, with trailing spaces on the line: + </p> + <p> + Code: + </p> + <preformat><hr /></preformat> + <p> + Hr’s: + </p> +</sec> +<sec id="inline-markup"> + <title>Inline Markup</title> + <p> + This is <italic>emphasized</italic>, and so <italic>is this</italic>. + </p> + <p> + This is <bold role="strong">strong</bold>, and so <bold role="strong">is + this</bold>. + </p> + <p> + An <italic><ext-link ext-link-type="uri" xlink:href="/url">emphasized + link</ext-link></italic>. + </p> + <p> + <bold role="strong"><italic>This is strong and em.</italic></bold> + </p> + <p> + So is <bold role="strong"><italic>this</italic></bold> word. + </p> + <p> + <bold role="strong"><italic>This is strong and em.</italic></bold> + </p> + <p> + So is <bold role="strong"><italic>this</italic></bold> word. + </p> + <p> + This is code: <monospace>></monospace>, <monospace>$</monospace>, + <monospace>\</monospace>, <monospace>\$</monospace>, + <monospace><html></monospace>. + </p> + <p> + <strike>This is <italic>strikeout</italic>.</strike> + </p> + <p> + Superscripts: a<sup>bc</sup>d a<sup><italic>hello</italic></sup> + a<sup>hello there</sup>. + </p> + <p> + Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O. + </p> + <p> + These should not be superscripts or subscripts, because of the unescaped + spaces: a^b c^d, a~b c~d. + </p> +</sec> +<sec id="smart-quotes-ellipses-dashes"> + <title>Smart quotes, ellipses, dashes</title> + <p> + “Hello,” said the spider. “‘Shelob’ is my name.” + </p> + <p> + ‘A’, ‘B’, and ‘C’ are letters. + </p> + <p> + ‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’ + </p> + <p> + ‘He said, “I want to go.”’ Were you alive in the 70’s? + </p> + <p> + Here is some quoted ‘<monospace>code</monospace>’ and a + “<ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&bar=2">quoted + link</ext-link>”. + </p> + <p> + Some dashes: one—two — three—four — five. + </p> + <p> + Dashes between numbers: 5–7, 255–66, 1987–1999. + </p> + <p> + Ellipses…and…and…. + </p> +</sec> +<sec id="latex"> + <title>LaTeX</title> + <list list-type="bullet"> + <list-item> + <p> + </p> + </list-item> + <list-item> + <p> + <inline-formula><alternatives> + <tex-math><![CDATA[2+2=4]]></tex-math> + <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mn>2</mml:mn><mml:mo>+</mml:mo><mml:mn>2</mml:mn><mml:mo>=</mml:mo><mml:mn>4</mml:mn></mml:mrow></mml:math></alternatives></inline-formula> + </p> + </list-item> + <list-item> + <p> + <inline-formula><alternatives> + <tex-math><![CDATA[x \in y]]></tex-math> + <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>x</mml:mi><mml:mo>∈</mml:mo><mml:mi>y</mml:mi></mml:mrow></mml:math></alternatives></inline-formula> + </p> + </list-item> + <list-item> + <p> + <inline-formula><alternatives> + <tex-math><![CDATA[\alpha \wedge \omega]]></tex-math> + <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>α</mml:mi><mml:mo>∧</mml:mo><mml:mi>ω</mml:mi></mml:mrow></mml:math></alternatives></inline-formula> + </p> + </list-item> + <list-item> + <p> + <inline-formula><alternatives> + <tex-math><![CDATA[223]]></tex-math> + <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mn>223</mml:mn></mml:math></alternatives></inline-formula> + </p> + </list-item> + <list-item> + <p> + <inline-formula><alternatives> + <tex-math><![CDATA[p]]></tex-math> + <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>p</mml:mi></mml:math></alternatives></inline-formula>-Tree + </p> + </list-item> + <list-item> + <p> + Here’s some display math: <disp-formula><alternatives> + <tex-math><![CDATA[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}]]></tex-math> + <mml:math display="block" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mfrac><mml:mi>d</mml:mi><mml:mrow><mml:mi>d</mml:mi><mml:mi>x</mml:mi></mml:mrow></mml:mfrac><mml:mi>f</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo>=</mml:mo><mml:munder><mml:mo>lim</mml:mo><mml:mrow><mml:mi>h</mml:mi><mml:mo>→</mml:mo><mml:mn>0</mml:mn></mml:mrow></mml:munder><mml:mfrac><mml:mrow><mml:mi>f</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo>+</mml:mo><mml:mi>h</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo><mml:mo>−</mml:mo><mml:mi>f</mml:mi><mml:mo stretchy="false" form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy="false" form="postfix">)</mml:mo></mml:mrow><mml:mi>h</mml:mi></mml:mfrac></mml:mrow></mml:math></alternatives></disp-formula> + </p> + </list-item> + <list-item> + <p> + Here’s one that has a line break in it: <inline-formula><alternatives> + <tex-math><![CDATA[\alpha + \omega \times x^2]]></tex-math> + <mml:math display="inline" xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mrow><mml:mi>α</mml:mi><mml:mo>+</mml:mo><mml:mi>ω</mml:mi><mml:mo>×</mml:mo><mml:msup><mml:mi>x</mml:mi><mml:mn>2</mml:mn></mml:msup></mml:mrow></mml:math></alternatives></inline-formula>. + </p> + </list-item> + </list> + <p> + These shouldn’t be math: + </p> + <list list-type="bullet"> + <list-item> + <p> + To get the famous equation, write <monospace>$e = mc^2$</monospace>. + </p> + </list-item> + <list-item> + <p> + $22,000 is a <italic>lot</italic> of money. So is $34,000. (It worked + if “lot” is emphasized.) + </p> + </list-item> + <list-item> + <p> + Shoes ($20) and socks ($5). + </p> + </list-item> + <list-item> + <p> + Escaped <monospace>$</monospace>: $73 <italic>this should be + emphasized</italic> 23$. + </p> + </list-item> + </list> + <p> + Here’s a LaTeX table: + </p> +</sec> +<sec id="special-characters"> + <title>Special Characters</title> + <p> + Here is some unicode: + </p> + <list list-type="bullet"> + <list-item> + <p> + I hat: Î + </p> + </list-item> + <list-item> + <p> + o umlaut: ö + </p> + </list-item> + <list-item> + <p> + section: § + </p> + </list-item> + <list-item> + <p> + set membership: ∈ + </p> + </list-item> + <list-item> + <p> + copyright: © + </p> + </list-item> + </list> + <p> + AT&T has an ampersand in their name. + </p> + <p> + AT&T is another way to write it. + </p> + <p> + This & that. + </p> + <p> + 4 < 5. + </p> + <p> + 6 > 5. + </p> + <p> + Backslash: \ + </p> + <p> + Backtick: ` + </p> + <p> + Asterisk: * + </p> + <p> + Underscore: _ + </p> + <p> + Left brace: { + </p> + <p> + Right brace: } + </p> + <p> + Left bracket: [ + </p> + <p> + Right bracket: ] + </p> + <p> + Left paren: ( + </p> + <p> + Right paren: ) + </p> + <p> + Greater-than: > + </p> + <p> + Hash: # + </p> + <p> + Period: . + </p> + <p> + Bang: ! + </p> + <p> + Plus: + + </p> + <p> + Minus: - + </p> +</sec> +<sec id="links"> + <title>Links</title> + <sec id="explicit"> + <title>Explicit</title> + <p> + Just a <ext-link ext-link-type="uri" xlink:href="/url/">URL</ext-link>. + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title">URL + and title</ext-link>. + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title preceded by two spaces">URL + and title</ext-link>. + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title preceded by a tab">URL + and title</ext-link>. + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title with "quotes" in it">URL + and title</ext-link> + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="title with single quotes">URL + and title</ext-link> + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="/url/with_underscore">with_underscore</ext-link> + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="mailto:nobody@nowhere.net">Email + link</ext-link> + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="">Empty</ext-link>. + </p> + </sec> + <sec id="reference"> + <title>Reference</title> + <p> + Foo <ext-link ext-link-type="uri" xlink:href="/url/">bar</ext-link>. + </p> + <p> + With <ext-link ext-link-type="uri" xlink:href="/url/">embedded + [brackets]</ext-link>. + </p> + <p> + <ext-link ext-link-type="uri" xlink:href="/url/">b</ext-link> by itself + should be a link. + </p> + <p> + Indented + <ext-link ext-link-type="uri" xlink:href="/url">once</ext-link>. + </p> + <p> + Indented + <ext-link ext-link-type="uri" xlink:href="/url">twice</ext-link>. + </p> + <p> + Indented + <ext-link ext-link-type="uri" xlink:href="/url">thrice</ext-link>. + </p> + <p> + This should [not][] be a link. + </p> + <preformat>[not]: /url</preformat> + <p> + Foo + <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="Title with "quotes" inside">bar</ext-link>. + </p> + <p> + Foo + <ext-link ext-link-type="uri" xlink:href="/url/" xlink:title="Title with "quote" inside">biz</ext-link>. + </p> + </sec> + <sec id="with-ampersands"> + <title>With ampersands</title> + <p> + Here’s a + <ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&bar=2">link + with an ampersand in the URL</ext-link>. + </p> + <p> + Here’s a link with an amersand in the link text: + <ext-link ext-link-type="uri" xlink:href="http://att.com/" xlink:title="AT&T">AT&T</ext-link>. + </p> + <p> + Here’s an + <ext-link ext-link-type="uri" xlink:href="/script?foo=1&bar=2">inline + link</ext-link>. + </p> + <p> + Here’s an + <ext-link ext-link-type="uri" xlink:href="/script?foo=1&bar=2">inline + link in pointy braces</ext-link>. + </p> + </sec> + <sec id="autolinks"> + <title>Autolinks</title> + <p> + With an ampersand: + <ext-link ext-link-type="uri" xlink:href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</ext-link> + </p> + <list list-type="bullet"> + <list-item> + <p> + In a list? + </p> + </list-item> + <list-item> + <p> + <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link> + </p> + </list-item> + <list-item> + <p> + It should. + </p> + </list-item> + </list> + <p> + An e-mail address: <email>nobody@nowhere.net</email> + </p> + <disp-quote> + <p> + Blockquoted: + <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link> + </p> + </disp-quote> + <p> + Auto-links should not occur here: + <monospace><http://example.com/></monospace> + </p> + <preformat>or here: <http://example.com/></preformat> + </sec> +</sec> +<sec id="images"> + <title>Images</title> + <p> + From “Voyage dans la Lune” by Georges Melies (1902): + </p> + <fig> + <caption>lalune</caption> + <graphic mimetype="image" mime-subtype="jpeg" xlink:href="lalune.jpg" xlink:title="Voyage dans la Lune" /> + </fig> + <p> + Here is a movie + <inline-graphic mimetype="image" mime-subtype="jpeg" xlink:href="movie.jpg" /> + icon. + </p> +</sec> +<sec id="footnotes"> + <title>Footnotes</title> + <p> + Here is a footnote reference,<fn> + <p> + Here is the footnote. It can go anywhere after the footnote reference. + It need not be placed at the end of the document. + </p> + </fn> and another.<fn> + <p> + Here’s the long note. This one contains multiple blocks. + </p> + <p> + Subsequent blocks are indented to show that they belong to the + footnote (as with list items). + </p> + <preformat> { <code> }</preformat> + <p> + If you want, you can indent every line, but you can also be lazy and + just indent the first line of each block. + </p> + </fn> This should <italic>not</italic> be a footnote reference, because it + contains a space.[^my note] Here is an inline note.<fn> + <p> + This is <italic>easier</italic> to type. Inline notes may contain + <ext-link ext-link-type="uri" xlink:href="http://google.com">links</ext-link> + and <monospace>]</monospace> verbatim characters, as well as + [bracketed text]. + </p> + </fn> + </p> + <disp-quote> + <p> + Notes can go in quotes.<fn> + <p> + In quote. + </p> + </fn> + </p> + </disp-quote> + <list list-type="order"> + <list-item> + <p> + And in list items.<fn> + <p> + In list. + </p> + </fn> + </p> + </list-item> + </list> + <p> + This paragraph should not be part of the note, as it is not indented. + </p> +</sec> +</body> +<back> +</back> +</article> diff --git a/test/pandoc-test14632-89 b/test/pandoc-test14632-89 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test14632-89 diff --git a/test/pandoc-test14632-90 b/test/pandoc-test14632-90 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test14632-90 diff --git a/test/pandoc-test14632-91 b/test/pandoc-test14632-91 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test14632-91 diff --git a/test/pandoc-test14632-94 b/test/pandoc-test14632-94 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test14632-94 diff --git a/test/pandoc-test14632-95 b/test/pandoc-test14632-95 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test14632-95 diff --git a/test/pandoc-test14632-96 b/test/pandoc-test14632-96 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test14632-96 diff --git a/test/pandoc-test14632-97 b/test/pandoc-test14632-97 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test14632-97 diff --git a/test/pandoc-test77993-78 b/test/pandoc-test77993-78 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test77993-78 diff --git a/test/pandoc-test77993-79 b/test/pandoc-test77993-79 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test77993-79 diff --git a/test/pandoc-test77993-82 b/test/pandoc-test77993-82 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test77993-82 diff --git a/test/pandoc-test77993-83 b/test/pandoc-test77993-83 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test77993-83 diff --git a/test/pandoc-test77993-86 b/test/pandoc-test77993-86 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test77993-86 diff --git a/test/pandoc-test77993-87 b/test/pandoc-test77993-87 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test77993-87 diff --git a/test/pandoc-test77993-90 b/test/pandoc-test77993-90 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test77993-90 diff --git a/test/pandoc-test77993-91 b/test/pandoc-test77993-91 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test77993-91 diff --git a/test/pandoc-test88473-110 b/test/pandoc-test88473-110 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test88473-110 diff --git a/test/pandoc-test88473-111 b/test/pandoc-test88473-111 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test88473-111 diff --git a/test/pandoc-test88473-112 b/test/pandoc-test88473-112 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test88473-112 diff --git a/test/pandoc-test88473-113 b/test/pandoc-test88473-113 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test88473-113 diff --git a/test/pandoc-test88473-116 b/test/pandoc-test88473-116 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test88473-116 diff --git a/test/pandoc-test88473-117 b/test/pandoc-test88473-117 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test88473-117 diff --git a/test/pandoc-test88473-118 b/test/pandoc-test88473-118 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test88473-118 diff --git a/test/pandoc-test88473-119 b/test/pandoc-test88473-119 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test88473-119 diff --git a/test/pandoc-test94017-86 b/test/pandoc-test94017-86 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test94017-86 diff --git a/test/pandoc-test94017-87 b/test/pandoc-test94017-87 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test94017-87 diff --git a/test/pandoc-test94017-90 b/test/pandoc-test94017-90 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test94017-90 diff --git a/test/pandoc-test94017-91 b/test/pandoc-test94017-91 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test94017-91 diff --git a/test/pandoc-test94017-92 b/test/pandoc-test94017-92 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test94017-92 diff --git a/test/pandoc-test94017-93 b/test/pandoc-test94017-93 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/pandoc-test94017-93 diff --git a/test/s5-fancy.html b/test/s5-fancy.html index 9f724af96..b326f9872 100644 --- a/test/s5-fancy.html +++ b/test/s5-fancy.html @@ -26,207 +26,7 @@ <link rel="stylesheet" href="s5/default/opera.css" type="text/css" media="projection" id="operaFix" /> <!-- S5 JS --> <script src="s5/default/slides.js" type="text/javascript"></script> - <script type="text/javascript">/*<![CDATA[*/ - /* - LaTeXMathML.js from http://math.etsu.edu/LaTeXMathML/ - Adapted by Jeff Knisely and Douglas Woodall from ASCIIMathML.js v. 1.4.7, - (c) 2005 Peter Jipsen http://www.chapman.edu/~jipsen. - Released under the GNU General Public License version 2 or later. - See the GNU General Public License (at http://www.gnu.org/copyleft/gpl.html) - for more details. - */ - var checkForMathML=true;var notifyIfNoMathML=true;var alertIfNoMathML=false;var mathcolor="";var mathfontfamily="";var showasciiformulaonhover=true;var isIE=document.createElementNS==null;if(document.getElementById==null) - alert("This webpage requires a recent browser such as \nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer") - function AMcreateElementXHTML(t){if(isIE)return document.createElement(t);else return document.createElementNS("http://www.w3.org/1999/xhtml",t);} - function AMnoMathMLNote(){var nd=AMcreateElementXHTML("h3");nd.setAttribute("align","center") - nd.appendChild(AMcreateElementXHTML("p"));nd.appendChild(document.createTextNode("To view the "));var an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("LaTeXMathML"));an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html");nd.appendChild(an);nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+"));an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("MathPlayer"));an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");nd.appendChild(an);nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));nd.appendChild(AMcreateElementXHTML("p"));return nd;} - function AMisMathMLavailable(){if(navigator.appName.slice(0,8)=="Netscape") - if(navigator.appVersion.slice(0,1)>="5")return null;else return AMnoMathMLNote();else if(navigator.appName.slice(0,9)=="Microsoft") - try{var ActiveX=new ActiveXObject("MathPlayer.Factory.1");return null;}catch(e){return AMnoMathMLNote();} - else return AMnoMathMLNote();} - var AMcal=[0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46];var AMfrk=[0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128];var AMbbb=[0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124];var CONST=0,UNARY=1,BINARY=2,INFIX=3,LEFTBRACKET=4,RIGHTBRACKET=5,SPACE=6,UNDEROVER=7,DEFINITION=8,TEXT=9,BIG=10,LONG=11,STRETCHY=12,MATRIX=13;var AMsqrt={input:"\\sqrt",tag:"msqrt",output:"sqrt",ttype:UNARY},AMroot={input:"\\root",tag:"mroot",output:"root",ttype:BINARY},AMfrac={input:"\\frac",tag:"mfrac",output:"/",ttype:BINARY},AMover={input:"\\stackrel",tag:"mover",output:"stackrel",ttype:BINARY},AMatop={input:"\\atop",tag:"mfrac",output:"",ttype:INFIX},AMchoose={input:"\\choose",tag:"mfrac",output:"",ttype:INFIX},AMsub={input:"_",tag:"msub",output:"_",ttype:INFIX},AMsup={input:"^",tag:"msup",output:"^",ttype:INFIX},AMtext={input:"\\mathrm",tag:"mtext",output:"text",ttype:TEXT},AMmbox={input:"\\mbox",tag:"mtext",output:"mbox",ttype:TEXT};var AMsymbols=[{input:"\\alpha",tag:"mi",output:"\u03B1",ttype:CONST},{input:"\\beta",tag:"mi",output:"\u03B2",ttype:CONST},{input:"\\gamma",tag:"mi",output:"\u03B3",ttype:CONST},{input:"\\delta",tag:"mi",output:"\u03B4",ttype:CONST},{input:"\\epsilon",tag:"mi",output:"\u03B5",ttype:CONST},{input:"\\varepsilon",tag:"mi",output:"\u025B",ttype:CONST},{input:"\\zeta",tag:"mi",output:"\u03B6",ttype:CONST},{input:"\\eta",tag:"mi",output:"\u03B7",ttype:CONST},{input:"\\theta",tag:"mi",output:"\u03B8",ttype:CONST},{input:"\\vartheta",tag:"mi",output:"\u03D1",ttype:CONST},{input:"\\iota",tag:"mi",output:"\u03B9",ttype:CONST},{input:"\\kappa",tag:"mi",output:"\u03BA",ttype:CONST},{input:"\\lambda",tag:"mi",output:"\u03BB",ttype:CONST},{input:"\\mu",tag:"mi",output:"\u03BC",ttype:CONST},{input:"\\nu",tag:"mi",output:"\u03BD",ttype:CONST},{input:"\\xi",tag:"mi",output:"\u03BE",ttype:CONST},{input:"\\pi",tag:"mi",output:"\u03C0",ttype:CONST},{input:"\\varpi",tag:"mi",output:"\u03D6",ttype:CONST},{input:"\\rho",tag:"mi",output:"\u03C1",ttype:CONST},{input:"\\varrho",tag:"mi",output:"\u03F1",ttype:CONST},{input:"\\varsigma",tag:"mi",output:"\u03C2",ttype:CONST},{input:"\\sigma",tag:"mi",output:"\u03C3",ttype:CONST},{input:"\\tau",tag:"mi",output:"\u03C4",ttype:CONST},{input:"\\upsilon",tag:"mi",output:"\u03C5",ttype:CONST},{input:"\\phi",tag:"mi",output:"\u03C6",ttype:CONST},{input:"\\varphi",tag:"mi",output:"\u03D5",ttype:CONST},{input:"\\chi",tag:"mi",output:"\u03C7",ttype:CONST},{input:"\\psi",tag:"mi",output:"\u03C8",ttype:CONST},{input:"\\omega",tag:"mi",output:"\u03C9",ttype:CONST},{input:"\\Gamma",tag:"mo",output:"\u0393",ttype:CONST},{input:"\\Delta",tag:"mo",output:"\u0394",ttype:CONST},{input:"\\Theta",tag:"mo",output:"\u0398",ttype:CONST},{input:"\\Lambda",tag:"mo",output:"\u039B",ttype:CONST},{input:"\\Xi",tag:"mo",output:"\u039E",ttype:CONST},{input:"\\Pi",tag:"mo",output:"\u03A0",ttype:CONST},{input:"\\Sigma",tag:"mo",output:"\u03A3",ttype:CONST},{input:"\\Upsilon",tag:"mo",output:"\u03A5",ttype:CONST},{input:"\\Phi",tag:"mo",output:"\u03A6",ttype:CONST},{input:"\\Psi",tag:"mo",output:"\u03A8",ttype:CONST},{input:"\\Omega",tag:"mo",output:"\u03A9",ttype:CONST},{input:"\\frac12",tag:"mo",output:"\u00BD",ttype:CONST},{input:"\\frac14",tag:"mo",output:"\u00BC",ttype:CONST},{input:"\\frac34",tag:"mo",output:"\u00BE",ttype:CONST},{input:"\\frac13",tag:"mo",output:"\u2153",ttype:CONST},{input:"\\frac23",tag:"mo",output:"\u2154",ttype:CONST},{input:"\\frac15",tag:"mo",output:"\u2155",ttype:CONST},{input:"\\frac25",tag:"mo",output:"\u2156",ttype:CONST},{input:"\\frac35",tag:"mo",output:"\u2157",ttype:CONST},{input:"\\frac45",tag:"mo",output:"\u2158",ttype:CONST},{input:"\\frac16",tag:"mo",output:"\u2159",ttype:CONST},{input:"\\frac56",tag:"mo",output:"\u215A",ttype:CONST},{input:"\\frac18",tag:"mo",output:"\u215B",ttype:CONST},{input:"\\frac38",tag:"mo",output:"\u215C",ttype:CONST},{input:"\\frac58",tag:"mo",output:"\u215D",ttype:CONST},{input:"\\frac78",tag:"mo",output:"\u215E",ttype:CONST},{input:"\\pm",tag:"mo",output:"\u00B1",ttype:CONST},{input:"\\mp",tag:"mo",output:"\u2213",ttype:CONST},{input:"\\triangleleft",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\triangleright",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\cdot",tag:"mo",output:"\u22C5",ttype:CONST},{input:"\\star",tag:"mo",output:"\u22C6",ttype:CONST},{input:"\\ast",tag:"mo",output:"\u002A",ttype:CONST},{input:"\\times",tag:"mo",output:"\u00D7",ttype:CONST},{input:"\\div",tag:"mo",output:"\u00F7",ttype:CONST},{input:"\\circ",tag:"mo",output:"\u2218",ttype:CONST},{input:"\\bullet",tag:"mo",output:"\u2022",ttype:CONST},{input:"\\oplus",tag:"mo",output:"\u2295",ttype:CONST},{input:"\\ominus",tag:"mo",output:"\u2296",ttype:CONST},{input:"\\otimes",tag:"mo",output:"\u2297",ttype:CONST},{input:"\\bigcirc",tag:"mo",output:"\u25CB",ttype:CONST},{input:"\\oslash",tag:"mo",output:"\u2298",ttype:CONST},{input:"\\odot",tag:"mo",output:"\u2299",ttype:CONST},{input:"\\land",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\wedge",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\lor",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\vee",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\cap",tag:"mo",output:"\u2229",ttype:CONST},{input:"\\cup",tag:"mo",output:"\u222A",ttype:CONST},{input:"\\sqcap",tag:"mo",output:"\u2293",ttype:CONST},{input:"\\sqcup",tag:"mo",output:"\u2294",ttype:CONST},{input:"\\uplus",tag:"mo",output:"\u228E",ttype:CONST},{input:"\\amalg",tag:"mo",output:"\u2210",ttype:CONST},{input:"\\bigtriangleup",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\bigtriangledown",tag:"mo",output:"\u25BD",ttype:CONST},{input:"\\dag",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\dagger",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\ddag",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\ddagger",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\lhd",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\rhd",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\unlhd",tag:"mo",output:"\u22B4",ttype:CONST},{input:"\\unrhd",tag:"mo",output:"\u22B5",ttype:CONST},{input:"\\sum",tag:"mo",output:"\u2211",ttype:UNDEROVER},{input:"\\prod",tag:"mo",output:"\u220F",ttype:UNDEROVER},{input:"\\bigcap",tag:"mo",output:"\u22C2",ttype:UNDEROVER},{input:"\\bigcup",tag:"mo",output:"\u22C3",ttype:UNDEROVER},{input:"\\bigwedge",tag:"mo",output:"\u22C0",ttype:UNDEROVER},{input:"\\bigvee",tag:"mo",output:"\u22C1",ttype:UNDEROVER},{input:"\\bigsqcap",tag:"mo",output:"\u2A05",ttype:UNDEROVER},{input:"\\bigsqcup",tag:"mo",output:"\u2A06",ttype:UNDEROVER},{input:"\\coprod",tag:"mo",output:"\u2210",ttype:UNDEROVER},{input:"\\bigoplus",tag:"mo",output:"\u2A01",ttype:UNDEROVER},{input:"\\bigotimes",tag:"mo",output:"\u2A02",ttype:UNDEROVER},{input:"\\bigodot",tag:"mo",output:"\u2A00",ttype:UNDEROVER},{input:"\\biguplus",tag:"mo",output:"\u2A04",ttype:UNDEROVER},{input:"\\int",tag:"mo",output:"\u222B",ttype:CONST},{input:"\\oint",tag:"mo",output:"\u222E",ttype:CONST},{input:":=",tag:"mo",output:":=",ttype:CONST},{input:"\\lt",tag:"mo",output:"<",ttype:CONST},{input:"\\gt",tag:"mo",output:">",ttype:CONST},{input:"\\ne",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\neq",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\le",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leq",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leqslant",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\ge",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geq",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geqslant",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\equiv",tag:"mo",output:"\u2261",ttype:CONST},{input:"\\ll",tag:"mo",output:"\u226A",ttype:CONST},{input:"\\gg",tag:"mo",output:"\u226B",ttype:CONST},{input:"\\doteq",tag:"mo",output:"\u2250",ttype:CONST},{input:"\\prec",tag:"mo",output:"\u227A",ttype:CONST},{input:"\\succ",tag:"mo",output:"\u227B",ttype:CONST},{input:"\\preceq",tag:"mo",output:"\u227C",ttype:CONST},{input:"\\succeq",tag:"mo",output:"\u227D",ttype:CONST},{input:"\\subset",tag:"mo",output:"\u2282",ttype:CONST},{input:"\\supset",tag:"mo",output:"\u2283",ttype:CONST},{input:"\\subseteq",tag:"mo",output:"\u2286",ttype:CONST},{input:"\\supseteq",tag:"mo",output:"\u2287",ttype:CONST},{input:"\\sqsubset",tag:"mo",output:"\u228F",ttype:CONST},{input:"\\sqsupset",tag:"mo",output:"\u2290",ttype:CONST},{input:"\\sqsubseteq",tag:"mo",output:"\u2291",ttype:CONST},{input:"\\sqsupseteq",tag:"mo",output:"\u2292",ttype:CONST},{input:"\\sim",tag:"mo",output:"\u223C",ttype:CONST},{input:"\\simeq",tag:"mo",output:"\u2243",ttype:CONST},{input:"\\approx",tag:"mo",output:"\u2248",ttype:CONST},{input:"\\cong",tag:"mo",output:"\u2245",ttype:CONST},{input:"\\Join",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\bowtie",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\in",tag:"mo",output:"\u2208",ttype:CONST},{input:"\\ni",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\owns",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\propto",tag:"mo",output:"\u221D",ttype:CONST},{input:"\\vdash",tag:"mo",output:"\u22A2",ttype:CONST},{input:"\\dashv",tag:"mo",output:"\u22A3",ttype:CONST},{input:"\\models",tag:"mo",output:"\u22A8",ttype:CONST},{input:"\\perp",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\smile",tag:"mo",output:"\u2323",ttype:CONST},{input:"\\frown",tag:"mo",output:"\u2322",ttype:CONST},{input:"\\asymp",tag:"mo",output:"\u224D",ttype:CONST},{input:"\\notin",tag:"mo",output:"\u2209",ttype:CONST},{input:"\\begin{eqnarray}",output:"X",ttype:MATRIX,invisible:true},{input:"\\begin{array}",output:"X",ttype:MATRIX,invisible:true},{input:"\\\\",output:"}&{",ttype:DEFINITION},{input:"\\end{eqnarray}",output:"}}",ttype:DEFINITION},{input:"\\end{array}",output:"}}",ttype:DEFINITION},{input:"\\big",tag:"mo",output:"X",atval:"1.2",ieval:"2.2",ttype:BIG},{input:"\\Big",tag:"mo",output:"X",atval:"1.6",ieval:"2.6",ttype:BIG},{input:"\\bigg",tag:"mo",output:"X",atval:"2.2",ieval:"3.2",ttype:BIG},{input:"\\Bigg",tag:"mo",output:"X",atval:"2.9",ieval:"3.9",ttype:BIG},{input:"\\left",tag:"mo",output:"X",ttype:LEFTBRACKET},{input:"\\right",tag:"mo",output:"X",ttype:RIGHTBRACKET},{input:"{",output:"{",ttype:LEFTBRACKET,invisible:true},{input:"}",output:"}",ttype:RIGHTBRACKET,invisible:true},{input:"(",tag:"mo",output:"(",atval:"1",ttype:STRETCHY},{input:"[",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\lbrack",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\{",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\lbrace",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\langle",tag:"mo",output:"\u2329",atval:"1",ttype:STRETCHY},{input:"\\lfloor",tag:"mo",output:"\u230A",atval:"1",ttype:STRETCHY},{input:"\\lceil",tag:"mo",output:"\u2308",atval:"1",ttype:STRETCHY},{input:")",tag:"mo",output:")",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"]",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrack",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\}",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrace",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rangle",tag:"mo",output:"\u232A",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rfloor",tag:"mo",output:"\u230B",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rceil",tag:"mo",output:"\u2309",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"|",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\|",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\vert",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\Vert",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\mid",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\parallel",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"/",tag:"mo",output:"/",atval:"1.01",ttype:STRETCHY},{input:"\\backslash",tag:"mo",output:"\u2216",atval:"1",ttype:STRETCHY},{input:"\\setminus",tag:"mo",output:"\\",ttype:CONST},{input:"\\!",tag:"mspace",atname:"width",atval:"-0.167em",ttype:SPACE},{input:"\\,",tag:"mspace",atname:"width",atval:"0.167em",ttype:SPACE},{input:"\\>",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\:",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\;",tag:"mspace",atname:"width",atval:"0.278em",ttype:SPACE},{input:"~",tag:"mspace",atname:"width",atval:"0.333em",ttype:SPACE},{input:"\\quad",tag:"mspace",atname:"width",atval:"1em",ttype:SPACE},{input:"\\qquad",tag:"mspace",atname:"width",atval:"2em",ttype:SPACE},{input:"\\prime",tag:"mo",output:"\u2032",ttype:CONST},{input:"'",tag:"mo",output:"\u02B9",ttype:CONST},{input:"''",tag:"mo",output:"\u02BA",ttype:CONST},{input:"'''",tag:"mo",output:"\u2034",ttype:CONST},{input:"''''",tag:"mo",output:"\u2057",ttype:CONST},{input:"\\ldots",tag:"mo",output:"\u2026",ttype:CONST},{input:"\\cdots",tag:"mo",output:"\u22EF",ttype:CONST},{input:"\\vdots",tag:"mo",output:"\u22EE",ttype:CONST},{input:"\\ddots",tag:"mo",output:"\u22F1",ttype:CONST},{input:"\\forall",tag:"mo",output:"\u2200",ttype:CONST},{input:"\\exists",tag:"mo",output:"\u2203",ttype:CONST},{input:"\\Re",tag:"mo",output:"\u211C",ttype:CONST},{input:"\\Im",tag:"mo",output:"\u2111",ttype:CONST},{input:"\\aleph",tag:"mo",output:"\u2135",ttype:CONST},{input:"\\hbar",tag:"mo",output:"\u210F",ttype:CONST},{input:"\\ell",tag:"mo",output:"\u2113",ttype:CONST},{input:"\\wp",tag:"mo",output:"\u2118",ttype:CONST},{input:"\\emptyset",tag:"mo",output:"\u2205",ttype:CONST},{input:"\\infty",tag:"mo",output:"\u221E",ttype:CONST},{input:"\\surd",tag:"mo",output:"\\sqrt{}",ttype:DEFINITION},{input:"\\partial",tag:"mo",output:"\u2202",ttype:CONST},{input:"\\nabla",tag:"mo",output:"\u2207",ttype:CONST},{input:"\\triangle",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\therefore",tag:"mo",output:"\u2234",ttype:CONST},{input:"\\angle",tag:"mo",output:"\u2220",ttype:CONST},{input:"\\diamond",tag:"mo",output:"\u22C4",ttype:CONST},{input:"\\Diamond",tag:"mo",output:"\u25C7",ttype:CONST},{input:"\\neg",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\lnot",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\bot",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\top",tag:"mo",output:"\u22A4",ttype:CONST},{input:"\\square",tag:"mo",output:"\u25AB",ttype:CONST},{input:"\\Box",tag:"mo",output:"\u25A1",ttype:CONST},{input:"\\wr",tag:"mo",output:"\u2240",ttype:CONST},{input:"\\arccos",tag:"mi",output:"arccos",ttype:UNARY,func:true},{input:"\\arcsin",tag:"mi",output:"arcsin",ttype:UNARY,func:true},{input:"\\arctan",tag:"mi",output:"arctan",ttype:UNARY,func:true},{input:"\\arg",tag:"mi",output:"arg",ttype:UNARY,func:true},{input:"\\cos",tag:"mi",output:"cos",ttype:UNARY,func:true},{input:"\\cosh",tag:"mi",output:"cosh",ttype:UNARY,func:true},{input:"\\cot",tag:"mi",output:"cot",ttype:UNARY,func:true},{input:"\\coth",tag:"mi",output:"coth",ttype:UNARY,func:true},{input:"\\csc",tag:"mi",output:"csc",ttype:UNARY,func:true},{input:"\\deg",tag:"mi",output:"deg",ttype:UNARY,func:true},{input:"\\det",tag:"mi",output:"det",ttype:UNARY,func:true},{input:"\\dim",tag:"mi",output:"dim",ttype:UNARY,func:true},{input:"\\exp",tag:"mi",output:"exp",ttype:UNARY,func:true},{input:"\\gcd",tag:"mi",output:"gcd",ttype:UNARY,func:true},{input:"\\hom",tag:"mi",output:"hom",ttype:UNARY,func:true},{input:"\\inf",tag:"mo",output:"inf",ttype:UNDEROVER},{input:"\\ker",tag:"mi",output:"ker",ttype:UNARY,func:true},{input:"\\lg",tag:"mi",output:"lg",ttype:UNARY,func:true},{input:"\\lim",tag:"mo",output:"lim",ttype:UNDEROVER},{input:"\\liminf",tag:"mo",output:"liminf",ttype:UNDEROVER},{input:"\\limsup",tag:"mo",output:"limsup",ttype:UNDEROVER},{input:"\\ln",tag:"mi",output:"ln",ttype:UNARY,func:true},{input:"\\log",tag:"mi",output:"log",ttype:UNARY,func:true},{input:"\\max",tag:"mo",output:"max",ttype:UNDEROVER},{input:"\\min",tag:"mo",output:"min",ttype:UNDEROVER},{input:"\\Pr",tag:"mi",output:"Pr",ttype:UNARY,func:true},{input:"\\sec",tag:"mi",output:"sec",ttype:UNARY,func:true},{input:"\\sin",tag:"mi",output:"sin",ttype:UNARY,func:true},{input:"\\sinh",tag:"mi",output:"sinh",ttype:UNARY,func:true},{input:"\\sup",tag:"mo",output:"sup",ttype:UNDEROVER},{input:"\\tan",tag:"mi",output:"tan",ttype:UNARY,func:true},{input:"\\tanh",tag:"mi",output:"tanh",ttype:UNARY,func:true},{input:"\\gets",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\leftarrow",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\to",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\rightarrow",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\leftrightarrow",tag:"mo",output:"\u2194",ttype:CONST},{input:"\\uparrow",tag:"mo",output:"\u2191",ttype:CONST},{input:"\\downarrow",tag:"mo",output:"\u2193",ttype:CONST},{input:"\\updownarrow",tag:"mo",output:"\u2195",ttype:CONST},{input:"\\Leftarrow",tag:"mo",output:"\u21D0",ttype:CONST},{input:"\\Rightarrow",tag:"mo",output:"\u21D2",ttype:CONST},{input:"\\Leftrightarrow",tag:"mo",output:"\u21D4",ttype:CONST},{input:"\\iff",tag:"mo",output:"~\\Longleftrightarrow~",ttype:DEFINITION},{input:"\\Uparrow",tag:"mo",output:"\u21D1",ttype:CONST},{input:"\\Downarrow",tag:"mo",output:"\u21D3",ttype:CONST},{input:"\\Updownarrow",tag:"mo",output:"\u21D5",ttype:CONST},{input:"\\mapsto",tag:"mo",output:"\u21A6",ttype:CONST},{input:"\\longleftarrow",tag:"mo",output:"\u2190",ttype:LONG},{input:"\\longrightarrow",tag:"mo",output:"\u2192",ttype:LONG},{input:"\\longleftrightarrow",tag:"mo",output:"\u2194",ttype:LONG},{input:"\\Longleftarrow",tag:"mo",output:"\u21D0",ttype:LONG},{input:"\\Longrightarrow",tag:"mo",output:"\u21D2",ttype:LONG},{input:"\\Longleftrightarrow",tag:"mo",output:"\u21D4",ttype:LONG},{input:"\\longmapsto",tag:"mo",output:"\u21A6",ttype:CONST},AMsqrt,AMroot,AMfrac,AMover,AMsub,AMsup,AMtext,AMmbox,AMatop,AMchoose,{input:"\\acute",tag:"mover",output:"\u00B4",ttype:UNARY,acc:true},{input:"\\grave",tag:"mover",output:"\u0060",ttype:UNARY,acc:true},{input:"\\breve",tag:"mover",output:"\u02D8",ttype:UNARY,acc:true},{input:"\\check",tag:"mover",output:"\u02C7",ttype:UNARY,acc:true},{input:"\\dot",tag:"mover",output:".",ttype:UNARY,acc:true},{input:"\\ddot",tag:"mover",output:"..",ttype:UNARY,acc:true},{input:"\\mathring",tag:"mover",output:"\u00B0",ttype:UNARY,acc:true},{input:"\\vec",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overrightarrow",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overleftarrow",tag:"mover",output:"\u20D6",ttype:UNARY,acc:true},{input:"\\hat",tag:"mover",output:"\u005E",ttype:UNARY,acc:true},{input:"\\widehat",tag:"mover",output:"\u0302",ttype:UNARY,acc:true},{input:"\\tilde",tag:"mover",output:"~",ttype:UNARY,acc:true},{input:"\\widetilde",tag:"mover",output:"\u02DC",ttype:UNARY,acc:true},{input:"\\bar",tag:"mover",output:"\u203E",ttype:UNARY,acc:true},{input:"\\overbrace",tag:"mover",output:"\uFE37",ttype:UNARY,acc:true},{input:"\\overbracket",tag:"mover",output:"\u23B4",ttype:UNARY,acc:true},{input:"\\overline",tag:"mover",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\underbrace",tag:"munder",output:"\uFE38",ttype:UNARY,acc:true},{input:"\\underbracket",tag:"munder",output:"\u23B5",ttype:UNARY,acc:true},{input:"\\underline",tag:"munder",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true",ttype:UNARY},{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false",ttype:UNARY},{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1",ttype:UNARY},{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2",ttype:UNARY},{input:"\\textrm",tag:"mstyle",output:"\\mathrm",ttype:DEFINITION},{input:"\\mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\textbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\mathit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\textit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\texttt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",ttype:UNARY},{input:"\\mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",ttype:UNARY,codes:AMbbb},{input:"\\mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",ttype:UNARY,codes:AMcal},{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",ttype:UNARY,codes:AMfrk},{input:"\\textcolor",tag:"mstyle",atname:"mathvariant",atval:"mathcolor",ttype:BINARY},{input:"\\colorbox",tag:"mstyle",atname:"mathvariant",atval:"background",ttype:BINARY}];function compareNames(s1,s2){if(s1.input>s2.input)return 1 - else return-1;} - var AMnames=[];function AMinitSymbols(){AMsymbols.sort(compareNames);for(i=0;i<AMsymbols.length;i++)AMnames[i]=AMsymbols[i].input;} - var AMmathml="http://www.w3.org/1998/Math/MathML";function AMcreateElementMathML(t){if(isIE)return document.createElement("m:"+t);else return document.createElementNS(AMmathml,t);} - function AMcreateMmlNode(t,frag){if(isIE)var node=document.createElement("m:"+t);else var node=document.createElementNS(AMmathml,t);node.appendChild(frag);return node;} - function newcommand(oldstr,newstr){AMsymbols=AMsymbols.concat([{input:oldstr,tag:"mo",output:newstr,ttype:DEFINITION}]);} - function AMremoveCharsAndBlanks(str,n){var st;st=str.slice(n);for(var i=0;i<st.length&&st.charCodeAt(i)<=32;i=i+1);return st.slice(i);} - function AMposition(arr,str,n){if(n==0){var h,m;n=-1;h=arr.length;while(n+1<h){m=(n+h)>>1;if(arr[m]<str)n=m;else h=m;} - return h;}else - for(var i=n;i<arr.length&&arr[i]<str;i++);return i;} - function AMgetSymbol(str){var k=0;var j=0;var mk;var st;var tagst;var match="";var more=true;for(var i=1;i<=str.length&&more;i++){st=str.slice(0,i);j=k;k=AMposition(AMnames,st,j);if(k<AMnames.length&&str.slice(0,AMnames[k].length)==AMnames[k]){match=AMnames[k];mk=k;i=match.length;} - more=k<AMnames.length&&str.slice(0,AMnames[k].length)>=AMnames[k];} - AMpreviousSymbol=AMcurrentSymbol;if(match!=""){AMcurrentSymbol=AMsymbols[mk].ttype;return AMsymbols[mk];} - AMcurrentSymbol=CONST;k=1;st=str.slice(0,1);if("0"<=st&&st<="9")tagst="mn";else tagst=(("A">st||st>"Z")&&("a">st||st>"z")?"mo":"mi");return{input:st,tag:tagst,output:st,ttype:CONST};} - var AMpreviousSymbol,AMcurrentSymbol;function AMparseSexpr(str){var symbol,node,result,result2,i,st,newFrag=document.createDocumentFragment();str=AMremoveCharsAndBlanks(str,0);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET) - return[null,str,null];if(symbol.ttype==DEFINITION){str=symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET) - return[null,str,null];} - str=AMremoveCharsAndBlanks(str,symbol.input.length);switch(symbol.ttype){case SPACE:node=AMcreateElementMathML(symbol.tag);node.setAttribute(symbol.atname,symbol.atval);return[node,str,symbol.tag];case UNDEROVER:if(isIE){if(symbol.input.substr(0,4)=="\\big"){str="\\"+symbol.input.substr(4)+str;symbol=AMgetSymbol(str);symbol.ttype=UNDEROVER;str=AMremoveCharsAndBlanks(str,symbol.input.length);}} - return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];case CONST:var output=symbol.output;if(isIE){if(symbol.input=="'") - output="\u2032";else if(symbol.input=="''") - output="\u2033";else if(symbol.input=="'''") - output="\u2033\u2032";else if(symbol.input=="''''") - output="\u2033\u2033";else if(symbol.input=="\\square") - output="\u25A1";else if(symbol.input.substr(0,5)=="\\frac"){var denom=symbol.input.substr(6,1);if(denom=="5"||denom=="6"){str=symbol.input.replace(/\\frac/,"\\frac ")+str;return[node,str,symbol.tag];}}} - node=AMcreateMmlNode(symbol.tag,document.createTextNode(output));return[node,str,symbol.tag];case LONG:node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));node.setAttribute("minsize","1.5");node.setAttribute("maxsize","1.5");node=AMcreateMmlNode("mover",node);node.appendChild(AMcreateElementMathML("mspace"));return[node,str,symbol.tag];case STRETCHY:if(isIE&&symbol.input=="\\backslash") - symbol.output="\\";node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(symbol.input=="|"||symbol.input=="\\vert"||symbol.input=="\\|"||symbol.input=="\\Vert"){node.setAttribute("lspace","0em");node.setAttribute("rspace","0em");} - node.setAttribute("maxsize",symbol.atval);if(symbol.rtag!=null) - return[node,str,symbol.rtag];else - return[node,str,symbol.tag];case BIG:var atval=symbol.atval;if(isIE) - atval=symbol.ieval;symbol=AMgetSymbol(str);if(symbol==null) - return[null,str,null];str=AMremoveCharsAndBlanks(str,symbol.input.length);node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height",atval+"ex");node=AMcreateMmlNode("mrow",node);node.appendChild(space);}else{node.setAttribute("minsize",atval);node.setAttribute("maxsize",atval);} - return[node,str,symbol.tag];case LEFTBRACKET:if(symbol.input=="\\left"){symbol=AMgetSymbol(str);if(symbol!=null){if(symbol.input==".") - symbol.invisible=true;str=AMremoveCharsAndBlanks(str,symbol.input.length);}} - result=AMparseExpr(str,true,false);if(symbol==null||(typeof symbol.invisible=="boolean"&&symbol.invisible)) - node=AMcreateMmlNode("mrow",result[0]);else{node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));node=AMcreateMmlNode("mrow",node);node.appendChild(result[0]);} - return[node,result[1],result[2]];case MATRIX:if(symbol.input=="\\begin{array}"){var mask="";symbol=AMgetSymbol(str);str=AMremoveCharsAndBlanks(str,0);if(symbol==null) - mask="l";else{str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="{") - mask="l";else do{symbol=AMgetSymbol(str);if(symbol!=null){str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="}") - mask=mask+symbol.input;}}while(symbol!=null&&symbol.input!=""&&symbol.input!="}");} - result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);mask=mask.replace(/l/g,"left ");mask=mask.replace(/r/g,"right ");mask=mask.replace(/c/g,"center ");node.setAttribute("columnalign",mask);node.setAttribute("displaystyle","false");if(isIE) - return[node,result[1],null];var lspace=AMcreateElementMathML("mspace");lspace.setAttribute("width","0.167em");var rspace=AMcreateElementMathML("mspace");rspace.setAttribute("width","0.167em");var node1=AMcreateMmlNode("mrow",lspace);node1.appendChild(node);node1.appendChild(rspace);return[node1,result[1],null];}else{result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);if(isIE) - node.setAttribute("columnspacing","0.25em");else - node.setAttribute("columnspacing","0.167em");node.setAttribute("columnalign","right center left");node.setAttribute("displaystyle","true");node=AMcreateMmlNode("mrow",node);return[node,result[1],null];} - case TEXT:if(str.charAt(0)=="{")i=str.indexOf("}");else i=0;if(i==-1) - i=str.length;st=str.slice(1,i);if(st.charAt(0)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);} - newFrag.appendChild(AMcreateMmlNode(symbol.tag,document.createTextNode(st)));if(st.charAt(st.length-1)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);} - str=AMremoveCharsAndBlanks(str,i+1);return[AMcreateMmlNode("mrow",newFrag),str,null];case UNARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str];if(typeof symbol.func=="boolean"&&symbol.func){st=str.charAt(0);if(st=="^"||st=="_"||st==","){return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}else{node=AMcreateMmlNode("mrow",AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node.appendChild(space);} - node.appendChild(result[0]);return[node,result[1],symbol.tag];}} - if(symbol.input=="\\sqrt"){if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height","1.2ex");space.setAttribute("width","0em");node=AMcreateMmlNode(symbol.tag,result[0]) - node.appendChild(space);return[node,result[1],symbol.tag];}else - return[AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];}else if(typeof symbol.acc=="boolean"&&symbol.acc){node=AMcreateMmlNode(symbol.tag,result[0]);var output=symbol.output;if(isIE){if(symbol.input=="\\hat") - output="\u0302";else if(symbol.input=="\\widehat") - output="\u005E";else if(symbol.input=="\\bar") - output="\u00AF";else if(symbol.input=="\\grave") - output="\u0300";else if(symbol.input=="\\tilde") - output="\u0303";} - var node1=AMcreateMmlNode("mo",document.createTextNode(output));if(symbol.input=="\\vec"||symbol.input=="\\check") - node1.setAttribute("maxsize","1.2");if(isIE&&symbol.input=="\\bar") - node1.setAttribute("maxsize","0.5");if(symbol.input=="\\underbrace"||symbol.input=="\\underline") - node1.setAttribute("accentunder","true");else - node1.setAttribute("accent","true");node.appendChild(node1);if(symbol.input=="\\overbrace"||symbol.input=="\\underbrace") - node.ttype=UNDEROVER;return[node,result[1],symbol.tag];}else{if(!isIE&&typeof symbol.codes!="undefined"){for(i=0;i<result[0].childNodes.length;i++) - if(result[0].childNodes[i].nodeName=="mi"||result[0].nodeName=="mi"){st=(result[0].nodeName=="mi"?result[0].firstChild.nodeValue:result[0].childNodes[i].firstChild.nodeValue);var newst=[];for(var j=0;j<st.length;j++) - if(st.charCodeAt(j)>64&&st.charCodeAt(j)<91)newst=newst+ - String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);else newst=newst+st.charAt(j);if(result[0].nodeName=="mi") - result[0]=AMcreateElementMathML("mo").appendChild(document.createTextNode(newst));else result[0].replaceChild(AMcreateElementMathML("mo").appendChild(document.createTextNode(newst)),result[0].childNodes[i]);}} - node=AMcreateMmlNode(symbol.tag,result[0]);node.setAttribute(symbol.atname,symbol.atval);if(symbol.input=="\\scriptstyle"||symbol.input=="\\scriptscriptstyle") - node.setAttribute("displaystyle","false");return[node,result[1],symbol.tag];} - case BINARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];result2=AMparseSexpr(result[1]);if(result2[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];if(symbol.input=="\\textcolor"||symbol.input=="\\colorbox"){var tclr=str.match(/\{\s*([#\w]+)\s*\}/);str=str.replace(/\{\s*[#\w]+\s*\}/,"");if(tclr!=null){if(IsColorName.test(tclr[1].toLowerCase())){tclr=LaTeXColor[tclr[1].toLowerCase()];}else{tclr=tclr[1];} - node=AMcreateElementMathML("mstyle");node.setAttribute(symbol.atval,tclr);node.appendChild(result2[0]);return[node,result2[1],symbol.tag];}} - if(symbol.input=="\\root"||symbol.input=="\\stackrel")newFrag.appendChild(result2[0]);newFrag.appendChild(result[0]);if(symbol.input=="\\frac")newFrag.appendChild(result2[0]);return[AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];case INFIX:str=AMremoveCharsAndBlanks(str,symbol.input.length);return[AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str,symbol.tag];default:return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}} - function AMparseIexpr(str){var symbol,sym1,sym2,node,result,tag,underover;str=AMremoveCharsAndBlanks(str,0);sym1=AMgetSymbol(str);result=AMparseSexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(symbol.ttype==INFIX){str=AMremoveCharsAndBlanks(str,symbol.input.length);result=AMparseSexpr(str);if(result[0]==null) - result[0]=AMcreateMmlNode("mo",document.createTextNode("\u25A1"));str=result[1];tag=result[2];if(symbol.input=="_"||symbol.input=="^"){sym2=AMgetSymbol(str);tag=null;underover=((sym1.ttype==UNDEROVER)||(node.ttype==UNDEROVER));if(symbol.input=="_"&&sym2.input=="^"){str=AMremoveCharsAndBlanks(str,sym2.input.length);var res2=AMparseSexpr(str);str=res2[1];tag=res2[2];node=AMcreateMmlNode((underover?"munderover":"msubsup"),node);node.appendChild(result[0]);node.appendChild(res2[0]);}else if(symbol.input=="_"){node=AMcreateMmlNode((underover?"munder":"msub"),node);node.appendChild(result[0]);}else{node=AMcreateMmlNode((underover?"mover":"msup"),node);node.appendChild(result[0]);} - node=AMcreateMmlNode("mrow",node);}else{node=AMcreateMmlNode(symbol.tag,node);if(symbol.input=="\\atop"||symbol.input=="\\choose") - node.setAttribute("linethickness","0ex");node.appendChild(result[0]);if(symbol.input=="\\choose") - node=AMcreateMmlNode("mfenced",node);}} - return[node,str,tag];} - function AMparseExpr(str,rightbracket,matrix){var symbol,node,result,i,tag,newFrag=document.createDocumentFragment();do{str=AMremoveCharsAndBlanks(str,0);result=AMparseIexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(node!=undefined){if((tag=="mn"||tag=="mi")&&symbol!=null&&typeof symbol.func=="boolean"&&symbol.func){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node=AMcreateMmlNode("mrow",node);node.appendChild(space);} - newFrag.appendChild(node);}}while((symbol.ttype!=RIGHTBRACKET)&&symbol!=null&&symbol.output!="");tag=null;if(symbol.ttype==RIGHTBRACKET){if(symbol.input=="\\right"){str=AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol!=null&&symbol.input==".") - symbol.invisible=true;if(symbol!=null) - tag=symbol.rtag;} - if(symbol!=null) - str=AMremoveCharsAndBlanks(str,symbol.input.length);var len=newFrag.childNodes.length;if(matrix&&len>0&&newFrag.childNodes[len-1].nodeName=="mrow"&&len>1&&newFrag.childNodes[len-2].nodeName=="mo"&&newFrag.childNodes[len-2].firstChild.nodeValue=="&"){var pos=[];var m=newFrag.childNodes.length;for(i=0;matrix&&i<m;i=i+2){pos[i]=[];node=newFrag.childNodes[i];for(var j=0;j<node.childNodes.length;j++) - if(node.childNodes[j].firstChild.nodeValue=="&") - pos[i][pos[i].length]=j;} - var row,frag,n,k,table=document.createDocumentFragment();for(i=0;i<m;i=i+2){row=document.createDocumentFragment();frag=document.createDocumentFragment();node=newFrag.firstChild;n=node.childNodes.length;k=0;for(j=0;j<n;j++){if(typeof pos[i][k]!="undefined"&&j==pos[i][k]){node.removeChild(node.firstChild);row.appendChild(AMcreateMmlNode("mtd",frag));k++;}else frag.appendChild(node.firstChild);} - row.appendChild(AMcreateMmlNode("mtd",frag));if(newFrag.childNodes.length>2){newFrag.removeChild(newFrag.firstChild);newFrag.removeChild(newFrag.firstChild);} - table.appendChild(AMcreateMmlNode("mtr",row));} - return[table,str];} - if(typeof symbol.invisible!="boolean"||!symbol.invisible){node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));newFrag.appendChild(node);}} - return[newFrag,str,tag];} - function AMparseMath(str){var result,node=AMcreateElementMathML("mstyle");var cclr=str.match(/\\color\s*\{\s*([#\w]+)\s*\}/);str=str.replace(/\\color\s*\{\s*[#\w]+\s*\}/g,"");if(cclr!=null){if(IsColorName.test(cclr[1].toLowerCase())){cclr=LaTeXColor[cclr[1].toLowerCase()];}else{cclr=cclr[1];} - node.setAttribute("mathcolor",cclr);}else{if(mathcolor!="")node.setAttribute("mathcolor",mathcolor);};if(mathfontfamily!="")node.setAttribute("fontfamily",mathfontfamily);node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);node=AMcreateMmlNode("math",node);if(showasciiformulaonhover) - node.setAttribute("title",str.replace(/\s+/g," "));if(false){var fnode=AMcreateElementXHTML("font");fnode.setAttribute("face",mathfontfamily);fnode.appendChild(node);return fnode;} - return node;} - function AMstrarr2docFrag(arr,linebreaks){var newFrag=document.createDocumentFragment();var expr=false;for(var i=0;i<arr.length;i++){if(expr)newFrag.appendChild(AMparseMath(arr[i]));else{var arri=(linebreaks?arr[i].split("\n\n"):[arr[i]]);newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[0])));for(var j=1;j<arri.length;j++){newFrag.appendChild(AMcreateElementXHTML("p"));newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[j])));}} - expr=!expr;} - return newFrag;} - function AMprocessNodeR(n,linebreaks){var mtch,str,arr,frg,i;if(n.childNodes.length==0){if((n.nodeType!=8||linebreaks)&&n.parentNode.nodeName!="form"&&n.parentNode.nodeName!="FORM"&&n.parentNode.nodeName!="textarea"&&n.parentNode.nodeName!="TEXTAREA"&&n.parentNode.nodeName!="pre"&&n.parentNode.nodeName!="PRE"){str=n.nodeValue;if(!(str==null)){str=str.replace(/\r\n\r\n/g,"\n\n");str=str.replace(/\x20+/g," ");str=str.replace(/\s*\r\n/g," ");mtch=(str.indexOf("\$")==-1?false:true);str=str.replace(/([^\\])\$/g,"$1 \$");str=str.replace(/^\$/," \$");arr=str.split(" \$");for(i=0;i<arr.length;i++) - arr[i]=arr[i].replace(/\\\$/g,"\$");if(arr.length>1||mtch){if(checkForMathML){checkForMathML=false;var nd=AMisMathMLavailable();AMnoMathML=nd!=null;if(AMnoMathML&¬ifyIfNoMathML) - if(alertIfNoMathML) - alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\nor Firefox/Mozilla/Netscape");else AMbody.insertBefore(nd,AMbody.childNodes[0]);} - if(!AMnoMathML){frg=AMstrarr2docFrag(arr,n.nodeType==8);var len=frg.childNodes.length;n.parentNode.replaceChild(frg,n);return len-1;}else return 0;}}}else return 0;}else if(n.nodeName!="math"){for(i=0;i<n.childNodes.length;i++) - i+=AMprocessNodeR(n.childNodes[i],linebreaks);} - return 0;} - function AMprocessNode(n,linebreaks,spanclassAM){var frag,st;if(spanclassAM!=null){frag=document.getElementsByTagName("span") - for(var i=0;i<frag.length;i++) - if(frag[i].className=="AM") - AMprocessNodeR(frag[i],linebreaks);}else{try{st=n.innerHTML;}catch(err){} - if(st==null||st.indexOf("\$")!=-1) - AMprocessNodeR(n,linebreaks);} - if(isIE){frag=document.getElementsByTagName('math');for(var i=0;i<frag.length;i++)frag[i].update()}} - var inAppendix=false;var sectionCntr=0;var IEcommentWarning=true;var biblist=[];var bibcntr=0;var LaTeXCounter=[];LaTeXCounter["definition"]=0;LaTeXCounter["proposition"]=0;LaTeXCounter["lemma"]=0;LaTeXCounter["theorem"]=0;LaTeXCounter["corollary"]=0;LaTeXCounter["example"]=0;LaTeXCounter["exercise"]=0;LaTeXCounter["subsection"]=0;LaTeXCounter["subsubsection"]=0;LaTeXCounter["figure"]=0;LaTeXCounter["equation"]=0;LaTeXCounter["table"]=0;var LaTeXColor=[];LaTeXColor["greenyellow"]="#D9FF4F";LaTeXColor["yellow"]="#FFFF00";LaTeXColor["goldenrod"]="#FFE529";LaTeXColor["dandelion"]="#FFB529";LaTeXColor["apricot"]="#FFAD7A";LaTeXColor["peach"]="#FF804D";LaTeXColor["melon"]="#FF8A80";LaTeXColor["yelloworange"]="#FF9400";LaTeXColor["orange"]="#FF6321";LaTeXColor["burntorange"]="#FF7D00";LaTeXColor["bittersweet"]="#C20300";LaTeXColor["redorange"]="#FF3B21";LaTeXColor["mahogany"]="#A60000";LaTeXColor["maroon"]="#AD0000";LaTeXColor["brickred"]="#B80000";LaTeXColor["red"]="#FF0000";LaTeXColor["orangered"]="#FF0080";LaTeXColor["rubinered"]="#FF00DE";LaTeXColor["wildstrawberry"]="#FF0A9C";LaTeXColor["salmon"]="#FF789E";LaTeXColor["carnationpink"]="#FF5EFF";LaTeXColor["magenta"]="#FF00FF";LaTeXColor["violetred"]="#FF30FF";LaTeXColor["rhodamine"]="#FF2EFF";LaTeXColor["mulberry"]="#A314FA";LaTeXColor["redviolet"]="#9600A8";LaTeXColor["fuchsia"]="#7303EB";LaTeXColor["lavender"]="#FF85FF";LaTeXColor["thistle"]="#E069FF";LaTeXColor["orchid"]="#AD5CFF";LaTeXColor["darkorchid"]="#9933CC";LaTeXColor["purple"]="#8C24FF";LaTeXColor["plum"]="#8000FF";LaTeXColor["violet"]="#361FFF";LaTeXColor["royalpurple"]="#401AFF";LaTeXColor["blueviolet"]="#1A0DF5";LaTeXColor["periwinkle"]="#6E73FF";LaTeXColor["cadetblue"]="#616EC4";LaTeXColor["cornflowerblue"]="#59DEFF";LaTeXColor["midnightblue"]="#007091";LaTeXColor["navyblue"]="#0F75FF";LaTeXColor["royalblue"]="#0080FF";LaTeXColor["blue"]="#0000FF";LaTeXColor["cerulean"]="#0FE3FF";LaTeXColor["cyan"]="#00FFFF";LaTeXColor["processblue"]="#0AFFFF";LaTeXColor["skyblue"]="#61FFE0";LaTeXColor["turquoise"]="#26FFCC";LaTeXColor["tealblue"]="#1FFAA3";LaTeXColor["aquamarine"]="#2EFFB2";LaTeXColor["bluegreen"]="#26FFAB";LaTeXColor["emerald"]="#00FF80";LaTeXColor["junglegreen"]="#03FF7A";LaTeXColor["seagreen"]="#4FFF80";LaTeXColor["green"]="#00FF00";LaTeXColor["forestgreen"]="#00E000";LaTeXColor["pinegreen"]="#00BF29";LaTeXColor["limegreen"]="#80FF00";LaTeXColor["yellowgreen"]="#8FFF42";LaTeXColor["springgreen"]="#BDFF3D";LaTeXColor["olivegreen"]="#009900";LaTeXColor["rawsienna"]="#8C0000";LaTeXColor["sepia"]="#4D0000";LaTeXColor["brown"]="#660000";LaTeXColor["tan"]="#DB9470";LaTeXColor["gray"]="#808080";LaTeXColor["grey"]="#808080";LaTeXColor["black"]="#000000";LaTeXColor["white"]="#FFFFFF";var IsColorName=/^(?:greenyellow|yellow|goldenrod|dandelion|apricot|peach|melon|yelloworange|orange|burntorange|bittersweet|redorange|mahogany|maroon|brickred|red|orangered|rubinered|wildstrawberry|salmon|carnationpink|magenta|violetred|rhodamine|mulberry|redviolet|fuchsia|lavender|thistle|orchid|darkorchid|purple|plum|violet|royalpurple|blueviolet|periwinkle|cadetblue|cornflowerblue|midnightblue|navyblue|royalblue|blue|cerulean|cyan|processblue|skyblue|turquoise|tealblue|aquamarine|bluegreen|emerald|junglegreen|seagreen|green|forestgreen|pinegreen|limegreen|yellowgreen|springgreen|olivegreen|rawsienna|sepia|brown|tan|gray|grey|black|white)$/;var IsCounter=/^(?:definition|proposition|lemma|theorem|corollary|example|exercise|subsection|subsubsection|figure|equation|table)$/;var IsLaTeXElement=/^(?:displayequation|title|author|address|date|abstract|keyword|section|subsection|subsubsection|ref|cite|thebibliography|definition|proposition|lemma|theorem|corollary|example|exercise|itemize|enumerate|enddefinition|endproposition|endlemma|endtheorem|endcorollary|endexample|endexercise|enditemize|endenumerate|LaTeXMathMLlabel|LaTeXMathML|smallskip|medskip|bigskip|quote|quotation|endquote|endquotation|center|endcenter|description|enddescription|inlinemath)$/;var IsTextOnlyArea=/^(?:form|textarea|pre)$/i;var tableid=0;function makeNumberString(cntr){if(sectionCntr>0){if(inAppendix){return"A"+sectionCntr+"."+cntr;}else{return sectionCntr+"."+cntr;}}else{return""+cntr;}};function LaTeXpreProcess(thebody){var TheBody=thebody;if(TheBody.hasChildNodes()){if(!(IsLaTeXElement.test(TheBody.className))) - {for(var i=0;i<TheBody.childNodes.length;i++){LaTeXpreProcess(TheBody.childNodes[i])}}} - else{if(TheBody.nodeType==3&&!(IsTextOnlyArea.test(TheBody.parentNode.nodeName))) - {var str=TheBody.nodeValue;if(!(str==null)){str=str.replace(/\\%/g,"<per>");str=str.replace(/%[^\n]*(?=\n)/g,"");str=str.replace(/%[^\r]*(?=\r)/g,"");str=str.replace(/%[^\n]*$/,"") - if(isIE&&str.match(/%/g)!=null&&IEcommentWarning){alert("Comments may not have parsed properly. Try putting in <pre class='LaTeX><div>..</div></pre> structure.");IEcommentWarning=false;} - str=str.replace(/<per>/g,"%");if(str.match(/XXX[\s\S]*/)!=null){var tmp=str.match(/XXX[\s\S]*/)[0];var tmpstr=tmp.charCodeAt(7)+"::"+tmp.charCodeAt(8)+"::"+tmp.charCodeAt(9)+"::"+tmp.charCodeAt(10)+"::"+tmp.charCodeAt(11)+"::"+tmp.charCodeAt(12)+"::"+tmp.charCodeAt(13);alert(tmpstr);} - str=str.replace(/([^\\])\\(\s)/g,"$1\u00A0$2");str=str.replace(/\\quad/g,"\u2001");str=str.replace(/\\qquad/g,"\u2001\u2001");str=str.replace(/\\enspace/g,"\u2002");str=str.replace(/\\;/g,"\u2004");str=str.replace(/\\:/g,"\u2005");str=str.replace(/\\,/g,"\u2006");str=str.replace(/\\thinspace/g,"\u200A");str=str.replace(/([^\\])~/g,"$1\u00A0");str=str.replace(/\\~/g,"~");str=str.replace(/\\\[/g," <DEQ> $\\displaystyle{");str=str.replace(/\\\]/g,"}$ <DEQ> ");str=str.replace(/\$\$/g,"${$<DEQ>$}$");str=str.replace(/\\begin\s*\{\s*array\s*\}/g,"\\begin{array}");str=str.replace(/\\end\s*\{\s*array\s*\}/g,"\\end{array}");str=str.replace(/\\begin\s*\{\s*eqnarray\s*\}/g," <DEQ>eqno$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*eqnarray\*\s*\}/g," <DEQ>$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\*\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*displaymath\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*displaymath\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\*\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\*\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\}/g," <DEQ>eqno$\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\}/g,"}$ <DEQ> ");str=str.split("<DEQ>");var newFrag=document.createDocumentFragment();for(var i=0;i<str.length;i++){if(i%2){var DEQtable=document.createElement("table");DEQtable.className='displayequation';var DEQtbody=document.createElement("tbody");var DEQtr=document.createElement("tr");var DEQtdeq=document.createElement("td");DEQtdeq.className='eq';str[i]=str[i].replace(/\$\}\$/g,"$\\displaystyle{");str[i]=str[i].replace(/\$\{\$/g,"}");var lbl=str[i].match(/\\label\s*\{\s*(\w+)\s*\}/);var ISeqno=str[i].match(/^eqno/);str[i]=str[i].replace(/^eqno/," ");str[i]=str[i].replace(/\\label\s*\{\s*\w+\s*\}/," ");DEQtdeq.appendChild(document.createTextNode(str[i]));DEQtr.appendChild(DEQtdeq);str[i]=str[i].replace(/\\nonumber/g,"");if(ISeqno!=null||lbl!=null){var DEQtdno=document.createElement("td");DEQtdno.className='eqno';LaTeXCounter["equation"]++;var eqnoString=makeNumberString(LaTeXCounter["equation"]);var DEQanchor=document.createElement("a");if(lbl!=null){DEQanchor.id=lbl[1]};DEQanchor.className="eqno";var anchorSpan=document.createElement("span");anchorSpan.className="eqno";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(eqnoString));DEQanchor.appendChild(anchorSpan);DEQtdno.appendChild(DEQanchor);var DEQspan=document.createElement("span");DEQspan.className="eqno";DEQspan.appendChild(document.createTextNode("("+eqnoString+")"));DEQtdno.appendChild(DEQspan);DEQtr.appendChild(DEQtdno);} - DEQtbody.appendChild(DEQtr);DEQtable.appendChild(DEQtbody);newFrag.appendChild(DEQtable);} - else{str[i]=str[i].replace(/\$\}\$/g,"");str[i]=str[i].replace(/\$\{\$/g,"");str[i]=str[i].replace(/\\maketitle/g,"");str[i]=str[i].replace(/\\begin\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\end\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\documentclass[^\}]*?\}/g,"");str[i]=str[i].replace(/\\usepackage[^\}]*?\}/g,"");str[i]=str[i].replace(/\\noindent/g,"");str[i]=str[i].replace(/\\notag/g,"");str[i]=str[i].replace(/\\ref\s*\{\s*(\w+)\}/g," \\[ref\\]$1\\[ ");str[i]=str[i].replace(/\\url\s*\{\s*([^\}\n]+)\}/g," \\[url\\]$1\\[ ");str[i]=str[i].replace(/\\href\s*\{\s*([^\}]+)\}\s*\{\s*([^\}]+)\}/g," \\[href\\]$1\\]$2\\[ ");str[i]=str[i].replace(/\\cite\s*\{\s*(\w+)\}/g," \\[cite\\]$1\\[ ");str[i]=str[i].replace(/\\qed/g,"\u220E");str[i]=str[i].replace(/\\endproof/g,"\u220E");str[i]=str[i].replace(/\\proof/g,"\\textbf{Proof: }");str[i]=str[i].replace(/\\n(?=\s)/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\newline/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\linebreak/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\smallskip/g," \\[logicalbreak\\]smallskip\\[ ");str[i]=str[i].replace(/\\medskip/g," \\[logicalbreak\\]medskip\\[ ");str[i]=str[i].replace(/\\bigskip/g," \\[logicalbreak\\]bigskip\\[ ");str[i]=str[i].replace(/[\n\r]+[ \f\n\r\t\v\u2028\u2029]*[\n\r]+/g," \\[logicalbreak\\]LaTeXMathML\\[ ");if(isIE){str[i]=str[i].replace(/\r/g," ");} - str[i]=str[i].replace(/\\bibitem\s*([^\{]*\{\s*\w*\s*\})/g," \\[bibitem\\]$1\\[ ");str[i]=str[i].replace(/\\bibitem\s*/g," \\[bibitem\\] \\[ ");str[i]=str[i].replace(/\\item\s*\[\s*(\w+)\s*\]/g," \\[alistitem\\]$1\\[ ");str[i]=str[i].replace(/\\item\s*/g," \\[alistitem\\] \\[ ");str[i]=str[i].replace(/\\appendix/g," \\[appendix\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*figure\s*\}([\s\S]+?)\\end\s*\{\s*figure\s*\}/g," \\[figure\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*table\s*\}([\s\S]+?)\\end\s*\{\s*table\s*\}/g," \\[table\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*theorem\s*\}/g," \\[theorem\\]Theorem \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*theorem\s*\}/g," \\[endtheorem\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*definition\s*\}/g," \\[definition\\]Definition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*definition\s*\}/g," \\[enddefinition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*lemma\s*\}/g," \\[lemma\\]Lemma \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*lemma\s*\}/g," \\[endlemma\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*corollary\s*\}/g," \\[corollary\\]Corollary \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*corollary\s*\}/g," \\[endcorollary\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proposition\s*\}/g," \\[proposition\\]Proposition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*proposition\s*\}/g," \\[endproposition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*example\s*\}/g," \\[example\\]Example \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*example\s*\}/g," \\[endexample\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*exercise\s*\}/g," \\[exercise\\]Exercise \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*exercise\s*\}/g," \\[endexercise\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}\s*\{\s*\w+\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*thebibliography\s*\}/g," \\[endthebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proof\s*\}/g," \\[proof\\]Proof: \\[ ");if(isIE){str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g,"\u220E \\[endproof\\] \\[ ");}else{str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g," \\[endproof\\] \\[ ");} - str[i]=str[i].replace(/\\title\s*\{\s*([^\}]+)\}/g," \\[title\\] \\[$1 \\[endtitle\\] \\[ ");str[i]=str[i].replace(/\\author\s*\{\s*([^\}]+)\}/g," \\[author\\] \\[$1 \\[endauthor\\] \\[ ");str[i]=str[i].replace(/\\address\s*\{\s*([^\}]+)\}/g," \\[address\\] \\[$1 \\[endaddress\\] \\[ ");str[i]=str[i].replace(/\\date\s*\{\s*([^\}]+)\}/g," \\[date\\] \\[$1 \\[enddate\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*keyword\s*\}/g," \\[keyword\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*keyword\s*\}/g," \\[endkeyword\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*abstract\s*\}/g," \\[abstract\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*abstract\s*\}/g," \\[endabstract\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[$1\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[end$1\\] \\[ ");var sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\section\s*\{/," \\[section\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);} - sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsection\s*\{/," \\[subsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);} - sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsubsection\s*\{/," \\[subsubsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);} - var CatToNextEven="";var strtmp=str[i].split("\\[");for(var j=0;j<strtmp.length;j++){if(j%2){var strtmparray=strtmp[j].split("\\]");switch(strtmparray[0]){case"section":var nodeTmp=document.createElement("H2");nodeTmp.className='section';sectionCntr++;for(var div in LaTeXCounter){LaTeXCounter[div]=0};var nodeAnchor=document.createElement("a");if(inAppendix){nodeAnchor.className='appendixsection';}else{nodeAnchor.className='section';} - var nodeNumString=makeNumberString("");var anchorSpan=document.createElement("span");anchorSpan.className="section";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='section';nodeSpan.appendChild(document.createTextNode(nodeNumString+" "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsection":var nodeTmp=document.createElement("H3");nodeTmp.className='subsection';LaTeXCounter["subsection"]++;LaTeXCounter["subsubsection"]=0;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsubsection":var nodeTmp=document.createElement("H4");nodeTmp.className='subsubsection';LaTeXCounter["subsubsection"]++;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsubsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]+"."+LaTeXCounter["subsubsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsubsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsubsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"href":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"url":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"figure":var nodeTmp=document.createElement("table");nodeTmp.className='figure';var FIGtbody=document.createElement("tbody");var FIGlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var FIGcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;FIGcap=tmp.substring(capstart,pos);break}}} - var FIGtr2=document.createElement("tr");var FIGtd2=document.createElement("td");FIGtd2.className="caption";var FIGanchor=document.createElement("a");FIGanchor.className="figure";if(FIGlbl!=null){FIGanchor.id=FIGlbl[1];} - LaTeXCounter["figure"]++;var fignmbr=makeNumberString(LaTeXCounter["figure"]);var anchorSpan=document.createElement("span");anchorSpan.className="figure";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(fignmbr));FIGanchor.appendChild(anchorSpan);FIGtd2.appendChild(FIGanchor);var FIGspan=document.createElement("span");FIGspan.className="figure";FIGspan.appendChild(document.createTextNode("Figure "+fignmbr+". "));FIGtd2.appendChild(FIGspan);FIGtd2.appendChild(document.createTextNode(""+FIGcap));FIGtr2.appendChild(FIGtd2);FIGtbody.appendChild(FIGtr2);var IsSpecial=false;var FIGinfo=strtmparray[1].match(/\\includegraphics\s*\{([^\}]+)\}/);if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\includegraphics\s*\[[^\]]*\]\s*\{\s*([^\}]+)\s*\}/);} - if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\special\s*\{\s*([^\}]+)\}/);IsSpecial=true};if(FIGinfo!=null){var FIGtr1=document.createElement("tr");var FIGtd1=document.createElement("td");FIGtd1.className="image";var FIGimg=document.createElement("img");var FIGsrc=FIGinfo[1];FIGimg.src=FIGsrc;FIGimg.alt="Figure "+FIGsrc+" did not load";FIGimg.title="Figure "+fignmbr+". "+FIGcap;FIGimg.id="figure"+fignmbr;FIGtd1.appendChild(FIGimg);FIGtr1.appendChild(FIGtd1);FIGtbody.appendChild(FIGtr1);} - nodeTmp.appendChild(FIGtbody);newFrag.appendChild(nodeTmp);break;case"table":var nodeTmp=document.createElement("table");if(strtmparray[1].search(/\\centering/)>=0){nodeTmp.className='LaTeXtable centered';nodeTmp.align="center";}else{nodeTmp.className='LaTeXtable';};tableid++;nodeTmp.id="LaTeXtable"+tableid;var TABlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var TABcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;TABcap=tmp.substring(capstart,pos);break}}} - if(TABcap!=""){var TABtbody=document.createElement("tbody");var TABcaption=document.createElement("caption");TABcaption.className="LaTeXtable centered";var TABanchor=document.createElement("a");TABanchor.className="LaTeXtable";if(TABlbl!=null){TABanchor.id=TABlbl[1];} - LaTeXCounter["table"]++;var tabnmbr=makeNumberString(LaTeXCounter["table"]);var anchorSpan=document.createElement("span");anchorSpan.className="LaTeXtable";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(tabnmbr));TABanchor.appendChild(anchorSpan);TABcaption.appendChild(TABanchor);var TABspan=document.createElement("span");TABspan.className="LaTeXtable";TABspan.appendChild(document.createTextNode("Table "+tabnmbr+". "));TABcaption.appendChild(TABspan);TABcaption.appendChild(document.createTextNode(""+TABcap));nodeTmp.appendChild(TABcaption);} - var TABinfo=strtmparray[1].match(/\\begin\s*\{\s*tabular\s*\}([\s\S]+)\\end\s*\{\s*tabular\s*\}/);if(TABinfo!=null){var TABtbody=document.createElement('tbody');var TABrow=null;var TABcell=null;var row=0;var col=0;var TABalign=TABinfo[1].match(/^\s*\{([^\}]+)\}/);TABinfo=TABinfo[1].replace(/^\s*\{[^\}]+\}/,"");TABinfo=TABinfo.replace(/\\hline/g,"");TABalign[1]=TABalign[1].replace(/\|/g,"");TABalign[1]=TABalign[1].replace(/\s/g,"");TABinfo=TABinfo.split("\\\\");for(row=0;row<TABinfo.length;row++){TABrow=document.createElement("tr");TABinfo[row]=TABinfo[row].split("&");for(col=0;col<TABinfo[row].length;col++){TABcell=document.createElement("td");switch(TABalign[1].charAt(col)){case"l":TABcell.align="left";break;case"c":TABcell.align="center";break;case"r":TABcell.align="right";break;default:TABcell.align="left";};TABcell.appendChild(document.createTextNode(TABinfo[row][col]));TABrow.appendChild(TABcell);} - TABtbody.appendChild(TABrow);} - nodeTmp.appendChild(TABtbody);} - newFrag.appendChild(nodeTmp);break;case"logicalbreak":var nodeTmp=document.createElement("p");nodeTmp.className=strtmparray[1];nodeTmp.appendChild(document.createTextNode("\u00A0"));newFrag.appendChild(nodeTmp);break;case"appendix":inAppendix=true;sectionCntr=0;break;case"alistitem":var EndDiv=document.createElement("div");EndDiv.className="endlistitem";newFrag.appendChild(EndDiv);var BegDiv=document.createElement("div");BegDiv.className="listitem";if(strtmparray[1]!=" "){var BegSpan=document.createElement("span");BegSpan.className="listitemmarker";var boldBegSpan=document.createElement("b");boldBegSpan.appendChild(document.createTextNode(strtmparray[1]+" "));BegSpan.appendChild(boldBegSpan);BegDiv.appendChild(BegSpan);} - newFrag.appendChild(BegDiv);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"bibitem":newFrag.appendChild(document.createElement("br"));var nodeTmp=document.createElement("a");nodeTmp.className='bibitem';var nodeSpan=document.createElement("span");nodeSpan.className='bibitem';bibcntr++;var lbl=strtmparray[1].match(/\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\s*\{\s*\w+\s*\}/g,"");strtmparray[1]=strtmparray[1].replace(/^\s*\[/,"");strtmparray[1]=strtmparray[1].replace(/\s*\]$/,"");strtmparray[1]=strtmparray[1].replace(/^\s+|\s+$/g,"");if(lbl==null){biblist[bibcntr]="bibitem"+bibcntr}else{biblist[bibcntr]=lbl[1];};nodeTmp.name=biblist[bibcntr];nodeTmp.id=biblist[bibcntr];if(strtmparray[1]!=""){nodeSpan.appendChild(document.createTextNode(strtmparray[1]));}else{nodeSpan.appendChild(document.createTextNode("["+bibcntr+"]"));} - nodeTmp.appendChild(nodeSpan);newFrag.appendChild(nodeTmp);break;case"cite":var nodeTmp=document.createElement("a");nodeTmp.className='cite';nodeTmp.name='cite';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;case"ref":var nodeTmp=document.createElement("a");nodeTmp.className='ref';nodeTmp.name='ref';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("div");nodeTmp.className=strtmparray[0];if(IsCounter.test(strtmparray[0])){LaTeXCounter[strtmparray[0]]++;var nodeAnchor=document.createElement("a");nodeAnchor.className=strtmparray[0];var divnum=makeNumberString(LaTeXCounter[strtmparray[0]]);var anchorSpan=document.createElement("span");anchorSpan.className=strtmparray[0];anchorSpan.appendChild(document.createTextNode(divnum));anchorSpan.style.display="none";nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]+" "+divnum+". "));nodeTmp.appendChild(nodeSpan);} - if(isIE){if(strtmparray[0]==("thebibliography"||"abstract"||"keyword"||"proof")){var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]));nodeTmp.appendChild(nodeSpan);}} - if(strtmparray[0]=="endenumerate"||strtmparray[0]=="enditemize"||strtmparray[0]=="enddescription"){var endDiv=document.createElement("div");endDiv.className="endlistitem";newFrag.appendChild(endDiv);} - newFrag.appendChild(nodeTmp);if(strtmparray[0]=="enumerate"||strtmparray[0]=="itemize"||strtmparray[0]=="description"){var endDiv=document.createElement("div");endDiv.className="listitem";newFrag.appendChild(endDiv);}}}else{strtmp[j]=strtmp[j].replace(/\\\$/g,"<per>");strtmp[j]=strtmp[j].replace(/\$([^\$]+)\$/g," \\[$1\\[ ");strtmp[j]=strtmp[j].replace(/<per>/g,"\\$");strtmp[j]=strtmp[j].replace(/\\begin\s*\{\s*math\s*\}([\s\S]+?)\\end\s*\{\s*math\s*\}/g," \\[$1\\[ ");var strtmptmp=strtmp[j].split("\\[");for(var jjj=0;jjj<strtmptmp.length;jjj++){if(jjj%2){var nodeTmp=document.createElement("span");nodeTmp.className='inlinemath';nodeTmp.appendChild(document.createTextNode("$"+strtmptmp[jjj]+"$"));newFrag.appendChild(nodeTmp);}else{var TagIndex=strtmptmp[jjj].search(/\\\w+/);var tmpIndex=TagIndex;while(tmpIndex>-1){if(/^\\textcolor/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\textcolor\s*\{\s*(\w+)\s*\}\s*/," \\[textcolor\\]$1\\]|");}else{if(/^\\colorbox/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\colorbox\s*\{\s*(\w+)\s*\}\s*/," \\[colorbox\\]$1\\]|");}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).replace(/\\\s*(\w+)\s*/," \\[$1\\]|");}} - TagIndex+=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\|/);TagIndex++;strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\]\|/,"\\] ");if(strtmptmp[jjj].charAt(TagIndex)=="{"){strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);var delimcnt=1;for(var kk=TagIndex;kk<strtmptmp[jjj].length;kk++){if(strtmptmp[jjj].charAt(kk)=="{"){delimcnt++};if(strtmptmp[jjj].charAt(kk)=="}"){delimcnt--};if(delimcnt==0){break;}} - strtmptmp[jjj]=strtmptmp[jjj].substring(0,kk)+"\\[ "+strtmptmp[jjj].substring(kk+1,strtmptmp[jjj].length);TagIndex=kk+3;}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+"\\[ "+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);TagIndex=TagIndex+3;} - if(TagIndex<strtmptmp[jjj].length){tmpIndex=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\\\w+/);} - else{tmpIndex=-1};TagIndex+=tmpIndex;} - strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\\s*\\\\/g,"\\\\");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\/g," \\[br\\] \\[ ");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\label\s*\{\s*(\w+)\s*\}/g," \\[a\\]$1\\[ ");var strlbls=strtmptmp[jjj].split("\\[");for(var jj=0;jj<strlbls.length;jj++){if(jj%2){var strtmparray=strlbls[jj].split("\\]");switch(strtmparray[0]){case"textcolor":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.color=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.color=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"colorbox":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.background=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.background=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"a":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathMLlabel';nodeTmp.id=strtmparray[1];nodeTmp.style.display="none";newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("span");nodeTmp.className=strtmparray[0];nodeTmp.appendChild(document.createTextNode(strtmparray[1])) - newFrag.appendChild(nodeTmp);}}else{newFrag.appendChild(document.createTextNode(strlbls[jj]));}}}}}}}};TheBody.parentNode.replaceChild(newFrag,TheBody);}}} - return TheBody;} - function LaTeXDivsAndRefs(thebody){var TheBody=thebody;var EndDivClass=null;var AllDivs=TheBody.getElementsByTagName("div");var lbl2id="";var lblnode=null;for(var i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){EndDivClass=EndDivClass[0];var DivClass=EndDivClass.substring(3,EndDivClass.length);var EndDivNode=AllDivs[i];break;}} - while(EndDivClass!=null){var newFrag=document.createDocumentFragment();var RootNode=EndDivNode.parentNode;var ClassCount=1;while(EndDivNode.previousSibling!=null&&ClassCount>0){switch(EndDivNode.previousSibling.className){case EndDivClass:ClassCount++;newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);break;case DivClass:if(EndDivNode.previousSibling.nodeName=="DIV"){ClassCount--;if(lbl2id!=""){EndDivNode.previousSibling.id=lbl2id;lbl2id=""} - if(ClassCount==0){RootNode=EndDivNode.previousSibling;}else{newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}};break;case'LaTeXMathMLlabel':lbl2id=EndDivNode.previousSibling.id;EndDivNode.parentNode.removeChild(EndDivNode.previousSibling);break;default:newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}} - RootNode.appendChild(newFrag);EndDivNode.parentNode.removeChild(EndDivNode);AllDivs=TheBody.getElementsByTagName("DIV");for(i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){ClassCount=0;EndDivClass=EndDivClass[0];DivClass=EndDivClass.substring(3,EndDivClass.length);EndDivNode=AllDivs[i];RootNode=EndDivNode.parentNode;break;}}} - var AllDivs=TheBody.getElementsByTagName("div");var DIV2LI=null;for(var i=0;i<AllDivs.length;i++){if(AllDivs[i].className=="itemize"||AllDivs[i].className=="enumerate"||AllDivs[i].className=="description"){if(AllDivs[i].className=="itemize"){RootNode=document.createElement("UL");}else{RootNode=document.createElement("OL");} - RootNode.className='LaTeXMathML';if(AllDivs[i].hasChildNodes()){AllDivs[i].removeChild(AllDivs[i].firstChild)};while(AllDivs[i].hasChildNodes()){if(AllDivs[i].firstChild.hasChildNodes()){DIV2LI=document.createElement("LI");while(AllDivs[i].firstChild.hasChildNodes()){DIV2LI.appendChild(AllDivs[i].firstChild.firstChild);} - if(DIV2LI.firstChild.className=="listitemmarker"){DIV2LI.style.listStyleType="none";} - RootNode.appendChild(DIV2LI)} - AllDivs[i].removeChild(AllDivs[i].firstChild);} - AllDivs[i].appendChild(RootNode);}} - var AllAnchors=TheBody.getElementsByTagName("a");for(var i=0;i<AllAnchors.length;i++){if(AllAnchors[i].className=="ref"||AllAnchors[i].className=="cite"){var label=AllAnchors[i].href.match(/\#(\w+)/);if(label!=null){var labelNode=document.getElementById(label[1]);if(labelNode!=null){var TheSpans=labelNode.getElementsByTagName("SPAN");if(TheSpans!=null){var refNode=TheSpans[0].cloneNode(true);refNode.style.display="inline" - refNode.className=AllAnchors[i].className;AllAnchors[i].appendChild(refNode);}}}}} - return TheBody;} - var AMbody;var AMnoMathML=false,AMtranslated=false;function translate(spanclassAM){if(!AMtranslated){AMtranslated=true;AMinitSymbols();var LaTeXContainers=[];var AllContainers=document.getElementsByTagName('*');var ExtendName="";for(var k=0,l=0;k<AllContainers.length;k++){ExtendName=" "+AllContainers[k].className+" ";if(ExtendName.match(/\sLaTeX\s/)!=null){LaTeXContainers[l]=AllContainers[k];l++;}};if(LaTeXContainers.length>0){for(var m=0;m<LaTeXContainers.length;m++){AMbody=LaTeXContainers[m];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");} - if(AMbody.tagName=="PRE"){var PreChilds=document.createDocumentFragment();var DivChilds=document.createElement("DIV");while(AMbody.hasChildNodes()){DivChilds.appendChild(AMbody.firstChild);} - PreChilds.appendChild(DivChilds);AMbody.parentNode.replaceChild(PreChilds,AMbody);AMbody=DivChilds;} - AMprocessNode(AMbody,false,spanclassAM);}}else{AMbody=document.getElementsByTagName("body")[0];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");} - AMprocessNode(AMbody,false,spanclassAM);}}} - if(isIE){document.write("<object id=\"mathplayer\" classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");} - function generic() - {translate();};if(typeof window.addEventListener!='undefined') - {window.addEventListener('load',generic,false);} - else if(typeof document.addEventListener!='undefined') - {document.addEventListener('load',generic,false);} - else if(typeof window.attachEvent!='undefined') - {window.attachEvent('onload',generic);} - else - {if(typeof window.onload=='function') - {var existing=onload;window.onload=function() - {existing();generic();};} - else - {window.onload=generic;}} - /*]]>*/ - </script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-AMS_CHTML-full" type="text/javascript"></script> </head> <body> <div class="layout"> @@ -254,7 +54,7 @@ <div id="math" class="slide section level1"> <h1>Math</h1> <ul class="incremental"> -<li><span class="LaTeX">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li> +<li><span class="math inline">\(\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\)</span></li> </ul> </div> </div> diff --git a/test/tables-rstsubset.native b/test/tables-rstsubset.native index 8b7ccdf76..5ea520d7c 100644 --- a/test/tables-rstsubset.native +++ b/test/tables-rstsubset.native @@ -53,7 +53,7 @@ ,[Plain [Str "1"]] ,[Plain [Str "1"]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"] -,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325] +,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.3375] [[Plain [Str "Centered",SoftBreak,Str "Header"]] ,[Plain [Str "Left",SoftBreak,Str "Aligned"]] ,[Plain [Str "Right",SoftBreak,Str "Aligned"]] @@ -65,9 +65,9 @@ ,[[Plain [Str "Second"]] ,[Plain [Str "row"]] ,[Plain [Str "5.0"]] - ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]] + ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"] -,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325] +,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.3375] [[Plain [Str "Centered",SoftBreak,Str "Header"]] ,[Plain [Str "Left",SoftBreak,Str "Aligned"]] ,[Plain [Str "Right",SoftBreak,Str "Aligned"]] @@ -79,7 +79,7 @@ ,[[Plain [Str "Second"]] ,[Plain [Str "row"]] ,[Plain [Str "5.0"]] - ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]] + ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]] ,Para [Str "Table",Space,Str "without",Space,Str "column",Space,Str "headers:"] ,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [7.5e-2,7.5e-2,7.5e-2,7.5e-2] [[] @@ -99,7 +99,7 @@ ,[Plain [Str "1"]] ,[Plain [Str "1"]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "column",Space,Str "headers:"] -,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325] +,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.3375] [[] ,[] ,[] @@ -111,4 +111,4 @@ ,[[Plain [Str "Second"]] ,[Plain [Str "row"]] ,[Plain [Str "5.0"]] - ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]]] + ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]]] diff --git a/test/tables.asciidoc b/test/tables.asciidoc index 91490a27a..75632157e 100644 --- a/test/tables.asciidoc +++ b/test/tables.asciidoc @@ -33,7 +33,7 @@ Simple table indented two spaces: Multiline table with caption: .Here’s the caption. It may span multiple lines. -[width="78%",cols="^21%,<17%,>20%,<42%",options="header",] +[width="80%",cols="^20%,<17%,>20%,<43%",options="header",] |======================================================================= |Centered Header |Left Aligned |Right Aligned |Default aligned |First |row |12.0 |Example of a row that spans multiple lines. @@ -42,7 +42,7 @@ Multiline table with caption: Multiline table without caption: -[width="78%",cols="^21%,<17%,>20%,<42%",options="header",] +[width="80%",cols="^20%,<17%,>20%,<43%",options="header",] |======================================================================= |Centered Header |Left Aligned |Right Aligned |Default aligned |First |row |12.0 |Example of a row that spans multiple lines. @@ -60,7 +60,7 @@ Table without column headers: Multiline table without column headers: -[width="78%",cols="^21%,<17%,>20%,42%",] +[width="80%",cols="^20%,<17%,>20%,43%",] |======================================================================= |First |row |12.0 |Example of a row that spans multiple lines. |Second |row |5.0 |Here’s another one. Note the blank line between rows. diff --git a/test/tables.context b/test/tables.context index 11dffc065..556d2c216 100644 --- a/test/tables.context +++ b/test/tables.context @@ -118,7 +118,7 @@ Multiline table with caption: \startxcell[align=middle,width={0.15\textwidth}] Centered Header \stopxcell \startxcell[align=right,width={0.14\textwidth}] Left Aligned \stopxcell \startxcell[align=left,width={0.16\textwidth}] Right Aligned \stopxcell -\startxcell[align=right,width={0.34\textwidth}] Default aligned \stopxcell +\startxcell[align=right,width={0.35\textwidth}] Default aligned \stopxcell \stopxrow \stopxtablehead \startxtablebody[body] @@ -126,7 +126,7 @@ Multiline table with caption: \startxcell[align=middle,width={0.15\textwidth}] First \stopxcell \startxcell[align=right,width={0.14\textwidth}] row \stopxcell \startxcell[align=left,width={0.16\textwidth}] 12.0 \stopxcell -\startxcell[align=right,width={0.34\textwidth}] Example of a row that spans +\startxcell[align=right,width={0.35\textwidth}] Example of a row that spans multiple lines. \stopxcell \stopxrow \stopxtablebody @@ -135,7 +135,7 @@ multiple lines. \stopxcell \startxcell[align=middle,width={0.15\textwidth}] Second \stopxcell \startxcell[align=right,width={0.14\textwidth}] row \stopxcell \startxcell[align=left,width={0.16\textwidth}] 5.0 \stopxcell -\startxcell[align=right,width={0.34\textwidth}] Here's another one. Note the +\startxcell[align=right,width={0.35\textwidth}] Here's another one. Note the blank line between rows. \stopxcell \stopxrow \stopxtablefoot @@ -151,7 +151,7 @@ Multiline table without caption: \startxcell[align=middle,width={0.15\textwidth}] Centered Header \stopxcell \startxcell[align=right,width={0.14\textwidth}] Left Aligned \stopxcell \startxcell[align=left,width={0.16\textwidth}] Right Aligned \stopxcell -\startxcell[align=right,width={0.34\textwidth}] Default aligned \stopxcell +\startxcell[align=right,width={0.35\textwidth}] Default aligned \stopxcell \stopxrow \stopxtablehead \startxtablebody[body] @@ -159,7 +159,7 @@ Multiline table without caption: \startxcell[align=middle,width={0.15\textwidth}] First \stopxcell \startxcell[align=right,width={0.14\textwidth}] row \stopxcell \startxcell[align=left,width={0.16\textwidth}] 12.0 \stopxcell -\startxcell[align=right,width={0.34\textwidth}] Example of a row that spans +\startxcell[align=right,width={0.35\textwidth}] Example of a row that spans multiple lines. \stopxcell \stopxrow \stopxtablebody @@ -168,7 +168,7 @@ multiple lines. \stopxcell \startxcell[align=middle,width={0.15\textwidth}] Second \stopxcell \startxcell[align=right,width={0.14\textwidth}] row \stopxcell \startxcell[align=left,width={0.16\textwidth}] 5.0 \stopxcell -\startxcell[align=right,width={0.34\textwidth}] Here's another one. Note the +\startxcell[align=right,width={0.35\textwidth}] Here's another one. Note the blank line between rows. \stopxcell \stopxrow \stopxtablefoot @@ -213,7 +213,7 @@ Multiline table without column headers: \startxcell[align=middle,width={0.15\textwidth}] First \stopxcell \startxcell[align=right,width={0.14\textwidth}] row \stopxcell \startxcell[align=left,width={0.16\textwidth}] 12.0 \stopxcell -\startxcell[width={0.34\textwidth}] Example of a row that spans multiple +\startxcell[width={0.35\textwidth}] Example of a row that spans multiple lines. \stopxcell \stopxrow \stopxtablebody @@ -222,7 +222,7 @@ lines. \stopxcell \startxcell[align=middle,width={0.15\textwidth}] Second \stopxcell \startxcell[align=right,width={0.14\textwidth}] row \stopxcell \startxcell[align=left,width={0.16\textwidth}] 5.0 \stopxcell -\startxcell[width={0.34\textwidth}] Here's another one. Note the blank line +\startxcell[width={0.35\textwidth}] Here's another one. Note the blank line between rows. \stopxcell \stopxrow \stopxtablefoot diff --git a/test/tables.custom b/test/tables.custom index 410b68d3f..b78b3a4e9 100644 --- a/test/tables.custom +++ b/test/tables.custom @@ -95,7 +95,7 @@ It may span multiple lines.</caption> <col width="15%" /> <col width="14%" /> <col width="16%" /> -<col width="34%" /> +<col width="35%" /> <tr class="header"> <th align="center">Centered Header</th> @@ -127,7 +127,7 @@ the blank line between rows.</td> <col width="15%" /> <col width="14%" /> <col width="16%" /> -<col width="34%" /> +<col width="35%" /> <tr class="header"> <th align="center">Centered Header</th> @@ -182,7 +182,7 @@ the blank line between rows.</td> <col width="15%" /> <col width="14%" /> <col width="16%" /> -<col width="34%" /> +<col width="35%" /> <tr class="odd"> <td align="center">First</td> <td align="left">row</td> diff --git a/test/tables.docbook4 b/test/tables.docbook4 index f86b1c390..a661805e5 100644 --- a/test/tables.docbook4 +++ b/test/tables.docbook4 @@ -228,7 +228,7 @@ <colspec colwidth="15*" align="center" /> <colspec colwidth="13*" align="left" /> <colspec colwidth="16*" align="right" /> - <colspec colwidth="33*" align="left" /> + <colspec colwidth="35*" align="left" /> <thead> <row> <entry> @@ -285,7 +285,7 @@ <colspec colwidth="15*" align="center" /> <colspec colwidth="13*" align="left" /> <colspec colwidth="16*" align="right" /> - <colspec colwidth="33*" align="left" /> + <colspec colwidth="35*" align="left" /> <thead> <row> <entry> @@ -397,7 +397,7 @@ <colspec colwidth="15*" align="center" /> <colspec colwidth="13*" align="left" /> <colspec colwidth="16*" align="right" /> - <colspec colwidth="33*" align="left" /> + <colspec colwidth="35*" align="left" /> <tbody> <row> <entry> diff --git a/test/tables.docbook5 b/test/tables.docbook5 index f86b1c390..a661805e5 100644 --- a/test/tables.docbook5 +++ b/test/tables.docbook5 @@ -228,7 +228,7 @@ <colspec colwidth="15*" align="center" /> <colspec colwidth="13*" align="left" /> <colspec colwidth="16*" align="right" /> - <colspec colwidth="33*" align="left" /> + <colspec colwidth="35*" align="left" /> <thead> <row> <entry> @@ -285,7 +285,7 @@ <colspec colwidth="15*" align="center" /> <colspec colwidth="13*" align="left" /> <colspec colwidth="16*" align="right" /> - <colspec colwidth="33*" align="left" /> + <colspec colwidth="35*" align="left" /> <thead> <row> <entry> @@ -397,7 +397,7 @@ <colspec colwidth="15*" align="center" /> <colspec colwidth="13*" align="left" /> <colspec colwidth="16*" align="right" /> - <colspec colwidth="33*" align="left" /> + <colspec colwidth="35*" align="left" /> <tbody> <row> <entry> diff --git a/test/tables.haddock b/test/tables.haddock index 678c5c15a..dcfc0f7ad 100644 --- a/test/tables.haddock +++ b/test/tables.haddock @@ -40,33 +40,33 @@ Simple table indented two spaces: Multiline table with caption: -> +----------+---------+-----------+-------------------------+ -> | Centered | Left | Right | Default aligned | -> | Header | Aligned | Aligned | | -> +==========+=========+===========+=========================+ -> | First | row | 12.0 | Example of a row that | -> | | | | spans multiple lines. | -> +----------+---------+-----------+-------------------------+ -> | Second | row | 5.0 | Here’s another one. | -> | | | | Note the blank line | -> | | | | between rows. | -> +----------+---------+-----------+-------------------------+ +> +----------+---------+-----------+--------------------------+ +> | Centered | Left | Right | Default aligned | +> | Header | Aligned | Aligned | | +> +==========+=========+===========+==========================+ +> | First | row | 12.0 | Example of a row that | +> | | | | spans multiple lines. | +> +----------+---------+-----------+--------------------------+ +> | Second | row | 5.0 | Here’s another one. Note | +> | | | | the blank line between | +> | | | | rows. | +> +----------+---------+-----------+--------------------------+ > > Here’s the caption. It may span multiple lines. Multiline table without caption: -> +----------+---------+-----------+-------------------------+ -> | Centered | Left | Right | Default aligned | -> | Header | Aligned | Aligned | | -> +==========+=========+===========+=========================+ -> | First | row | 12.0 | Example of a row that | -> | | | | spans multiple lines. | -> +----------+---------+-----------+-------------------------+ -> | Second | row | 5.0 | Here’s another one. | -> | | | | Note the blank line | -> | | | | between rows. | -> +----------+---------+-----------+-------------------------+ +> +----------+---------+-----------+--------------------------+ +> | Centered | Left | Right | Default aligned | +> | Header | Aligned | Aligned | | +> +==========+=========+===========+==========================+ +> | First | row | 12.0 | Example of a row that | +> | | | | spans multiple lines. | +> +----------+---------+-----------+--------------------------+ +> | Second | row | 5.0 | Here’s another one. Note | +> | | | | the blank line between | +> | | | | rows. | +> +----------+---------+-----------+--------------------------+ Table without column headers: @@ -80,11 +80,11 @@ Table without column headers: Multiline table without column headers: -> +----------+---------+-----------+-------------------------+ -> | First | row | 12.0 | Example of a row that | -> | | | | spans multiple lines. | -> +----------+---------+-----------+-------------------------+ -> | Second | row | 5.0 | Here’s another one. | -> | | | | Note the blank line | -> | | | | between rows. | -> +----------+---------+-----------+-------------------------+ +> +----------+---------+-----------+--------------------------+ +> | First | row | 12.0 | Example of a row that | +> | | | | spans multiple lines. | +> +----------+---------+-----------+--------------------------+ +> | Second | row | 5.0 | Here’s another one. Note | +> | | | | the blank line between | +> | | | | rows. | +> +----------+---------+-----------+--------------------------+ diff --git a/test/tables.html4 b/test/tables.html4 index 5bb7a7de2..0f699133b 100644 --- a/test/tables.html4 +++ b/test/tables.html4 @@ -94,13 +94,13 @@ </tbody> </table> <p>Multiline table with caption:</p> -<table style="width:79%;"> +<table style="width:80%;"> <caption>Here’s the caption. It may span multiple lines.</caption> <colgroup> <col width="15%" /> <col width="13%" /> <col width="16%" /> -<col width="33%" /> +<col width="35%" /> </colgroup> <thead> <tr class="header"> @@ -126,12 +126,12 @@ </tbody> </table> <p>Multiline table without caption:</p> -<table style="width:79%;"> +<table style="width:80%;"> <colgroup> <col width="15%" /> <col width="13%" /> <col width="16%" /> -<col width="33%" /> +<col width="35%" /> </colgroup> <thead> <tr class="header"> @@ -180,12 +180,12 @@ </tbody> </table> <p>Multiline table without column headers:</p> -<table style="width:79%;"> +<table style="width:80%;"> <colgroup> <col width="15%" /> <col width="13%" /> <col width="16%" /> -<col width="33%" /> +<col width="35%" /> </colgroup> <tbody> <tr class="odd"> diff --git a/test/tables.html5 b/test/tables.html5 index 17a82110f..533d2fd25 100644 --- a/test/tables.html5 +++ b/test/tables.html5 @@ -94,13 +94,13 @@ </tbody> </table> <p>Multiline table with caption:</p> -<table style="width:79%;"> +<table style="width:80%;"> <caption>Here’s the caption. It may span multiple lines.</caption> <colgroup> <col style="width: 15%" /> <col style="width: 13%" /> <col style="width: 16%" /> -<col style="width: 33%" /> +<col style="width: 35%" /> </colgroup> <thead> <tr class="header"> @@ -126,12 +126,12 @@ </tbody> </table> <p>Multiline table without caption:</p> -<table style="width:79%;"> +<table style="width:80%;"> <colgroup> <col style="width: 15%" /> <col style="width: 13%" /> <col style="width: 16%" /> -<col style="width: 33%" /> +<col style="width: 35%" /> </colgroup> <thead> <tr class="header"> @@ -180,12 +180,12 @@ </tbody> </table> <p>Multiline table without column headers:</p> -<table style="width:79%;"> +<table style="width:80%;"> <colgroup> <col style="width: 15%" /> <col style="width: 13%" /> <col style="width: 16%" /> -<col style="width: 33%" /> +<col style="width: 35%" /> </colgroup> <tbody> <tr class="odd"> diff --git a/test/tables.icml b/test/tables.icml index 0280cafed..10945ef46 100644 --- a/test/tables.icml +++ b/test/tables.icml @@ -395,7 +395,7 @@ <Column Name="0" SingleColumnWidth="75.0" /> <Column Name="1" SingleColumnWidth="68.75" /> <Column Name="2" SingleColumnWidth="81.25" /> - <Column Name="3" SingleColumnWidth="168.75" /> + <Column Name="3" SingleColumnWidth="175.0" /> <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell"> <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar > TableHeader > CenterAlign"> <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle"> @@ -497,7 +497,7 @@ <Column Name="0" SingleColumnWidth="75.0" /> <Column Name="1" SingleColumnWidth="68.75" /> <Column Name="2" SingleColumnWidth="81.25" /> - <Column Name="3" SingleColumnWidth="168.75" /> + <Column Name="3" SingleColumnWidth="175.0" /> <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell"> <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar > TableHeader > CenterAlign"> <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle"> @@ -695,7 +695,7 @@ <Column Name="0" SingleColumnWidth="75.0" /> <Column Name="1" SingleColumnWidth="68.75" /> <Column Name="2" SingleColumnWidth="81.25" /> - <Column Name="3" SingleColumnWidth="168.75" /> + <Column Name="3" SingleColumnWidth="175.0" /> <Cell Name="0:0" AppliedCellStyle="CellStyle/Cell"> <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/TablePar > CenterAlign"> <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle"> diff --git a/test/tables.jats b/test/tables.jats index 50e8498f4..70f71e384 100644 --- a/test/tables.jats +++ b/test/tables.jats @@ -122,7 +122,7 @@ <col width="15*" align="center" /> <col width="13*" align="left" /> <col width="16*" align="right" /> - <col width="33*" align="left" /> + <col width="35*" align="left" /> <thead> <tr> <th>Centered Header</th> @@ -152,7 +152,7 @@ <col width="15*" align="center" /> <col width="13*" align="left" /> <col width="16*" align="right" /> - <col width="33*" align="left" /> + <col width="35*" align="left" /> <thead> <tr> <th>Centered Header</th> @@ -208,7 +208,7 @@ <col width="15*" align="center" /> <col width="13*" align="left" /> <col width="16*" align="right" /> - <col width="33*" align="left" /> + <col width="35*" align="left" /> <tbody> <tr> <td>First</td> diff --git a/test/tables.latex b/test/tables.latex index 759b35dfa..4616448a9 100644 --- a/test/tables.latex +++ b/test/tables.latex @@ -58,7 +58,7 @@ Centered Header\strut Left Aligned\strut \end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft Right Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[b]{0.31\columnwidth}\raggedright Default aligned\strut \end{minipage}\tabularnewline \midrule @@ -70,7 +70,7 @@ Centered Header\strut Left Aligned\strut \end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft Right Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[b]{0.31\columnwidth}\raggedright Default aligned\strut \end{minipage}\tabularnewline \midrule @@ -81,7 +81,7 @@ First\strut row\strut \end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft 12.0\strut -\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright Example of a row that spans multiple lines.\strut \end{minipage}\tabularnewline \begin{minipage}[t]{0.13\columnwidth}\centering @@ -90,7 +90,7 @@ Second\strut row\strut \end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft 5.0\strut -\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright Here's another one. Note the blank line between rows.\strut \end{minipage}\tabularnewline \bottomrule @@ -106,7 +106,7 @@ Centered Header\strut Left Aligned\strut \end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft Right Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[b]{0.31\columnwidth}\raggedright Default aligned\strut \end{minipage}\tabularnewline \midrule @@ -117,7 +117,7 @@ First\strut row\strut \end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft 12.0\strut -\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright Example of a row that spans multiple lines.\strut \end{minipage}\tabularnewline \begin{minipage}[t]{0.13\columnwidth}\centering @@ -126,7 +126,7 @@ Second\strut row\strut \end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft 5.0\strut -\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright Here's another one. Note the blank line between rows.\strut \end{minipage}\tabularnewline \bottomrule @@ -154,7 +154,7 @@ First\strut row\strut \end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft 12.0\strut -\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright Example of a row that spans multiple lines.\strut \end{minipage}\tabularnewline \begin{minipage}[t]{0.13\columnwidth}\centering @@ -163,7 +163,7 @@ Second\strut row\strut \end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft 5.0\strut -\end{minipage} & \begin{minipage}[t]{0.30\columnwidth}\raggedright +\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright Here's another one. Note the blank line between rows.\strut \end{minipage}\tabularnewline \bottomrule diff --git a/test/tables.man b/test/tables.man index dd6a3cce9..8c9385b4f 100644 --- a/test/tables.man +++ b/test/tables.man @@ -138,7 +138,7 @@ Multiline table with caption: Here's the caption. It may span multiple lines. .TS tab(@); -cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n). +cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n). T{ Centered Header T}@T{ @@ -174,7 +174,7 @@ Multiline table without caption: .PP .TS tab(@); -cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n). +cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n). T{ Centered Header T}@T{ @@ -244,7 +244,7 @@ Multiline table without column headers: .PP .TS tab(@); -cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n). +cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n). T{ First T}@T{ diff --git a/test/tables.markdown b/test/tables.markdown index f5ee776fa..7f89bfc08 100644 --- a/test/tables.markdown +++ b/test/tables.markdown @@ -28,33 +28,33 @@ Simple table indented two spaces: Multiline table with caption: - ------------------------------------------------------------- + -------------------------------------------------------------- Centered Left Right Default aligned Header Aligned Aligned - ----------- ---------- ------------ ------------------------- + ----------- ---------- ------------ -------------------------- First row 12.0 Example of a row that spans multiple lines. Second row 5.0 Here's another one. Note the blank line between rows. - ------------------------------------------------------------- + -------------------------------------------------------------- : Here's the caption. It may span multiple lines. Multiline table without caption: - ------------------------------------------------------------- + -------------------------------------------------------------- Centered Left Right Default aligned Header Aligned Aligned - ----------- ---------- ------------ ------------------------- + ----------- ---------- ------------ -------------------------- First row 12.0 Example of a row that spans multiple lines. Second row 5.0 Here's another one. Note the blank line between rows. - ------------------------------------------------------------- + -------------------------------------------------------------- Table without column headers: @@ -66,11 +66,11 @@ Table without column headers: Multiline table without column headers: - ----------- ---------- ------------ ------------------------- + ----------- ---------- ------------ -------------------------- First row 12.0 Example of a row that spans multiple lines. Second row 5.0 Here's another one. Note the blank line between rows. - ----------- ---------- ------------ ------------------------- + ----------- ---------- ------------ -------------------------- diff --git a/test/tables.mediawiki b/test/tables.mediawiki index ce7c17887..5402b286b 100644 --- a/test/tables.mediawiki +++ b/test/tables.mediawiki @@ -79,7 +79,7 @@ Multiline table with caption: !align="center" width="15%"| Centered Header !width="13%"| Left Aligned !align="right" width="16%"| Right Aligned -!width="33%"| Default aligned +!width="35%"| Default aligned |- |align="center"| First | row @@ -98,7 +98,7 @@ Multiline table without caption: !align="center" width="15%"| Centered Header !width="13%"| Left Aligned !align="right" width="16%"| Right Aligned -!width="33%"| Default aligned +!width="35%"| Default aligned |- |align="center"| First | row @@ -136,7 +136,7 @@ Multiline table without column headers: |align="center" width="15%"| First |width="13%"| row |align="right" width="16%"| 12.0 -|width="33%"| Example of a row that spans multiple lines. +|width="35%"| Example of a row that spans multiple lines. |- |align="center"| Second | row diff --git a/test/tables.ms b/test/tables.ms index 21b3bd4e2..6d9138c64 100644 --- a/test/tables.ms +++ b/test/tables.ms @@ -135,10 +135,10 @@ T} .LP Multiline table with caption: .PP -Here's the caption. It may span multiple lines. +Here’s the caption. It may span multiple lines. .TS delim(@@) tab( ); -cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n). +cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n). T{ Centered Header T} T{ @@ -165,7 +165,7 @@ row T} T{ 5.0 T} T{ -Here's another one. +Here’s another one. Note the blank line between rows. T} .TE @@ -174,7 +174,7 @@ Multiline table without caption: .PP .TS delim(@@) tab( ); -cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n). +cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n). T{ Centered Header T} T{ @@ -201,7 +201,7 @@ row T} T{ 5.0 T} T{ -Here's another one. +Here’s another one. Note the blank line between rows. T} .TE @@ -244,7 +244,7 @@ Multiline table without column headers: .PP .TS delim(@@) tab( ); -cw(10.5n) lw(9.6n) rw(11.4n) lw(23.6n). +cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n). T{ First T} T{ @@ -261,7 +261,7 @@ row T} T{ 5.0 T} T{ -Here's another one. +Here’s another one. Note the blank line between rows. T} .TE diff --git a/test/tables.native b/test/tables.native index a60f9b586..62ed56bb4 100644 --- a/test/tables.native +++ b/test/tables.native @@ -53,7 +53,7 @@ ,[Plain [Str "1"]] ,[Plain [Str "1"]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"] -,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",SoftBreak,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.3375] +,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",SoftBreak,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.35] [[Plain [Str "Centered",SoftBreak,Str "Header"]] ,[Plain [Str "Left",SoftBreak,Str "Aligned"]] ,[Plain [Str "Right",SoftBreak,Str "Aligned"]] @@ -67,7 +67,7 @@ ,[Plain [Str "5.0"]] ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",Space,Str "rows."]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"] -,Table [] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.3375] +,Table [] [AlignCenter,AlignLeft,AlignRight,AlignLeft] [0.15,0.1375,0.1625,0.35] [[Plain [Str "Centered",SoftBreak,Str "Header"]] ,[Plain [Str "Left",SoftBreak,Str "Aligned"]] ,[Plain [Str "Right",SoftBreak,Str "Aligned"]] @@ -99,7 +99,7 @@ ,[Plain [Str "1"]] ,[Plain [Str "1"]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "column",Space,Str "headers:"] -,Table [] [AlignCenter,AlignLeft,AlignRight,AlignDefault] [0.15,0.1375,0.1625,0.3375] +,Table [] [AlignCenter,AlignLeft,AlignRight,AlignDefault] [0.15,0.1375,0.1625,0.35] [[] ,[] ,[] diff --git a/test/tables.plain b/test/tables.plain index 7013d0caa..e46317a6f 100644 --- a/test/tables.plain +++ b/test/tables.plain @@ -28,33 +28,33 @@ Simple table indented two spaces: Multiline table with caption: - ------------------------------------------------------------- + -------------------------------------------------------------- Centered Left Right Default aligned Header Aligned Aligned - ----------- ---------- ------------ ------------------------- + ----------- ---------- ------------ -------------------------- First row 12.0 Example of a row that spans multiple lines. Second row 5.0 Here’s another one. Note the blank line between rows. - ------------------------------------------------------------- + -------------------------------------------------------------- : Here’s the caption. It may span multiple lines. Multiline table without caption: - ------------------------------------------------------------- + -------------------------------------------------------------- Centered Left Right Default aligned Header Aligned Aligned - ----------- ---------- ------------ ------------------------- + ----------- ---------- ------------ -------------------------- First row 12.0 Example of a row that spans multiple lines. Second row 5.0 Here’s another one. Note the blank line between rows. - ------------------------------------------------------------- + -------------------------------------------------------------- Table without column headers: @@ -66,11 +66,11 @@ Table without column headers: Multiline table without column headers: - ----------- ---------- ------------ ------------------------- + ----------- ---------- ------------ -------------------------- First row 12.0 Example of a row that spans multiple lines. Second row 5.0 Here’s another one. Note the blank line between rows. - ----------- ---------- ------------ ------------------------- + ----------- ---------- ------------ -------------------------- diff --git a/test/tables.rst b/test/tables.rst index e76c505aa..4559883cd 100644 --- a/test/tables.rst +++ b/test/tables.rst @@ -42,31 +42,31 @@ Multiline table with caption: .. table:: Here’s the caption. It may span multiple lines. - +----------+---------+-----------+-------------------------+ - | Centered | Left | Right | Default aligned | - | Header | Aligned | Aligned | | - +==========+=========+===========+=========================+ - | First | row | 12.0 | Example of a row that | - | | | | spans multiple lines. | - +----------+---------+-----------+-------------------------+ - | Second | row | 5.0 | Here’s another one. | - | | | | Note the blank line | - | | | | between rows. | - +----------+---------+-----------+-------------------------+ + +----------+---------+-----------+--------------------------+ + | Centered | Left | Right | Default aligned | + | Header | Aligned | Aligned | | + +==========+=========+===========+==========================+ + | First | row | 12.0 | Example of a row that | + | | | | spans multiple lines. | + +----------+---------+-----------+--------------------------+ + | Second | row | 5.0 | Here’s another one. Note | + | | | | the blank line between | + | | | | rows. | + +----------+---------+-----------+--------------------------+ Multiline table without caption: -+----------+---------+-----------+-------------------------+ -| Centered | Left | Right | Default aligned | -| Header | Aligned | Aligned | | -+==========+=========+===========+=========================+ -| First | row | 12.0 | Example of a row that | -| | | | spans multiple lines. | -+----------+---------+-----------+-------------------------+ -| Second | row | 5.0 | Here’s another one. | -| | | | Note the blank line | -| | | | between rows. | -+----------+---------+-----------+-------------------------+ ++----------+---------+-----------+--------------------------+ +| Centered | Left | Right | Default aligned | +| Header | Aligned | Aligned | | ++==========+=========+===========+==========================+ +| First | row | 12.0 | Example of a row that | +| | | | spans multiple lines. | ++----------+---------+-----------+--------------------------+ +| Second | row | 5.0 | Here’s another one. Note | +| | | | the blank line between | +| | | | rows. | ++----------+---------+-----------+--------------------------+ Table without column headers: @@ -80,11 +80,11 @@ Table without column headers: Multiline table without column headers: -+----------+---------+-----------+-------------------------+ -| First | row | 12.0 | Example of a row that | -| | | | spans multiple lines. | -+----------+---------+-----------+-------------------------+ -| Second | row | 5.0 | Here’s another one. | -| | | | Note the blank line | -| | | | between rows. | -+----------+---------+-----------+-------------------------+ ++----------+---------+-----------+--------------------------+ +| First | row | 12.0 | Example of a row that | +| | | | spans multiple lines. | ++----------+---------+-----------+--------------------------+ +| Second | row | 5.0 | Here’s another one. Note | +| | | | the blank line between | +| | | | rows. | ++----------+---------+-----------+--------------------------+ diff --git a/test/tables.rtf b/test/tables.rtf index 57030b114..97ea46bad 100644 --- a/test/tables.rtf +++ b/test/tables.rtf @@ -187,7 +187,7 @@ {\pard \ql \f0 \sa180 \li0 \fi0 Multiline table with caption:\par} { \trowd \trgaph120 -\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6804 +\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6912 \trkeep\intbl { {{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Centered Header\par} @@ -202,7 +202,7 @@ \intbl\row} { \trowd \trgaph120 -\cellx1296\cellx2484\cellx3888\cellx6804 +\cellx1296\cellx2484\cellx3888\cellx6912 \trkeep\intbl { {{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par} @@ -217,7 +217,7 @@ \intbl\row} { \trowd \trgaph120 -\cellx1296\cellx2484\cellx3888\cellx6804 +\cellx1296\cellx2484\cellx3888\cellx6912 \trkeep\intbl { {{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par} @@ -234,7 +234,7 @@ {\pard \ql \f0 \sa180 \li0 \fi0 Multiline table without caption:\par} { \trowd \trgaph120 -\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6804 +\clbrdrb\brdrs\cellx1296\clbrdrb\brdrs\cellx2484\clbrdrb\brdrs\cellx3888\clbrdrb\brdrs\cellx6912 \trkeep\intbl { {{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Centered Header\par} @@ -249,7 +249,7 @@ \intbl\row} { \trowd \trgaph120 -\cellx1296\cellx2484\cellx3888\cellx6804 +\cellx1296\cellx2484\cellx3888\cellx6912 \trkeep\intbl { {{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par} @@ -264,7 +264,7 @@ \intbl\row} { \trowd \trgaph120 -\cellx1296\cellx2484\cellx3888\cellx6804 +\cellx1296\cellx2484\cellx3888\cellx6912 \trkeep\intbl { {{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par} @@ -328,7 +328,7 @@ {\pard \ql \f0 \sa180 \li0 \fi0 Multiline table without column headers:\par} { \trowd \trgaph120 -\cellx1296\cellx2484\cellx3888\cellx6804 +\cellx1296\cellx2484\cellx3888\cellx6912 \trkeep\intbl { {{\pard\intbl \qc \f0 \sa0 \li0 \fi0 First\par} @@ -343,7 +343,7 @@ \intbl\row} { \trowd \trgaph120 -\cellx1296\cellx2484\cellx3888\cellx6804 +\cellx1296\cellx2484\cellx3888\cellx6912 \trkeep\intbl { {{\pard\intbl \qc \f0 \sa0 \li0 \fi0 Second\par} diff --git a/test/tables.texinfo b/test/tables.texinfo index b82006f1a..4f09246af 100644 --- a/test/tables.texinfo +++ b/test/tables.texinfo @@ -83,7 +83,7 @@ Right Multiline table with caption: @float -@multitable @columnfractions 0.15 0.14 0.16 0.34 +@multitable @columnfractions 0.15 0.14 0.16 0.35 @headitem Centered Header @tab Left Aligned @@ -104,7 +104,7 @@ Second @end float Multiline table without caption: -@multitable @columnfractions 0.15 0.14 0.16 0.34 +@multitable @columnfractions 0.15 0.14 0.16 0.35 @headitem Centered Header @tab Left Aligned @@ -144,7 +144,7 @@ Table without column headers: Multiline table without column headers: -@multitable @columnfractions 0.15 0.14 0.16 0.34 +@multitable @columnfractions 0.15 0.14 0.16 0.35 @item First @tab row diff --git a/test/tables.textile b/test/tables.textile index 6c6b234e6..9c71ec383 100644 --- a/test/tables.textile +++ b/test/tables.textile @@ -80,7 +80,7 @@ Multiline table with caption: <col width="15%" /> <col width="13%" /> <col width="16%" /> -<col width="33%" /> +<col width="35%" /> <thead> <tr class="header"> <th align="center">Centered Header</th> @@ -111,7 +111,7 @@ Multiline table without caption: <col width="15%" /> <col width="13%" /> <col width="16%" /> -<col width="33%" /> +<col width="35%" /> <thead> <tr class="header"> <th align="center">Centered Header</th> @@ -148,7 +148,7 @@ Multiline table without column headers: <col width="15%" /> <col width="13%" /> <col width="16%" /> -<col width="33%" /> +<col width="35%" /> <tbody> <tr class="odd"> <td align="center">First</td> diff --git a/test/test-pandoc.hs.orig b/test/test-pandoc.hs.orig new file mode 100644 index 000000000..4cf1a952d --- /dev/null +++ b/test/test-pandoc.hs.orig @@ -0,0 +1,83 @@ +{-# OPTIONS_GHC -Wall #-} + +module Main where + +import GHC.IO.Encoding +import Test.Tasty +import qualified Tests.Command +import qualified Tests.Lua +import qualified Tests.Old +import qualified Tests.Readers.Creole +import qualified Tests.Readers.Docx +import qualified Tests.Readers.EPUB +import qualified Tests.Readers.HTML +import qualified Tests.Readers.JATS +import qualified Tests.Readers.LaTeX +import qualified Tests.Readers.Markdown +import qualified Tests.Readers.Muse +import qualified Tests.Readers.Odt +import qualified Tests.Readers.Org +import qualified Tests.Readers.RST +import qualified Tests.Readers.Txt2Tags +import qualified Tests.Shared +import qualified Tests.Writers.AsciiDoc +import qualified Tests.Writers.ConTeXt +import qualified Tests.Writers.Docbook +import qualified Tests.Writers.Docx +import qualified Tests.Writers.FB2 +import qualified Tests.Writers.HTML +import qualified Tests.Writers.JATS +import qualified Tests.Writers.LaTeX +import qualified Tests.Writers.Markdown +import qualified Tests.Writers.Muse +import qualified Tests.Writers.Native +import qualified Tests.Writers.Org +import qualified Tests.Writers.Plain +import qualified Tests.Writers.Powerpoint +import qualified Tests.Writers.RST +import qualified Tests.Writers.TEI +import Text.Pandoc.Shared (inDirectory) + +tests :: TestTree +tests = testGroup "pandoc tests" [ Tests.Command.tests + , testGroup "Old" Tests.Old.tests + , testGroup "Shared" Tests.Shared.tests + , testGroup "Writers" + [ testGroup "Native" Tests.Writers.Native.tests + , testGroup "ConTeXt" Tests.Writers.ConTeXt.tests + , testGroup "LaTeX" Tests.Writers.LaTeX.tests + , testGroup "HTML" Tests.Writers.HTML.tests + , testGroup "JATS" Tests.Writers.JATS.tests + , testGroup "Docbook" Tests.Writers.Docbook.tests + , testGroup "Markdown" Tests.Writers.Markdown.tests + , testGroup "Org" Tests.Writers.Org.tests + , testGroup "Plain" Tests.Writers.Plain.tests + , testGroup "AsciiDoc" Tests.Writers.AsciiDoc.tests + , testGroup "Docx" Tests.Writers.Docx.tests + , testGroup "RST" Tests.Writers.RST.tests + , testGroup "TEI" Tests.Writers.TEI.tests + , testGroup "Muse" Tests.Writers.Muse.tests + , testGroup "FB2" Tests.Writers.FB2.tests + , testGroup "PowerPoint" Tests.Writers.Powerpoint.tests + ] + , testGroup "Readers" + [ testGroup "LaTeX" Tests.Readers.LaTeX.tests + , testGroup "Markdown" Tests.Readers.Markdown.tests + , testGroup "HTML" Tests.Readers.HTML.tests + , testGroup "JATS" Tests.Readers.JATS.tests + , testGroup "Org" Tests.Readers.Org.tests + , testGroup "RST" Tests.Readers.RST.tests + , testGroup "Docx" Tests.Readers.Docx.tests + , testGroup "Odt" Tests.Readers.Odt.tests + , testGroup "Txt2Tags" Tests.Readers.Txt2Tags.tests + , testGroup "EPUB" Tests.Readers.EPUB.tests + , testGroup "Muse" Tests.Readers.Muse.tests + , testGroup "Creole" Tests.Readers.Creole.tests + ] + , testGroup "Lua filters" Tests.Lua.tests + ] + +main :: IO () +main = do + setLocaleEncoding utf8 + inDirectory "test" $ defaultMain tests diff --git a/test/writer.fb2 b/test/writer.fb2 index 641d833cd..b2d002230 100644 --- a/test/writer.fb2 +++ b/test/writer.fb2 @@ -32,9 +32,7 @@ John Gruber’s markdown test suite.</p> </title> <section> <title> -<p>Level 2 with an embedded link<a l:href="#l1" type="note"> -<sup>[1]</sup> -</a> +<p>Level 2 with an <a l:href="/url">embedded link</a> </p> </title> <section> @@ -492,9 +490,8 @@ crisp, pleasant to taste</p> </title> <p>This is <emphasis>emphasized</emphasis>, and so <emphasis>is this</emphasis>.</p> <p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p> -<p>An <emphasis>emphasized link<a l:href="#l2" type="note"> -<sup>[2]</sup> -</a> +<p>An <emphasis> +<a l:href="/url">emphasized link</a> </emphasis>.</p> <p> <strong> @@ -534,9 +531,7 @@ because of the unescaped spaces: a^b c^d, a~b c~d.</p> So is ‘pine.’</p> <p>‘He said, “I want to go.”’ Were you alive in the 70’s?</p> -<p>Here is some quoted ‘<code>code</code>’ and a “quoted link<a l:href="#l3" type="note"> -<sup>[3]</sup> -</a>”.</p> +<p>Here is some quoted ‘<code>code</code>’ and a “<a l:href="http://example.com/?foo=1&bar=2">quoted link</a>”.</p> <p>Some dashes: one—two — three—four — five.</p> <p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p> <p>Ellipses…and…and….</p> @@ -610,112 +605,71 @@ So is ‘pine.’</p> <title> <p>Explicit</p> </title> -<p>Just a URL<a l:href="#l4" type="note"> -<sup>[4]</sup> -</a>.</p> -<p>URL and title<a l:href="#l5" type="note"> -<sup>[5]</sup> -</a>.</p> -<p>URL and title<a l:href="#l6" type="note"> -<sup>[6]</sup> -</a>.</p> -<p>URL and title<a l:href="#l7" type="note"> -<sup>[7]</sup> -</a>.</p> -<p>URL and title<a l:href="#l8" type="note"> -<sup>[8]</sup> -</a> +<p>Just a <a l:href="/url/">URL</a>.</p> +<p> +<a l:href="/url/">URL and title</a>.</p> +<p> +<a l:href="/url/">URL and title</a>.</p> +<p> +<a l:href="/url/">URL and title</a>.</p> +<p> +<a l:href="/url/">URL and title</a> </p> -<p>URL and title<a l:href="#l9" type="note"> -<sup>[9]</sup> -</a> +<p> +<a l:href="/url/">URL and title</a> </p> -<p>with_underscore<a l:href="#l10" type="note"> -<sup>[10]</sup> -</a> +<p> +<a l:href="/url/with_underscore">with_underscore</a> </p> -<p>Email link<a l:href="#l11" type="note"> -<sup>[11]</sup> -</a> +<p> +<a l:href="mailto:nobody@nowhere.net">Email link</a> </p> -<p>Empty<a l:href="#l12" type="note"> -<sup>[12]</sup> -</a>.</p> +<p> +<a l:href="">Empty</a>.</p> </section> <section> <title> <p>Reference</p> </title> -<p>Foo bar<a l:href="#l13" type="note"> -<sup>[13]</sup> -</a>.</p> -<p>With embedded [brackets]<a l:href="#l14" type="note"> -<sup>[14]</sup> -</a>.</p> -<p>b<a l:href="#l15" type="note"> -<sup>[15]</sup> -</a> by itself should be a link.</p> -<p>Indented once<a l:href="#l16" type="note"> -<sup>[16]</sup> -</a>.</p> -<p>Indented twice<a l:href="#l17" type="note"> -<sup>[17]</sup> -</a>.</p> -<p>Indented thrice<a l:href="#l18" type="note"> -<sup>[18]</sup> -</a>.</p> +<p>Foo <a l:href="/url/">bar</a>.</p> +<p>With <a l:href="/url/">embedded [brackets]</a>.</p> +<p> +<a l:href="/url/">b</a> by itself should be a link.</p> +<p>Indented <a l:href="/url">once</a>.</p> +<p>Indented <a l:href="/url">twice</a>.</p> +<p>Indented <a l:href="/url">thrice</a>.</p> <p>This should [not][] be a link.</p> <empty-line /> <p> <code>[not]: /url</code> </p> <empty-line /> -<p>Foo bar<a l:href="#l19" type="note"> -<sup>[19]</sup> -</a>.</p> -<p>Foo biz<a l:href="#l20" type="note"> -<sup>[20]</sup> -</a>.</p> +<p>Foo <a l:href="/url/">bar</a>.</p> +<p>Foo <a l:href="/url/">biz</a>.</p> </section> <section> <title> <p>With ampersands</p> </title> -<p>Here’s a link with an ampersand in the URL<a l:href="#l21" type="note"> -<sup>[21]</sup> -</a>.</p> -<p>Here’s a link with an amersand in the link text: AT&T<a l:href="#l22" type="note"> -<sup>[22]</sup> -</a>.</p> -<p>Here’s an inline link<a l:href="#l23" type="note"> -<sup>[23]</sup> -</a>.</p> -<p>Here’s an inline link in pointy braces<a l:href="#l24" type="note"> -<sup>[24]</sup> -</a>.</p> +<p>Here’s a <a l:href="http://example.com/?foo=1&bar=2">link with an ampersand in the URL</a>.</p> +<p>Here’s a link with an amersand in the link text: <a l:href="http://att.com/">AT&T</a>.</p> +<p>Here’s an <a l:href="/script?foo=1&bar=2">inline link</a>.</p> +<p>Here’s an <a l:href="/script?foo=1&bar=2">inline link in pointy braces</a>.</p> </section> <section> <title> <p>Autolinks</p> </title> -<p>With an ampersand: http://example.com/?foo=1&bar=2<a l:href="#l25" type="note"> -<sup>[25]</sup> -</a> +<p>With an ampersand: <a l:href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a> </p> <p>• In a list?</p> -<p>• http://example.com/<a l:href="#l26" type="note"> -<sup>[26]</sup> -</a> +<p>• <a l:href="http://example.com/">http://example.com/</a> </p> <p>• It should.</p> -<p>An e-mail address: nobody@nowhere.net<a l:href="#l27" type="note"> -<sup>[27]</sup> -</a> +<p>An e-mail address: <a l:href="mailto:nobody@nowhere.net">nobody@nowhere.net</a> </p> <cite> -<p>Blockquoted: http://example.com/<a l:href="#l28" type="note"> -<sup>[28]</sup> -</a> +<p>Blockquoted: <a l:href="http://example.com/">http://example.com/</a> </p> </cite> <p>Auto-links should not occur here: <code><http://example.com/></code> @@ -741,257 +695,40 @@ So is ‘pine.’</p> <title> <p>Footnotes</p> </title> -<p>Here is a footnote reference,<a l:href="#n29" type="note"> -<sup>[29]</sup> -</a> and another.<a l:href="#n30" type="note"> -<sup>[30]</sup> +<p>Here is a footnote reference,<a l:href="#n1" type="note"> +<sup>[1]</sup> +</a> and another.<a l:href="#n2" type="note"> +<sup>[2]</sup> </a> This should <emphasis>not</emphasis> be a footnote reference, because it -contains a space.[^my note] Here is an inline note.<a l:href="#n31" type="note"> -<sup>[31]</sup> +contains a space.[^my note] Here is an inline note.<a l:href="#n3" type="note"> +<sup>[3]</sup> </a> </p> <cite> -<p>Notes can go in quotes.<a l:href="#n32" type="note"> -<sup>[32]</sup> +<p>Notes can go in quotes.<a l:href="#n4" type="note"> +<sup>[4]</sup> </a> </p> </cite> -<p>1. And in list items.<a l:href="#n33" type="note"> -<sup>[33]</sup> +<p>1. And in list items.<a l:href="#n5" type="note"> +<sup>[5]</sup> </a> </p> <p>This paragraph should not be part of the note, as it is not indented.</p> </section> </body> <body name="notes"> -<section id="l1"> +<section id="n1"> <title> <p>1</p> </title> -<p> -<code>/url</code> -</p> -</section> -<section id="l2"> -<title> -<p>2</p> -</title> -<p> -<code>/url</code> -</p> -</section> -<section id="l3"> -<title> -<p>3</p> -</title> -<p> -<code>http://example.com/?foo=1&bar=2</code> -</p> -</section> -<section id="l4"> -<title> -<p>4</p> -</title> -<p> -<code>/url/</code> -</p> -</section> -<section id="l5"> -<title> -<p>5</p> -</title> -<p>title: <code>/url/</code> -</p> -</section> -<section id="l6"> -<title> -<p>6</p> -</title> -<p>title preceded by two spaces: <code>/url/</code> -</p> -</section> -<section id="l7"> -<title> -<p>7</p> -</title> -<p>title preceded by a tab: <code>/url/</code> -</p> -</section> -<section id="l8"> -<title> -<p>8</p> -</title> -<p>title with "quotes" in it: <code>/url/</code> -</p> -</section> -<section id="l9"> -<title> -<p>9</p> -</title> -<p>title with single quotes: <code>/url/</code> -</p> -</section> -<section id="l10"> -<title> -<p>10</p> -</title> -<p> -<code>/url/with_underscore</code> -</p> -</section> -<section id="l11"> -<title> -<p>11</p> -</title> -<p> -<code>mailto:nobody@nowhere.net</code> -</p> -</section> -<section id="l12"> -<title> -<p>12</p> -</title> -<p> -<code> -</code> -</p> -</section> -<section id="l13"> -<title> -<p>13</p> -</title> -<p> -<code>/url/</code> -</p> -</section> -<section id="l14"> -<title> -<p>14</p> -</title> -<p> -<code>/url/</code> -</p> -</section> -<section id="l15"> -<title> -<p>15</p> -</title> -<p> -<code>/url/</code> -</p> -</section> -<section id="l16"> -<title> -<p>16</p> -</title> -<p> -<code>/url</code> -</p> -</section> -<section id="l17"> -<title> -<p>17</p> -</title> -<p> -<code>/url</code> -</p> -</section> -<section id="l18"> -<title> -<p>18</p> -</title> -<p> -<code>/url</code> -</p> -</section> -<section id="l19"> -<title> -<p>19</p> -</title> -<p>Title with "quotes" inside: <code>/url/</code> -</p> -</section> -<section id="l20"> -<title> -<p>20</p> -</title> -<p>Title with "quote" inside: <code>/url/</code> -</p> -</section> -<section id="l21"> -<title> -<p>21</p> -</title> -<p> -<code>http://example.com/?foo=1&bar=2</code> -</p> -</section> -<section id="l22"> -<title> -<p>22</p> -</title> -<p>AT&T: <code>http://att.com/</code> -</p> -</section> -<section id="l23"> -<title> -<p>23</p> -</title> -<p> -<code>/script?foo=1&bar=2</code> -</p> -</section> -<section id="l24"> -<title> -<p>24</p> -</title> -<p> -<code>/script?foo=1&bar=2</code> -</p> -</section> -<section id="l25"> -<title> -<p>25</p> -</title> -<p> -<code>http://example.com/?foo=1&bar=2</code> -</p> -</section> -<section id="l26"> -<title> -<p>26</p> -</title> -<p> -<code>http://example.com/</code> -</p> -</section> -<section id="l27"> -<title> -<p>27</p> -</title> -<p> -<code>mailto:nobody@nowhere.net</code> -</p> -</section> -<section id="l28"> -<title> -<p>28</p> -</title> -<p> -<code>http://example.com/</code> -</p> -</section> -<section id="n29"> -<title> -<p>29</p> -</title> <p>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</p> </section> -<section id="n30"> +<section id="n2"> <title> -<p>30</p> +<p>2</p> </title> <p>Here’s the long note. This one contains multiple blocks.</p> @@ -1005,29 +742,26 @@ footnote (as with list items).</p> <p>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</p> </section> -<section id="n31"> +<section id="n3"> <title> -<p>31</p> +<p>3</p> </title> <p>This is <emphasis>easier</emphasis> to type. Inline notes may contain -links<a l:href="#l31" type="note"> -<sup>[31]</sup> -</a> and <code>]</code> verbatim characters, +<a l:href="http://google.com">links</a> and <code>]</code> verbatim characters, as well as [bracketed text].</p> </section> -<section id="n32"> +<section id="n4"> <title> -<p>32</p> +<p>4</p> </title> <p>In quote.</p> </section> -<section id="n33"> +<section id="n5"> <title> -<p>33</p> +<p>5</p> </title> <p>In list.</p> </section> </body> </FictionBook> - diff --git a/test/writer.ms b/test/writer.ms index a9ca07259..e7ac44bb9 100644 --- a/test/writer.ms +++ b/test/writer.ms @@ -67,12 +67,15 @@ Pandoc Test Suite John MacFarlane .AU Anonymous -.ND "July 17, 2006" +.AU +.sp 0.5 +.ft R +July 17, 2006 .\" 1 column (use .2C for two column) .1C .LP This is a set of tests for pandoc. -Most of them are adapted from John Gruber's markdown test suite. +Most of them are adapted from John Gruber’s markdown test suite. .HLINE .SH 1 Headers @@ -86,7 +89,7 @@ Level 2 with an \c .pdfhref O 2 "Level 2 with an embedded link" .pdfhref M "level-2-with-an-embedded-link" .SH 3 -Level 3 with \f[I]emphasis\f[] +Level 3 with \f[BI]emphasis\f[B] .pdfhref O 3 "Level 3 with emphasis" .pdfhref M "level-3-with-emphasis" .SH 4 @@ -102,7 +105,7 @@ Level 1 .pdfhref O 1 "Level 1" .pdfhref M "level-1" .SH 2 -Level 2 with \f[I]emphasis\f[] +Level 2 with \f[BI]emphasis\f[B] .pdfhref O 2 "Level 2 with emphasis" .pdfhref M "level-2-with-emphasis" .SH 3 @@ -123,7 +126,7 @@ Paragraphs .pdfhref O 1 "Paragraphs" .pdfhref M "paragraphs" .LP -Here's a regular paragraph. +Here’s a regular paragraph. .PP In Markdown 1.0.0 and earlier. Version 8. @@ -131,7 +134,7 @@ This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item. .PP -Here's one with a bullet. +Here’s one with a bullet. * criminey. .PP There should be a hard line break @@ -311,7 +314,7 @@ Item 1, graf one. .PP Item 1. graf two. -The quick brown fox jumped over the lazy dog's back. +The quick brown fox jumped over the lazy dog’s back. .RE .IP " 2." 4 Item 2. @@ -332,7 +335,7 @@ Tab .RE .RE .LP -Here's another: +Here’s another: .IP " 1." 4 First .IP " 2." 4 @@ -481,13 +484,13 @@ yellow fruit .RE .LP Multiple blocks with italics: -.IP "\f[I]apple\f[]" +.IP "\f[I]apple\f[R]" red fruit .RS .PP contains seeds, crisp, pleasant to taste .RE -.IP "\f[I]orange\f[]" +.IP "\f[I]orange\f[R]" orange fruit .RS .IP @@ -564,10 +567,10 @@ foo bar .LP Interpreted markdown in a table: -This is \f[I]emphasized\f[] -And this is \f[B]strong\f[] +This is \f[I]emphasized\f[R] +And this is \f[B]strong\f[R] .PP -Here's a simple block: +Here’s a simple block: .LP foo .LP @@ -614,36 +617,36 @@ Code: \f[] .fi .LP -Hr's: +Hr’s: .HLINE .SH 1 Inline Markup .pdfhref O 1 "Inline Markup" .pdfhref M "inline-markup" .LP -This is \f[I]emphasized\f[], and so \f[I]is this\f[]. +This is \f[I]emphasized\f[R], and so \f[I]is this\f[R]. .PP -This is \f[B]strong\f[], and so \f[B]is this\f[]. +This is \f[B]strong\f[R], and so \f[B]is this\f[R]. .PP An \f[I]\c .pdfhref W -D "/url" -A "\c" \ -- "emphasized link" -\&\f[]. +\&\f[R]. .PP -\f[B]\f[BI]This is strong and em.\f[B]\f[] +\f[B]\f[BI]This is strong and em.\f[B]\f[R] .PP -So is \f[B]\f[BI]this\f[B]\f[] word. +So is \f[B]\f[BI]this\f[B]\f[R] word. .PP -\f[B]\f[BI]This is strong and em.\f[B]\f[] +\f[B]\f[BI]This is strong and em.\f[B]\f[R] .PP -So is \f[B]\f[BI]this\f[B]\f[] word. +So is \f[B]\f[BI]this\f[B]\f[R] word. .PP -This is code: \f[C]>\f[], \f[C]$\f[], \f[C]\\\f[], \f[C]\\$\f[], -\f[C]<html>\f[]. +This is code: \f[C]>\f[R], \f[C]$\f[R], \f[C]\\\f[R], \f[C]\\$\f[R], +\f[C]<html>\f[R]. .PP -\m[strikecolor]This is \f[I]strikeout\f[].\m[] +\m[strikecolor]This is \f[I]strikeout\f[R].\m[] .PP -Superscripts: a\*{bc\*}d a\*{\f[I]hello\f[]\*} a\*{hello\~there\*}. +Superscripts: a\*{bc\*}d a\*{\f[I]hello\f[R]\*} a\*{hello\~there\*}. .PP Subscripts: H\*<2\*>O, H\*<23\*>O, H\*<many\~of\~them\*>O. .PP @@ -663,9 +666,9 @@ Smart quotes, ellipses, dashes `Oak,' `elm,' and `beech' are names of trees. So is `pine.' .PP -`He said, \[lq]I want to go.\[rq]' Were you alive in the 70's? +`He said, \[lq]I want to go.\[rq]' Were you alive in the 70’s? .PP -Here is some quoted `\f[C]code\f[]' and a \[lq]\c +Here is some quoted `\f[C]code\f[R]' and a \[lq]\c .pdfhref W -D "http://example.com/?foo=1&bar=2" -A "\c" \ -- "quoted link" \&\[rq]. @@ -692,26 +695,26 @@ LaTeX .IP \[bu] 3 @p@-Tree .IP \[bu] 3 -Here's some display math: +Here’s some display math: .EQ d over {d x} f ( x ) = lim sub {h -> 0} {f ( x + h ) \[u2212] f ( x )} over h .EN .IP \[bu] 3 -Here's one that has a line break in it: @alpha + omega times x sup 2@. +Here’s one that has a line break in it: @alpha + omega times x sup 2@. .LP -These shouldn't be math: +These shouldn’t be math: .IP \[bu] 3 -To get the famous equation, write \f[C]$e\ =\ mc\[ha]2$\f[]. +To get the famous equation, write \f[C]$e\ =\ mc\[ha]2$\f[R]. .IP \[bu] 3 -$22,000 is a \f[I]lot\f[] of money. +$22,000 is a \f[I]lot\f[R] of money. So is $34,000. (It worked if \[lq]lot\[rq] is emphasized.) .IP \[bu] 3 Shoes ($20) and socks ($5). .IP \[bu] 3 -Escaped \f[C]$\f[]: $73 \f[I]this should be emphasized\f[] 23$. +Escaped \f[C]$\f[R]: $73 \f[I]this should be emphasized\f[R] 23$. .LP -Here's a LaTeX table: +Here’s a LaTeX table: .HLINE .SH 1 Special Characters @@ -882,22 +885,22 @@ With ampersands .pdfhref O 2 "With ampersands" .pdfhref M "with-ampersands" .LP -Here's a \c +Here’s a \c .pdfhref W -D "http://example.com/?foo=1&bar=2" -A "\c" \ -- "link with an ampersand in the URL" \&. .PP -Here's a link with an amersand in the link text: \c +Here’s a link with an amersand in the link text: \c .pdfhref W -D "http://att.com/" -A "\c" \ -- "AT&T" \&. .PP -Here's an \c +Here’s an \c .pdfhref W -D "/script?foo=1&bar=2" -A "\c" \ -- "inline link" \&. .PP -Here's an \c +Here’s an \c .pdfhref W -D "/script?foo=1&bar=2" -A "\c" \ -- "inline link in pointy braces" \&. @@ -932,7 +935,7 @@ Blockquoted: \c \& .RE .LP -Auto-links should not occur here: \f[C]<http://example.com/>\f[] +Auto-links should not occur here: \f[C]<http://example.com/>\f[R] .IP .nf \f[C] @@ -964,7 +967,7 @@ It need not be placed at the end of the document. .FE and another.\** .FS -Here's the long note. +Here’s the long note. This one contains multiple blocks. .PP Subsequent blocks are indented to show that they belong to the footnote (as @@ -979,14 +982,14 @@ with list items). If you want, you can indent every line, but you can also be lazy and just indent the first line of each block. .FE -This should \f[I]not\f[] be a footnote reference, because it contains a +This should \f[I]not\f[R] be a footnote reference, because it contains a space.[\[ha]my note] Here is an inline note.\** .FS -This is \f[I]easier\f[] to type. +This is \f[I]easier\f[R] to type. Inline notes may contain \c .pdfhref W -D "http://google.com" -A "\c" \ -- "links" -\& and \f[C]]\f[] verbatim characters, as well as [bracketed text]. +\& and \f[C]]\f[R] verbatim characters, as well as [bracketed text]. .FE .RS .LP diff --git a/test/writer.muse b/test/writer.muse index 83a53a1ab..9492a5517 100644 --- a/test/writer.muse +++ b/test/writer.muse @@ -79,7 +79,7 @@ nested </quote> </quote> -This should not be a block quote: 2 <verbatim>></verbatim> 1. +This should not be a block quote: 2 > 1. And a following paragraph. @@ -562,7 +562,7 @@ This & that. 4 <verbatim><</verbatim> 5. -6 <verbatim>></verbatim> 5. +6 > 5. Backslash: \ @@ -584,7 +584,7 @@ Left paren: ( Right paren: ) -Greater-than: <verbatim>></verbatim> +Greater-than: > Hash: <verbatim>#</verbatim> diff --git a/test/writer.rst b/test/writer.rst index 93158f0c3..0c986b887 100644 --- a/test/writer.rst +++ b/test/writer.rst @@ -69,30 +69,30 @@ Block Quotes E-mail style: - This is a block quote. It is pretty short. + This is a block quote. It is pretty short. .. - Code in a block quote: + Code in a block quote: - :: + :: - sub status { - print "working"; - } + sub status { + print "working"; + } - A list: + A list: - 1. item one - 2. item two + 1. item one + 2. item two - Nested block quotes: + Nested block quotes: - nested + nested - .. + .. - nested + nested This should not be a block quote: 2 > 1. @@ -107,21 +107,21 @@ Code: :: - ---- (should be four hyphens) + ---- (should be four hyphens) - sub status { - print "working"; - } + sub status { + print "working"; + } - this code block is indented by one tab + this code block is indented by one tab And: :: - this code block is indented by two tabs + this code block is indented by two tabs - These should not be escaped: \$ \\ \> \[ \{ + These should not be escaped: \$ \\ \> \[ \{ -------------- @@ -302,83 +302,83 @@ Definition Lists Tight using spaces: apple - red fruit + red fruit orange - orange fruit + orange fruit banana - yellow fruit + yellow fruit Tight using tabs: apple - red fruit + red fruit orange - orange fruit + orange fruit banana - yellow fruit + yellow fruit Loose: apple - red fruit + red fruit orange - orange fruit + orange fruit banana - yellow fruit + yellow fruit Multiple blocks with italics: *apple* - red fruit + red fruit - contains seeds, crisp, pleasant to taste + contains seeds, crisp, pleasant to taste *orange* - orange fruit + orange fruit - :: + :: - { orange code block } + { orange code block } - .. + .. - orange block quote + orange block quote Multiple definitions, tight: apple - red fruit - computer + red fruit + computer orange - orange fruit - bank + orange fruit + bank Multiple definitions, loose: apple - red fruit + red fruit - computer + computer orange - orange fruit + orange fruit - bank + bank Blank line after term, indented marker, alternate markers: apple - red fruit + red fruit - computer + computer orange - orange fruit + orange fruit - 1. sublist - 2. sublist + 1. sublist + 2. sublist HTML Blocks =========== @@ -491,15 +491,15 @@ This should be a code block, though: :: - <div> - foo - </div> + <div> + foo + </div> As should this: :: - <div>foo</div> + <div>foo</div> Now, nested: @@ -554,7 +554,7 @@ Code block: :: - <!-- Comment --> + <!-- Comment --> Just plain comment, with trailing spaces on the line: @@ -566,7 +566,7 @@ Code: :: - <hr /> + <hr /> Hr’s: @@ -615,21 +615,21 @@ This is *emphasized*, and so *is this*. This is **strong**, and so **is this**. -An *`emphasized link </url>`__*. +An `emphasized link </url>`__. -***This is strong and em.*** +**This is strong and em.** -So is ***this*** word. +So is **this** word. -***This is strong and em.*** +**This is strong and em.** -So is ***this*** word. +So is **this** word. This is code: ``>``, ``$``, ``\``, ``\$``, ``<html>``. -[STRIKEOUT:This is *strikeout*.] +[STRIKEOUT:This is strikeout.] -Superscripts: a\ :sup:`bc`\ d a\ :sup:`*hello*` a\ :sup:`hello there`. +Superscripts: a\ :sup:`bc`\ d a\ :sup:`hello` a\ :sup:`hello there`. Subscripts: H\ :sub:`2`\ O, H\ :sub:`23`\ O, H\ :sub:`many of them`\ O. @@ -793,7 +793,7 @@ This should [not][] be a link. :: - [not]: /url + [not]: /url Foo `bar </url/>`__. @@ -822,13 +822,13 @@ With an ampersand: http://example.com/?foo=1&bar=2 An e-mail address: nobody@nowhere.net - Blockquoted: http://example.com/ + Blockquoted: http://example.com/ Auto-links should not occur here: ``<http://example.com/>`` :: - or here: <http://example.com/> + or here: <http://example.com/> -------------- @@ -853,7 +853,7 @@ Here is a footnote reference, [1]_ and another. [2]_ This should *not* be a footnote reference, because it contains a space.[^my note] Here is an inline note. [3]_ - Notes can go in quotes. [4]_ + Notes can go in quotes. [4]_ 1. And in list items. [5]_ @@ -871,7 +871,7 @@ This paragraph should not be part of the note, as it is not indented. :: - { <code> } + { <code> } If you want, you can indent every line, but you can also be lazy and just indent the first line of each block. diff --git a/tools/update-readme.lua b/tools/update-readme.lua index 4f77c59c2..eabaf2285 100644 --- a/tools/update-readme.lua +++ b/tools/update-readme.lua @@ -1,38 +1,22 @@ -- update README.md based on MANUAL.txt --- assumes that the README.md has a div with id 'description'. --- this gets replaced by the contents of the 'description' section --- of the manual. +-- inserts contents of input-formats and output-formats + +local f = assert(io.open("MANUAL.txt", "r")) +local manual = f:read("*all") +mdoc = pandoc.read(manual, "markdown") +f:close() +result = {} function Div(elem) - if elem.classes[1] and elem.classes[1] == 'description' then - local f = assert(io.open("MANUAL.txt", "r")) - local manual = f:read("*all") - f:close() - local description = {} - local i = 1 - local include = false - local mdoc = pandoc.read(manual, "markdown") - local blocks = mdoc.blocks - while blocks[i] do - if blocks[i].t == 'Header' then - include = false - end - if include then - table.insert(description, pandoc.walk_block(blocks[i], - -- remove internal links - { Link = function(el) - if el.target:match("^#") then - return el.content - end - end })) - end - if blocks[i].t == 'Header' and - blocks[i].identifier == 'description' then - include = true - end - i = i + 1 - end - return pandoc.Div(description, pandoc.Attr("description",{},{})) + local ident = elem.identifier or "" + local get = function(el) + if el.identifier == ident then + result = el + end + end + if ident == 'input-formats' or ident == 'output-formats' then + pandoc.walk_block(pandoc.Div(mdoc.blocks), { Div = get }) + return result end end |