git.iko.soy/typeable/pandoc
on master help sign in
Creole reader (#3994)

This is feature complete but not very thoroughly tested yet.

commit66fd3247eac9a564aca179ca9fe4fd007ee471e7 authorSascha Wilde <wilde@sha-bang.de> dateFri 27 Oct 2017, 01:19 (9 years ago) parent7688667
5 files changed+596
pandoc.cabal+2 src/Text/Pandoc/Readers.hs+3 src/Text/Pandoc/Readers/Creole.hs+316 test/Tests/Readers/Creole.hs+273 test/test-pandoc.hs+2
pandoc.cabal+2
@@ -385,6 +385,7 @@ library
385385 Text.Pandoc.Readers.LaTeX.Types,
386386 Text.Pandoc.Readers.Markdown,
387387 Text.Pandoc.Readers.CommonMark,
388+ Text.Pandoc.Readers.Creole,
388389 Text.Pandoc.Readers.MediaWiki,
389390 Text.Pandoc.Readers.Vimwiki,
390391 Text.Pandoc.Readers.RST,
@@ -583,6 +584,7 @@ test-suite test-pandoc
583584 Tests.Readers.Txt2Tags
584585 Tests.Readers.EPUB
585586 Tests.Readers.Muse
587+ Tests.Readers.Creole
586588 Tests.Writers.Native
587589 Tests.Writers.ConTeXt
588590 Tests.Writers.Docbook
src/Text/Pandoc/Readers.hs+3
@@ -45,6 +45,7 @@ module Text.Pandoc.Readers
4545 , readOdt
4646 , readMarkdown
4747 , readCommonMark
48+ , readCreole
4849 , readMediaWiki
4950 , readVimwiki
5051 , readRST
@@ -76,6 +77,7 @@ import Text.Pandoc.Error
7677import Text.Pandoc.Extensions
7778import Text.Pandoc.Options
7879import Text.Pandoc.Readers.CommonMark
80+import Text.Pandoc.Readers.Creole
7981import Text.Pandoc.Readers.DocBook
8082import Text.Pandoc.Readers.Docx
8183import Text.Pandoc.Readers.EPUB
@@ -117,6 +119,7 @@ readers = [ ("native" , TextReader readNative)
117119 ,("markdown_github" , TextReader readMarkdown)
118120 ,("markdown_mmd", TextReader readMarkdown)
119121 ,("commonmark" , TextReader readCommonMark)
122+ ,("creole" , TextReader readCreole)
120123 ,("gfm" , TextReader readCommonMark)
121124 ,("rst" , TextReader readRST)
122125 ,("mediawiki" , TextReader readMediaWiki)
src/Text/Pandoc/Readers/Creole.hsnew file+316
@@ -0,0 +1,316 @@
1+{-
2+ Copyright (C) 2017 Sascha Wilde <wilde@sha-bang.de>
3+
4+ partly based on all the other readers, especialy the work by
5+ John MacFarlane <jgm@berkeley.edu> and
6+ Alexander Sulfrian <alexander.sulfrian@fu-berlin.de>
7+ all bugs are solely created by me.
8+
9+This program is free software; you can redistribute it and/or modify
10+it under the terms of the GNU General Public License as published by
11+the Free Software Foundation; either version 2 of the License, or
12+(at your option) any later version.
13+
14+This program is distributed in the hope that it will be useful,
15+but WITHOUT ANY WARRANTY; without even the implied warranty of
16+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+GNU General Public License for more details.
18+
19+You should have received a copy of the GNU General Public License
20+along with this program; if not, write to the Free Software
21+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22+-}
23+
24+{- |
25+ Module : Text.Pandoc.Readers.Creole
26+ Copyright : Copyright (C) 2017 Sascha Wilde
27+ License : GNU GPL, version 2 or above
28+
29+ Maintainer : Sascha Wilde <wilde@sha-bang.de>
30+ Stability : WIP
31+ Portability : portable
32+
33+Conversion of creole text to 'Pandoc' document.
34+-}
35+module Text.Pandoc.Readers.Creole ( readCreole
36+ ) where
37+
38+import Control.Monad.Except (liftM2, throwError, guard)
39+import qualified Data.Foldable as F
40+import qualified Text.Pandoc.Builder as B
41+import Text.Pandoc.Class (PandocMonad(..))
42+import Text.Pandoc.Definition
43+import Text.Pandoc.Options
44+import Text.Pandoc.Parsing hiding (enclosed)
45+import Text.Pandoc.Shared (crFilter)
46+import Data.Maybe (fromMaybe)
47+import Data.Monoid
48+import Data.Text (Text)
49+import qualified Data.Text as T
50+
51+
52+-- | Read creole from an input string and return a Pandoc document.
53+readCreole :: PandocMonad m
54+ => ReaderOptions
55+ -> Text
56+ -> m Pandoc
57+readCreole opts s = do
58+ res <- readWithM parseCreole def{ stateOptions = opts }
59+ (T.unpack (crFilter s) ++ "\n\n")
60+ case res of
61+ Left e -> throwError e
62+ Right d -> return d
63+
64+type CRLParser = ParserT [Char] ParserState
65+
66+--
67+-- Utility funcitons
68+--
69+
70+(<+>) :: (Monad m, Monoid a) => m a -> m a -> m a
71+(<+>) = liftM2 (<>)
72+
73+-- we have to redefine `enclosed' from Text.Pandoc.Parsing, because it
74+-- assumes, that there can't be a space after the start parser, but
75+-- with creole this is possible.
76+enclosed :: (Show end, PandocMonad m) => CRLParser m start -- ^ start parser
77+ -> CRLParser m end -- ^ end parser
78+ -> CRLParser m a -- ^ content parser (to be used repeatedly)
79+ -> CRLParser m [a]
80+enclosed start end parser = try $ start >> many1Till parser end
81+
82+--
83+-- main parser
84+--
85+
86+specialChars :: [Char]
87+specialChars = "*/~{}\\|[]()<>\"'"
88+
89+parseCreole :: PandocMonad m => CRLParser m Pandoc
90+parseCreole = do
91+ bs <- mconcat <$> many block
92+ spaces
93+ eof
94+ return $ B.doc bs
95+
96+
97+--
98+-- block parsers
99+--
100+
101+block :: PandocMonad m => CRLParser m B.Blocks
102+block = do
103+ res <- mempty <$ skipMany1 blankline
104+ <|> nowiki
105+ <|> header
106+ <|> horizontalRule
107+ <|> anyList 1
108+ <|> table
109+ <|> para
110+ skipMany blankline
111+ return res
112+
113+nowiki :: PandocMonad m => CRLParser m B.Blocks
114+nowiki = try $ nowikiStart >> manyTill content nowikiEnd >>= return . B.codeBlock . mconcat
115+ where
116+ content = brackets <|> line
117+ brackets = try $ option "" ((:[]) <$> newline)
118+ <+> (char ' ' >> (many (char ' ') <+> string "}}}") <* eol)
119+ line = option "" ((:[]) <$> newline) <+> manyTill anyChar eol
120+ eol = lookAhead $ try $ nowikiEnd <|> newline
121+ nowikiStart = optional newline >> string "{{{" >> skipMany spaceChar >> newline
122+ nowikiEnd = try $ linebreak >> string "}}}" >> skipMany spaceChar >> newline
123+
124+header :: PandocMonad m => CRLParser m B.Blocks
125+header = try $ do
126+ skipSpaces
127+ level <- many1 (char '=') >>= return . length
128+ guard $ level <= 6
129+ skipSpaces
130+ content <- B.str <$> manyTill (noneOf "\n") headerEnd
131+ return $ B.header level content
132+ where
133+ headerEnd = try $ skipSpaces >> many (char '=') >> skipSpaces >> newline
134+
135+unorderedList :: PandocMonad m => Int -> CRLParser m B.Blocks
136+unorderedList = list '*' B.bulletList
137+
138+orderedList :: PandocMonad m => Int -> CRLParser m B.Blocks
139+orderedList = list '#' B.orderedList
140+
141+anyList :: PandocMonad m => Int -> CRLParser m B.Blocks
142+anyList n = unorderedList n <|> orderedList n
143+
144+anyListItem :: PandocMonad m => Int -> CRLParser m B.Blocks
145+anyListItem n = listItem '*' n <|> listItem '#' n
146+
147+list :: PandocMonad m => Char -> ([B.Blocks] -> B.Blocks) -> Int -> CRLParser m B.Blocks
148+list c f n = many1 (itemPlusSublist <|> listItem c n)
149+ >>= return . f
150+ where itemPlusSublist = try $ listItem c n <+> anyList (n+1)
151+
152+listItem :: PandocMonad m => Char -> Int -> CRLParser m B.Blocks
153+listItem c n = (listStart >> many1Till inline itemEnd)
154+ >>= return . B.plain . B.trimInlines .mconcat
155+ where
156+ listStart = try $ optional newline >> skipSpaces >> count n (char c)
157+ >> (lookAhead $ noneOf [c]) >> skipSpaces
158+ itemEnd = endOfParaElement <|> nextItem n
159+ <|> if n < 3 then nextItem (n+1)
160+ else nextItem (n+1) <|> nextItem (n-1)
161+ nextItem x = lookAhead $ try $ blankline >> anyListItem x >> return mempty
162+
163+table :: PandocMonad m => CRLParser m B.Blocks
164+table = try $ do
165+ headers <- optionMaybe headerRow
166+ rows <- many1 row
167+ return $ B.simpleTable (fromMaybe [mempty] headers) rows
168+ where
169+ headerRow = try $ skipSpaces >> many1Till headerCell rowEnd
170+ headerCell = B.plain . B.trimInlines . mconcat
171+ <$> (string "|=" >> many1Till inline cellEnd)
172+ row = try $ skipSpaces >> many1Till cell rowEnd
173+ cell = B.plain . B.trimInlines . mconcat
174+ <$> (char '|' >> many1Till inline cellEnd)
175+ rowEnd = try $ optional (char '|') >> skipSpaces >> newline
176+ cellEnd = lookAhead $ try $ char '|' <|> rowEnd
177+
178+para :: PandocMonad m => CRLParser m B.Blocks
179+para = many1Till inline endOfParaElement >>= return . result . mconcat
180+ where
181+ result content = if F.all (==Space) content
182+ then mempty
183+ else B.para $ B.trimInlines content
184+
185+endOfParaElement :: PandocMonad m => CRLParser m ()
186+endOfParaElement = lookAhead $ endOfInput <|> endOfPara
187+ <|> startOfList <|> startOfTable
188+ <|> startOfHeader <|> hr <|> startOfNowiki
189+ where
190+ endOfInput = try $ skipMany blankline >> skipSpaces >> eof
191+ endOfPara = try $ blankline >> skipMany1 blankline
192+ startOf :: PandocMonad m => CRLParser m a -> CRLParser m ()
193+ startOf p = try $ blankline >> p >> return mempty
194+ startOfList = startOf $ anyList 1
195+ startOfTable = startOf $ table
196+ startOfHeader = startOf header
197+ startOfNowiki = startOf nowiki
198+ hr = startOf horizontalRule
199+
200+horizontalRule :: PandocMonad m => CRLParser m B.Blocks
201+horizontalRule = try $ skipSpaces >> string "----" >> skipSpaces >> newline
202+ >> return B.horizontalRule
203+
204+--
205+-- inline parsers
206+--
207+
208+inline :: PandocMonad m => CRLParser m B.Inlines
209+inline = choice [ whitespace
210+ , escapedLink
211+ , escapedChar
212+ , link
213+ , inlineNowiki
214+ , placeholder
215+ , image
216+ , forcedLinebreak
217+ , bold
218+ , finalBold
219+ , italics
220+ , finalItalics
221+ , str
222+ , symbol
223+ ] <?> "inline"
224+
225+escapedChar :: PandocMonad m => CRLParser m B.Inlines
226+escapedChar = (try $ char '~' >> noneOf "\t\n ") >>= return . B.str . (:[])
227+
228+escapedLink :: PandocMonad m => CRLParser m B.Inlines
229+escapedLink = try $ do
230+ char '~'
231+ (orig, _) <- uri
232+ return $ B.str orig
233+
234+image :: PandocMonad m => CRLParser m B.Inlines
235+image = try $ do
236+ (orig, src) <- wikiImg
237+ return $ B.image src "" (B.str $ orig)
238+ where
239+ linkSrc = many $ noneOf "|}\n\r\t"
240+ linkDsc = char '|' >> many (noneOf "}\n\r\t")
241+ wikiImg = try $ do
242+ string "{{"
243+ src <- linkSrc
244+ dsc <- option "" linkDsc
245+ string "}}"
246+ return (dsc, src)
247+
248+link :: PandocMonad m => CRLParser m B.Inlines
249+link = try $ do
250+ (orig, src) <- uriLink <|> wikiLink
251+ return $ B.link src "" orig
252+ where
253+ linkSrc = many $ noneOf "|]\n\r\t"
254+ linkDsc :: PandocMonad m => String -> CRLParser m B.Inlines
255+ linkDsc otxt = B.str
256+ <$> (try $ option otxt
257+ (char '|' >> many (noneOf "]\n\r\t")))
258+ linkImg = try $ char '|' >> image
259+ wikiLink = try $ do
260+ string "[["
261+ src <- linkSrc
262+ dsc <- linkImg <|> linkDsc src
263+ string "]]"
264+ return (dsc, src)
265+ uriLink = try $ do
266+ (orig, src) <- uri
267+ return (B.str orig, src)
268+
269+inlineNowiki :: PandocMonad m => CRLParser m B.Inlines
270+inlineNowiki = B.code <$> (start >> manyTill (noneOf "\n\r") end)
271+ where
272+ start = try $ string "{{{"
273+ end = try $ string "}}}" >> (lookAhead $ noneOf "}")
274+
275+placeholder :: PandocMonad m => CRLParser m B.Inlines
276+-- The semantics of the placeholder is basicallly implementation
277+-- dependent, so there is no way to DTRT for all cases.
278+-- So for now we just drop them.
279+placeholder = B.text <$> (try $ string "<<<" >> manyTill anyChar (string ">>>")
280+ >> return "")
281+
282+whitespace :: PandocMonad m => CRLParser m B.Inlines
283+whitespace = (lb <|> regsp) >>= return
284+ where lb = try $ skipMany spaceChar >> linebreak >> return B.space
285+ regsp = try $ skipMany1 spaceChar >> return B.space
286+
287+linebreak :: PandocMonad m => CRLParser m B.Inlines
288+linebreak = newline >> notFollowedBy newline >> (lastNewline <|> innerNewline)
289+ where lastNewline = eof >> return mempty
290+ innerNewline = return B.space
291+
292+symbol :: PandocMonad m => CRLParser m B.Inlines
293+symbol = oneOf specialChars >>= return . B.str . (:[])
294+
295+str :: PandocMonad m => CRLParser m B.Inlines
296+str = let strChar = noneOf ("\t\n " ++ specialChars) in
297+ many1 strChar >>= return . B.str
298+
299+bold :: PandocMonad m => CRLParser m B.Inlines
300+bold = B.strong . mconcat <$>
301+ enclosed (string "**") (try $ string "**") inline
302+
303+italics :: PandocMonad m => CRLParser m B.Inlines
304+italics = B.emph . mconcat <$>
305+ enclosed (string "//") (try $ string "//") inline
306+
307+finalBold :: PandocMonad m => CRLParser m B.Inlines
308+finalBold = B.strong . mconcat <$>
309+ try (string "**" >> many1Till inline endOfParaElement)
310+
311+finalItalics :: PandocMonad m => CRLParser m B.Inlines
312+finalItalics = B.emph . mconcat <$>
313+ try (string "//" >> many1Till inline endOfParaElement)
314+
315+forcedLinebreak :: PandocMonad m => CRLParser m B.Inlines
316+forcedLinebreak = try $ string "\\\\" >> return B.linebreak
test/Tests/Readers/Creole.hsnew file+273
@@ -0,0 +1,273 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Creole (tests) where
3+
4+import Data.Text (Text)
5+import qualified Data.Text as T
6+import Test.Tasty
7+import Tests.Helpers
8+import Text.Pandoc
9+import Text.Pandoc.Arbitrary ()
10+import Text.Pandoc.Builder
11+
12+creole :: Text -> Pandoc
13+creole = purely $ readCreole def{ readerStandalone = True }
14+
15+infix 4 =:
16+(=:) :: ToString c
17+ => String -> (Text, c) -> TestTree
18+(=:) = test creole
19+
20+tests :: [TestTree]
21+tests = [
22+ testGroup "Basic Text Formatting" [
23+ "bold, single line, fully delimited" =:
24+ "only **bold** is bold"
25+ =?> para ("only " <> strong "bold" <> " is bold")
26+ , "italics, single line, fully delimited" =:
27+ "only //this// is in italics"
28+ =?> para ("only " <> emph "this" <> " is in italics")
29+ , "bold in italics, fully delimited" =:
30+ "//**this**// is in bold italics"
31+ =?> para (emph (strong "this") <> " is in bold italics")
32+ , "italics in bold, fully delimited" =:
33+ "**//this//** is in bold italics"
34+ =?> para (strong (emph "this") <> " is in bold italics")
35+
36+ , "escape bold marker" =:
37+ "~**not bold" =?> para "**not bold"
38+ , "escape italics marker" =:
39+ "~//not in italics" =?> para "//not in italics"
40+
41+ , "inline nowiki, simple" =:
42+ "this is {{{**not** ~interpreted}}} at all"
43+ =?> para ("this is " <> code "**not** ~interpreted" <> " at all")
44+ , "inline nowiki, curly braces inside" =:
45+ "this is {{{{{{//including// some `}' chars}}}}}}"
46+ =?> para ("this is " <> code "{{{//including// some `}' chars}}}")
47+
48+ , "placeholder" =:
49+ "foo <<<place holder>>> bar"
50+ =?> para "foo bar"
51+ , "placeholder escaped" =:
52+ "foo ~<<<no place holder>>> bar"
53+ =?> para "foo <<<no place holder>>> bar"
54+ ]
55+ , testGroup "Headers" [
56+ "header level 1, no space, no trailing =" =:
57+ "= Top-Level Header"
58+ =?> header 1 (str "Top-Level Header")
59+ , "header level 1, leading space, trailing =" =:
60+ " = Top-Level Header = "
61+ =?> header 1 (str "Top-Level Header")
62+ , "header level 2, no space, no trailing =" =:
63+ "== Second Level"
64+ =?> header 2 (str "Second Level")
65+ , "header level 2, leading space, no trailing =" =:
66+ " == Second Level"
67+ =?> header 2 (str "Second Level")
68+ , "header level 3, no space, no trailing =" =:
69+ "=== Third"
70+ =?> header 3 (str "Third")
71+ , "header level 3, no space, > 3 trailing =" =:
72+ "=== Third ======="
73+ =?> header 3 (str "Third")
74+ , "header level 4, no space, no trailing =" =:
75+ "==== Fourth Level Heading"
76+ =?> header 4 (str "Fourth Level Heading")
77+ , "header level 4, no space, < 4 trailing =" =:
78+ "==== Fourth Level Heading =="
79+ =?> header 4 (str "Fourth Level Heading")
80+ , "header level 5, no space, no trailing =" =:
81+ "===== Fifth"
82+ =?> header 5 (str "Fifth")
83+ , "header level 6, no space, no trailing =" =:
84+ "====== Sixth"
85+ =?> header 6 (str "Sixth")
86+ ]
87+ , testGroup "Paragraphs" [
88+ "paragraphs: multiple, one line" =:
89+ "first line\n\nanother line\n"
90+ =?> para "first line" <> para "another line"
91+ ]
92+ , testGroup "Lists" [
93+ "unordered list, two entries, one separating space" =:
94+ "* foo\n* bar"
95+ =?> bulletList [ plain "foo", plain "bar" ]
96+ , "unordered list, three entries, one separating space" =:
97+ "* foo\n* bar\n* baz"
98+ =?> bulletList [ plain "foo", plain "bar", plain "baz" ]
99+ , "para followed by, unordered list, two entries, one separating space" =:
100+ "blubber\n* foo\n* bar"
101+ =?> para "blubber" <> bulletList [ plain "foo", plain "bar" ]
102+ , "nested unordered list, one separating space" =:
103+ "* foo\n** bar\n** baz\n* blubb"
104+ =?> bulletList [ plain "foo"
105+ <> bulletList [ plain "bar", plain "baz" ]
106+ , plain "blubb" ]
107+ , "nested many unordered lists, one separating space" =:
108+ ("* foo\n** bar\n*** third\n*** third two\n** baz\n*** third again\n"
109+ <> "**** fourth\n***** fith\n* blubb")
110+ =?> bulletList [ plain "foo"
111+ <> bulletList [ plain "bar"
112+ <> bulletList [ plain "third"
113+ , plain "third two"]
114+ , plain "baz"
115+ <> bulletList [ plain "third again"
116+ <> bulletList [
117+ plain "fourth"
118+ <> bulletList [
119+ plain "fith"
120+ ]
121+ ]
122+ ]
123+ ]
124+ , plain "blubb" ]
125+ , "nested unordered list, mixed separating space" =:
126+ "*foo\n ** bar\n **baz\n * blubb"
127+ =?> bulletList [ plain "foo"
128+ <> bulletList [ plain "bar", plain "baz" ]
129+ , plain "blubb" ]
130+ , "ordered list, two entries, one separating space" =:
131+ "# foo\n# bar"
132+ =?> orderedList [ plain "foo", plain "bar" ]
133+ , "ordered list, three entries, one separating space" =:
134+ "# foo\n# bar\n# baz"
135+ =?> orderedList [ plain "foo", plain "bar", plain "baz" ]
136+ , "para followed by, ordered list, two entries, one separating space" =:
137+ "blubber\n# foo\n# bar"
138+ =?> para "blubber" <> orderedList [ plain "foo", plain "bar" ]
139+ , "nested ordered list, one separating space" =:
140+ "# foo\n## bar\n## baz\n# blubb"
141+ =?> orderedList [ plain "foo"
142+ <> orderedList [ plain "bar", plain "baz" ]
143+ , plain "blubb" ]
144+ , "nested many ordered lists, one separating space" =:
145+ ("# foo\n## bar\n### third\n### third two\n## baz\n### third again\n"
146+ <> "#### fourth\n##### fith\n# blubb")
147+ =?> orderedList [ plain "foo"
148+ <> orderedList [ plain "bar"
149+ <> orderedList [ plain "third"
150+ , plain "third two"]
151+ , plain "baz"
152+ <> orderedList [ plain "third again"
153+ <> orderedList [
154+ plain "fourth"
155+ <> orderedList [
156+ plain "fith"
157+ ]
158+ ]
159+ ]
160+ ]
161+ , plain "blubb" ]
162+ , "nested ordered list, mixed separating space" =:
163+ "#foo\n ## bar\n ##baz\n # blubb"
164+ =?> orderedList [ plain "foo"
165+ <> orderedList [ plain "bar", plain "baz" ]
166+ , plain "blubb" ]
167+ , "mixed nested ordered and unordered lists, one separating space" =:
168+ ("# foo\n** bar\n### third\n### third two\n** baz\n### third again\n"
169+ <> "#### fourth\n***** fith\n# blubb")
170+ =?> orderedList [ plain "foo"
171+ <> bulletList [ plain "bar"
172+ <> orderedList [ plain "third"
173+ , plain "third two"]
174+ , plain "baz"
175+ <> orderedList [ plain "third again"
176+ <> orderedList [
177+ plain "fourth"
178+ <> bulletList [
179+ plain "fith"
180+ ]
181+ ]
182+ ]
183+ ]
184+ , plain "blubb" ]
185+ ]
186+ , testGroup "NoWiki" [
187+ "quoted block, simple" =:
188+ "{{{\nfoo bar\n //baz//\n}}}"
189+ =?> codeBlock "foo bar\n //baz//"
190+ , "quoted block, curly bracket exception" =:
191+ "{{{\nfoo bar\n }}}\nbaz\n }}}\n}}}"
192+ =?> codeBlock "foo bar\n }}}\nbaz\n}}}"
193+ , "forced line breaks" =:
194+ "{{{no break!\\\\here}}} but a break\\\\here!"
195+ =?> para (code "no break!\\\\here" <> " but a break"
196+ <> linebreak <> "here!")
197+ ]
198+ , testGroup "Images and Links" [
199+ "image simple" =:
200+ "{{foo.png}}" =?> para (image "foo.png" "" (str ""))
201+ , "image with alt text" =:
202+ "Image of a bar: {{/path/to/bar.png|A Bar}} look at it!"
203+ =?> para ("Image of a bar: "
204+ <> image "/path/to/bar.png" "" (str "A Bar") <> " look at it!")
205+
206+ , "auto link" =:
207+ "foo http://foo.example.com/bar/baz.html bar"
208+ =?> para ("foo "
209+ <> link "http://foo.example.com/bar/baz.html" ""
210+ (str "http://foo.example.com/bar/baz.html")
211+ <> " bar")
212+ , "escaped auto link" =:
213+ "foo ~http://foo.example.com/bar/baz.html bar"
214+ =?> para ("foo http://foo.example.com/bar/baz.html bar")
215+ , "wiki link simple" =:
216+ "foo [[http://foo.example.com/foo.png]] bar"
217+ =?> para ("foo "
218+ <> link "http://foo.example.com/foo.png" ""
219+ (str "http://foo.example.com/foo.png")
220+ <> " bar")
221+ , "wiki link with name" =:
222+ "foo [[http://foo.example.com/foo.png|my link]] bar"
223+ =?> para ("foo "
224+ <> link "http://foo.example.com/foo.png" ""
225+ (str "my link")
226+ <> " bar")
227+ , "image link" =:
228+ "[[http://foo.example.com/|{{foo.png}}]]"
229+ =?> para (link "http://foo.example.com/" "" (image "foo.png" "" (str "")))
230+ ]
231+ , testGroup "Table" [
232+ "Table with Header" =:
233+ T.unlines [ "|= Foo |= Bar |= Baz |"
234+ , "| One | Two | Three |"
235+ , "| 1 | 2 | 3 |"
236+ , "| A | B | C |"
237+ ]
238+ =?> simpleTable
239+ [plain "Foo", plain "Bar" , plain "Baz"]
240+ [[plain "One", plain "Two" , plain "Three"]
241+ ,[plain "1", plain "2" , plain "3"]
242+ ,[plain "A", plain "B" , plain "C"]]
243+ , "Table without Header" =:
244+ T.unlines [ "| One | Two | Three |"
245+ , "| 1 | 2 | 3 |"
246+ , "| A | B | C |"
247+ ]
248+ =?> simpleTable [mempty]
249+ [[plain "One", plain "Two" , plain "Three"]
250+ ,[plain "1", plain "2" , plain "3"]
251+ ,[plain "A", plain "B" , plain "C"]]
252+ , "Table without Header, no markers at line ends" =:
253+ T.unlines [ "| One | Two | Three"
254+ , "| 1 | 2 | 3"
255+ , "| A | B | C "
256+ ]
257+ =?> simpleTable [mempty]
258+ [[plain "One", plain "Two" , plain "Three"]
259+ ,[plain "1", plain "2" , plain "3"]
260+ ,[plain "A", plain "B" , plain "C"]]
261+ , "Table with Header, with formatting" =:
262+ T.unlines [ "|= **Foo** |= **Bar** |= **Baz** |"
263+ , "|//one// element |//second// elt|Three |"
264+ , "| {{{1}}} | {{{{}}}} | [[link]] |"
265+ ]
266+ =?> simpleTable
267+ [plain $ strong "Foo", plain $ strong "Bar" , plain $ strong "Baz"]
268+ [[plain (emph "one" <> " element"), plain (emph "second" <> " elt")
269+ ,plain "Three"]
270+ ,[plain $ code "1", plain $ code "{}"
271+ ,plain $ link "link" "" (str "link")]]
272+ ]
273+ ]
test/test-pandoc.hs+2
@@ -17,6 +17,7 @@ import qualified Tests.Readers.Org
1717import qualified Tests.Readers.RST
1818import qualified Tests.Readers.Txt2Tags
1919import qualified Tests.Readers.Muse
20+import qualified Tests.Readers.Creole
2021import qualified Tests.Shared
2122import qualified Tests.Writers.AsciiDoc
2223import qualified Tests.Writers.ConTeXt
@@ -63,6 +64,7 @@ tests = testGroup "pandoc tests" [ Tests.Command.tests
6364 , testGroup "Txt2Tags" Tests.Readers.Txt2Tags.tests
6465 , testGroup "EPUB" Tests.Readers.EPUB.tests
6566 , testGroup "Muse" Tests.Readers.Muse.tests
67+ , testGroup "Creole" Tests.Readers.Creole.tests
6668 ]
6769 , testGroup "Lua filters" Tests.Lua.tests
6870 ]