aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MANUAL.txt4
-rw-r--r--data/vimwiki.css82
-rw-r--r--pandoc.cabal2
-rw-r--r--src/Text/Pandoc/Readers.hs3
-rw-r--r--src/Text/Pandoc/Readers/Vimwiki.hs655
-rw-r--r--test/Tests/Old.hs4
-rw-r--r--test/vimwiki-reader.native305
-rw-r--r--test/vimwiki-reader.wiki414
8 files changed, 1467 insertions, 2 deletions
diff --git a/MANUAL.txt b/MANUAL.txt
index 772871bd9..275b47c72 100644
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -16,8 +16,8 @@ another, and a command-line tool that uses this library. It can read
Markdown], [MultiMarkdown], and (subsets of) [Textile],
[reStructuredText], [HTML], [LaTeX], [MediaWiki markup], [TWiki markup],
[Haddock markup], [OPML], [Emacs Org mode], [DocBook], [Muse], [txt2tags],
-[EPUB], [ODT] and [Word docx]; and it can write plain text, [Markdown],
-[CommonMark], [PHP Markdown Extra], [GitHub-Flavored Markdown],
+[EPUB], [ODT], [Vimwiki] and [Word docx]; and it can write plain text,
+[Markdown], [CommonMark], [PHP Markdown Extra], [GitHub-Flavored Markdown],
[MultiMarkdown], [reStructuredText], [XHTML], [HTML5], [LaTeX]
\(including [`beamer`] slide shows\), [ConTeXt], [RTF], [OPML],
[DocBook], [OpenDocument], [ODT], [Word docx], [GNU Texinfo], [MediaWiki
diff --git a/data/vimwiki.css b/data/vimwiki.css
new file mode 100644
index 000000000..0a8841a32
--- /dev/null
+++ b/data/vimwiki.css
@@ -0,0 +1,82 @@
+pre{
+ font-size: 1.5em
+}
+
+img {vertical-align: middle}
+
+body {font-family: Tahoma, Geneva, sans-serif; margin: 1em 2em 1em 2em; font-size: 120%; line-height: 130%;}
+h1, h2, h3, h4, h5, h6 {font-family: Trebuchet MS, Helvetica, sans-serif; font-weight: bold; line-height:100%; margin-top: 1.5em; margin-bottom: 0.5em;}
+h1 {font-size: 2.6em; color: #000000;}
+h2 {font-size: 2.2em; color: #404040;}
+h3 {font-size: 1.8em; color: #707070;}
+h4 {font-size: 1.4em; color: #909090;}
+h5 {font-size: 1.3em; color: #989898;}
+h6 {font-size: 1.2em; color: #9c9c9c;}
+p, pre, blockquote, table, ul, ol, dl {margin-top: 1em; margin-bottom: 1em;}
+ul ul, ul ol, ol ol, ol ul {margin-top: 0.5em; margin-bottom: 0.5em;}
+li {margin: 0.3em auto;}
+ul {margin-left: 2em; padding-left: 0.5em;}
+dt {font-weight: bold;}
+img {border: none;}
+pre {border-left: 1px solid #ccc; margin-left: 2em; padding-left: 0.5em;}
+blockquote {padding: 0.4em; background-color: #f6f5eb;}
+th, td {border: 1px solid #ccc; padding: 0.3em;}
+th {background-color: #f0f0f0;}
+hr {border: none; border-top: 1px solid #ccc; width: 100%;}
+del {text-decoration: line-through; color: #777777;}
+.toc li {list-style-type: none;}
+.todo {font-weight: bold; background-color: #f0ece8; color: #a03020;}
+.justleft {text-align: left;}
+.justright {text-align: right;}
+.justcenter {text-align: center;}
+.center {margin-left: auto; margin-right: auto;}
+div.center > table {margin-left: auto; margin-right: auto;}
+.tag {background-color: #eeeeee; font-family: monospace; padding: 2px;}
+
+/* classes for items of todo lists */
+.done0 {
+ /* list-style: none; */
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAxQAAAMUBHc26qAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAA7SURBVCiR7dMxEgAgCANBI3yVRzF5KxNbW6wsuH7LQ2YKQK1mkswBVERYF5Os3UV3gwd/jF2SkXy66gAZkxS6BniubAAAAABJRU5ErkJggg==);
+ background-repeat: no-repeat;
+ background-position: 0 .2em;
+ padding-left: 1.5em;
+}
+.done1 {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAxQAAAMUBHc26qAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABtSURBVCiR1ZO7DYAwDER9BDmTeZQMFXmUbGYpOjrEryA0wOvO8itOslFrJYAug5BMM4BeSkmjsrv3aVTa8p48Xw1JSkSsWVUFwD05IqS1tmYzk5zzae9jnVVVzGyXb8sALjse+euRkEzu/uirFomVIdDGOLjuAAAAAElFTkSuQmCC);
+ background-repeat: no-repeat;
+ background-position: 0 .15em;
+ padding-left: 1.5em;
+}
+.done2 {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAxQAAAMUBHc26qAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAB1SURBVCiRzdO5DcAgDAVQGxjAYgTvxlDIu1FTIRYAp8qlFISkSH7l5kk+ZIwxKiI2mIyqWoeILYRgZ7GINDOLjnmF3VqklKCUMgTee2DmM661Qs55iI3Zm/1u5h9sm4ig9z4ERHTFzLyd4G4+nFlVrYg8+qoF/c0kdpeMsmcAAAAASUVORK5CYII=);
+ background-repeat: no-repeat;
+ background-position: 0 .15em;
+ padding-left: 1.5em;
+}
+.done3 {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAxQAAAMUBHc26qAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABoSURBVCiR7dOxDcAgDATA/0DtUdiKoZC3YhLkHjkVKF3idJHiztKfvrHZWnOSE8Fx95RJzlprimJVnXktvXeY2S0SEZRSAAAbmxnGGKH2I5T+8VfxPhIReQSuuY3XyYWa3T2p6quvOgGrvSFGlewuUAAAAABJRU5ErkJggg==);
+ background-repeat: no-repeat;
+ background-position: 0 .15em;
+ padding-left: 1.5em;
+}
+.done4 {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAzgAAAM4BlP6ToAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIISURBVDiNnZQ9SFtRFMd/773kpTaGJoQk1im4VDpWQcTNODhkFBcVTCNCF0NWyeDiIIiCm82QoIMIUkHUxcFBg1SEQoZszSat6cdTn1qNue92CMbEr9Sey+XC/Z/zu+f8h6ukUil3sVg0+M+4cFxk42/jH2wAqqqKSCSiPQdwcHHAnDHH9s/tN1h8V28ETdP+eU8fT9Nt62ancYdIPvJNtsu87bmjrJlrTDVM4RROJs1JrHPrD4Bar7A6cpc54iKOaTdJXCUI2UMVrQZ0Js7YPN18ECKkYNQcJe/OE/4dZsw7VqNXQMvHy3QZXQypQ6ycrtwDjf8aJ+PNEDSCzLpn7+m2pD8ZKHlKarYhy6XjEoCYGcN95qansQeA3fNdki+SaJZGTMQIOoL3W/Z89rxv+tokubNajlvk/vm+LFpF2XnUKZHI0I+QrI7Dw0OZTqdzUkpsM7mZTyfy5OPGyw1tK7AFSvmB/Ks8w8YwbUYbe6/3QEKv0vugfxWPnMLJun+d/kI/WLdizpNjMbAIKrhMF4OuwadBALqqs+RfInwUvuNi+fBd+wjogfogAFVRmffO02q01mZZ0HHdgXIzdz0QQLPezIQygX6llxNKKgOFARYCC49CqhoHIUTlss/Vx2phlYwjw8j1CAlfAiwQiJpiy7o1VHnsG5FISkoJu7Q/2YmmaV+i0ei7v38L2CBguSi5AAAAAElFTkSuQmCC);
+ background-repeat: no-repeat;
+ background-position: 0 .15em;
+ padding-left: 1.5em;
+}
+
+*:not(pre) > code {
+ font-family: Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;
+ -webkit-border-radius: 1px;
+ -moz-border-radius: 1px;
+ border-radius: 1px;
+ -moz-background-clip: padding;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ padding: 0px 3px;
+ display: inline-block;
+ color: #52595d;
+ border: 1px solid #ccc;
+ background-color: #f9f9f9;
+}
diff --git a/pandoc.cabal b/pandoc.cabal
index 9dbd52a07..ff61c6a2c 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -162,6 +162,7 @@ Extra-Source-Files:
test/markdown-citations.txt
test/textile-reader.textile
test/mediawiki-reader.wiki
+ test/vimwiki-reader.wiki
test/rst-reader.rst
test/s5-basic.html
test/s5-fancy.html
@@ -368,6 +369,7 @@ Library
Text.Pandoc.Readers.Markdown,
Text.Pandoc.Readers.CommonMark,
Text.Pandoc.Readers.MediaWiki,
+ Text.Pandoc.Readers.Vimwiki,
Text.Pandoc.Readers.RST,
Text.Pandoc.Readers.Org,
Text.Pandoc.Readers.DocBook,
diff --git a/src/Text/Pandoc/Readers.hs b/src/Text/Pandoc/Readers.hs
index 4c95d5d28..20e503a7e 100644
--- a/src/Text/Pandoc/Readers.hs
+++ b/src/Text/Pandoc/Readers.hs
@@ -46,6 +46,7 @@ module Text.Pandoc.Readers
, readMarkdown
, readCommonMark
, readMediaWiki
+ , readVimwiki
, readRST
, readOrg
, readLaTeX
@@ -82,6 +83,7 @@ import Text.Pandoc.Readers.HTML
import Text.Pandoc.Readers.LaTeX
import Text.Pandoc.Readers.Markdown
import Text.Pandoc.Readers.MediaWiki
+import Text.Pandoc.Readers.Vimwiki
import Text.Pandoc.Readers.Muse
import Text.Pandoc.Readers.Native
import Text.Pandoc.Readers.Odt
@@ -115,6 +117,7 @@ readers = [ ("native" , TextReader readNative)
,("commonmark" , TextReader readCommonMark)
,("rst" , TextReader readRST)
,("mediawiki" , TextReader readMediaWiki)
+ ,("vimwiki" , TextReader readVimwiki)
,("docbook" , TextReader readDocBook)
,("opml" , TextReader readOPML)
,("org" , TextReader readOrg)
diff --git a/src/Text/Pandoc/Readers/Vimwiki.hs b/src/Text/Pandoc/Readers/Vimwiki.hs
new file mode 100644
index 000000000..07e23fa1e
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Vimwiki.hs
@@ -0,0 +1,655 @@
+{-
+ Copyright (C) 2017 Yuchen Pei <me@ypei.me>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Vimwiki
+ Copyright : Copyright (C) 2017 Yuchen Pei
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Yuchen Pei <me@ypei.me>
+ Stability : alpha
+ Portability : portable
+
+Conversion of vimwiki text to 'Pandoc' document.
+-}
+{--
+ progress:
+* block parsers:
+ * [X] header
+ * [X] hrule
+ * [X] comment
+ * [X] blockquote
+ * [X] preformatted
+ * [X] displaymath
+ * [X] bulletlist / orderedlist
+ * [X] orderedlist with 1., i., a) etc identification.
+ * [X] todo lists -- not list builder with attributes? using span.
+ * [X] table
+ * [X] centered table -- using div
+ * [O] colspan and rowspan -- pandoc limitation, see issue #1024
+ * [X] paragraph
+ * [X] definition list
+* inline parsers:
+ * [X] bareURL
+ * [X] strong
+ * [X] emph
+ * [X] strikeout
+ * [X] code
+ * [X] link
+ * [X] image
+ * [X] inline math
+ * [X] tag
+ * [X] sub- and super-scripts
+* misc:
+ * [X] `TODO:` mark
+ * [X] metadata placeholders: %title and %date
+ * [O] control placeholders: %template and %nohtml -- %template added to
+ meta, %nohtml ignored
+--}
+
+module Text.Pandoc.Readers.Vimwiki ( readVimwiki
+ ) where
+import Control.Monad.Except (throwError)
+import Control.Monad (guard)
+import Data.Default
+import Data.Maybe
+import Data.Monoid ((<>))
+import Data.List (isInfixOf, isPrefixOf)
+import Data.Text (Text, unpack)
+import Text.Pandoc.Builder (Blocks, Inlines, trimInlines, fromList, toList)
+import qualified Text.Pandoc.Builder
+ as B (headerWith, str, space, strong, emph, strikeout, code, link, image,
+ spanWith, para, horizontalRule, blockQuote, bulletList, plain,
+ orderedList, simpleTable, softbreak, codeBlockWith, imageWith, divWith,
+ setMeta, definitionList, superscript, subscript)
+import Text.Pandoc.Class (PandocMonad, report)
+import Text.Pandoc.Definition (Pandoc(..), Inline(Space),
+ Block(BulletList, OrderedList), Attr, nullMeta, Meta, ListNumberStyle(..),
+ ListNumberDelim(..))
+import Text.Pandoc.Logging (LogMessage(ParsingTrace))
+import Text.Pandoc.Options (ReaderOptions)
+import Text.Pandoc.Parsing (readWithM, ParserT, stateOptions, ParserState,
+ stateMeta', blanklines, registerHeader, spaceChar, emailAddress, uri, F, runF,
+ orderedListMarker, many1Till)
+import Text.Pandoc.Shared (splitBy, stripFirstAndLast, stringify)
+import Text.Parsec.Char (spaces, char, anyChar, newline, string, noneOf,
+ alphaNum)
+import Text.Parsec.Combinator (eof, choice, many1, manyTill, count, skipMany1,
+ notFollowedBy, option)
+import Text.Parsec.Prim (many, getPosition, try, updateState, getState)
+import Text.Parsec.Char (oneOf, space)
+import Text.Parsec.Combinator (lookAhead, between)
+import Text.Parsec.Prim ((<|>))
+
+readVimwiki :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
+readVimwiki opts s = do
+ res <- readWithM parseVimwiki def{ stateOptions = opts } (unpack s)
+ case res of
+ Left e -> throwError e
+ Right result -> return result
+
+type VwParser = ParserT [Char] ParserState
+
+
+-- constants
+
+specialChars :: [Char]
+specialChars = "=*-#[]_~{}`$|:%^,"
+
+spaceChars :: [Char]
+spaceChars = " \t\n"
+
+-- main parser
+
+parseVimwiki :: PandocMonad m => VwParser m Pandoc
+parseVimwiki = do
+ bs <- mconcat <$> many block
+ spaces
+ eof
+ st <- getState
+ let meta = runF (stateMeta' st) st
+ return $ Pandoc meta (toList bs)
+
+-- block parser
+
+block :: PandocMonad m => VwParser m Blocks
+block = do
+ pos <- getPosition
+ res <- choice [ mempty <$ blanklines
+ , header
+ , hrule
+ , mempty <$ comment
+ , mixedList
+ , preformatted
+ , displayMath
+ , table
+ , mempty <$ placeholder
+ , blockQuote
+ , definitionList
+ , para
+ ]
+ report $ ParsingTrace (take 60 $ show $ toList res) pos
+ return res
+
+blockML :: PandocMonad m => VwParser m Blocks
+blockML = choice [preformatted, displayMath, table]
+
+header :: PandocMonad m => VwParser m Blocks
+header = try $ do
+ sp <- many spaceChar
+ eqs <- many1 (char '=')
+ spaceChar
+ let lev = length eqs
+ guard $ lev <= 6
+ contents <- trimInlines . mconcat <$> manyTill inline (try $ spaceChar
+ >> (string eqs) >> many spaceChar >> newline)
+ attr <- registerHeader (makeId contents,
+ (if sp == "" then [] else ["justcenter"]), []) contents
+ return $ B.headerWith attr lev contents
+
+para :: PandocMonad m => VwParser m Blocks
+para = try $ do
+ contents <- trimInlines . mconcat <$> many1 inline
+ if all (==Space) (toList contents)
+ then return mempty
+ else return $ B.para contents
+
+hrule :: PandocMonad m => VwParser m Blocks
+hrule = try $ B.horizontalRule <$ (string "----" >> many (char '-') >> newline)
+
+comment :: PandocMonad m => VwParser m ()
+comment = try $ do
+ many spaceChar >> string "%%" >> many (noneOf "\n")
+ return ()
+
+blockQuote :: PandocMonad m => VwParser m Blocks
+blockQuote = try $ do
+ string " "
+ contents <- trimInlines . mconcat <$> many1 inlineBQ
+ if all (==Space) (toList contents)
+ then return mempty
+ else return $ B.blockQuote $ B.plain contents
+
+definitionList :: PandocMonad m => VwParser m Blocks
+definitionList = try $
+ B.definitionList <$> (many1 (dlItemWithDT <|> dlItemWithoutDT))
+
+dlItemWithDT :: PandocMonad m => VwParser m (Inlines, [Blocks])
+dlItemWithDT = do
+ dt <- definitionTerm
+ dds <- many definitionDef
+ return $ (dt, dds)
+
+dlItemWithoutDT :: PandocMonad m => VwParser m (Inlines, [Blocks])
+dlItemWithoutDT = do
+ dds <- many1 definitionDef
+ return $ (mempty, dds)
+
+definitionDef :: PandocMonad m => VwParser m Blocks
+definitionDef = try $
+ (notFollowedBy definitionTerm) >> many spaceChar
+ >> (definitionDef1 <|> definitionDef2)
+
+definitionDef1 :: PandocMonad m => VwParser m Blocks
+definitionDef1 = try $ mempty <$ defMarkerE
+
+definitionDef2 :: PandocMonad m => VwParser m Blocks
+definitionDef2 = try $ B.plain <$>
+ (defMarkerM >> (trimInlines . mconcat <$> many inline') <* newline)
+
+
+definitionTerm :: PandocMonad m => VwParser m Inlines
+definitionTerm = try $ do
+ x <- definitionTerm1 <|> definitionTerm2
+ guard $ (stringify x /= "")
+ return x
+
+definitionTerm1 :: PandocMonad m => VwParser m Inlines
+definitionTerm1 = try $
+ trimInlines . mconcat <$> manyTill inline' (try $ defMarkerE)
+
+definitionTerm2 :: PandocMonad m => VwParser m Inlines
+definitionTerm2 = try $ trimInlines . mconcat <$> manyTill inline'
+ (try $ lookAhead $ (defMarkerM >> notFollowedBy hasDefMarkerM))
+
+defMarkerM :: PandocMonad m => VwParser m Char
+defMarkerM = string "::" >> spaceChar
+
+defMarkerE :: PandocMonad m => VwParser m Char
+defMarkerE = string "::" >> newline
+
+hasDefMarkerM :: PandocMonad m => VwParser m String
+hasDefMarkerM = manyTill (noneOf "\n") (try defMarkerM)
+
+preformatted :: PandocMonad m => VwParser m Blocks
+preformatted = try $ do
+ many spaceChar >> string "{{{"
+ attrText <- many (noneOf "\n")
+ lookAhead newline
+ contents <- manyTill anyChar (try (char '\n' >> many spaceChar >> string "}}}"
+ >> many spaceChar >> newline))
+ if (not $ contents == "") && (head contents == '\n')
+ then return $ B.codeBlockWith (makeAttr attrText) (tail contents)
+ else return $ B.codeBlockWith (makeAttr attrText) contents
+
+makeAttr :: String -> Attr
+makeAttr s =
+ let xs = splitBy (`elem` " \t") s in
+ ("", [], catMaybes $ map nameValue xs)
+
+nameValue :: String -> Maybe (String, String)
+nameValue s =
+ let t = splitBy (== '=') s in
+ if length t /= 2
+ then Nothing
+ else let (a, b) = (head t, last t) in
+ if ((length b) < 2) || ((head b, last b) /= ('"', '"'))
+ then Nothing
+ else Just (a, stripFirstAndLast b)
+
+
+displayMath :: PandocMonad m => VwParser m Blocks
+displayMath = try $ do
+ many spaceChar >> string "{{$"
+ mathTag <- option "" mathTagParser
+ contents <- manyTill anyChar (try (char '\n' >> many spaceChar >> string "}}$"
+ >> many spaceChar >> newline))
+ let contentsWithTags
+ | mathTag == "" = "\\[" ++ contents ++ "\n\\]"
+ | otherwise = "\\begin{" ++ mathTag ++ "}" ++ contents
+ ++ "\n\\end{" ++ mathTag ++ "}"
+ return $ B.plain $ B.str contentsWithTags
+
+mixedList :: PandocMonad m => VwParser m Blocks
+mixedList = try $ do
+ (bl, _) <- mixedList' (-1)
+ return $ head bl
+
+mixedList' :: PandocMonad m => Int -> VwParser m ([Blocks], Int)
+mixedList' prevInd = do
+ (curInd, builder) <- option (-1, "na") (lookAhead listStart)
+ if curInd < prevInd
+ then return ([], curInd)
+ else do
+ listStart
+ curLine <- listItemContent
+ let listBuilder =
+ if builder == "ul" then B.bulletList else B.orderedList
+ (subList, lowInd) <- (mixedList' curInd)
+ if lowInd >= curInd
+ then do
+ (sameIndList, endInd) <- (mixedList' lowInd)
+ let curList = (combineList curLine subList) ++ sameIndList
+ if curInd > prevInd
+ then return ([listBuilder curList], endInd)
+ else return (curList, endInd)
+ else do
+ let (curList, endInd) = ((combineList curLine subList),
+ lowInd)
+ if curInd > prevInd
+ then return ([listBuilder curList], endInd)
+ else return (curList, endInd)
+
+plainInlineML' :: PandocMonad m => Inlines -> VwParser m Blocks
+plainInlineML' w = do
+ xs <- many inlineML
+ newline
+ return $ B.plain $ trimInlines $ mconcat $ w:xs
+
+plainInlineML :: PandocMonad m => VwParser m Blocks
+plainInlineML = (notFollowedBy listStart) >> spaceChar >> plainInlineML' mempty
+
+
+listItemContent :: PandocMonad m => VwParser m Blocks
+listItemContent = try $ do
+ w <- option mempty listTodoMarker
+ x <- plainInlineML' w
+ y <- many blocksThenInline
+ z <- many blockML
+ return $ mconcat $ x:y ++ z
+
+blocksThenInline :: PandocMonad m => VwParser m Blocks
+blocksThenInline = try $ do
+ y <- many1 blockML
+ x <- plainInlineML
+ return $ mconcat $ y ++ [x]
+
+listTodoMarker :: PandocMonad m => VwParser m Inlines
+listTodoMarker = try $ do
+ x <- between (many spaceChar >> char '[') (char ']' >> spaceChar)
+ (oneOf " .oOX")
+ return $ makeListMarkerSpan x
+
+makeListMarkerSpan :: Char -> Inlines
+makeListMarkerSpan x =
+ let cl = case x of
+ ' ' -> "done0"
+ '.' -> "done1"
+ 'o' -> "done2"
+ 'O' -> "done3"
+ 'X' -> "done4"
+ _ -> ""
+ in
+ B.spanWith ("", [cl], []) mempty
+
+combineList :: Blocks -> [Blocks] -> [Blocks]
+combineList x [y] = case toList y of
+ [BulletList z] -> [fromList $ (toList x)
+ ++ [BulletList z]]
+ [OrderedList attr z] -> [fromList $ (toList x)
+ ++ [OrderedList attr z]]
+ _ -> x:[y]
+combineList x xs = x:xs
+
+listStart :: PandocMonad m => VwParser m (Int, String)
+listStart = try $ do
+ s <- many spaceChar
+ listType <- bulletListMarkers <|> orderedListMarkers
+ spaceChar
+ return (length s, listType)
+
+bulletListMarkers :: PandocMonad m => VwParser m String
+bulletListMarkers = "ul" <$ (char '*' <|> char '-')
+
+orderedListMarkers :: PandocMonad m => VwParser m String
+orderedListMarkers =
+ ("ol" <$ (choice $ (orderedListMarker Decimal Period):(($OneParen)
+ <$> orderedListMarker
+ <$> [Decimal, LowerRoman, UpperRoman, LowerAlpha, UpperAlpha])))
+ <|> ("ol" <$ char '#')
+
+--many need trimInlines
+table :: PandocMonad m => VwParser m Blocks
+table = try $ do
+ indent <- lookAhead (many spaceChar)
+ (th, trs) <- table1 <|> table2
+ let tab = B.simpleTable th trs
+ if indent == ""
+ then return tab
+ else return $ B.divWith ("", ["center"], []) tab
+
+-- table with header
+table1 :: PandocMonad m => VwParser m ([Blocks], [[Blocks]])
+table1 = try $ do
+ th <- tableRow
+ many1 tableHeaderSeparator
+ trs <- many tableRow
+ return (th, trs)
+
+-- headerless table
+table2 :: PandocMonad m => VwParser m ([Blocks], [[Blocks]])
+table2 = try $ do
+ trs <- many1 tableRow
+ return (take (length $ head trs) $ repeat mempty, trs)
+
+tableHeaderSeparator :: PandocMonad m => VwParser m ()
+tableHeaderSeparator = try $ do
+ many spaceChar >> char '|' >> many1 ((many1 $ char '-') >> char '|')
+ >> many spaceChar >> newline
+ return ()
+
+tableRow :: PandocMonad m => VwParser m [Blocks]
+tableRow = try $ do
+ many spaceChar >> char '|'
+ s <- lookAhead $ manyTill anyChar (try (char '|' >> many spaceChar
+ >> newline))
+ guard $ not $ "||" `isInfixOf` ("|" ++ s ++ "|")
+ tr <- many tableCell
+ many spaceChar >> char '\n'
+ return tr
+
+tableCell :: PandocMonad m => VwParser m Blocks
+tableCell = try $
+ B.plain <$> trimInlines . mconcat <$> (manyTill inline' (char '|'))
+
+placeholder :: PandocMonad m => VwParser m ()
+placeholder = try $
+ (choice (ph <$> ["title", "date"])) <|> noHtmlPh <|> templatePh
+
+ph :: PandocMonad m => String -> VwParser m ()
+ph s = try $ do
+ many spaceChar >> (string $ '%':s) >> spaceChar
+ contents <- (trimInlines . mconcat <$> (manyTill inline (lookAhead newline)))
+ --use lookAhead because of placeholder in the whitespace parser
+ let meta' = return $ B.setMeta s contents nullMeta :: F Meta
+ updateState $ \st -> st { stateMeta' = stateMeta' st <> meta' }
+
+noHtmlPh :: PandocMonad m => VwParser m ()
+noHtmlPh = try $
+ () <$ (many spaceChar >> string "%nohtml" >> many spaceChar
+ >> (lookAhead newline))
+
+templatePh :: PandocMonad m => VwParser m ()
+templatePh = try $
+ () <$ (many spaceChar >> string "%template" >> (many $ noneOf "\n")
+ >> (lookAhead newline))
+
+-- inline parser
+
+inline :: PandocMonad m => VwParser m Inlines
+inline = choice $ (whitespace endlineP):inlineList
+
+inlineList :: PandocMonad m => [VwParser m Inlines]
+inlineList = [ bareURL
+ , todoMark
+ , str
+ , strong
+ , emph
+ , strikeout
+ , code
+ , link
+ , image
+ , inlineMath
+ , tag
+ , superscript
+ , subscript
+ , special
+ ]
+
+-- inline parser without softbreaks or comment breaks
+inline' :: PandocMonad m => VwParser m Inlines
+inline' = choice $ whitespace':inlineList
+
+-- inline parser for blockquotes
+inlineBQ :: PandocMonad m => VwParser m Inlines
+inlineBQ = choice $ (whitespace endlineBQ):inlineList
+
+-- inline parser for mixedlists
+inlineML :: PandocMonad m => VwParser m Inlines
+inlineML = choice $ (whitespace endlineML):inlineList
+
+str :: PandocMonad m => VwParser m Inlines
+str = B.str <$> (many1 $ noneOf $ spaceChars ++ specialChars)
+
+whitespace :: PandocMonad m => VwParser m () -> VwParser m Inlines
+whitespace endline = B.space <$ (skipMany1 spaceChar <|>
+ (try (newline >> (comment <|> placeholder))))
+ <|> B.softbreak <$ endline
+
+whitespace' :: PandocMonad m => VwParser m Inlines
+whitespace' = B.space <$ skipMany1 spaceChar
+
+special :: PandocMonad m => VwParser m Inlines
+special = B.str <$> count 1 (oneOf specialChars)
+
+bareURL :: PandocMonad m => VwParser m Inlines
+bareURL = try $ do
+ (orig, src) <- uri <|> emailAddress
+ return $ B.link src "" (B.str orig)
+
+strong :: PandocMonad m => VwParser m Inlines
+strong = try $ do
+ s <- lookAhead $ between (char '*') (char '*') (many1 $ noneOf "*")
+ guard $ (not $ (head s) `elem` spaceChars)
+ && (not $ (last s) `elem` spaceChars)
+ char '*'
+ contents <- mconcat <$> (manyTill inline' $ char '*'
+ >> notFollowedBy alphaNum)
+ return $ (B.spanWith ((makeId contents), [], []) mempty)
+ <> (B.strong contents)
+
+makeId :: Inlines -> String
+makeId i = concat (stringify <$> (toList i))
+
+emph :: PandocMonad m => VwParser m Inlines
+emph = try $ do
+ s <- lookAhead $ between (char '_') (char '_') (many1 $ noneOf "_")
+ guard $ (not $ (head s) `elem` spaceChars)
+ && (not $ (last s) `elem` spaceChars)
+ char '_'
+ contents <- mconcat <$> (manyTill inline' $ char '_'
+ >> notFollowedBy alphaNum)
+ return $ B.emph contents
+
+strikeout :: PandocMonad m => VwParser m Inlines
+strikeout = try $ do
+ string "~~"
+ contents <- mconcat <$> (many1Till inline' $ string $ "~~")
+ return $ B.strikeout contents
+
+code :: PandocMonad m => VwParser m Inlines
+code = try $ do
+ char '`'
+ contents <- many1Till (noneOf "\n") (char '`')
+ return $ B.code contents
+
+superscript :: PandocMonad m => VwParser m Inlines
+superscript = try $
+ B.superscript <$> mconcat <$> (char '^' >> many1Till inline' (char '^'))
+
+subscript :: PandocMonad m => VwParser m Inlines
+subscript = try $
+ B.subscript <$> mconcat <$> (string ",,"
+ >> many1Till inline' (try $ string ",,"))
+
+link :: PandocMonad m => VwParser m Inlines
+link = try $ do
+ string "[["
+ contents <- lookAhead $ manyTill anyChar (string "]]")
+ case '|' `elem` contents of
+ False -> do
+ manyTill anyChar (string "]]")
+-- not using try here because [[hell]o]] is not rendered as a link in vimwiki
+ return $ B.link (procLink contents) "" (B.str contents)
+ True -> do
+ url <- manyTill anyChar $ char '|'
+ lab <- mconcat <$> (manyTill inline $ string "]]")
+ return $ B.link (procLink url) "" lab
+
+image :: PandocMonad m => VwParser m Inlines
+image = try $ do
+ string "{{"
+ contentText <- lookAhead $ manyTill (noneOf "\n") (try $ string "}}")
+ images $ length $ filter (== '|') contentText
+
+images :: PandocMonad m => Int -> VwParser m Inlines
+images k
+ | k == 0 = do
+ imgurl <- manyTill anyChar (try $ string "}}")
+ return $ B.image (procImgurl imgurl) "" (B.str "")
+ | k == 1 = do
+ imgurl <- manyTill anyChar (char '|')
+ alt <- mconcat <$> (manyTill inline $ (try $ string "}}"))
+ return $ B.image (procImgurl imgurl) "" alt
+ | k == 2 = do
+ imgurl <- manyTill anyChar (char '|')
+ alt <- mconcat <$> (manyTill inline $ char '|')
+ attrText <- manyTill anyChar (try $ string "}}")
+ return $ B.imageWith (makeAttr attrText) (procImgurl imgurl) "" alt
+ | otherwise = do
+ imgurl <- manyTill anyChar (char '|')
+ alt <- mconcat <$> (manyTill inline $ char '|')
+ attrText <- manyTill anyChar (char '|')
+ manyTill anyChar (try $ string "}}")
+ return $ B.imageWith (makeAttr attrText) (procImgurl imgurl) "" alt
+
+procLink' :: String -> String
+procLink' s
+ | ((take 6 s) == "local:") = "file" ++ (drop 5 s)
+ | ((take 6 s) == "diary:") = "diary/" ++ (drop 6 s) ++ ".html"
+ | or ((`isPrefixOf` s) <$> [ "http:", "https:", "ftp:", "file:", "mailto:",
+ "news:", "telnet:" ])
+ = s
+ | s == "" = ""
+ | (last s) == '/' = s
+ | otherwise = s ++ ".html"
+
+procLink :: String -> String
+procLink s = procLink' x ++ y
+ where (x, y) = break (=='#') s
+
+procImgurl :: String -> String
+procImgurl s = if ((take 6 s) == "local:") then "file" ++ (drop 5 s) else s
+
+inlineMath :: PandocMonad m => VwParser m Inlines
+inlineMath = try $ do
+ char '$'
+ contents <- many1Till (noneOf "\n") (char '$')
+ return $ B.str $ "\\(" ++ contents ++ "\\)"
+
+tag :: PandocMonad m => VwParser m Inlines
+tag = try $ do
+ char ':'
+ s <- manyTill (noneOf spaceChars) (try (char ':' >> (lookAhead space)))
+ guard $ not $ "::" `isInfixOf` (":" ++ s ++ ":")
+ let ss = splitBy (==':') s
+ return $ mconcat $ (makeTagSpan' $ head ss):(makeTagSpan <$> (tail ss))
+
+todoMark :: PandocMonad m => VwParser m Inlines
+todoMark = try $ do
+ string "TODO:"
+ return $ B.spanWith ("", ["todo"], []) (B.str "TODO:")
+
+-- helper functions and parsers
+endlineP :: PandocMonad m => VwParser m ()
+endlineP = () <$ try (newline <* nFBTTBSB <* notFollowedBy blockQuote)
+
+endlineBQ :: PandocMonad m => VwParser m ()
+endlineBQ = () <$ try (newline <* nFBTTBSB <* string " ")
+
+endlineML :: PandocMonad m => VwParser m ()
+endlineML = () <$ try (newline <* nFBTTBSB <* many1 spaceChar)
+
+--- nFBTTBSB is short for notFollowedByThingsThatBreakSoftBreaks
+nFBTTBSB :: PandocMonad m => VwParser m ()
+nFBTTBSB =
+ notFollowedBy newline <*
+ notFollowedBy hrule <*
+ notFollowedBy tableRow <*
+ notFollowedBy header <*
+ notFollowedBy listStart <*
+ notFollowedBy preformatted <*
+ notFollowedBy displayMath <*
+ notFollowedBy hasDefMarker
+
+hasDefMarker :: PandocMonad m => VwParser m ()
+hasDefMarker = () <$ (manyTill (noneOf "\n") (string "::" >> oneOf spaceChars))
+
+makeTagSpan' :: String -> Inlines
+makeTagSpan' s = B.spanWith ('-' : s, [], []) (B.str "") <>
+ B.spanWith (s, ["tag"], []) (B.str s)
+
+makeTagSpan :: String -> Inlines
+makeTagSpan s = (B.space) <> (makeTagSpan' s)
+
+mathTagParser :: PandocMonad m => VwParser m String
+mathTagParser = do
+ s <- try $ lookAhead (char '%' >> (manyTill (noneOf spaceChars)
+ (try $ char '%' >> many (noneOf $ '%':spaceChars) >> space)))
+ char '%' >> string s >> char '%'
+ return s
diff --git a/test/Tests/Old.hs b/test/Tests/Old.hs
index fceb776f7..b807719bc 100644
--- a/test/Tests/Old.hs
+++ b/test/Tests/Old.hs
@@ -99,6 +99,10 @@ tests = [ testGroup "markdown"
, 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"]
diff --git a/test/vimwiki-reader.native b/test/vimwiki-reader.native
new file mode 100644
index 000000000..26388b71a
--- /dev/null
+++ b/test/vimwiki-reader.native
@@ -0,0 +1,305 @@
+Pandoc (Meta {unMeta = fromList [("date",MetaInlines [Str "2017-05-01"]),("title",MetaInlines [Str "title"])]})
+[Header 1 ("implemented",[],[]) [Emph [Span ("implemented",[],[]) [],Strong [Str "implemented"]]]
+,Header 1 ("header",[],[]) [Str "header"]
+,Header 2 ("header level two",[],[]) [Str "header",Space,Str "level",Space,Str "two"]
+,Header 3 ("header level 3",[],[]) [Str "header",Space,Code ("",[],[]) "level",Space,Str "3"]
+,Header 4 ("header level four",[],[]) [Str "header",Space,Strikeout [Str "level"],Space,Str "four"]
+,Header 5 ("header level 5",[],[]) [Str "header",Space,Emph [Span ("level",[],[]) [],Strong [Str "level"],Space,Str "5"]]
+,Header 6 ("header level 6",[],[]) [Str "header",Space,Str "level",Space,Str "6"]
+,Para [Str "=======",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "========"]
+,Para [Str "hi==",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "=="]
+,Para [Str "===",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "=="]
+,Para [Str "===",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "===-"]
+,Para [Str "not",Space,Str "a",Space,Str "header:"]
+,Para [Str "=n="]
+,Para [Str "===",Space,Str "not",Space,Str "a",Space,Str "header",Space,Str "===="]
+,Header 2 ("centred header",["justcenter"],[]) [Str "centred",Space,Str "header"]
+,Header 2 ("header with some == in between",[],[]) [Str "header",Space,Str "with",Space,Str "some",Space,Code ("",[],[]) "==",Space,Str "in",Space,Str "between"]
+,Header 2 ("header with some == in between",[],[]) [Str "header",Space,Str "with",Space,Str "some",Space,Str "==",Space,Str "in",Space,Str "between"]
+,Header 2 ("header with some ==in between",[],[]) [Str "header",Space,Str "with",Space,Str "some",Space,Str "==in",Space,Str "between"]
+,Header 2 ("emph strong and strikeout",[],[]) [Str "emph",Space,Str "strong",Space,Str "and",Space,Str "strikeout"]
+,Para [Emph [Str "emph"],Space,Span ("strong",[],[]) [],Strong [Str "strong"]]
+,Para [Span ("strong and emph",[],[]) [],Strong [Emph [Str "strong",Space,Str "and",Space,Str "emph"]]]
+,Para [Emph [Span ("emph and strong",[],[]) [],Strong [Str "emph",Space,Str "and",Space,Str "strong"]]]
+,Para [Span ("emph inside strong",[],[]) [],Strong [Emph [Str "emph",Space,Str "inside"],Space,Str "strong"]]
+,Para [Span ("strong with emph",[],[]) [],Strong [Str "strong",Space,Str "with",Space,Emph [Str "emph"]]]
+,Para [Emph [Span ("strong inside",[],[]) [],Strong [Str "strong",Space,Str "inside"],Space,Str "emph"]]
+,Para [Emph [Strikeout [Str "strikeout"],Space,Str "inside",Space,Str "emph"]]
+,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "struck",Space,Str "out"],Space,Str "with",Space,Str "emph"]]
+,Para [Str "*not",SoftBreak,Str "strong*"]
+,Para [Str "just",Space,Str "two",Space,Str "stars:",Space,Str "**"]
+,Para [Str "just",Space,Str "two",Space,Str "underscores:",Space,Str "__"]
+,Para [Str "just",Space,Str "four",Space,Str "~s:",Space,Str "~~~~"]
+,Para [Str "_not",SoftBreak,Str "emph_"]
+,Para [Str "~~not",SoftBreak,Str "strikeout~~"]
+,Header 2 ("horizontal rule",[],[]) [Str "horizontal",Space,Str "rule"]
+,Para [Str "top"]
+,HorizontalRule
+,Para [Str "middle"]
+,HorizontalRule
+,Para [Str "not",Space,Str "a",Space,Str "rule-----"]
+,Para [Str "not",Space,Str "a",Space,Str "rule",Space,Str "(trailing",Space,Str "spaces):",SoftBreak,Str "-----"]
+,Para [Str "not",Space,Str "a",Space,Str "rule",Space,Str "(leading",Space,Str "spaces):",SoftBreak,Str "----"]
+,Header 2 ("comments",[],[]) [Str "comments"]
+,Para [Str "this",SoftBreak,Str "is",Space,Str "%%",Space,Str "not",Space,Str "secret"]
+,Header 2 ("inline code",[],[]) [Str "inline",Space,Str "code"]
+,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Code ("",[],[]) "inline code",Str "."]
+,Para [Str "Just",Space,Str "two",Space,Str "backticks:",Space,Str "``"]
+,Header 2 ("preformatted text",[],[]) [Str "preformatted",Space,Str "text"]
+,CodeBlock ("",[],[]) " Tyger! Tyger! burning bright\n In the forests of the night,\n What immortal hand or eye\n Could frame thy fearful symmetry?\n In what distant deeps or skies\n Burnt the fire of thine eyes?\n On what wings dare he aspire?\n What the hand dare sieze the fire?"
+,Header 3 ("preformatted text with attributes",[],[]) [Str "preformatted",Space,Str "text",Space,Str "with",Space,Str "attributes"]
+,CodeBlock ("",[],[("class","python"),("style","color:blue")]) " for i in range(1, 5):\n print(i)"
+,Header 2 ("block quotes",[],[]) [Str "block",Space,Str "quotes"]
+,BlockQuote
+ [Plain [Str "(indentation",Space,Str "4",Space,Str "spaces)",Space,Str "This",Space,Str "would",Space,Str "be",Space,Str "a",Space,Str "blockquote",Space,Str "in",Space,Str "Vimwiki.",Space,Str "It",Space,Str "is",Space,Str "not",Space,Span ("highlighted",[],[]) [],Strong [Str "highlighted"],Space,Str "in",Space,Str "Vim",Space,Str "but",SoftBreak,Str "(indentation",Space,Str "1",Space,Str "space",Space,Str "followed",Space,Str "by",Space,Str "1",Space,Str "tab",Space,Str "of",Space,Str "width",Space,Str "4)",Space,Str "could",Space,Str "be",Space,Str "styled",Space,Str "by",Space,Str "CSS",Space,Str "in",Space,Str "HTML.",Space,Str "Blockquotes",Space,Str "are",Space,Str "usually",Space,Str "used",Space,Str "to",Space,Str "quote",Space,Str "a",SoftBreak,Str "(indentation",Space,Str "1",Space,Str "tab",Space,Str "of",Space,Str "width",Space,Str "4)",Space,Str "long",Space,Str "piece",Space,Str "of",Space,Str "text",Space,Str "from",Space,Str "another",Space,Str "source.",Space,Strikeout [Str "blah",Space,Str "blah"],Space,Span ("-blockquote",[],[]) [Str ""],Span ("blockquote",["tag"],[]) [Str "blockquote"]]]
+,Header 2 ("external links",[],[]) [Str "external",Space,Str "links"]
+,Para [Link ("",[],[]) [Emph [Str "Google"],Space,Str "search",Space,Str "engine"] ("http://google.com","")]
+,Para [Link ("",[],[]) [Str "http://pandoc.org"] ("http://pandoc.org","")]
+,Para [Link ("",[],[]) [Str "ftp://vim.org"] ("ftp://vim.org","")]
+,Para [Link ("",[],[]) [Str "http://google.com"] ("http://google.com","")]
+,Para [Link ("",[],[]) [Str "email",Space,Str "me"] ("mailto:info@example.org","")]
+,Para [Link ("",[],[]) [Str "mailto:hello@bye.com"] ("mailto:hello@bye.com","")]
+,Header 2 ("internal links",[],[]) [Str "internal",Space,Str "links"]
+,Para [Link ("",[],[]) [Str "This is a link"] ("This is a link.html","")]
+,Para [Link ("",[],[]) [Str "Description",Space,Str "of",Space,Str "the",Space,Str "link"] ("This is a link source.html","")]
+,Para [Link ("",[],[]) [Str "projects/Important Project 1"] ("projects/Important Project 1.html",""),SoftBreak,Link ("",[],[]) [Str "../index"] ("../index.html",""),SoftBreak,Link ("",[],[]) [Str "Other",Space,Str "files"] ("a subdirectory/","")]
+,Para [Link ("",[],[]) [Str "try",Space,Str "me",Space,Str "to",Space,Str "test",Space,Str "tag",Space,Str "anchors"] ("#tag-one","")]
+,Para [Link ("",[],[]) [Str "try",Space,Str "me",Space,Str "to",Space,Str "test",Space,Str "header",Space,Str "anchors"] ("#block quotes","")]
+,Para [Link ("",[],[]) [Str "try",Space,Str "me",Space,Str "to",Space,Str "test",Space,Str "strong",Space,Str "anchors"] ("#strong","")]
+,Para [Link ("",[],[]) [Str "Tasks",Space,Str "for",Space,Str "tomorrow"] ("Todo List.html#Tomorrow","")]
+,Para [Link ("",[],[]) [Str "diary:2017-05-01"] ("diary/2017-05-01.html","")]
+,Para [Link ("",[],[]) [Str "Important",Space,Str "Data"] ("file:../assets/data.csv","")]
+,Header 3 ("links with thumbnails",[],[]) [Str "links",Space,Str "with",Space,Str "thumbnails"]
+,Para [Link ("",[],[]) [Image ("",[],[]) [Str ""] ("./movie.jpg","")] ("http://www.google.com","")]
+,Header 2 ("images",[],[]) [Str "images"]
+,Para [Image ("",[],[]) [Str ""] ("file:./lalune.jpg","")]
+,Para [Image ("",[],[]) [Str "Vimwiki"] ("http://vimwiki.googlecode.com/hg/images/vimwiki_logo.png",""),SoftBreak,Image ("",[],[]) [Str ""] ("file:./movie.jpg","")]
+,Header 3 ("image with attributes",[],[]) [Str "image",Space,Str "with",Space,Str "attributes"]
+,Para [Image ("",[],[("style","width:150px;height:120px;")]) [Emph [Str "cool",Space,Str "stuff"]] ("lalune.jpg","")]
+,Para [Image ("",[],[("style","font-color:red")]) [Span ("Non-existing",[],[]) [],Strong [Str "Non-existing"],Space,Str "image"] ("nonexist.jpg","")]
+,Para [Image ("",[],[("style","width:150px;height:120px;")]) [Emph [Str "cool",Space,Str "stuff"]] ("lalune.jpg","")]
+,Header 2 ("lists",[],[]) [Str "lists"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "ordered",Space,Str "list",Space,Str "item",Space,Str "1,",Space,Str "and",Space,Str "here",Space,Str "is",Space,Str "some",Space,Str "math",Space,Str "belonging",Space,Str "to",Space,Str "list",Space,Str "item",Space,Str "1"]
+ ,Plain [Str "\\[\n a^2 + b^2 = c^2\n\\]"]
+ ,Plain [Str "and",Space,Str "some",Space,Str "preformatted",Space,Str "and",Space,Str "tables",Space,Str "belonging",Space,Str "to",Space,Str "item",Space,Str "1",Space,Str "as",Space,Str "well"]
+ ,CodeBlock ("",[],[]) "I'm part of item 1."
+ ,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "this",Space,Str "table"]]
+ ,[Plain [Str "is"]]]
+ ,[[Plain [Str "also",Space,Str "a",Space,Str "part"]]
+ ,[Plain [Str "of",Space,Str "item",Space,Str "1"]]]]
+ ,Plain [Str "and",Space,Str "some",Space,Str "more",Space,Str "text",Space,Str "belonging",Space,Str "to",Space,Str "item",Space,Str "1."]]
+ ,[Plain [Str "ordered",Space,Str "list",Space,Str "item",Space,Str "2"]]]
+,BulletList
+ [[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "2"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "the",Space,Str "#",Space,Str "become",Space,Str "numbers",Space,Str "when",Space,Str "converted",Space,Str "to",Space,Str "HTML"]]]
+,BulletList
+ [[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "2"]]]
+,BulletList
+ [[Plain [Str "Item",Space,Str "1"]]
+ ,[Plain [Str "Item",Space,Str "2"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Sub",Space,Str "item",Space,Str "1",Space,Str "(indentation",Space,Str "4",Space,Str "spaces)",SoftBreak,Str "Sub",Space,Str "item",Space,Str "1",Space,Str "continued",Space,Str "line.",SoftBreak,Str "Sub",Space,Str "item",Space,Str "1",Space,Str "next",Space,Str "continued",Space,Str "line."]]
+ ,[Plain [Str "Sub",Space,Str "item",Space,Str "2,",Space,Str "as",Space,Str "an",Space,Str "ordered",Space,Str "list",Space,Str "item",Space,Str "even",Space,Str "though",Space,Str "the",Space,Str "identifier",Space,Str "is",Space,Code ("",[],[]) "*",Space,Str "(indentation",Space,Str "2",Space,Str "spaces",Space,Str "followed",Space,Str "by",Space,Str "one",Space,Str "tab",Space,Str "of",Space,Str "width",Space,Str "4)"]]
+ ,[Plain [Str "etc.",SoftBreak,Str "Continuation",Space,Str "of",Space,Str "Item",Space,Str "2",SoftBreak,Str "Next",Space,Str "continuation",Space,Str "of",Space,Str "Item",Space,Str "2"]]]]]
+,Para [Str "But",Space,Str "this",Space,Str "is",Space,Str "a",Space,Str "new",Space,Str "paragraph."]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "1"]
+ ,BulletList
+ [[Plain [Code ("",[],[]) "1.1"]]]]
+ ,[Plain [Str "2"]
+ ,BulletList
+ [[Plain [Str "2.1"]]]]]
+,BulletList
+ [[Plain [Str "3"]]]
+,Header 3 ("ordered lists with non-# identifiers",[],[]) [Str "ordered",Space,Str "lists",Space,Str "with",Space,Str "non-#",Space,Str "identifiers"]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "2"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,BulletList
+ [[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "2"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "sub",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "more",Space,Str "..."]
+ ,BulletList
+ [[Plain [Str "and",Space,Str "more",Space,Str "..."]]
+ ,[Plain [Str "..."]]]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "sub",Space,Str "item",Space,Str "3"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Numbered",Space,Str "list",Space,Str "sub",Space,Str "sub",Space,Str "item",Space,Str "1"]]
+ ,[Plain [Str "Numbered",Space,Str "list",Space,Str "sub",Space,Str "sub",Space,Str "item",Space,Str "2"]]]]
+ ,[Plain [Str "etc."]]]]
+ ,[Plain [Str "Bulleted",Space,Str "list",Space,Str "item",Space,Str "3"]]]
+,Header 2 ("todo lists",[],[]) [Str "todo",Space,Str "lists"]
+,BulletList
+ [[Plain [Span ("",["done0"],[]) [],Str "task",Space,Str "1"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Span ("",["done1"],[]) [],Str "5"]]]]
+ ,[Plain [Span ("",["done2"],[]) [],Str "3"]]
+ ,[Plain [Str "[]",Space,Str "not",Space,Str "a",Space,Str "todo",Space,Str "item"]]
+ ,[Plain [Str "[",Space,Str "]not",Space,Str "a",Space,Str "todo",Space,Str "item"]]
+ ,[Plain [Str "[r]",Space,Str "not",Space,Str "a",Space,Str "todo",Space,Str "item"]]
+ ,[Plain [Str "[",Space,Str "]",Space,Str "not",Space,Str "a",Space,Str "todo",Space,Str "item"]]
+ ,[Plain [Span ("",["done2"],[]) [],Str "a",Space,Str "tab",Space,Str "in",Space,Str "the",Space,Str "todo",Space,Str "list",Space,Str "marker",Space,Code ("",[],[]) "[ ]"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Span ("",["done3"],[]) [],Str "4",SoftBreak,Str "5"]]
+ ,[Plain [Span ("",["done4"],[]) []]
+ ,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "a"]]
+ ,[Plain [Str "b"]]]]]]]
+ ,[Plain [Span ("",["done4"],[]) [],Str "task",Space,Str "2"]]]
+,Header 2 ("math",[],[]) [Str "math"]
+,Para [Str "\\( \\sum_i a_i^2 = 1 \\)"]
+,Plain [Str "\\[\n\\sum_i a_i^2\n=\n1\n\\]"]
+,Plain [Str "\\begin{align}\n\\sum_i a_i^2 &= 1 + 1 \\\\\n&= 2.\n\\end{align}"]
+,Para [Str "Just",Space,Str "two",Space,Str "dollar",Space,Str "signs:",Space,Str "$$"]
+,Para [Str "[not",Space,Str "math]",Space,Str "You",Space,Str "have",Space,Str "$1",SoftBreak,Str "and",Space,Str "I",Space,Str "have",Space,Str "$1."]
+,Header 2 ("tags",[],[]) [Str "tags"]
+,Para [Span ("-tag-one",[],[]) [Str ""],Span ("tag-one",["tag"],[]) [Str "tag-one"],Space,Span ("-tag-two",[],[]) [Str ""],Span ("tag-two",["tag"],[]) [Str "tag-two"]]
+,Header 2 ("tables",[],[]) [Str "tables"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "Year"]]
+ ,[Plain [Str "Temperature",Space,Str "(low)"]]
+ ,[Plain [Str "Temperature",Space,Str "(high)"]]]
+ [[[Plain [Str "1900"]]
+ ,[Plain [Str "-10"]]
+ ,[Plain [Str "25"]]]
+ ,[[Plain [Str "1910"]]
+ ,[Plain [Str "-15"]]
+ ,[Plain [Str "30"]]]
+ ,[[Plain [Str "1920"]]
+ ,[Plain [Str "-10"]]
+ ,[Plain [Str "32"]]]
+ ,[[Plain [Str "1930"]]
+ ,[Plain [Emph [Str "N/A"]]]
+ ,[Plain [Emph [Str "N/A"]]]]
+ ,[[Plain [Str "1940"]]
+ ,[Plain [Str "-2"]]
+ ,[Plain [Str "40"]]]]
+,Header 3 ("centered headerless tables",[],[]) [Str "centered",Space,Str "headerless",Space,Str "tables"]
+,Div ("",["center"],[])
+ [Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "a"]]
+ ,[Plain [Str "b"]]]
+ ,[[Plain [Str "c"]]
+ ,[Plain [Str "d"]]]]]
+,Header 2 ("paragraphs",[],[]) [Str "paragraphs"]
+,Para [Str "This",Space,Str "is",Space,Str "first",Space,Str "paragraph",SoftBreak,Str "with",Space,Str "two",Space,Str "lines."]
+,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "second",Space,Str "paragraph",Space,Str "with",SoftBreak,Str "two",Space,Str "lines",Space,Str "after",Space,Str "many",Space,Str "blank",Space,Str "lines."]
+,Header 2 ("definition list",[],[]) [Str "definition",Space,Str "list"]
+,DefinitionList
+ [([Str "Term",Space,Str "1"],
+ [[Plain [Str "Definition",Space,Str "1"]]])
+ ,([Str "Term",Space,Str "2"],
+ [[Plain [Str "Definition",Space,Str "2"]]
+ ,[Plain [Str "Definition",Space,Str "3"]]])
+ ,([Str "Term",Space,Str "::",Space,Span ("separated",[],[]) [],Strong [Str "separated"],Space,Str "by",Space,Str "::",Space,Emph [Str "double",Space,Str "colons"]],
+ [[Plain [Str "Def1"]]
+ ,[Plain [Str "Def2"]]])
+ ,([Str "Term",Space,Str "with",Space,Str "lots",Space,Str "of",Space,Str "trailing",Space,Str "colons:::::::"],
+ [[Plain [Str "Definition"]]])
+ ,([Str "::",Space,Str "This",Space,Str "is",Space,Str "::",Space,Str "A",Space,Str "term",Space,Str "(rather",Space,Str "than",Space,Str "a",Space,Str "definition)"],
+ [[Plain [Str "and",Space,Str "this",Space,Str "is",Space,Str "a",Space,Str "definition"]]])
+ ,([Str "Term",Space,Str "Without",Space,Str "definitions"],
+ [[]])
+ ,([Str "Part",Space,Str "::",Space,Str "of",Space,Str "::",Space,Str "dt"],
+ [[Plain [Str "part",Space,Str "of",Space,Str "::dd"]]])]
+,DefinitionList
+ [([],
+ [[Plain [Str "Definition",Space,Str "1",Space,Str "without",Space,Str "a",Space,Str "term"]]
+ ,[Plain [Str "Definition",Space,Str "2",Space,Str "without",Space,Str "a",Space,Str "term"]]])]
+,DefinitionList
+ [([Str "T1"],
+ [[Plain [Str "D1"]]])]
+,Para [Str "new",Space,Str "paragraph"]
+,DefinitionList
+ [([Str "T1"],
+ [[Plain [Str "D1"]]])]
+,Para [Str "Not::Definition"]
+,Para [Str "Not",Space,Str "::Definition"]
+,Para [Str "::Not",Space,Str "definition"]
+,BlockQuote
+ [Plain [Str "::",Space,Str "blockquote"]]
+,BlockQuote
+ [Plain [Str "block",Space,Str "::",Space,Str "quote"]]
+,Header 2 ("metadata placeholders",[],[]) [Str "metadata",Space,Str "placeholders"]
+,Para [Str "%this",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "placeholder"]
+,Para [Str "placeholders",SoftBreak,Str "serves",Space,Str "as",Space,Str "space",Space,Str "/",Space,Str "softbreak",Space,Str "in",Space,Str "paragraphs"]
+,Header 2 ("sup, sub",[],[]) [Str "sup,",Space,Str "sub"]
+,Para [Str "super",Superscript [Str "script"]]
+,Para [Str "sub",Subscript [Str "script"]]
+,Header 2 ("the todo mark",[],[]) [Str "the",Space,Str "todo",Space,Str "mark"]
+,Para [Span ("",["todo"],[]) [Str "TODO:"]]
+,Header 1 ("not implemented yet",[],[]) [Emph [Span ("not implemented yet",[],[]) [],Strong [Str "not",Space,Str "implemented",Space,Str "yet"]]]
+,Header 2 ("tables with spans",[],[]) [Str "tables",Space,Str "with",Space,Str "spans"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "a"]]
+ ,[Plain [Str "b"]]
+ ,[Plain [Str "c"]]
+ ,[Plain [Str "d"]]]
+ ,[[Plain [Str "\\/"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str ">"]]
+ ,[Plain [Str "f"]]]
+ ,[[Plain [Str "\\/"]]
+ ,[Plain [Str "\\/"]]
+ ,[Plain [Str ">"]]
+ ,[Plain [Str "g"]]]
+ ,[[Plain [Str "h"]]
+ ,[Plain [Str ">"]]
+ ,[Plain [Str ">"]]
+ ,[Plain [Str ">"]]]]
+,Header 2 ("tables with multiple lines of headers",[],[]) [Str "tables",Space,Str "with",Space,Str "multiple",Space,Str "lines",Space,Str "of",Space,Str "headers"]
+,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "a"]]
+ ,[Plain [Str "b"]]]
+ ,[[Plain [Str "c"]]
+ ,[Plain [Str "d"]]]
+ ,[[Plain [Str "---"]]
+ ,[Plain [Str "---"]]]]
+,Header 2 ("some other placeholders",[],[]) [Str "some",Space,Str "other",Space,Str "placeholders"]
+,Para [Code ("",[],[]) "template",Space,Str "placeholder",Space,Str "is",Space,Str "ignored."]
+,Para [Code ("",[],[]) "nohtml",Space,Str "placeholder",Space,Str "is",Space,Str "ignored."]]
diff --git a/test/vimwiki-reader.wiki b/test/vimwiki-reader.wiki
new file mode 100644
index 000000000..ad724e090
--- /dev/null
+++ b/test/vimwiki-reader.wiki
@@ -0,0 +1,414 @@
+= _*implemented*_ =
+= header =
+
+== header level two ==
+
+=== header `level` 3 ===
+
+==== header ~~level~~ four ====
+
+===== header _*level* 5_ =====
+
+====== header level 6 ======
+
+======= not a header ========
+
+hi== not a header ==
+
+=== not a header ==
+
+=== not a header ===-
+
+not a header:
+
+=n=
+
+=== not a header ====
+
+ == centred header ==
+
+== header with some `==` in between ==
+== header with some == in between ==
+== header with some ==in between ==
+
+== emph strong and strikeout ==
+
+_emph_ *strong*
+
+*_strong and emph_*
+
+_*emph and strong*_
+
+*_emph inside_ strong*
+
+*strong with _emph_*
+
+_*strong inside* emph_
+
+_~~strikeout~~ inside emph_
+
+~~This is _struck out_ with emph~~
+
+*not
+strong*
+
+just two stars: **
+
+just two underscores: __
+
+just four ~s: ~~~~
+
+_not
+%%comment
+emph_
+
+~~not
+ %%comment
+ %%comment
+strikeout~~
+
+== horizontal rule ==
+
+top
+----
+middle
+
+-------
+
+not a rule-----
+
+not a rule (trailing spaces):
+-----
+
+not a rule (leading spaces):
+ ----
+
+== comments ==
+
+%% you can't see me.
+
+this
+%% secret
+is %% not secret
+
+== inline code ==
+
+Here is some `inline code`.
+
+Just two backticks: ``
+
+== preformatted text ==
+
+{{{
+ Tyger! Tyger! burning bright
+ In the forests of the night,
+ What immortal hand or eye
+ Could frame thy fearful symmetry?
+ In what distant deeps or skies
+ Burnt the fire of thine eyes?
+ On what wings dare he aspire?
+ What the hand dare sieze the fire?
+}}}
+
+=== preformatted text with attributes ===
+
+ {{{class="python" style="color:blue"
+ for i in range(1, 5):
+ print(i)
+ }}}
+
+== block quotes ==
+
+ (indentation 4 spaces) This would be a blockquote in Vimwiki. It is not *highlighted* in Vim but
+ (indentation 1 space followed by 1 tab of width 4) could be styled by CSS in HTML. Blockquotes are usually used to quote a
+ (indentation 1 tab of width 4) long piece of text from another source. ~~blah blah~~ :blockquote:
+
+== external links ==
+
+[[http://google.com|_Google_ search engine]]
+
+http://pandoc.org
+
+ftp://vim.org
+
+[[http://google.com]]
+
+[[mailto:info@example.org|email me]]
+
+mailto:hello@bye.com
+
+== internal links ==
+
+[[This is a link]]
+
+[[This is a link source|Description of the link]]
+
+[[projects/Important Project 1]]
+
+[[../index]]
+
+[[a subdirectory/|Other files]]
+
+[[#tag-one|try me to test tag anchors]]
+
+[[#block quotes|try me to test header anchors]]
+
+[[#strong|try me to test strong anchors]]
+
+[[Todo List#Tomorrow|Tasks for tomorrow]]
+
+[[diary:2017-05-01]]
+
+[[file:../assets/data.csv|Important Data]]
+
+=== links with thumbnails ===
+[[http://www.google.com|{{./movie.jpg}}]]
+
+== images ==
+
+{{file:./lalune.jpg}}
+
+{{http://vimwiki.googlecode.com/hg/images/vimwiki_logo.png|Vimwiki}}
+
+{{local:./movie.jpg}}
+
+
+=== image with attributes ===
+{{lalune.jpg|_cool stuff_|style="width:150px;height:120px;"}}
+
+{{nonexist.jpg|*Non-existing* image|class="center flow blabla" style="font-color:red"}}
+
+{{lalune.jpg|_cool stuff_|style="width:150px;height:120px;"|anything in this segment is ignored}}
+
+
+== lists ==
+
+
+# ordered list item 1, and here is some math belonging to list item 1
+ {{$
+ a^2 + b^2 = c^2
+ }}$
+ and some preformatted and tables belonging to item 1 as well
+{{{
+I'm part of item 1.
+}}}
+| this table | is |
+| also a part | of item 1 |
+ and some more text belonging to item 1.
+# ordered list item 2
+
+
+* Bulleted list item 1
+* Bulleted list item 2
+
+
+# Bulleted list item 1
+# the # become numbers when converted to HTML
+
+- Bulleted list item 1
+- Bulleted list item 2
+
+* Item 1
+* Item 2
+ # Sub item 1 (indentation 4 spaces)
+ Sub item 1 continued line.
+%%comments
+ Sub item 1 next continued line.
+ * Sub item 2, as an ordered list item even though the identifier is `*` (indentation 2 spaces followed by one tab of width 4)
+ * etc.
+ Continuation of Item 2
+ Next continuation of Item 2
+But this is a new paragraph.
+
+# 1
+ * `1.1`
+ * 2
+ * 2.1
+ * 3
+
+=== ordered lists with non-# identifiers ===
+1. Numbered list item 1
+2. Numbered list item 2
+3. Numbered list item 3
+
+4. Numbered list item 1
+5. Numbered list item 2
+6. Numbered list item 3
+
+1) Numbered list item 1
+2) Numbered list item 2
+3) Numbered list item 3
+
+a) Numbered list item 1
+b) Numbered list item 2
+c) Numbered list item 3
+
+A) Numbered list item 1
+B) Numbered list item 2
+C) Numbered list item 3
+
+i) Numbered list item 1
+ii) Numbered list item 2
+iii) Numbered list item 3
+
+I) Numbered list item 1
+II) Numbered list item 2
+III) Numbered list item 3
+
+- Bulleted list item 1
+- Bulleted list item 2
+ a) Numbered list sub item 1
+ b) more ...
+ * and more ...
+ * ...
+ c) Numbered list sub item 3
+ 1. Numbered list sub sub item 1
+ 2. Numbered list sub sub item 2
+ d) etc.
+- Bulleted list item 3
+
+== todo lists ==
+* [ ] task 1
+ 1. [.] 5
+* [o] 3
+* [] not a todo item
+* [ ]not a todo item
+* [r] not a todo item
+* [ ] not a todo item
+* [o] a tab in the todo list marker `[ ]`
+ III) [O] 4
+ 5
+ i) [X]
+| a | b |
+* [X] task 2
+
+== math ==
+
+$ \sum_i a_i^2 = 1 $
+
+{{$
+\sum_i a_i^2
+=
+1
+}}$
+
+{{$%align%
+\sum_i a_i^2 &= 1 + 1 \\
+&= 2.
+}}$
+
+Just two dollar signs: $$
+
+[not math] You have $1
+and I have $1.
+
+== tags ==
+
+:tag-one:tag-two:
+
+== tables ==
+
+| Year | Temperature (low) | Temperature (high) |
+|------|-------------------|--------------------|
+| 1900 | -10 | 25 |
+| 1910 | -15 | 30 |
+| 1920 | -10 | 32 |
+| 1930 | _N/A_ | _N/A_ |
+| 1940 | -2 | 40 |
+
+
+=== centered headerless tables ===
+ | a | b |
+ | c | d |
+
+
+== paragraphs ==
+
+This is first paragraph
+with two lines.
+
+
+
+
+
+
+
+
+This is a second paragraph with
+two lines after many blank lines.
+
+== definition list ==
+
+Term 1:: Definition 1
+Term 2::
+:: Definition 2
+ :: Definition 3
+Term :: *separated* by :: _double colons_ :: Def1
+:: Def2
+Term with lots of trailing colons::::::::: Definition
+:: This is :: A term (rather than a definition) :: and this is a definition
+Term Without definitions ::
+::
+Part :: of :: dt :: part of ::dd
+
+:: Definition 1 without a term
+:: Definition 2 without a term
+
+T1 :: D1
+new paragraph
+T1 :: D1
+
+Not::Definition
+
+Not ::Definition
+
+::Not definition
+
+ :: blockquote
+
+ block :: quote
+
+== metadata placeholders ==
+%title title
+%date 2017-05-01
+
+%title second title is ignored
+%date second date is ignored
+
+%this is not a placeholder
+
+placeholders
+%title another title
+%date 2017-04-23
+serves as space / softbreak in paragraphs
+
+
+== sup, sub ==
+
+super^script^
+
+sub,,script,,
+
+== the todo mark ==
+TODO:
+
+= _*not implemented yet*_ =
+== tables with spans ==
+| a | b | c | d |
+| \/ | e | > | f |
+| \/ | \/ | > | g |
+| h | > | > | > |
+
+== tables with multiple lines of headers ==
+| a | b |
+| c | d |
+|---|---|
+
+== some other placeholders ==
+`template` placeholder is ignored.
+%template template
+
+`nohtml` placeholder is ignored.
+%nohtml
+
+